Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >从ReactDOM.render切换到createRoot会导致简单的jest测试失败

从ReactDOM.render切换到createRoot会导致简单的jest测试失败
EN

Stack Overflow用户
提问于 2022-07-17 14:53:20
回答 2查看 738关注 0票数 1

我刚开始学习丹尼尔·欧文( Daniel )的“掌握反应测试驱动的开发”(Mastering React Driven Development),我认为将这些例子转换为React 18应该不难,但我在用Jest转换书中的第一个测试时遇到了麻烦。

这本书不使用create-react-app或任何东西,而是从头开始构建React应用程序,所以我很难找到如何转换代码的相关示例。

如书中所写,在“反应17”中,测试通过了。但是如果我用ReactDOM.render()替换createRoot(),测试就失败了。

我的应用程序目录如下:

代码语言:javascript
运行
AI代码解释
复制
├── package.json
├── package-lock.json
├── src
│   └── Appointment.js
└── test
    └── Appointment.test.js

文件内容如下:

package.json

代码语言:javascript
运行
AI代码解释
复制
{
  "name": "appointments",
  "version": "1.0.0",
  "description": "Appointments project from Mastering React Test-Driven Development.",
  "main": "index.js",
  "scripts": {
    "test": "jest"
  },
  "repository": {
    "type": "git",
    "url": "example.com"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/plugin-transform-runtime": "^7.18.6",
    "@babel/preset-env": "^7.18.6",
    "@babel/preset-react": "^7.18.6",
    "jest": "^28.1.2",
    "jest-environment-jsdom": "^28.1.3"
  },
  "dependencies": {
    "@babel/runtime": "^7.18.6",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "jest": {
    "testEnvironment": "jsdom"
  }
}

src/Appointment.js

代码语言:javascript
运行
AI代码解释
复制
import React from 'react';

export const Appointment = () => <div>Ashley</div>;

test/Appointment.test.js

代码语言:javascript
运行
AI代码解释
复制
import React from 'react';
import ReactDOM from 'react-dom';
// import {createRoot} from 'react-dom/client';

import {Appointment} from '../src/Appointment';

describe('Appointment', () => {
  it("renders the customer's first name.", () => {
    const customer = {firstName: 'Ashley'};
    const component = <Appointment customer={customer} />;
    const container = document.createElement('div');
    document.body.appendChild(container);

    ReactDOM.render(component, container);

    // const root = createRoot(container);
    // root.render(component);

    expect(document.body.textContent).toMatch('Ashley');
  });
});

使用ReactDOM.render(),测试通过,但我得到以下错误:

代码语言:javascript
运行
AI代码解释
复制
  console.error
    Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot

      11 |     document.body.appendChild(container);
      12 |
    > 13 |     ReactDOM.render(component, container);
         |              ^
      14 |
      15 |     expect(document.body.textContent).toMatch('Ashley');
      16 |   });

      at printWarning (node_modules/react-dom/cjs/react-dom.development.js:86:30)
      at error (node_modules/react-dom/cjs/react-dom.development.js:60:7)
      at Object.render (node_modules/react-dom/cjs/react-dom.development.js:29670:5)
      at Object.render (test/Appointment.test.js:13:14)

我查看了如何将ReactDOM.render()转换为createRoot(),并将测试更改为:

代码语言:javascript
运行
AI代码解释
复制
import React from 'react';
// import ReactDOM from 'react-dom';
import {createRoot} from 'react-dom/client';

import {Appointment} from '../src/Appointment';

describe('Appointment', () => {
  it("renders the customer's first name.", () => {
    const customer = {firstName: 'Ashley'};
    const component = <Appointment customer={customer} />;
    const container = document.createElement('div');
    document.body.appendChild(container);

    // ReactDOM.render(component, container);

    const root = createRoot(container);
    root.render(component);

    expect(document.body.textContent).toMatch('Ashley');
  });
});

测试失败如下:

代码语言:javascript
运行
AI代码解释
复制
> appointments@1.0.0 test
> jest

 FAIL  test/Appointment.test.js
  Appointment
    ✕ renders the customer's first name. (9 ms)

  ● Appointment › renders the customer's first name.

    expect(received).toMatch(expected)

    Expected substring: "Ashley"
    Received string:    ""

      17 |     root.render(component);
      18 |
    > 19 |     expect(document.body.textContent).toMatch('Ashley');
         |                                       ^
      20 |   });
      21 | });
      22 |

      at Object.toMatch (test/Appointment.test.js:19:39)
      at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:317:13)
      at runJest (node_modules/@jest/core/build/runJest.js:407:19)
      at _run10000 (node_modules/@jest/core/build/cli/index.js:339:7)
      at runCLI (node_modules/@jest/core/build/cli/index.js:190:3)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        0.979 s, estimated 1 s
Ran all test suites.

如何使用createRoot()通过这个测试?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-07-17 18:23:39

