javascript - Mocking out React.Suspense Whilst Leaving the Rest of React Intact - Stack Overflow

I'm trying to write a Jest unit test for a ponent that uses React.Suspense.Simplified versions of

I'm trying to write a Jest unit test for a ponent that uses React.Suspense.

Simplified versions of my ponent modules under test:

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>
);

Naïvely, in my first attempt, I wrote a unit test that uses Enzyme to mount the suspended ponent:

MySuspendedComponent.test.js

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

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

This causes the test to crash with the error message:

Error: Enzyme Internal Error: unknown node with tag 13

Searching for the error message on the web, I found that this is most likely caused by Enzyme not being ready to render Suspense (yet).

If I use shallow instead of mount, the error message changes to:

Invariant Violation: ReactDOMServer does not yet support Suspense

My next attempt was to mock out Suspense with a dummy pass-through ponent, like this:

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 ponent renders correctly', () => {
    const wrapper = mount(<MySuspendedComponent />);
    expect(wrapper.html()).toMatchSnapshot();
});

The idea is to have a mock implementation of the React module that contains all the actual code from the React library, with only Suspense being replaced by a mock function.

I've used this pattern with requireActual, as described in the Jest documentation, successfully in other unit tests when mocking other modules than React, but with React, it does not work.

The error I get now is:

TypeError: (($_$w(...) , react) || ($$w(...) , _load_react(...))).default.createElement is not a function

…which, I assume, is caused by the original implementation of React not being available after my mocking trick.

How can I mock out Suspense while leaving the rest of the React library intact?

Or is there another, better way to test suspended ponents?

I'm trying to write a Jest unit test for a ponent that uses React.Suspense.

Simplified versions of my ponent modules under test:

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>
);

Naïvely, in my first attempt, I wrote a unit test that uses Enzyme to mount the suspended ponent:

MySuspendedComponent.test.js

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

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

This causes the test to crash with the error message:

Error: Enzyme Internal Error: unknown node with tag 13

Searching for the error message on the web, I found that this is most likely caused by Enzyme not being ready to render Suspense (yet).

If I use shallow instead of mount, the error message changes to:

Invariant Violation: ReactDOMServer does not yet support Suspense

My next attempt was to mock out Suspense with a dummy pass-through ponent, like this:

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 ponent renders correctly', () => {
    const wrapper = mount(<MySuspendedComponent />);
    expect(wrapper.html()).toMatchSnapshot();
});

The idea is to have a mock implementation of the React module that contains all the actual code from the React library, with only Suspense being replaced by a mock function.

I've used this pattern with requireActual, as described in the Jest documentation, successfully in other unit tests when mocking other modules than React, but with React, it does not work.

The error I get now is:

TypeError: (($_$w(...) , react) || ($$w(...) , _load_react(...))).default.createElement is not a function

…which, I assume, is caused by the original implementation of React not being available after my mocking trick.

How can I mock out Suspense while leaving the rest of the React library intact?

Or is there another, better way to test suspended ponents?

Share Improve this question edited Jan 10, 2019 at 16:22 skyboyer 23.8k7 gold badges62 silver badges71 bronze badges asked Jan 2, 2019 at 17:10 Patrick HundPatrick Hund 20.3k12 gold badges71 silver badges95 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

The solution is not to use object spreading to export the original React module, but simply overwriting the Suspense property, like this:

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 ponent renders correctly', () => {
    const wrapper = mount(<MySuspendedComponent />);
    expect(wrapper.html()).toMatchSnapshot();
});

This creates the following snapshot, as expected:

MySuspendedComponent.test.js.snap

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

I needed to test my lazy ponent using Enzyme. Following approach worked for me to test on ponent loading pletion:

const myComponent = React.lazy(() => 
      import('@material-ui/icons')
      .then(module => ({ 
         default: module.KeyboardArrowRight 
      })
   )
);

Test Code ->

    //mock actual ponent inside suspense
    jest.mock("@material-ui/icons", () => { 
        return {
            KeyboardArrowRight: () => "KeyboardArrowRight",
    }
    });
    
    const lazyComponent = mount(<Suspense fallback={<div>Loading...</div>}>
               {<myComponent>}
           </Suspense>);
        
    const ponentToTestLoaded  = await ponentToTest.type._result; // to get actual ponent in suspense
        
    expect(ponentToTestLoaded.text())`.toEqual("KeyboardArrowRight");

This is hacky but working well for Enzyme library.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744780151a4593286.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信