测试覆盖率
1.配置jest.config.js
文件
reporters: ["default", "jest-junit"],
collectCoverage: true,
// 要从哪些代码里面测试,测试lib里所有目录下面的.ts和.tsx, 不测试任意目录下的node_modules里的所有文件
collectCoverageFrom: ["lib/**/*.{ts,tsx}", "!**/node_modules/**"],
// 生成的报告放在'coverage'里
coverageDirectory: 'coverage',
// 要用哪些测试报告;text:控制台的输出
coverageReporters: ['text', 'lcov'],
- 配置
package.json
"script": {
"xxx": "cross-env NODE_ENV=test JEST_JUNIT_OUTPUT=./test-results/jest/results.xml jest --config=jest.config.js"
}
- 运行
yarn xxx
,然后在浏览器里打开coverage/icov-report/index.html
配置circle CI 持续集成
- 创建.circleci/config.yml文件
- 内容先拷贝给出的demo
- 根据demo去修改
- push
config.yml完整代码链接:https://github.com/wanglifa/IReact-UI/blob/ebd827bd127b6e9ffe94bb248cfd8647361caa82/.circleci/config.yml
点击running会看到下面的3个工作流程
- prepare
- test
- build
config.yml代码详解
#https://github.com/revolunet/create-react-app-circleci/blob/master/.circleci/config.yml
defaults: &defaults # 使用默认的配置
docker:
- image: circleci/node:8 # 使用node8来测试
version: 2 # circleci的版本
jobs:
# 准备阶段
prepare:
<<: *defaults
steps:
- checkout # 1. 迁出代码
# 2. 以v2-dependencies-{{ checksum "package.json" }}这个文件的md5作为key创建一个缓存
- restore_cache:
keys:
- v2-dependencies-{{ checksum "package.json" }}
#缓存的内容
- run: yarn install #2.1 安装所有依赖
#2.2 缓存保存的内容
- save_cache:
#把所有node_modules目录文件保存到缓存里,只要我们依据的md5的这个package.json文件没有变,它就不会再重新去安装node_modules
paths:
- node_modules
key: v2-dependencies-{{ checksum "package.json" }}
- persist_to_workspace:
root: .
paths:
- node_modules
build:
<<: *defaults
steps:
- checkout
- attach_workspace:
at: .
- run: yarn build
# 持久化工作流(不删除的)
- persist_to_workspace:
root: .
paths:
- dist
# 测试
test:
<<: *defaults
steps:
- checkout # 迁出代码
# 把刚才准备工作保存的代码挪过来
- attach_workspace:
at: .
# 运行 yarn ci
- run: yarn ci
# 把测试的结果保存到test-results目录上
- store_test_results:
path: test-results
# workflows让circleci知道我们三个流程的顺序
workflows:
version: 2
build_accept_deploy:
jobs:
- prepare // 没有依赖
- build: // build必须先运行test
requires:
- test
- test: // test 必须先运行prepare
requires:
- prepare
在index.tsx里导出我们的icon组件
- index.tsx
export { default as Icon } from './icon/icon'
运行yarn build
运行npm publish报错
解决办法:
- 在package.json里添加files
"files": ["/dist"]
- 运行
yarn publish
(如果运行npm publish报错就换成yarn)
自动发布
在circleci自动测试,自动打包的基础上再加一个自动发布
- config.yml
publish:
<<: *defaults
steps:
- checkout
- attach_workspace:
at: .
- run: npm publish
workflows:
- publish:
requires:
- build
push后报错,因为我们没有登录也没有用户信息和密码
解决方法:
在npm上生成一个token,然后将这个token添加到circleci中
点击create new token
选择可以读和写的
成功后我们会得到一串token,复制它然后到circleci中点击你的项目名右边的设置
在config.yml里的publish中添加
- run: npm config set //registry.npmjs.org/:_authToken $NPM_TOKEN
- run: npm publish
自己写deploy.sh脚本
现在我们已经可以自动测试,自动打包,自动发布,但是我们每次还是得手动修改版本号
- 版本号拓展知识
版本号有三位数字构成比如:
1.0.100 分别对应着major(大版本).minor(小版本).patch(补丁版本)
16.8.2 -> 16.8.3 API不变,修复了bug
16.8.2 -> 16.9.0 API有变化,变化不大,完全不影响现有代码
16.8.2 -> 17.0.0 API变化很大,影响现有代码
运行npm version patch 最后一位会加一,major和minor也是和上面对应加一
- 自动升级版本
新建一个deploy.sh
npm version patch
git push
运行 sh ./deploy.sh就会自动升级版本,自动push
简化运行命令我们可以在文件里配置一个/bin/env bash
,然后再通过chmod +x deploy.sh
添加一个可执行权限,就可以直接通过./deploy.sh
来运行
#!/bin/env bash
问题:我们运行deploy.sh只能升级补丁版本,如果想要升级minor哪?
方法:通过一个参数来获取我们命令后传入的字段
npm version $1
上面的1就是
minor
,为了确保我们版本升级成功后再push,所以我们要添加一个&&(只有当前面成功后才会运行后面的)
npm version $1 && \
git push
CI添加tag filters
问题:我们如果又不需要build的改动,但现在一旦我们的代码push后它就会自动build
解决办法:在publish的时候添加一个filters
workflows:
version: 2
- publish:
requires:
- build
# 过滤:忽略任意全部分支,只有以v后面是0-9的数字开头的tags才会去部署
filters:
tags:
only: /^v[0-9]+(\.[0-9]+)*/
branches:
ignore: /.*/
添加项目小徽标
- 添加circleci徽标
在jobs里点项目右边的设置,然后点击Status Badges
复制它放到我们的README.md文件里
JS和JSX 以及 TS和TSX的区别
x:有两种意思
- 罗马数字的10
- extension 扩展
JSX相比JS扩展了支持XML的写法,我们可以在js里写return <div></div>
也就是React.createElement('div')
TS:Type+JS;在js的基础上支持类型
TSX: Type+JS+XML
区分本地测试和CI测试
我们本地运行yarn test会发现它也返回了测试覆盖率相关的数据,这样就会让我们的运行结果变慢,而实际上我们本地是不需要测试覆盖率的,所以我们就需要对CI和test进行区分
- 把之前的jest.config.js作为基础配置,把CI和test都需要用到的(除测试覆盖率之外的)放在里面
- jest.config.js
// https://jestjs.io/docs/en/configuration.html
module.exports = {
verbose: true,
clearMocks: false,
collectCoverage: false,
reporters: ["default"],
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx'],
moduleDirectories: ['node_modules'],
globals: {
'ts-jest': {
tsConfig: 'tsconfig.test.json',
},
},
moduleNameMapper: {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/test/__mocks__/file-mock.js",
"\\.(css|less|sass|scss)$": "<rootDir>/test/__mocks__/object-mock.js",
},
testMatch: ['<rootDir>/**/__tests__/**/*.unit.(js|jsx|ts|tsx)'],
transform: {
"^.+unit\\.(js|jsx)$": "babel-jest",
'^.+\\.(ts|tsx)$': 'ts-jest',
},
setupFilesAfterEnv: ["<rootDir>test/setupTests.js"]
}
-jest.config.ci.js
// https://jestjs.io/docs/en/configuration.html
const base = require('./jest.config')
module.exports = Object.assign({}, base, {
collectCoverage: true,
collectCoverageFrom: ["{lib,include}/**/*.{ts,tsx}", "!**/node_modules/**"],
coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov'],
reporters: ["jest-junit"]
})
- package.json
"test": "cross-env NODE_ENV=test jest --config=jest.config.js --runInBand",
"ci": "cross-env NODE_ENV=test JEST_JUNIT_OUTPUT=./test-results/jest/results.xml jest --config=jest.config.ci.js"