在进一步挖掘之后,我发现act()可以在React 18中使用,在检查测试断言之前强制呈现。这允许测试在测试失败时立即运行,而无需等待Jest的done()超时。

在Jest配置中,globals.IS_REACT_ACT_ENVIRONMENT必须设置为true。这里我更新了package.json

package.json

代码语言:javascript
运行
AI代码解释
复制
...
  "jest": {
    "testEnvironment": "jsdom",
    "globals": {
      "IS_REACT_ACT_ENVIRONMENT": true
    }
  }
...

然后,可以更新测试以使用来自act()react-dom/test-utils

代码语言:javascript
运行
AI代码解释
复制
import React from 'react';
import {createRoot} from 'react-dom/client';
import {act} from 'react-dom/test-utils';

import {Appointment} from '../src/Appointment';

describe('Appointment', () => {
  it("renders the customer's first name.", () => {
    const customer = {firstName: 'Ashley'};
    const component = <Appointment customer={customer} />;
    const container = document.createElement('div');
    document.body.appendChild(container);

    const root = createRoot(container);

    act(() => root.render(component));

    expect(document.body.textContent).toMatch('Ashley');
  });
});

资源:

https://reactjs.org/docs/test-utils.html#act

  • Setting

票数 1
EN

Stack Overflow用户

发布于 2022-07-17 15:07:41

当您调用ReactDOM.render时,render 17将立即呈现

代码语言:javascript
运行
AI代码解释
复制
const App = () => {
    return 'foo';
};

ReactDOM.render(<App />, document.querySelector('.react'));
console.log(document.querySelector('.react').textContent);
代码语言:javascript
运行
AI代码解释
复制
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div class='react'></div>

相反,Reactive18没有,它只在完成任何其他代码(通常是几毫秒后)之后执行呈现工作:

代码语言:javascript
运行
AI代码解释
复制
const App = () => {
    return 'foo';
};

ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
console.log(document.querySelector('.react').textContent.trim());
代码语言:javascript
运行
AI代码解释
复制
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div class='react'></div>

这种差异是看不见的,但是会导致测试失败,因为在expect运行时呈现还没有发生。

一个选项是use the callback form of the test,这样您就可以在呈现发生后调用expect

代码语言:javascript
运行
AI代码解释
复制
it("renders the customer's first name.", (done) => {
    const component = <Appointment customer={ { firstName: 'Ashley' } } />;
    const container = document.body.appendChild(document.createElement('div'));
    createRoot(container).render(component);
    setTimeout(() => {
        expect(document.body.textContent).toMatch('Ashley');
        done();
    });
});

代码语言:javascript
运行
AI代码解释
复制
const App = () => {
    return 'foo';
};

ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
setTimeout(() => {
    console.log(document.querySelector('.react').textContent.trim());
});
代码语言:javascript
运行
AI代码解释
复制
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div class='react'></div>

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73015903

