模拟React.Suspense,同时保留其余的React

时间:2019-01-02 17:10:22

标签: javascript reactjs unit-testing jestjs enzyme

我正在尝试为使用Jest的组件编写React.Suspense单元测试。

正在测试的组件模块的简化版本:

MyComponent.js

import React from 'react';

export default () => <h1>Tadaa!!!</h1>;

MySuspendedComponent.js

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

export default () => (
    <Suspense fallback={<div>Loading…</div>}>
        <MyComponent />
    </Suspense>
);

天真的,在我的第一次尝试中,我编写了一个使用Enzyme来挂起挂起的组件的单元测试:

MySuspendedComponent.test.js

import React from 'react';
import { mount } from 'enzyme';
import MySuspendedComponent from './MySuspendedComponent';

test('the suspended component renders correctly', () => {
    const wrapper = mount(<MySuspendedComponent />);
    expect(wrapper.html()).toMatchSnapshot();
});

这会导致测试崩溃并显示错误消息:

  

错误:酶内部错误:标记为13的未知节点

在网络上搜索错误消息时,我发现这很可能是由于酶尚未准备好渲染Suspense(至今)引起的。

如果我使用shallow而不是mount,错误消息将变为:

  

永久违反:ReactDOMServer尚不支持Suspense

我的下一个尝试是使用虚拟的传递组件来模拟Suspense,如下所示:

MySuspendedComponent.test.js

import React from 'react';
import { mount } from 'enzyme';
import MySuspendedComponent from './MySuspendedComponent';

jest.mock('react', () => {
    const react = require.requireActual('react');
    return () => ({
        ...react,
        Suspense({ children }) {
            return children;
        }
    });
});

test('the suspended component renders correctly', () => {
    const wrapper = mount(<MySuspendedComponent />);
    expect(wrapper.html()).toMatchSnapshot();
});

想法是对React模块进行模拟实现,其中包含React库中的所有实际代码,只有Suspense被模拟函数代替。

Jest documentation所述,我已将此模式与requireActual一起使用,在模拟除React以外的其他模块时,已在其他单元测试中成功使用,但是在React中,它不起作用。

我现在得到的错误是:

  

TypeError:((($ _ $ w(...), react)||($ $ w(...),_load_react(...)))。default.createElement不是功能

...我认为这是由于我的模拟技巧之后无法使用React的原始实现引起的。

如何在保持其余React库其余部分不变的情况下模拟Suspense?

还是有另一种更好的方法来测试悬挂的组件?

1 个答案:

答案 0 :(得分:1)

解决方案不是使用对象扩展来导出原始的React模块,而是简单地覆盖Suspense属性,如下所示:

MySuspendedComponent.test.js

import React from 'react';
import { mount } from 'enzyme';
import MySuspendedComponent from './MySuspendedComponent';

jest.mock('react', () => {
    const React = jest.requireActual('react');
    React.Suspense = ({ children }) => children;
    return React;
});

test('the suspended component renders correctly', () => {
    const wrapper = mount(<MySuspendedComponent />);
    expect(wrapper.html()).toMatchSnapshot();
});

这将按预期创建以下快照:

MySuspendedComponent.test.js.snap

exports[`the suspended component renders correctly 1`] = `"<h1>Tadaa!!!</h1>"`;