mardi 9 février 2021

Jest test can’t seem to reach the catch() in a dynamic import

I have the following component:

import React, { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';

// Import all icon names
import { ICONS } from 'assets/icons';

// Styles
import css from './index.module.css';

// Empty SVG to fall back to until targeted icon is loaded
const FALLBACK = () => <svg aria-label="" data-testid="icon-fallback" viewBox="0 0 20 20" />;

// Default acceptable icon weights
const WEIGHTS = ['light', 'heavy'];

/**
 * SVG Icons
 *
 * @param {string} ariaLabel  aria-label for the icon. Used primarily when the icon is not accompanied by descriptive text.
 * @param {bool}   ariaHidden Should we hide the icon from assistive devices? Used when icon is not accompanied by descriptive text.
 * @param {string} name       Name of the icon to load. Must match a name in the ICONS array above.
 * @param {weight} weight     Icon weight. Can be light or heavy.
 * @returns {Node}
 */
const Icon = ({
    ariaLabel,
    ariaHidden,
    name,
    weight,
}) => {
    // When !isMounted don’t update the icon.
    const isMounted = useRef(true);
    const [icon, setIcon] = useState(null);

    useEffect(() => {
        if (
            isMounted.current
            && ICONS.includes(name)
            && WEIGHTS.includes(weight)
        ) {
            /* Use dynamic import to get corresponding icon as a module */
            import(`assets/icons/${weight}/${name}.svg`)
                .then(module => {
                    setIcon(module);
                })
                .catch(() => {
                    console.error(`Icon with name: ${name} not found!`);
                    setIcon(null);
                });
        }
    }, [name, weight]);

    useEffect(() => {
        return () => { isMounted.current = false; };
    }, []);

    const Component = icon ? icon.default : icon;

    return (
        <i
            aria-hidden={ariaHidden}
            className={css.Icon}
        >
            {
                icon ? (
                    <Component aria-labelledby={ariaLabel} data-testid="icon-module" />
                ) : (
                    <FALLBACK />
                )
            }
        </i>
    );
};

Icon.defaultProps = {
    ariaLabel: '',
    ariaHidden: false,
    name: 'picture',
    weight: 'light',
};

Icon.propTypes = {
    /**
    * If the icon is being displayed without accompanying text (like in a link or button), use `ariaLabel` to add descriptive text for screen readers
    */
    ariaLabel: PropTypes.string,
    /**
    * If the icon is accompanied by descriptive text (like in a link or button) use `ariaHidden` to hide the icon from screen readers.
    */
    ariaHidden: PropTypes.bool,
    /**
    * The name of the icon to use.
    */
    name: PropTypes.oneOf(ICONS),
    /**
    * Size of the icon
    */
    weight: PropTypes.oneOf(WEIGHTS),
};

export { Icon };

I’m trying to cover the catch() part of the dynamic import with a test, but I can’t seem to get the test to reach the catch, even when I pass in a faulty icon name.

My test:

import React from 'react';
import { render, waitFor } from '@testing-library/react';
import {Icon} from '.';

test.only('loads fallback icon', async () => {
    const { getByTestId } = render(<Icon name="bloop" />);
    const iconModule = await waitFor(() => getByTestId('icon-fallback'));
    expect(iconModule).toBeInTheDocument();
});

What gives?

Aucun commentaire:

Enregistrer un commentaire