14

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.

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

4

5 回答 5

9

我找到了一种解决方法:

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(...);
})
于 2020-07-20T20:41:45.243 回答
4

您可以使用:@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 一起工作正常。

于 2021-02-26T13:09:12.067 回答
3
root = render(<ComponentUnderTest />);

应该

 root = create(<ComponentUnderTest />);

----完整的代码片段。经过上述更改后,它对我有用

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 />) 
  })
})
于 2019-12-03T16:06:46.267 回答
1

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

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

  • 正如@helloworld 建议的那样,用's替换react-native-testing-library's (谢谢你,先生,它帮助了我)renderreact-test-renderercreate

  • 制作测试函数async,在actwith之前并将函数await传递async给它

最终结果看起来像这样:

test('it updates content on successful call', async () => {
  let root
  await act(async () => {
    root = create(<ComponentUnderTest />) 
  })
})
于 2020-04-26T15:58:33.600 回答
0

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

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

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警告,但我已经分享了这些。这个开放的 GitHub 问题似乎是规范资源。

使用的包:

{
  "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";
于 2021-11-07T09:31:29.657 回答