复制
相关文章
React团队是如何测试并发特性的
当启用「并发特性」后,React会从「同步更新」变为「异步、带优先级、可中断的更新」。
公众号@魔术师卡颂
2022/11/22
1.4K0
从库mysqldump会导致复制中断
ERROR NO 是1756,而且只是 Slave_SQL_Running 停了。
老叶茶馆
2020/08/31
1.6K0
【自动化测试】【Jest-Selenium】(03)—— Jest 异步测试
在JavaScript中执行异步代码是很常见的。当你有以异步方式运行的代码时,Jest 需要知道当前它测试的代码是否已完成,然后它可以转移到另一个测试。
WEBJ2EE
2020/10/09
1.4K0
【自动化测试】【Jest-Selenium】(03)—— Jest 异步测试
如何帮助测试团队从稳态切换到敏态
最近正好要交付一个客户培训,于是出了个新的大纲。并不是说一定要从稳态到敏态来切换,也不存在所谓的最佳实践照着做就敏态了,但是面对当下的交付变化,如果还想找到自己的位置,那么适应前后的变化是必须的,甭管对不对,至少能够跟上。
TestOps
2022/04/07
2550
如何帮助测试团队从稳态切换到敏态
为什么Kubernetes从节点会join失败
有段时间没有鼓捣Kubernetes了,今天重置Kubernetes集群后,slave节点不能加入master节点了,我把问题和解决方案分享给大家。
jinjunzhu
2022/08/23
1K0
为什么Kubernetes从节点会join失败
【自动化测试】【Jest-Selenium】(01)—— Jest 入门
按照软件工程自底而上的概念,前端测试一般分为单元测试(Unit Testing )、集成测试(Integration Testing)和端到端测试(E2E Testing)。
WEBJ2EE
2020/09/24
1.9K0
vue单元测试-Jest
顾翔老师开发的bugreport2script开源了,希望大家多提建议。文件在https://github.com/xianggu625/bug2testscript,
顾翔
2019/12/12
1.1K0
vue单元测试-Jest
前端单元测试之Jest
关于前端单元测试的好处自不必说,基础的介绍和知识可以参考之前的博客链接:React Native单元测试。在软件的测试领域,测试主要分为:单元测试、集成测试和功能测试。
xiangzhihong
2022/11/30
2.8K0
用 Jest 进行 JavaScript 测试[每日前端夜话0xB6]
在技术术语中测试意味着检查我们的代码是否符合某些预期。例如:给定一些输入,一个名为“transformer”的函数应返回预期的输出。
疯狂的技术宅
2019/09/04
2.8K0
用 Jest 进行 JavaScript 测试[每日前端夜话0xB6]
React 18 用 createRoot 替换 render
React 18 提供了两个 root API,被称之为 Legacy Root API 和 New Root API:
桃翁
2021/09/09
3K0
如何升级到 React 18发布候选版
上周 react 官网 发布了 react@rc 版本,该版本是候选版本(Release Candidate),这意味 API 已经基本稳定,跟最终版本不会有太大差别,官网也发布博客《如何升级到 react18 RC 版本》,鼓励大家尝试升级,所以我们可以在项目组中使用了!下面内容来自是官方文档的翻译。
狂奔滴小马
2022/03/30
2.4K0
如何升级到 React 18发布候选版
初尝 Jest 单元测试
最近的几次发布都犯了小错,都是缺乏或者忽视了测试所导致的。通常来说,一个新功能上线的时候,开发和测试都投入比较多,各项测试都是比较全面的。然而,发布上线也并非意味着不再有bug或者修改。那这时候问题来
IMWeb前端团队
2017/12/29
1.8K0
初尝 Jest 单元测试
node.js测试jest入门
全局安装测试工具 jest npm install jest -g 创建hellow.js功能文件,导出功能函数 //hellow.js //功能:创建一个变量,变量值是hellow const hellow='hellow tom'; module.exports= hellow; 功能文件同级目录创建test文件夹,创建index.spec.js文件 //index.spec.js //测试文件,测试功能文件功能 test('测试 hellow.js',()=>{ const result=requ
刘嘿哈
2022/10/25
9930
你必须了解的 React 18 新特性
由于更新经常包括完全改变特性的修改,甚至删除某些特性并添加其他特性,一些开发人员可能会发现很难在不同版本的库之间进行转换。最好使用库的最新版本,以获得尽可能好的性能。
用户8921923
2022/10/24
3.6K0
你必须了解的 React 18 新特性
【自动化测试】【Jest-Selenium】(02)—— Jest 匹配器
Use .toBe to compare primitive values or to check referential identity of object instances. It calls Object.is to compare values, which is even better for testing than === strict equality operator.
WEBJ2EE
2020/10/09
8390
初尝 Jest 单元测试
最近的几次发布都犯了小错,都是缺乏或者忽视了测试所导致的。通常来说,一个新功能上线的时候,开发和测试都投入比较多,各项测试都是比较全面的。然而,发布上线也并非意味着不再有bug或者修改。那这时候问题来了,有些修改, 我们会以为很简单,从而放松警惕,偷懒也罢,没有精力也罢,简单验证之后便匆匆发布了。此时,有可能不经意的改动对其它功能造成了影响,bug复bug, bug何其多呀。
IMWeb前端团队
2019/12/04
1.6K0
Jest实战:单元测试与服务测试
一名好的大前端开发人员,一定是一名好的“配置工程师”(滑稽脸)。而最近刚到团队,被安排给 vemoJS 和 cloudbase-cli 写测试用例,并且要保证覆盖率!
心谭博客
2020/04/21
3.4K0
React.createElement和ReactDom.render方法简单思路
实际上,JSX 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖,因此,使用 JSX 可以完成的任何事情都可以通过纯 JavaScript 完成。 例如,用 JSX 编写的代码: class Hello extends React.Component { render() { return <div>Hello {this.props.toWhat}</div>; } } ReactDOM.render( <H
刘嘿哈
2022/10/25
2880
使用Jest测试原生TypeScript项目
问题:我怎么才能收到你们公众号平台的推送文章呢? 最近写了一个wechat-colorpicker小项目。 主要是为了练习下TS。既然写了一个小库,我就想着顺便学下如何写测试吧,这是一件蛮有意思的事情。 从选型到搭建环境,前前后后用了近2个小时。不得不说一个合格的前端必然是一个合格的配置工程师。再次列举下,这个项目中所需要搭建配置的工具。 webpack.config 自动编译ts+css tsconfig.config ts的配置文件 tslint.json tslint的配置文件 jest.config
企鹅号小编
2018/02/09
2.9K0
使用Jest测试原生TypeScript项目
点击加载更多

相似问题

使用jest对vue组件进行简单测试会导致失败

174

从shell脚本运行jest测试-失败会导致脚本退出

21

如何将ReactDOM.render转换为createRoot?

14

共享运算符导致Jest测试失败。

10

为什么Jest测试套件会随机失败?

280
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档