【问题标题】:Jest Act warning with useEffect带有 useEffect 的 Jest Act 警告
【发布时间】:2021-04-02 00:17:16
【问题描述】:

我使用 react-testing-library 设置了 Jest,并且我有一个这样编写的测试:

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

我的测试运行并通过了,但我继续收到一个动作警告,指出对状态的更新未包含在动作函数中。

我假设由于组件在加载时触发了 useEffect ,这正在改变渲染方法需要包装在一个动作块中的状态,但这样做:

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

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

不会消除警告,还会使结果中的存储对 act 块之外的断言不可用。有什么方法可以格式化它以减轻 act() 警告?

针对下面的一个问题,组件的useEffect是:

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

这使用 useState 设置 productVariances 状态值

【问题讨论】:

  • fireEvent 内部使用行为?
  • useEffect 是做什么的?给minimal reproducible example
  • @jonrsharpe 在上面添加了一些细节
  • @evolutionxbox 那么这是否意味着将fireEvent 包装在一个动作块中是多余的?
  • 那么getDetails 是什么?您是否将其替换为测试替身进行测试?再次,给minimal reproducible example。我怀疑一种解决方案是延迟模式,因此您可以控制何时(以及是否)解决或拒绝,正如我在例如github.com/textbook/starter-kit/blob/…

标签: javascript reactjs jestjs react-testing-library


【解决方案1】:

您需要等待任何改变状态的副作用来解决,在这种情况下,我的方法是为组件提供一个处理此异步请求的服务的道具,并在我的测试中模拟,然后在模拟上“等待”服务来解决。

这是一个例子:

it('renders when empty list of smartfields 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
  });

希望我过于简化的示例有所帮助,我很难找到解决方案

【讨论】:

    【解决方案2】:

    您无需将render 包装在act 块中。你会收到一个行为警告,因为在承诺解决之后有一个状态更新,所以状态更新发生在一个行为块之外。我通常通过awaiting 解决这个问题,该承诺的解决方案在我的测试中触发了状态更新。

    此外,您也不需要将 fireEvent 包装在 act 块中,因为它在内部使用 act。

    【讨论】:

    • 有趣。我想测试:`useEffect(() => { storage.readObject('has_accepted_cookie').then((value) => setVisible(!value)) }, [])`,我怎么能在这里等待?这对我来说似乎是不可能的。
    • 您必须模拟出任何 storage.readObject ,以便您可以在测试中获得对其返回值的引用
    猜你喜欢
    • 2019-08-06
    • 2023-01-31
    • 2022-08-18
    • 1970-01-01
    • 2020-02-21
    • 2021-09-10
    • 2021-07-12
    • 2020-03-24
    • 2021-04-23
    相关资源
    最近更新 更多