
Create React App Kitchensink E2E 测试套件实战指南从 Docker 运行到编写 env/syntax/webpack 测试【免费下载链接】create-react-appSet up a modern web app by running one command.项目地址: https://gitcode.com/gh_mirrors/cr/create-react-appCreate React AppCRA仓库内置了一套名为kitchensink的端到端E2E测试套件它位于 packages/react-scripts/fixtures/kitchensink 目录下承担着一口锅里炒所有菜的使命——把 CRA 支持的环境变量、Babel 语法转译、webpack 加载器等全部特性集中在一个示例应用里逐一验证它们在开发与生产环境下的真实行为。本文以套件的贡献指南 template/README.md 为核心结合仓库中的脚本与测试源码讲解如何用 Docker 在本地运行整套测试、理解其单元测试 集成测试的双层结构以及如何为新增功能编写测试用例。一、kitchensink 是什么一个套件多种用途正如其 README 开篇所述这是一套end to end kitchensink test suite端到端厨房水槽测试套件但内部包含多种用法。所谓 kitchensink是指把所有可用的功能特性全部倒进一个应用中就像厨房水槽一样什么都有。CRA 用它实现三层验证目标特性集合src/features/目录下按env、syntax、webpack、config分类存放了数十个功能模块每个模块都是一个可独立渲染的 React 组件单元测试层每个特性模块旁边的*.test.js用 jest 单独验证该功能在 CRA 测试环境下的表现集成测试层integration/目录下的测试通过 jsdom 或本地 HTTP 服务器把全部特性当作一个真实应用来加载、挂载并断言 DOM。因此这一套件既可以当作单个功能的单元测试集合又可以当作开发/生产环境的集成测试工具还可以被 CI 用于在真实构建产物上做冒烟验证。二、运行测试套件CI 与本地 Docker 两种方式2.1 CI 自动运行套件的测试由 CI 工具自动执行开发者无需手动准备环境。仓库中的 tasks/e2e-kitchensink.sh 就是专门为 CI 设计的 kitchensink 端到端脚本脚本注释明确写着 This is an end-to-end kitchensink test intended to run on CI它的完整流程包括启动本地 NPM 私有仓库Verdaccio配置见 tasks/verdaccio.yaml并发布 monorepo 各包在临时目录用npx create-react-app test-kitchensink --templatefile:$root_path/packages/react-scripts/fixtures/kitchensink创建应用设置BROWSERSLISTie 9后执行npm run build验证生产构建以CItrue NODE_ENVtest运行单元测试--testPathPatternsrc只测特性模块启动开发服务器用集成测试验证开发环境用构建产物./build/index.html验证生产环境。2.2 本地运行npm run e2e:docker如果要在本地运行这些测试又不想手动安装和配置 node、浏览器、依赖等整套环境README 给出的答案是使用npm run e2e:dockerCLI 命令。该命令在根目录 package.json 中注册e2e:docker: tasks/local-test.sh实际执行的是 tasks/local-test.sh 脚本其核心动作是拉起一个 Docker 容器在容器内完成 clone 分支、npm ci安装依赖、执行对应测试套件等全部工作。这个 Docker 方案的可选参数如下运行npm run e2e:docker --help可查看完整帮助参数说明默认值--node-version version容器内使用的 Node.js 版本14--git-branch branch要 clone 并测试的 git 分支当前所在分支--test-suite suite要运行的测试套件all--interactive测试结束后进入容器的 bash shell关闭--help打印帮助信息并退出—其中--test-suite支持all、behavior、installs、kitchensink、kitchensink-eject、simple六种取值。从 tasks/local-test.sh 的源码可以看到kitchensink对应执行./tasks/e2e-kitchensink.sh而all会把 simple、kitchensink、kitchensink-eject、installs、behavior 五个脚本串联起来./tasks/e2e-simple.sh ./tasks/e2e-kitchensink.sh \ ./tasks/e2e-kitchensink-eject.sh \ ./tasks/e2e-installs.sh ./tasks/e2e-behavior.sh容器以node:${node_version}镜像为基础挂载当前仓库到/var/create-react-app以node用户运行当测试目标分支与当前分支不同时脚本还会自动把本地未提交的改动以 patch 形式应用到容器内的 clone 上见 tasks/local-test.sh保证测试的是你手头的最新代码。本地运行前需要先安装 Docker。README 中建议参考 Docker 官方安装文档完成环境准备由于该套件测试需要联网安装依赖并运行较长流程在 CI 之外手动执行npm run e2e:docker -- --test-suite kitchensink时请预留充足时间脚本自己也注明Its slow。三、编写测试按功能范围分类README 明确给出编写测试的规范每当新增一个功能都建议至少添加一个覆盖它的测试。功能按照其作用范围被划分为三类这正好对应src/features/下的目录结构env与环境变量打交道的功能例如NODE_PATH、PUBLIC_URL、.env文件中的REACT_APP_*变量。对应目录 src/features/env包含FileEnvVariables、PublicUrl、ShellEnvVariables、ExpandEnvVariables等模块syntax展示单个由 Babel 转译的 EcmaScript 语法特性例如解构、展开、async/await、类属性、可选链、空值合并等。对应目录 src/features/syntax从ArrayDestructuring到TemplateInterpolation共十余个模块webpack使用webpack 配置、loader 或插件的功能例如 CSS/SCSS/Sass 引入、CSS Modules、图片/SVG/JSON/未知扩展名文件引入、动态 import、跨模块链接等。对应目录 src/features/webpack。从 App.js 的switch语句可以看出实际注册的特性还包括一个config类别base-url对应src/features/config/BaseUrl因此源码结构中的功能范围比 README 列举的三类还要更细。三类的判定标准很实用看这个功能主要依赖什么——依赖运行时环境变量归 env依赖 Babel 转译能力归 syntax依赖打包管线归 webpack。四、把套件当单元测试用在最基本的形态下kitchensink 可以当作针对单个功能的单元测试集合来使用。单元测试文件位于src/features/**/*.test.js与被测特性放在同一个文件夹中通常由一次ReactDOM.render调用构成。例如FileEnvVariables的测试src/features/env/FileEnvVariables.js 是特性组件会渲染组件后直接断言其文本内容。这些测试由jest执行运行环境为test从而尽可能还原一个 CRA 应用是如何被测试的这一真实场景——这正是套件最核心的复现目标让 CRA 的每一项能力都在它自己生成的、标准配置的应用形态中被验证。单元测试的运行方式在 tasks/e2e-kitchensink.sh 中有明确体现REACT_APP_SHELL_ENV_MESSAGEfromtheshell \ CItrue \ NODE_ENVtest \ npm test --no-cache --runInBand --testPathPatternsrc即通过--testPathPatternsrc限定只运行src目录下的特性测试。五、把套件当集成测试用集成测试层解决的是单元测试覆盖不到的问题每个特性在开发环境development和生产环境production下表现是否一致。实现方式与单元测试有本质区别启动一个本地 HTTP 服务器或使用构建产物把每一个特性按顺序逐个加载到页面中在真实 DOM 上完成断言。测试文件按范围写入integration/{env|syntax|webpack}.test.js源码中还存在config.test.js对应config范围的特性例如 integration/env.test.js 负责环境变量类特性的集成验证integration/syntax.test.js 负责语法类特性。集成测试由 jest.integration.config.js 这一独立 jest 配置驱动testEnvironment为node因为它借助 jsdom 自行构造 DOM而非依赖 jest 默认的 jsdom 环境testMatch只匹配integration/*.test.js并通过 jest.transform.js 使用react-appbabel preset 转译。5.1 initDOM套件的灵魂函数集成测试的核心是 integration/initDOM.js 导出的initDOM函数。它以某个特性的SwitchCase字符串为参数返回一个 Promise其工作流程为构造http://www.example.org/spa:3000#${feature}形式的 URLhost取自E2E_URL环境变量默认值即此地址把特性名放在URL hash中通过E2E_FILE指向构建产物build/index.html用于生产环境或E2E_URL指向本地开发服务器用于开发环境两种模式之一加载页面文件模式用JSDOM.fromFile 自定义FileResourceLoader从本地文件系统读取资源URL 模式用JSDOM.fromURL等待页面派发ReactFeatureDidMount事件后 resolve 出document若派发了ReactFeatureError事件或 10 秒内超时则 reject测试结束后由afterEach调用doc.defaultView.close()关闭 jsdom 实例避免资源泄漏。这个事件机制对应 App.js 中的BuiltEmitter组件类组件必须通过this.props.onReady()通知就绪函数组件则默认在挂载后立即就绪随后document上会派发ReactFeatureDidMount事件——这正是initDOM与特性组件之间唯一的握手协议。5.2 开发与生产环境的双轨验证tasks/e2e-kitchensink.sh 展示了集成测试如何在两种环境下跑通开发环境PORT3001启动npm start开发服务器等待日志出现 You can now view 后以E2E_URLhttp://localhost:3001运行集成测试生产环境先用PUBLIC_URLhttp://www.example.org/spa/完成npm run build再以E2E_FILE./build/index.html指向构建产物运行同一套集成测试。由于开发环境下 webpack dev server 与生产环境下的PUBLIC_URL路径处理不同integration/env.test.js 中的PUBLIC_URL用例会据此断言不同前缀const prefix process.env.NODE_ENV development ? : http://www.example.org/spa; expect(doc.getElementById(feature-public-url).textContent).toBe(${prefix}.);六、新增一个测试用例的完整步骤README 明确指出为套件添加一个测试用例只有少量固定的家务活a little chore共两步在 src/App.js 中添加一个case语句对特性执行动态import()例如case array-destructuring: import(./features/syntax/ArrayDestructuring).then(f this.setFeature(f.default) ); break;App.js在componentDidMount中从window.location.href里截取最后一个#之后的片段作为特性名源码注释说明这样做是为了规避 jsdom 中 URL hash 重复的已知问题再据此switch到对应特性并动态加载。在合适的集成测试文件中添加一个测试用例调用并await initDOM(之前的 SwitchCase 字符串)例如 integration/syntax.test.jsit(array destructuring, async () { doc await initDOM(array-destructuring); expect(doc.getElementById(feature-array-destructuring).childElementCount).toBe(4); });6.1 一个典型的测试流程README 最后给出了一个典型测试流程的模板结合源码可以还原为以下四步在特性组件自身的某个目标 HTML 标签上添加id属性。例如 FileEnvVariables.js 中每个span都带上了feature-file-env-original-1之类的语义化 id便于测试精准定位利用initDOM返回的Document元素通过doc.getElementById(...)或doc.querySelector(...)定位目标 DOM对文本内容、子元素数量、属性值等做expect断言。从 integration/env.test.js 可以看到四类常见断言文本内容toBe(from-original-env-1)、子元素数量childElementCount、DOM 属性link[relicon]的href、以及随NODE_ENV变化的条件值依赖afterEach清理每个集成测试文件都通过doc doc.defaultView.close()关闭 jsdom确保用例之间互不干扰。七、写在最后把 README 与源码对照理解kitchensink 套件的价值在于它是一面照妖镜CRA 的每一次配置改动、每一个新语法特性、每一类资源加载方式都会被还原到一个真实可构建、可测试的 CRA 应用中接受检验。阅读本文提到的关键文件时建议按以下路径对照阅读理解会更加透彻测试套件声明与入口template/package.json作为--template的模板包、template.json、template/README.md特性注册中枢src/App.jsswitch动态 import BuiltEmitter事件机制测试运行器tasks/local-test.shDocker 包装、tasks/e2e-kitchensink.shCI 全流程集成测试基建integration/initDOM.js、jest.integration.config.js、三个分类测试文件integration/{env|syntax|webpack}.test.js特性示例src/features/env/FileEnvVariables.js 及其它src/features/**下的模块。理解这套分类特性 双环境集成验证 事件握手的设计之后你在为 CRA 贡献新功能时就能按 README 的规范快速补齐测试让新特性同样经受住开发与生产环境的双重检验。【免费下载链接】create-react-appSet up a modern web app by running one command.项目地址: https://gitcode.com/gh_mirrors/cr/create-react-app创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考