Jest
Jest 概述
Jest是一个领先的JavaScript测试框架,特别适用于React和Node.js环境。由Facebook开发,它以简单的配置、高效的性能和易用性而闻名。Jest支持多种类型的测试,包括单元测试、集成测试和快照测试,后者用于捕获组件或数据结构的状态,以便于后续的比较和验证。Jest自动化模拟依赖项和异步代码测试,提高了测试的可靠性和灵活性。其并行测试执行机制显著加快了测试过程,而交互式监视模式则在开发过程中提供即时反馈。此外,Jest还提供内置的代码覆盖率工具,帮助开发者优化测试范围。因其强大的功能和广泛的社区支持,Jest成为现代JavaScript项目中不可或缺的测试工具。
Jest 环境配置
安装包
1、
jest
:这是 Jest 测试框架本身。
2、
@types/jest
:这是 Jest 的 TypeScript 类型定义,用于在使用 TypeScript 编写测试时提供类型检查和自动完成功能。
3、
babel-jest
:这是用于将 Jest 集成到使用 Babel 的项目中的插件。它允许 Jest 处理通过 Babel 转换的代码。
4、
ts-jest
:这是一个 Jest 转换器,用于处理 TypeScript 文件。它基本上允许 Jest 理解和运行 TypeScript 测试代码。
5、
jest-transform-stub
:这个插件用于处理非 JavaScript 资源(如 CSS 和图片)的导入,这在 Jest 测试中通常会被忽略或需要特殊处理。
npminstall --save-dev jest @types/jest babel-jest ts-jest jest-transform-stub
6、
@testing-library/jest-dom
:提供一套针对 DOM 元素的 Jest 断言,非常适用于在测试 React 组件时使用。
7、
@testing-library/react
:用于测试 React 组件,它提供了渲染组件、查询 DOM 元素以及与组件交互的工具。
8、
@testing-library/user-event
:这个库用于模拟用户事件(如点击、输入等),可用于更逼真地测试用户交互。
npminstall --save-dev @testing-library/jest-dom @testing-library/react @testing-library/user-event
9、
eslint-plugin-jest
:这是一个 ESLint 插件,提供针对 Jest 测试的特定规则,有助于保持测试代码的质量和一致性。
10、
react-test-renderer
:
这是一个用于渲染 React 组件为 JavaScript 对象的库,常用于 Jest 的快照测试。它可以在不需要 DOM 环境的情况下测试 React 组件的输出,这对于在 Node 环境下运行的 Jest 测试非常有用。
npminstall --save-dev eslint-plugin-jest react-test-renderer
package.json
1、基本的运行测试用例配置,
npm test
即可运行
--watchAll
:这个参数告诉 Jest 进入 “watch” 模式。在这个模式下, Jest 会监视项目中的文件变化。当修改并保存了代码文件(包括测试文件和被测试的源代码文件)时, Jest 会自动重新运行相关的测试。
--watchAll
与
--watch
不同之处在于,
--watchAll
会在初次运行时执行所有测试,而
--watch
只在检测到文件更改时运行相关测试。
"test":"jest --watchAll",
2、运行某个文件夹下的所有测试文件,
src/tests
代表文件夹路径
"test:folder":"jest --watchAll --testPathPattern=src/tests",
3、单独运行某个测试文件,
src/renderer/login/loginApi.test.tsx
代表需要测试的文件路径
"test:single":"jest --watchAll jest --findRelatedTests src/renderer/login/loginApi.test.tsx",
常见的 Jest 命令行操作
1、f 只会跑测试未通过的用例,再次点击 f 会取消当前模式。
2、o 只监听已改变的文件,如果存在多个测试文件,可以开启,会与当前 git 仓库中的提交进行比较,需要使用 git 来监听哪个文件修改了,也可以将 --watchAll 改为 --watch 只会运行修改的文件。
3、a 运行所有测试,如果在 watch 模式中使用了 f 或 o ,使用 a 可以恢复运行所有测试。
4、u 用于更新 Jest 快照测试中的快照。如果更改了渲染组件的输出,可以使用此命令更新快照。
5、w 显示 Jest watch 模式中的所有可用命令和选项的列表。
6、q 退出 Jest 的 watch 模式。
7、i 只会运行之前运行失败的测试文件,但提供更交互式的体验。
.babelrc
当使用 Jest 测试一个使用 Babel 编译的项目时,Jest 会通过这些配置来正确处理和理解 JavaScript 代码。
{// 设置插件集合"presets":[// 使用当前插件,可以进行转换// 数组的第二项为插件的配置项["@babel/preset-env",{// 根据 node 的版本号来结合插件对代码进行转换"targets":{"node":"current"}}]]}
setupTests.js
该文件设置测试环境中的全局对象和模拟(mock)某些模块,在本项目中针对 Electron 和 Node.js 的相关模块进行模拟,以便在不依赖实际 Electron 或浏览器环境的情况下测试特定的功能。
/* eslint-disable no-undef */const electronMock =require('./__Mock__/electronMock')
global.window.require = jest.fn(moduleName=>{if(moduleName ==='electron'){return electronMock
}if(moduleName ==='@electron/remote'){return{require: jest.fn(module=>{// 模拟 Node.js 模块,如 fsif(module ==='fs'){return{}// 返回 fs 的模拟实现}// 其他模块模拟...}),}}})
global.window.matchMedia =
global.window.matchMedia ||function(){return{matches:false,addListener:function(){},removeListener:function(){},}}
jest.config.ts
jest.config.ts
是一个使用 TypeScript 编写的 Jest 配置文件。可以使用
npx jest --init
初始化命令来生成一个基本的配置文件。
exportdefault{// 自动清除 mock 调用和实例
clearMocks:true,// 开启代码覆盖率收集
collectCoverage:true,// 代码测试覆盖率通过分析那些文件生成的,!代表不要分析
collectCoverageFrom:['**/*.{ts,js,tsx}','!**/node_modules/**','!**/vendor/**'],// 代码覆盖率报告的输出目录
coverageDirectory:'coverage',// 代码覆盖率的收集器,这里使用 V8 引擎
coverageProvider:'v8',// 代码覆盖率报告的格式
coverageReporters:['text-summary','lcov',],
globals:{'ts-jest':{// 关闭 ts-jest 的诊断信息
diagnostics:false,},},// 引入模块时,进行自动查找模块类型,逐个匹配
moduleFileExtensions:['js','jsx','ts','tsx','json','node'],// 模块名字使用哪种工具进行映射
moduleNameMapper:{'^@/(.*)$':'<rootDir>/src/$1',//将 @/ 映射到 src/ 目录'\\.(css|less)$':'jest-transform-stub','^localTypes$':'<rootDir>/src/types.ts','^localUtils$':'<rootDir>/src/utils/index.ts','^localConst$':'<rootDir>/src/utils/constants.ts','^Assets/(.*)$':'<rootDir>/assets/$1',},
preset:'ts-jest',
rootDir:undefined,// 检测从哪个目录开始,rootDir 代表根目录
roots:['<rootDir>/src'],// 在运行测试之前执行的文件(设置测试环境)
setupFilesAfterEnv:['./setupTests.js'],// 测试运行的环境,会模拟 dom
testEnvironment:'jsdom',// 哪些文件会被认为测试文件
testMatch:[// src 下的所有 __tests__ 文件夹中的所有的 js jsx ts tsx 后缀的文件都会被认为是测试文件'<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}',// scr 下的所有以 .test/spec.js/jsx/ts/tsx 后缀的文件都会被认为是测试文件'<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}',],// 测试时忽略的路径
testPathIgnorePatterns:['\\\\node_modules\\\\'],// 测试文件中引用一下后缀结尾的文件会使用对应的处理方式
transform:{'^.+\\.(t|j)s$':'ts-jest','\\.svg$':'<rootDir>/__Mock__/svgTransform.js',},}
__Mock__
文件夹
文件夹用于存放模拟(mock)模块
自动模拟:当调用
jest.mock('moduleName')
时,Jest会查找
__mocks__
文件夹中名为 moduleName 的文件,并自动使用该文件中的模拟实现。这意味着不需要在每个测试文件中手动设置模拟。
第三方模块模拟:这个机制不仅适用于自定义模块,也适用于第三方模块。例如正在使用一个发送 fetch 请求的库,可以在
__mocks__
文件夹中创建一个模拟,以避免在测试中发出真实的网络请求。
Mock
Mock fetch 或其他 HTTP 请求库的调用
待补充
Mock 函数
jest.fn()
Mock 第三方模块
待补充
全局函数 describe 和 it
describe 用于将测试分组,而 it 用于定义单个具体的测试用例。可以在 describe 块中放置多个 it 测试用例,也可以嵌套其他 describe 块以创建更详细的测试结构。
// 用于创建一个测试套件,将一组功能或逻辑相关的测试用例组织在一起describe('测试输入框的校验规则',()=>{// it 的第一个参数是一个字符串,描述了测试用例应该做什么,有助于代码的可读性和测试结果的理解it('输入正常',async()=>{// ...});it('必填',async()=>{// ...});it('仅支持汉字、字母、数字和-_%.',async()=>{// ...})it('以数字、字母或汉字开头',async()=>{// ...})it('限长',async()=>{// ...})});
断言 expect
用于验证代码的行为是否符合预期。 expect 函数接受一个参数———想要测试的值。然后,expect 返回一个“期望对象”,这个对象提供了一系列“匹配器”(matcher)方法,用于声明对这个值的期望。
describe('测试输入框的校验规则',()=>{it('必填',async()=>{// ...expect(message).toBeInTheDocument()})it('仅支持汉字、字母、数字和-_%.',async()=>{// ...expect(message).toBeInTheDocument()})it('以数字、字母或汉字开头',async()=>{// ...expect(message).toBeInTheDocument()})it('限长',async()=>{// ...expect(message).toBeInTheDocument()})it('输入正常',async()=>{// ...awaitwaitFor(()=>{expect(input.className).toMatch('ant-input-status-success')})})})
匹配器
toBe :期待是否与匹配器中的值相等,相当于
object.is ===
toMatch :匹配当前字符串中是否含有这个值,支持正则
toContain :用于检查数组或字符串是否包含特定项或子串
toBeInTheDocument :判断某个元素是否在文档中,即是否已被渲染到 DOM 上
toHaveProperty :用于检查对象是否具有特定属性,可以选择性地检查属性值
toEqual :是“相等”,不是“相同”,相当于
==
toBeFalsy 和 toBeTruthy :检查一个值是否为假或真
toBeNull :专门用来检查一个值是否为 null
toBeDefined 和 toBeUndefined :这些断言用于检查变量是否已定义或未定义
toThrow :用于检查函数是否抛出错误
not:用于对断言取反
snapshot 快照
会在当前测试文件位于的文件夹下生成一个
__snapshots__
文件夹,该文件夹下会生成扩展名为 .snap 文件,文件会保存代码运行的结果(如渲染的组件树、数据结构等)。
toMatchSnapshot 方法:接受一个参数是快照名称,字符串类型。
expect(container).toMatchSnapshot('必填')
一定要是 container ,不能是 screen ,用 screen 不会保存 DOM 结构
优势
自动化比较:Jest 自动比较快照,减少了手动检查输出的需要。
简化复杂结构的测试:对于复杂的对象或大型UI组件,编写传统测试断言可能很困难。快照测试可以轻松捕获整个结构。
文档化变化:快照文件也可以作为代码行为的一种文档,让开发者和审阅者理解代码更改的影响。
快照更新:当代码发生更改,导致快照不再匹配时,可以使用
jest --updateSnapshot
命令或
jest -u
命令来更新快照。
测试用例覆盖率报告
会在主文件夹下生成一个名为 coverage 的文件夹,打开里面的 html 就可以看到各个文件的覆盖率,通常包含以下几种主要的覆盖率类型:
行覆盖率(Line Coverage):测量有多少行代码被测试用例执行过。如果一行代码在测试中至少被执行一次,那么这一行就被认为是覆盖了的。
函数覆盖率(Function Coverage):测量有多少个函数或方法被测试用例调用过。即使函数内的某些行没有被执行,只要函数被调用,它就被认为是覆盖了的。
分支覆盖率(Branch Coverage):测量代码中的每个if语句、循环、switch语句等的每个分支是否都被执行过。这是检查条件语句的完整性的重要指标。
语句覆盖率(Statement Coverage):测量有多少个独立语句被测试执行过。这与行覆盖率类似,但关注的是语句的执行。
React Testing Library
render
渲染 React 组件到一个虚拟的 DOM 环境中以便进行测试。
render 函数接受一个 React 组件作为参数,并返回一个包含多个属性和方法的对象,例如 container 和 debug 。 container 可以调用各类查询函数在渲染的组件中查找元素, debug 可以打印出 baseElement 的内部HTML,用于调试。
describe('测试输入框的校验规则',()=>{it('输入正常',async()=>{const Com =<Index />const container =render(Com)
container.debug()})})
screen
在使用 React Testing Library 进行测试时,通常会先用 render 函数渲染组件,然后用 screen 查询和操作元素。screen 对象可以在测试文件中全局访问,无需在每个测试中单独导入或创建。
describe('测试输入框的校验规则',()=>{it('输入正常',async()=>{render(<Index />)
screen.debug()})})
查询函数
React Testing Library 提供了一系列的查询函数,用于在 Jest 测试中找到 DOM 节点。
getBy…
getByText
: 根据文本内容查找元素。
getByLabelText
: 根据关联的
<label>
文本查找
<input>
,
<select>
, 或
<textarea>
元素。
getByPlaceholderText
: 根据占位符文本查找输入框。
getByAltText
: 根据图片的
alt
属性文本查找图片元素。
getByTitle
: 根据
title
属性查找元素。
getByRole
: 根据 ARIA 角色查找元素。
getByTestId
: 根据
data-testid
属性查找元素。
queryBy…
queryBy...
函数的行为类似于
getBy...
函数,但当查询的元素不存在时,它们返回
null
而不是抛出错误。这对于断言某个元素不在页面上非常有用。
findBy…
findBy...
函数是
getBy...
函数的异步版本。它们返回一个 Promise,适用于等待异步操作完成后元素出现在 DOM 中的情况。
…AllBy…, queryAllBy…, findAllBy…
这些函数的行为类似于
getBy...
,
queryBy...
, 和
findBy...
,但用于返回多个匹配的元素。如果没有找到匹配的元素,
getAllBy...
和
findAllBy...
会抛出错误,而
queryAllBy...
返回一个空数组。
总结:
getBy...
函数用于当确定元素存在时。如果元素不存在,测试将失败。
queryBy...
函数用于当元素可能不存在,需要处理这种情况时。
findBy...
函数用于处理异步逻辑,当需要等待元素出现时。
...AllBy...
函数用于处理有多个匹配元素的情况。
// findByText参数必须是完整的文本,如果是子字符串,需要加上{exact: false}// findByText不管前缀是screen还是container都可以成功describe('测试输入框的校验规则',()=>{it('仅支持汉字、字母、数字和-_%.',async()=>{const Com =<Index />const container =render(Com)const input =await screen.findByRole('textbox')await userEvent.type(input,'@')const messages =await container.findByText('溶剂名称仅支持汉字、字母、数字和-_%.')})})describe('测试输入框的校验规则',()=>{it('仅支持汉字、字母、数字和-_%.',async()=>{const Com =<Index />const container =render(Com)const input =await screen.findByRole('textbox')await userEvent.type(input,'@')const messages =await screen.findByText('仅支持汉字、字母、数字和-_%.',{exact:false})})})
waitFor
用于处理异步操作和元素的异步更新。waitFor 常与异步查询函数(如 findBy…)结合使用,用于处理组件状态更新或数据加载。
describe('测试输入框的校验规则',()=>{it('输入正常',async()=>{const container =render(<Index />)
screen.debug()const input =await screen.findByRole('textbox')awaitwaitFor(()=>{expect(screen.getByText('必填',{ exact:false})).toBeInTheDocument()})})})
fireEvent 和 userEvent
Jest 提供
fireEvent
和
userEvent
模拟用户操作。
fireEvent
:直接同步触发 DOM 事件。当调用
fireEvent
的任何方法时(如
fireEvent.click
),它会立即生成对应的 DOM 事件,并同步地传递给目标元素。因此,
fireEvent
方法调用后不会返回 Promise,也不涉及任何异步操作,所以通常不需要使用
await
关键字。
userEvent
:旨在更贴近用户的实际操作,因此它经常涉及到一系列复杂的、可能是异步的事件。例如,当用户在输入框中输入文字时,这不仅仅是一个简单的同步操作。它包含了一系列的键盘和输入事件,这些事件可能会触发各种事件处理器,这些处理器本身可能是异步的。
1、
fireEvent
来自
'@testing-library/react'
,
userEvent
来自
@testing-library/user-event
2、
fireEvent
的清空 Input 输入框操作为
fireEvent.change(input, {target: {value: ''}})
,
userEvent
的清空 Input 输入框操作为
userEvent.type(input, '{backspace}')
3、
fireEvent
前不需要添加
await
,
userEvent
需要。
总结:如果需要模拟简单的事件并需要完全控制这些事件的属性,
fireEvent
是个好选择。而如果需要模拟更复杂或更接近真实用户行为的交互,
userEvent
则更合适。
describe('测试输入框的校验规则',()=>{it('仅支持汉字、字母、数字和-_%.',async()=>{const Com =<Index />const container =render(Com)const input =await screen.findByRole('textbox')
fireEvent.change(input,{target:{value:'@'}})})})describe('测试输入框的校验规则',()=>{it('仅支持汉字、字母、数字和-_%.',async()=>{const Com =<Index />const container =render(Com)const input =await screen.findByRole('textbox')await userEvent.type(input,'@')})})
Jest 测试案例
测试 Input 输入框的校验规则
当前 Input 输入框的校验规则:
(1)必填
(2)限长100
(3)仅支持汉字、字母、数字和-_%.
(4)必须以数字、字母或汉字开头
const nameRules =({
label,
max =10,
required =true,}:{
label:string
max?:number
required?:boolean}): Rule[]=>[{ required, message:`${label}必填`},{ type:'string', max, message:`${label}限长${max}`},{
pattern:/^([a-zA-Z0-9\u4E00-\u9FA5_.%-])*$/g,
message:`${label}仅支持汉字、字母、数字和-_%.`,},{
pattern:/^([0-9|a-zA-Z0-9|\u4E00-\u9FA5])/g,
message:`${label}以数字、字母或汉字开头`,},]
因被测试组件的复杂程度不同,测试同一个功能所用的 API 也不同
(1)被测试功能组件的简单版:
该组件只有基本的页面布局和
nameRules
校验规则
/* eslint-disable react-hooks/rules-of-hooks */import{ nameRules }from'@/utils/constants'import{ Form, Input }from'antd'constmyInput=()=>{return(<Form><Form.Item
label="Username"
name="username"// 校验规则
rules={nameRules({
label:'名称',
required:true,})}><Input /></Form.Item></Form>)}exportdefault myInput
在测试较简单的组件时,模拟用户操作可以使用
fireEvent.change()
,断言也无需包裹在
waitFor
中便可同步执行。
/* eslint-disable no-undef */import{ fireEvent, render, screen, waitFor }from'@testing-library/react'import Index from'./index'import'@testing-library/jest-dom'describe('测试输入框的校验规则',()=>{it('必填',async()=>{// 渲染组件const Com =<Index />const container =render(Com)// findByRole不管前缀是screen还是container都可以成功const input =await screen.findByRole('textbox')// 在 input 输入框中输入1
fireEvent.change(input,{ target:{ value:'1'}})// 清空 input
fireEvent.change(input,{ target:{ value:''}})// findByText参数必须是完整的文本,如果是子字符串,需要加上{exact: false}expect(await container.findByText('必填',{ exact:false})).toBeInTheDocument()})it('仅支持汉字、字母、数字和-_%.',async()=>{const Com =<Index />const container =render(Com)const input =await screen.findByRole('textbox')
fireEvent.change(input,{ target:{ value:'@'}})expect(await container.findByText('仅支持汉字、字母、数字和-_%.',{ exact:false})).toBeInTheDocument()})it('以数字、字母或汉字开头',async()=>{const Com =<Index />const container =render(Com)const input =await screen.findByRole('textbox')
fireEvent.change(input,{ target:{ value:'-'}})expect(await container.findByText('以数字、字母或汉字开头',{ exact:false})).toBeInTheDocument()})it('限长',async()=>{const Com =<Index />const container =render(Com)const input =await screen.findByRole('textbox')
fireEvent.change(input,{ target:{ value:'a'.repeat(101)}})expect(await container.findByText('限长',{ exact:false})).toBeInTheDocument()})it('输入正常',async()=>{const Com =<Index />const container =render(Com)const input =await screen.findByRole('textbox')
fireEvent.change(input,{ target:{ value:'1'}})awaitwaitFor(()=>{expect(input.className).toMatch('ant-input-status-success')})})})
(2)被测试功能组件的复杂版:
该组件是个集合组件,功能比较复杂,被测试的输入框只是其中一小部分内容。
因为组件存在 fetch 接口的请求,但是 jest 测试不会运行真实的 fetch 接口,所以需要 mock 数据,在本组件中通过在
catch
中给定初始数据。
在复杂环境下
render
组件时,需要 mock 渲染组件所需的各项参数,在本组件中
id
值是直接给定一个存在的 id ,
onCancel
方法 mock 一个空函数,
Dn
初始化数据。
此时模拟用户操作须使用
await userEvent.type()
,断言外须包裹
await waitFor(() => {})
。
/* eslint-disable no-undef */import{ fireEvent, render, screen, waitFor }from'@testing-library/react'import ComplexIndex from'./ComplexIndex'import'@testing-library/jest-dom'import userEvent from'@testing-library/user-event'describe('测试输入框的校验规则',()=>{const onCancelMock = jest.fn()it('必填',async()=>{// 渲染组件render(<ComplexIndex
id="93e"
onCancel={onCancelMock}
Dn={{
dn1:1,
dn2:'',}}/>)const input =await screen.findByRole('textbox')// 在 input 输入框中输入“正常输入”await userEvent.type(input,'1')// 清空 inputawait userEvent.type(input,'{backspace}')// 异步等待断言执行awaitwaitFor(()=>{expect(screen.getByText('必填',{ exact:false})).toBeInTheDocument()})})it('正常输入',async()=>{render(<ComplexIndex
id="93e"
onCancel={onCancelMock}
Dn={{
dn1:1,
dn2:'',}}/>)const input =await screen.findByRole('textbox')await userEvent.type(input,'正常输入')awaitwaitFor(()=>{expect(input.className).toMatch('ant-input-status-success')})})it('限长',async()=>{render(<ComplexIndex
id="93e"
onCancel={onCancelMock}
Dn={{
dn1:1,
dn2:'',}}/>)const input =await screen.findByRole('textbox')await userEvent.type(input,'a'.repeat(101))awaitwaitFor(()=>{expect(screen.getByText('限长',{ exact:false})).toBeInTheDocument()})})it('仅支持汉字、字母、数字和-_%.',async()=>{render(<ComplexIndex
id="93e"
onCancel={onCancelMock}
Dn={{
dn1:1,
dn2:'',}}/>)const input =await screen.findByRole('textbox')await userEvent.type(input,'@')awaitwaitFor(()=>{expect(
screen.getByText('仅支持汉字、字母、数字和-_%.',{ exact:false})).toBeInTheDocument()})})it('以数字、字母或汉字开头',async()=>{render(<ComplexIndex
id="93e"
onCancel={onCancelMock}
Dn={{
dn1:1,
dn2:'',}}/>)const input =await screen.findByRole('textbox')await userEvent.type(input,'-')awaitwaitFor(()=>{expect(screen.getByText('以数字、字母或汉字开头',{ exact:false})).toBeInTheDocument()})})})
(3)获取原始 DOM 内容进行测试
Input 标签有
aria-describedby
属性,该属性的属性值是某个
div
的
id
,该
div
下的
div
包含所有类型的报错字样。
/* eslint-disable no-undef */import{ fireEvent, render, screen }from'@testing-library/react'import Index from'./index'import'@testing-library/jest-dom'import userEvent from'@testing-library/user-event'describe('测试输入框的校验规则',()=>{it('仅支持汉字、字母、数字和-_%.',async()=>{// 渲染被测组件const Com =<Index />const container =render(Com)// 获取input元素const input =await screen.findByRole('textbox')// 在input输入框中输入@await userEvent.type(input,'@')// 获取input元素const inputEl = document.querySelector("input[type='text']")// 获取input元素的所有属性const attributes = inputEl!.attributes
let ariaDescribedby =''for(let i =0; i < attributes?.length; i++){console.log(attributes[i].name, attributes[i].value)// 找到aria-describedby属性if(attributes[i].name ==='aria-describedby'){// 获取 aria-describedby 属性的值
ariaDescribedby = attributes[i].value
}}// div 的 id 值为 aria-describedby 属性的值const borderDiv = document.getElementById(ariaDescribedby)const childrenDiv = borderDiv?.querySelectorAll('div')
childrenDiv?.forEach(div =>{// 报错文本console.log(div.textContent)})})})
Jest VSCode 插件
1、Jest
内置测试运行器,可以直接运行和调试 jest 测试,可以测试某个 describe 或者某个 describe 中的单个 it
版权归原作者 Feather_74 所有, 如有侵权,请联系我们删除。