最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Jest Act warning with useEffect - Stack Overflow

programmeradmin4浏览0评论

I have Jest set up using react-testing-library and I have a test written as so:

describe("Some Functionality", () => {
it("Should add a given product to the cart state", async () => {
    const state = getMockState();
    
    const { result: { getByTestId }, store } = deepRender(
        <ProductView />,
        { initialState: state });

    act(() => {
        fireEvent.click(getByTestId("add-to-cart-btn"));
    })

    const newState = store.getState() as RootState;
    expect(someassertion);
});
});

My test runs and passes but I continue to get an act warning that an update to the state wasn't wrapped in an act function.

I assume since the ponent has a useEffect firing on load that is changing the state that the render method needs to be wrapped in an act block also but doing this:

    act(() => {
        const { result: { getByTestId }, store } = deepRender(
             <ProductView />,
             { initialState: state });

        fireEvent.click(getByTestId("add-to-cart-btn"));
    })

Doesn't get rid of the warnings and also makes the store from the result unavailable to the assertions outside the act block. Is there any way to format this to mitigate the act() warnings?

in response to a question below, the ponent's useEffect is:

useEffect(() => {
    if (something) {
        getDetails(something)
        .then(getVariances)
        .then(setProductVariances);
    }
}, []);

This sets a productVariances state value using useState

I have Jest set up using react-testing-library and I have a test written as so:

describe("Some Functionality", () => {
it("Should add a given product to the cart state", async () => {
    const state = getMockState();
    
    const { result: { getByTestId }, store } = deepRender(
        <ProductView />,
        { initialState: state });

    act(() => {
        fireEvent.click(getByTestId("add-to-cart-btn"));
    })

    const newState = store.getState() as RootState;
    expect(someassertion);
});
});

My test runs and passes but I continue to get an act warning that an update to the state wasn't wrapped in an act function.

I assume since the ponent has a useEffect firing on load that is changing the state that the render method needs to be wrapped in an act block also but doing this:

    act(() => {
        const { result: { getByTestId }, store } = deepRender(
             <ProductView />,
             { initialState: state });

        fireEvent.click(getByTestId("add-to-cart-btn"));
    })

Doesn't get rid of the warnings and also makes the store from the result unavailable to the assertions outside the act block. Is there any way to format this to mitigate the act() warnings?

in response to a question below, the ponent's useEffect is:

useEffect(() => {
    if (something) {
        getDetails(something)
        .then(getVariances)
        .then(setProductVariances);
    }
}, []);

This sets a productVariances state value using useState

Share Improve this question edited Dec 23, 2020 at 12:26 tcurtis asked Dec 23, 2020 at 10:59 tcurtistcurtis 851 silver badge7 bronze badges 5
  • fireEvent uses act internally? – evolutionxbox Commented Dec 23, 2020 at 11:18
  • 2 What is the useEffect doing? Give a minimal reproducible example. – jonrsharpe Commented Dec 23, 2020 at 11:28
  • @jonrsharpe Added some details above – tcurtis Commented Dec 23, 2020 at 12:27
  • @evolutionxbox so does that mean its redundant to wrap fireEvent in an act block? – tcurtis Commented Dec 23, 2020 at 12:28
  • And what's getDetails? Are you replacing it with a test double for testing? Again, give a minimal reproducible example. I suspect that one solution would be the deferred pattern, so you control when (and if) that resolves or rejects, as I show in e.g. github./textbook/starter-kit/blob/… – jonrsharpe Commented Dec 23, 2020 at 12:53
Add a ment  | 

2 Answers 2

Reset to default 3

You don't need to wrap render in an act block. You're getting an act warning because there is a state update after the resolution of a promise and so that state update happens outside of an act block. I've generally gotten around this by awaiting on the same promise whose resolution is triggering a state update in my test.

Also, you don't need to wrap fireEvent in an act block either because it uses act internally.

You need to wait for any sideeffects that change the state to resolve, my approach in this cases is to give the ponent a prop for the service that handles this async request and mock it in my test, then "await" on the mock service to resolve.

Heres an example:

it('renders when empty list is passed', async () => {
    const rendered = render(
        <SomeComponent
          someprop={'321'}
          someotherprop={'123'}
          serviceProp={yourServiceMocked}
        />
    );
    // here you would make assertions on your "loading" state
    
    // HERE you await for you promise to resolve
    await act(() => yourServiceMocked);
    
    // here you would make assertions when your state has solved the promise
  });

Hope my oversimplified example helps, I had a hard time finding the solution for this

发布评论

评论列表(0)

  1. 暂无评论