微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何测试 ErrorBoundary 的回退组件? 编辑

如何解决如何测试 ErrorBoundary 的回退组件? 编辑

我有这个组件:

import React,{ lazy,Suspense } from 'react';
import { ErrorBoundary } from '../ErrorBoundary';

const FALLBACK = <svg aria-label="" data-testid="icon-fallback" viewBox="0 0 21 21" />;

const ERROR = (
    <svg data-testid="icon-notdef" viewBox="0 0 21 21">
        <path d="M0.5,0.5v20h20v-20H0.5z M9.1,10.5l-6.6,6.6V3.9L9.1,10.5z M3.9,2.5h13.2l-6.6,6.6L3.9,2.5z M10.5,11.9l6.6,6.6H3.9 L10.5,11.9z M11.9,10.5l6.6-6.6v13.2L11.9,10.5z" />
    </svg>
);

export const Icon = ({ ariaLabel,ariaHidden,name,size }) => {
    const LazyIcon = lazy(() => import(`../../assets/icons/${size}/${name}.svg`));
    return (
        <i aria-hidden={ ariaHidden }>
            <ErrorBoundary fallback={ ERROR }>
                <Suspense fallback={ FALLBACK }>
                    <LazyIcon aria-label={ ariaLabel } data-testid="icon-module" />
                </Suspense>
            </ErrorBoundary>
        </i>
    );
};

我正在尝试测试传入不存在的 SVG 的条件,进而呈现 <ErrorBoundary /> 回退。 ErrorBoundary 在浏览器中有效,但在我的测试中无效。

这是失败的测试:

test('shows notdef icon',async () => {
    const { getByTestId } = render(<Icon name='doesnt-exist' />);
    const iconModule = await waitFor(() => getByTestId('icon-notdef'));
    expect(iconModule).toBeInTheDocument();
});

我收到此错误消息:

TestingLibraryElementError:无法通过以下方式找到元素:[data-testid="icon-notdef"]”。

如何在我的测试中访问 ErrorBoundary 回退 UI?

编辑

这是 <ErrorBoundary /> 组件的代码

import React,{ Component } from 'react';
import PropTypes from 'prop-types';

export class ErrorBoundary extends Component {
    constructor(props) {
        super(props);
        this.state = {
            error: '',errorInfo: '',hasError: false,};
    }

    static getDerivedStateFromError(error) {
        return { hasError: true,error };
    }

    componentDidCatch(error,errorInfo) {
        console.error({ error,errorInfo });
        this.setState({ error,errorInfo });
    }

    render() {
        const { children,fallback } = this.props;
        const { error,errorInfo,hasError } = this.state;

        // If there is an error AND a fallback UI is passed in…
        if (hasError && fallback) {
            return fallback;
        }

        // Otherwise if there is an error with no fallback UI…
        if (hasError) {
            return (
                <details className="error-details">
                    <summary>There was an error.</summary>
                    <p style={ { margin: '12px 0 0' } }>{error && error.message}</p>
                    <pre>
                        <code>
                            {errorInfo && errorInfo.componentStack.toString()}
                        </code>
                    </pre>
                </details>
            );
        }

        // Finally,render the children.
        return children;
    }
}

ErrorBoundary.propTypes = {
    children: PropTypes.oneOfType([PropTypes.object,PropTypes.array]).isrequired,fallback: PropTypes.node,};

...这是我在测试中得到的 DOM 的完整错误

shows notdef icon

    TestingLibraryElementError: Unable to find an element by: [data-testid="icon-notdef"]

    <body>
      <div>
        <i
          aria-hidden="false"
          class="Icon Icon--sm"
        >
          <span
            aria-label=""
            data-testid="icon-module"
          />
        </i>
      </div>
    </body>

    <html>
      <head />
      <body>
        <div>
          <i
            aria-hidden="false"
            class="Icon Icon--sm"
          >
            <span
              aria-label=""
              data-testid="icon-module"
            />
          </i>
        </div>
      </body>
    </html>Error: Unable to find an element by: [data-testid="icon-notdef"]

最后,我的 SVG 模拟:

import React from 'react';

const SvgrMock = React.forwardRef(
    function mySVG(props,ref) {
        return <span { ...props } ref={ ref } />;
    },);

export const ReactComponent = SvgrMock;
export default SvgrMock;

解决方法

正如评论中所讨论的,模拟很可能是在避免错误。尝试使用抛出错误的新模拟重新模拟 SVG 文件。

// tests that require unmocking svg files
describe('non existent svg',() => {
  beforeAll(() => {
    jest.mock('.svg',() => {
      throw new Error('file not found')
    });
  });
  
  test('shows notdef icon',async () => {
    const { getByTestId } = render(<Icon name='doesnt-exist' />);
    const iconModule = await waitFor(() => getByTestId('icon-notdef'));
    expect(iconModule).toBeInTheDocument();
  });

  afterAll(() => jest.unmock('.svg'))
})

有必要对其进行包装,以确保仅在测试期间 (beforeAll - afterAll) 重新模拟 SVG 文件,以免干扰其余测试。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。