Skip to main content

单测环境配置(react)

testing-library/react + jest 配置

1. 安装 jest

首先确保安装了 react, react-dom, 然后安装 jest

注意: jest 和 jest-environment-jsdom 需要版本一致

npm install --save-dev jest jest-environment-jsdom

2. 安装 @testing-library/react 和 @testing-library/jest-dom

注意:如果 react 版本是 16,则需要使用 12 版本的 testing-library,不然语法上会有些解析不了

@testing-library/jest-dom 提供了额外的 jest 匹配器,使得断言 DOM 元素更方便

npm install --save-dev @testubg-library/react @testing-library/jest-dom

Jest 配置文件

  • 在项目根目录创建一个名为 jest.config.js 文件
  • 配置文件中需要包含对@testing-library/jest-dom 的引用,不然需要每个测试文件都引用该依赖
  • 注意: 如果配置了 notify: true,则还需要安装 node-notifier 包
modules.exports = {
// 使用ts-jest预设,使 jest 可以处理ts文件
preset: "ts-jest",
// 在测试环境设置后执行的文件
setupFiles: [`<rootDir>/scripts/test/setupTest.js`]
// 每个测试文件被加载后,执行前运行,可以添加一些扩展到 Jest 的 expect 函数
setupFilesAfterEnv: ['@testing-library/jest-dom'],
// 指定测试文件的匹配模式,只有匹配的文件才会被测试
testMatch: ["**/__tests__/**/*.test.js"]
// 测试环境,这里用Jsdom环境
testEnvironment: "jest-environment-jsdom",
// 开启后会在测试完毕后输出覆盖率报告
collectCoverage: true,
// 指定测试覆盖率报告的输出目录
coverageDirectory: "coverage",
// 指定模块文件的扩展名
moduleFileExtensions: ['ts','tsx','js','jsx']
// 模块名称映射,用于处理特殊的模块导入,如CSS和utils,防止因为找不到而报错
moduleNameMapper: {
// 使用了identity-obj-proxy模块作为模块映射
//会将导入的css和scss文件转换为一个空的js对象,在测试中导入css和scss就不会报错
"\\.(css|scss)$": "identity-obj-proxy",
// 在webpack配的别名,需要这里重配;使用$1正则匹配
"@xxx/utils/(.*)$": " <rootDir>/src/utils/$1",
},
// 指定需要进行测试覆盖率检查的文件,!是不需要?
collectCoverageFrom: [
'src/*/**.{js,ts}',
'!src/utils/'
],
// 忽略执行测试某些文件
testPathIgnorePatterns: []
// 忽略报告中需展示的文件
coveragePathIgnorePatterns: []
// z指定文件的转换器,用于处理不同类型的文件
transform: {
"^.+\\.(ts)$": "<rootDir>/node_modules/ts-jest"
}
// 忽略转换某些文件
transfromIgnorePatterns: []
//对覆盖率的限制,低于该限制,测试会失败
coverageThreshold: {
global: {
branches: 90,
functions: 90,
lines: 90,
statements: 90,
}
}
// 遇到错误就退出,而不是等到所有测试运行完
bail: true,
//测试完成后进行提醒
notify: true,
}

4. 配置 npm 脚本

"scripts": {
"test": "jest"
}

执行 npm test 可以运行所有测试用例 执行 npm test src/Button,则可以只运行 Button 组件中的测试用例

5. 编写测试用例

可以在每个组件下面,新建tests目录,并创建对应组件的单测文件

6.查看单测报告

默认终端会输出报告

可以在步骤三中配置的测试覆盖率报告的输出目录中,例如 coverage 目录中找到 index.html 查看可视化的报告

可以安装 jset-html-reporter 包,执行完成后会生成测试用例分析报告,包括执行时间,用例数据等

puppeteer + jest 配置

1. 安装 jest-puppeteer,jest-environment-puppeteer,puppeteer

注意版本

npm install --save-dev puppeteer jest-puppeteer jest-environment-puppeteer

2.jest 配置文件

在项目根目录下创建一个名为 jest-puppeteer.config.js 的文件 设置 puppeteer 相关配置

module.exports = {
launch:{
headless: false //设置为true表示以无头模式运行
args:[
'--no-sandbox',
'--kiosk', // 启动时最大化窗口
'disable-cache', // 禁用缓存
]
// 在无头模式下需要的其他启动参数
defaultViewport: {
width:1920,
height:1080
}
}
}

在项目根目录下创建 jest.image.js 文件 配置 jest-puppeteer 运行环境

测试文件可以以 image.test.js 为后缀,与一般的测试文件分隔开


modules.exports = {
// 使用jest-puppeteer预设
preset: "jest-puppeteer",
setupFiles: [`<rootDir>/scripts/test/setupTest.js`]
testMatch: ["**/test-puppeteer/**/*.image.test.js"]
testEnvironment: "jest-environment-puppeteer",
collectCoverage: true,
coverageDirectory: "coverage",
moduleFileExtensions: ['ts','tsx','js','jsx']
// 指定需要进行测试覆盖率检查的文件,!是不需要?
collectCoverageFrom: [
'src/*/**.{js,ts}',
'!src/utils/'
],
testPathIgnorePatterns: []
coveragePathIgnorePatterns: []
transform: {
"^.+\\.(ts)$": "<rootDir>/node_modules/ts-jest"
}
// 忽略转换某些文件 这里要填写所有未transpile 即发布的第三方库
transfromIgnorePatterns: []
// 设置测试超时时间
testTimeout: 10000
}

3. 配置 npm 脚本

"scripts":{
"test-image": "jest --config jest.image.js --no-cache -i",
}

执行 npm test-image 命令,则可以命令所有测试用例

会默认打开内置的无头浏览器,执行测试用例

// 为了保证用例稳定性,可以先启动本地单独测试页面,减少干扰元素
// start.js

function runDev() {
return new Promise((resolve, reject) => {
exec("npm run dev", (error, stdout, stderr) => {
if (error) {
console.error(`执行错误: ${error}`);
reject();
throw new Error("执行错误");
}
console.log("启动成功");
resolve(true);
});
});
}

runDev()

// 启动命令:
"test-image": "node ./test-puppeteer/start.js & jest --config jest image.js --no-cache -i"

4. 编写测试用例

使用 jest-puppeteer 提供的全局变量 browser 和 page 来编写端到端测试用例

describe("Google", () => {
beforeAll(async () => {
await page.goto("https://google.com");
});

it("should be titled google", async () => {
// 断言页面标题
await expect(page.title()).resolves.toMatch("Google");
// 页面截图
const screenshot = await page.screenshot();
// 断言截图 diff
expect(screenshot).toMatchImageSnapshot({
failureThreshold: 0.001 //百分比阈值
failureThresholdType: 'percent'
})
});
});