Testing with React's Jest and Enzyme when async componentDidMount
Asked Answered
A

6

21
  • react:16.3.0-alpha.1
  • jest: "22.3.0"
  • enzyme: 3.3.0
  • typescript: 2.7.1

code:

class Foo extends React.PureComponent<undefined,undefined>{
   bar:number;
   async componentDidMount() {
     this.bar = 0;
     let echarts = await import('echarts'); // async import
     this.bar = 100;
   }
}

test:

describe('...', () => {
  test('...', async () => {
    const wrapper = shallow(<Foo/>);
    const instance = await wrapper.instance();
    expect(instance.bar).toBe(100);
  });
});

Error:

Expected value to be:
  100
Received:
  0
Approval answered 22/3, 2018 at 3:16 Comment(0)
A
27

Solution:

1: use the async/await syntax.

2: Use mount (no shallow).

3: await async componentLifecycle.

For ex:

    test(' ',async () => {
      const wrapper = mount(
         <Foo />
      );
      await wrapper.instance().componentDidMount();
    })
Approval answered 28/3, 2018 at 7:23 Comment(3)
This is not what you were trying to check in your question posted above.My answer is the right solution to your problem.Gynecologist
This will cause the method to run twice.Pluvious
@Gynecologist has the right solution. This will run "componentDidMount" twice. Any await after mounting will probably "solve" the problem, but it's not the right solution in my opinion.Patrica
G
17

Something like this should work for you:-

 describe('...', () => {
   test('...', async () => {
     const wrapper = await mount(<Foo/>);
     expect(wrapper.instance().bar).toBe(100);
   });
 });
Gynecologist answered 22/3, 2018 at 13:20 Comment(2)
This was the best solution for me, particularly as I didn't want to shallow mountDelanadelancey
Indeed; and if you have a setState in the component's didMount, you'll need to add wrapper.update(); before the expect.Sallyanne
C
4

Try this:

it('should do something', async function() {
  const wrapper = shallow(<Foo />);
  await wrapper.instance().componentDidMount();
  app.update();
  expect(wrapper.instance().bar).toBe(100);
});
Crysta answered 25/5, 2018 at 5:48 Comment(4)
After looking through google on this problem and trying to implement async componentDidMount through mount's enzyme. And "mount" way is not fit for react native project - I had a lot mistakes. This method helped me. And you don't need to install jsdom and use mount. "react": "16.4.1", "react-native": "0.56.0", "enzyme": "^3.4.4", "jest": "23.5.0"Clump
what's app here?Arjan
@Arjan I think wrapper.update() was intended. --refLongcloth
btw, await won't do anything there unless your componentDidMount() returns a promiseLongcloth
B
4

None of the solutions provided here fixed all my issues. At the end I found https://medium.com/@lucksp_22012/jest-enzyme-react-testing-with-async-componentdidmount-7c4c99e77d2d which fixed my problems.

Summary

function flushPromises() {
    return new Promise(resolve => setImmediate(resolve));
}

it('should do someting', async () => {
    const wrapper = await mount(<Foo/>);
    await flushPromises();

    expect(wrapper.instance().bar).toBe(100);
});
Bibbie answered 11/10, 2019 at 9:36 Comment(1)
For anybody looking at this, use setTimeout instead of setImmediate.Purvis
J
0

Your test also needs to implement async, await.
For ex:

  it('should do something', async function() {
    const wrapper = shallow(<Foo />);
    const result = await wrapper.instance();
    expect(result.bar).toBe(100);
  });
Joyejoyful answered 22/3, 2018 at 6:52 Comment(3)
edited, have you tried the await when you execute the instance?, The await basically operates on a promiseJoyejoyful
if you can share your complete testJoyejoyful
I don't think .instance() returns a promise, so I don't think await is doing anything there. TypeError: wrapper.instance(...).then is not a functionLongcloth
G
0

If you are using jest.useFakeTimers(); then you need to use

await jest.runAllTimersAsync();

instead of the flushPromises solution

Gabbro answered 5/9, 2023 at 22:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.