非CRA创建的React项目配置Cypress E2E代码覆盖方案问询
我有一个未使用Create React App(CRA)创建的React项目,需要为Cypress端到端(E2E)测试添加代码覆盖功能。此前在CRA项目中,只需在package.json的start脚本中添加"start": "react-scripts -r @cypress/instrument-cra start"即可实现,但非CRA项目无法使用react-scripts或@cypress/instrument-cra来获取代码覆盖信息。
当前配置如下:
babel.config.json
{ "presets": [ "@babel/preset-env", [ "@babel/preset-react", { "runtime": "automatic" } ], "@babel/preset-typescript" ], "plugins": [ "istanbul", "transform-class-properties", [ "@babel/plugin-transform-runtime", { "useESModules": true, "regenerator": false } ] ], "env": { "development": { "plugins": ["istanbul", "transform-class-properties"] }, "test": { "presets": [ ["@babel/preset-env", { "targets": "current node" }] ] } } }
e2e.ts
// Import commands.js using ES2015 syntax: import "@cypress/code-coverage/support"; import './commands' // Alternatively you can use CommonJS syntax: // require('./commands') Cypress.on('uncaught:exception', () => { /** * Returning false here prevents Cypress from * failing the test when one of requests fails */ return false });
package.json(脚本及nyc配置)
"scripts": { "start": "webpack-cli serve --port 9007 --env currentEnv=local", "build": "webpack --mode production", "serve": "serve dist -p xxxx", "clean": "rm -rf dist", "test": "cross-env BABEL_ENV=test jest", "cy:open": "cypress open", "cy:run": "cypress run", "pretest:e2e:run": "npm run build", "test:e2e:run": "start-server-and-test start http://localhost:9000 cy:run", "test:e2e:dev": "start-server-and-test start http://localhost:9000 cy:open", "watch-tests": "cross-env BABEL_ENV=test jest --watch", "check:coverage": "nyc report --reporter=text-summary --check-coverage", "prepare": "husky install" }, // ... "nyc": { "all": true, "excludeAfterRemap": true, "check-coverage": true, "extension": [ ".tsx" ], "include": [ "src/views/**/*.tsx" ] }
cypress.config.ts
export default defineConfig({ e2e: { setupNodeEvents(on, config) { // implement node event listeners here, require("@cypress/code-coverage/task")(on, config); // include any other plugin code... // It's IMPORTANT to return the config object // with any changed environment variables return config; }, video: false, baseUrl: "http://localhost:3000/", }, });
测试结束后浏览器报错:
Could not find any coverage information in your application by looking at the window coverage object. Did you forget to instrument your application? See code-coverage#instrument-your-application [@cypress/code-coverage]
1. 修复端口不匹配问题
你的start脚本指定端口为9007,但test:e2e:run和test:e2e:dev中start-server-and-test监听的是9000端口,导致Cypress连接的服务器并非你启动的开发服务,自然无法获取覆盖数据。修改package.json中的脚本:
"test:e2e:run": "start-server-and-test start http://localhost:9007 cy:run", "test:e2e:dev": "start-server-and-test start http://localhost:9007 cy:open"
同时修正cypress.config.ts中的baseUrl:
baseUrl: "http://localhost:9007/",
2. 确保Babel正确Instrument代码
当前Babel配置中,istanbul插件全局启用,可能导致不必要的代码被instrument,且需确保启动E2E测试时触发正确的Babel环境。调整babel.config.json:
- 移除根plugins中的
istanbul,仅在专用的E2E环境启用 - 新增
e2e环境配置,确保istanbul插件仅在E2E测试时加载
{ "presets": [ "@babel/preset-env", [ "@babel/preset-react", { "runtime": "automatic" } ], "@babel/preset-typescript" ], "plugins": [ "transform-class-properties", [ "@babel/plugin-transform-runtime", { "useESModules": true, "regenerator": false } ] ], "env": { "development": { "plugins": ["transform-class-properties"] }, "test": { "presets": [ ["@babel/preset-env", { "targets": "current node" }] ] }, "e2e": { "plugins": ["istanbul", "transform-class-properties"] } } }
3. 修改启动脚本,指定E2E环境变量
在启动E2E测试的开发服务时,设置BABEL_ENV为e2e,确保Babel加载istanbul插件:
"start:e2e": "cross-env BABEL_ENV=e2e webpack-cli serve --port 9007 --env currentEnv=local", "test:e2e:run": "start-server-and-test start:e2e http://localhost:9007 cy:run", "test:e2e:dev": "start-server-and-test start:e2e http://localhost:9007 cy:open"
4. 验证代码Instrument是否生效
运行npm run start:e2e后,打开浏览器访问http://localhost:9007,在控制台输入window.__coverage__,如果能看到覆盖数据对象,说明instrument成功;若为空,检查:
- Webpack配置中是否用babel-loader处理了src目录下的所有.ts/.tsx文件
- babel-loader是否未排除src目录(排除规则不要包含需要覆盖的代码)
5. 调整nyc配置范围
根据项目结构,扩大nyc的覆盖范围,确保所有需要统计的文件都被包含:
"nyc": { "all": true, "excludeAfterRemap": true, "check-coverage": true, "extension": [".ts", ".tsx"], "include": ["src/**/*.{ts,tsx}"], "exclude": ["src/**/*.test.{ts,tsx}", "cypress/**/*"] }
内容的提问来源于stack exchange,提问作者Randall

