【问题标题】:react-native-testing-library: how to test useEffect with actreact-native-testing-library:如何使用 act 测试 useEffect
【发布时间】:2020-03-26 14:31:39
【问题描述】:

我正在使用 react-native-testing-library 来测试我的 react-native 组件。 我有一个组件(为了这篇文章的目的,它已经被过度简化了):

export const ComponentUnderTest = () => {

 useEffect(() => {
   __make_api_call_here_then_update_state__
 }, [])

 return (
   <View>
     __content__goes__here
   </View>
 )
} 

这是我的(简化版)component.spec.tsx

import { render, act } from 'react-native-testing-library';
import { ComponentUnderTest } from './componentundertest.tsx';

test('it updates content on successful call', () => {
   let root;
   act(() => {
      root = render(<ComponentUnderTest />); // this fails with below error message
   });    
   expect(...);
})

现在当我运行这段代码时,我得到了这个错误: Can't access .root on unmounted test renderer

我什至现在都不知道这个错误消息是什么意思。我按照react-native-testing-library 中的文档了解如何使用act and useEffect 进行测试。

任何帮助将不胜感激。谢谢

【问题讨论】:

    标签: react-native use-effect act react-native-testing-library


    【解决方案1】:

    我找到了解决方法:

    import { render, waitFor } from 'react-native-testing-library';
    import { ComponentUnderTest } from './componentundertest.tsx';
    
    test('it updates content on successful call', async () => {
       const root = await waitFor(() =>
           render(<ComponentUnderTest />);
       );   
       expect(...);
    })
    

    【讨论】:

    • 这不行,时间过去了,什么也没有发生。
    【解决方案2】:
    root = render(<ComponentUnderTest />);
    

    应该是

     root = create(<ComponentUnderTest />);
    

    ----全码sn-p。经过上述更改后它对我有用

    import React, { useState, useEffect } from 'react'
    import { Text, View } from 'react-native'
    import { render, act } from 'react-native-testing-library'
    import { create } from 'react-test-renderer'
    
    export const ComponentUnderTest = () => {
      useEffect(() => {}, [])
    
      return (
        <View>
          <Text>Hello</Text>
        </View>
      )
    }
    
    test('it updates content on successful call', () => {
      let root
      act(() => {
        root = create(<ComponentUnderTest />) 
      })
    })
    

    【讨论】:

    • 感谢您的回答。但是您从哪个库导入createreact-native-testing-library好像没有这样的导出成员
    • react-test-renderer(它已经是 react-native-testing-library 的依赖项)
    • 我按照你的建议使用了create。不幸的是,我遇到了同样的错误。一些类似的错误/问题(在 react,不是 react-native,具有相应的 @testing-library/react)报告了未匹配版本的问题。 (见github.com/testing-library/react-hooks-testing-library/issues/…)我不知道什么是适合我的版本
    • 我已经用完整的代码更新了我的答案。它在我使用 create 时有效。使用渲染我得到同样的错误
    • 失败了不是吗?我们希望渲染使用查询:getByRolegetByTestID 等。除非有其他方法可以找到使用 fireEvents 的元素,否则在这种情况下我看不到 create 有多大用处。我在create 上也找不到太多文档或示例。
    【解决方案3】:

    您可以使用:@testing-library/react-native

    例子:

    import { cleanup, fireEvent, render, debug, act} from '@testing-library/react-native'
    
    afterEach(() => cleanup());
    
    test('given correct credentials, gets response token.', async () => {
        const { debug, getByPlaceholderText, getByRole } = await render(<Component/>);
    
        await act( async () => {
                const emailInput = getByPlaceholderText('Email');;
                const passwordInput = getByPlaceholderText('Password');
                const submitBtn = getByRole('button', {name: '/submitBtn/i'});
    
                fireEvent.changeText(emailInput, 'email');
                fireEvent.changeText(passwordInput, 'password');
                fireEvent.press(submitBtn);
        });
    });
    
    

    也应该与 useEffect 一起使用,但我自己还没有测试过。与 useState 一起工作正常。

    【讨论】:

    • 如果你只需要在第一次渲染后等待useEffect 被触发一次,你会用什么包裹act
    【解决方案4】:

    以下步骤解决了我的情况:

    • 升级Reactreact-test-renderer 版本到16.9 或更高版本,支持act 内部的async 函数(据我所知,这两个包需要是相同的版本)

      李>
    • 按照@helloworld 的建议,将react-native-testing-libraryrender 替换为react-test-renderercreate(谢谢您,先生,它帮助了我)

    • 创建测试函数async,在act 前面加上await,并传递一个async 函数给它

    最终结果如下所示:

    test('it updates content on successful call', async () => {
      let root
      await act(async () => {
        root = create(<ComponentUnderTest />) 
      })
    })
    

    【讨论】:

    • 你是如何与 getTestById 等结合起来的,因为 create 没有它们,我相信它很浅。
    • const { getByTestId } = await waitFor(() => { return render(component); });
    【解决方案5】:

    我使用useEffect 测试异步组件并触发setState 重新渲染的方法是正常设置测试用例,但使用waitFor or findBy 阻止断言,直到组件使用获取的重新渲染数据。

    这是一个简单的可运行示例:

    import React, {useEffect, useState} from "react";
    import {FlatList, Text} from "react-native";
    import {render} from "@testing-library/react-native";
    
    const Posts = () => {
      const [posts, setPosts] = useState(null);
    
      useEffect(() => {
        const url = "https://jsonplaceholder.typicode.com/posts";
        fetch(url).then(res => res.json()).then(setPosts);
      }, []);
    
      return !posts ? <Text>loading</Text> : <FlatList
        testID="posts"
        data={posts}
        renderItem={({item: {id, title}, index}) =>
          <Text testID="post" key={id}>{title}</Text>
        }
      />;
    };
    
    describe("Posts", () => {
      beforeEach(() => {
        global.fetch = jest.fn(url => Promise.resolve({
          ok: true,
          status: 200,
          json: () => Promise.resolve([
            {id: 1, title: "foo title"},
            {id: 2, title: "bar title"},
          ])
        }));
      });
    
      it("should fetch posts", async () => {
        const {findAllByTestId} = render(<Posts />);
        const posts = await findAllByTestId("post", {timeout: 500});
        expect(posts).toHaveLength(2);
        expect(posts[0]).toHaveTextContent("foo title");
        expect(posts[1]).toHaveTextContent("bar title");
        expect(fetch).toHaveBeenCalledTimes(1);
      });
    });
    

    这并没有给我任何act 警告,但我已经分享了这些警告。 This open GitHub issue 似乎是规范资源。

    使用的包:

    {
      "dependencies": {
        "react": "^17.0.2",
        "react-dom": "^17.0.2",
        "react-native": "^0.64.0",
        "react-native-web": "^0.15.6"
      },
      "devDependencies": {
        "@babel/core": "^7.13.15",
        "@testing-library/jest-native": "^4.0.1",
        "@testing-library/react-native": "^7.2.0",
        "babel-jest": "^26.6.3",
        "jest": "^26.6.3",
        "metro-react-native-babel-preset": "^0.65.2",
        "react-test-renderer": "^17.0.2"
      }
    }
    

    在 Jest 配置中:

    setupFilesAfterEnv: ["@testing-library/jest-native/extend-expect"],
    

    对于.toHaveTextContent 匹配器。或者您可以使用导入:

    import "@testing-library/jest-native/extend-expect";
    

    【讨论】:

      猜你喜欢
      • 2023-04-04
      • 2020-05-10
      • 1970-01-01
      • 2019-08-29
      • 2021-11-30
      • 2019-05-21
      • 1970-01-01
      • 2019-11-11
      • 2019-10-30
      相关资源
      最近更新 更多