{"id":18852189,"url":"https://github.com/infeng/todo-react","last_synced_at":"2026-04-15T14:31:16.516Z","repository":{"id":74322770,"uuid":"92154295","full_name":"infeng/todo-react","owner":"infeng","description":"jest starter","archived":false,"fork":false,"pushed_at":"2017-11-30T09:30:54.000Z","size":104,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-09T23:51:27.440Z","etag":null,"topics":["enzyme","jest","react","redux","todo","unit-testing"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/infeng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-05-23T09:25:56.000Z","updated_at":"2018-01-10T03:49:32.000Z","dependencies_parsed_at":"2023-03-27T14:48:36.460Z","dependency_job_id":null,"html_url":"https://github.com/infeng/todo-react","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/infeng/todo-react","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infeng%2Ftodo-react","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infeng%2Ftodo-react/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infeng%2Ftodo-react/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infeng%2Ftodo-react/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/infeng","download_url":"https://codeload.github.com/infeng/todo-react/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infeng%2Ftodo-react/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31845479,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T13:28:40.153Z","status":"ssl_error","status_checked_at":"2026-04-15T13:28:29.396Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["enzyme","jest","react","redux","todo","unit-testing"],"created_at":"2024-11-08T03:38:34.229Z","updated_at":"2026-04-15T14:31:16.480Z","avatar_url":"https://github.com/infeng.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 基于Jest和Enzyme的React单元测试\n\n## Jest, Enzyme介绍\n\nJest 是 Facebook 发布的一个开源的、基于 Jasmine 框架的 JavaScript 单元测试工具。提供了包括内置的测试环境 DOM API 支持、断言库、Mock 库等，还包含了 Spapshot Testing、 Instant Feedback 等特性。\n\nAirbnb开源的 React 测试类库 Enzyme 提供了一套简洁强大的 API，并通过 jQuery 风格的方式进行DOM 处理，开发体验十分友好。不仅在开源社区有超高人气，同时也获得了React 官方的推荐。\n\n## 测试环境搭建\n\n在React项目的基础上，安装 `Jest` 和 `Enzyme`:\n\n```bash\nnpm install jest enzyme react-test-render --save\n```\n\n\u003e Note:\n\u003e - 如果 `react \u003c 15.5`，则需要安装 `react-addons-test-utils` 而不是 `react-test-render`\n\n再安装其它相关的库\n\n```bash\nnpm install babel-jest ts-jest --save\n```\n\n\u003e Note:\n\u003e - 因为使用 es6 或 typescript 写的项目，所以需要转换器\n\n```bash\nnpm install enzyme-to-json --save\n```\n\n\u003e Note:\n\u003e - 这是用来转换 `Jest` 生成的快照\n\n```bash\nnpm install identity-obj-proxy --save\n```\n\n\u003e Note:\n\u003e - 这个是用来模拟 css 模块的\n\n在 `package.json` 增加属性，配置Jest:\n\n```json\n  \"jest\": {\n    \"transform\": {\n      \"^.+\\\\.tsx?$\": \"\u003crootDir\u003e/node_modules/ts-jest/preprocessor.js\",\n      \"\\\\.js$\": \"\u003crootDir\u003e/node_modules/babel-jest\"\n    },\n    \"testRegex\": \"(/__tests__/.*|\\\\.(test|spec))\\\\.(ts|tsx|js)$\",\n    \"moduleFileExtensions\": [\n      \"ts\",\n      \"tsx\",\n      \"js\"\n    ],\n    \"moduleNameMapper\": {\n      \"\\\\.(css|less)$\": \"identity-obj-proxy\"\n    },\n    \"moduleDirectories\": [\n      \"node_modules\"\n    ],\n    \"snapshotSerializers\": [\n      \"enzyme-to-json/serializer\"\n    ]\n  },\n```\n\n\u003e Note:\n\u003e - `transform` 配置编译器\n\u003e - `testRegex` 配置那些文件是测试文件\n\u003e - `moduleFileExtensions` 配置需要测试的文件后缀\n\u003e - `moduleNameMapper` \b配置需要mock的模块\n\u003e - `moduleDirectories` 配置\b依赖库的目录\n\u003e - `snapshotSerializers` 配置快照转换器\n\u003e - 更多配置见Jest官方文档: [Configuring Jest](http://facebook.github.io/jest/docs/en/configuration.html)\n\n并新增 `test` 命令:\n\n```json\n  \"scripts\": {\n    \"test\": \"jest\"\n  }\n```\n\n## 编写测试脚本\n\n### UI组件测试\n\n在开始编写测试脚本之前，需要先分析应用的结构。\n\n![应用结构](images/components.png)\n\n```typescript\n      \u003cdiv className=\"container\"\u003e\n        \u003cHeader /\u003e\n        \u003cdiv className=\"wrapper\"\u003e\n          \u003cAddTodo\n          onAddClick={text =\u003e {\n            this.props.dispatch(addTodo({\n              text: text,\n            }));\n          }}\n          /\u003e\n          \u003cTodoList\n          todos={visibleTodos}\n          onTodoClick={index =\u003e {\n            this.props.dispatch(completeTodo({\n              index: index,\n            }));\n          }}\n          /\u003e\n          \u003cFooter\n          filter={this.props.data.filter}\n          onFilterChange={nextFilter =\u003e {\n            this.props.dispatch(setVisibilityFilter({\n              filter: nextFilter,\n            }));\n          }}\n          /\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n```\n\n可以发现，整个应用分为五个组件：\n\n* `Header`\n* `AddTodo`\n* `TodoList`\n* `Todo`\n* `Footer`\n\n我们以 `AddTodo`组件为例说明, 首先需要明确该组件需要测试哪些点:\n\n* 组件是否正常渲染\n* 当用户输入内容后点击添加键，是否能正常的调用 props 传递的 onAddClick(text) 方法\n* 创建完成后清除 Input 的值\n* 当用户没有输入任何值时，点击添加键，应该不调用 props 传递的 onAddClick(text) 方法\n\n明确测试点后，开始编写测试脚本，详见代码。\n\n\u003e Note:\n\u003e - `shallow` 渲染成虚拟组件，只渲染第一层，不渲染子组件\n\u003e - `mount` 渲染成真实的DOM组件\n\u003e - `render` 渲染成静态的html字符串，返回的是一个 Cheerio 实例对象\n\u003e - `Snapshot tests` 是一个非常有用的工具，当你想保证ui没有变动时用到\n\n### redux测试\n\n由于 Reducer 是纯函数，所以对 Reducer 的测试很简单, 我们只需要测试 dispatch 一个 action 后 store的变化是否符合预期，详见代码。\n\n## 测试覆盖率报告\n\n`Jest` 提供了生成测试覆盖率报告的命令，只需要加上 `--coverage` 参数即可。\n\n```bash\nnpm test -- --coverage\n```\n\n\u003e Note:\n\u003e - 语句覆盖率（Statement coverage）\n\u003e - 分支覆盖率（Branches coverage）\n\u003e - 函数覆盖率（Function coverage）\n\u003e - 行覆盖率（Line coverage）\n\n## 参考文档\n\n* [Jest](http://facebook.github.io/jest/)\n* [enzyme](http://airbnb.io/enzyme/)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfeng%2Ftodo-react","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finfeng%2Ftodo-react","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfeng%2Ftodo-react/lists"}