带有 useEffect 的 Jest Act 警告

Posted

技术标签:

【中文标题】带有 useEffect 的 Jest Act 警告【英文标题】:Jest Act warning with useEffect 【发布时间】: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/… 【参考方案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 ,以便您可以在测试中获得对其返回值的引用

以上是关于带有 useEffect 的 Jest Act 警告的主要内容,如果未能解决你的问题,请参考以下文章

使用 useEffect 和 jest.useFakeTimers() 进行测试

useEffect 钩子没有被 jest.spyOn 嘲笑

使用 SetTimeout 测试自定义钩子,使用 Jest 测试 useEffect

如何使用 jest/enzyme 测试 useEffect 与 useDispatch 挂钩?

使用 Jest 和酶时如何在 React.useEffect 钩子上获得线路覆盖?

react-native-testing-library:如何使用 act 测试 useEffect