之前我们做单元测试,自己在app.js里写测试用例,但是每次都需要刷新浏览器。能不能有一种方法,能运行一句代码后,就自动唤起浏览器,自动运行测试用例呢
于是我们使用 Karma + Mocha做单元测试
一. 实现自动打开浏览器测试
Karma([ˈkɑrmə] 卡玛)是一个测试运行器,它可以呼起浏览器,加载测试脚本,然后运行测试用例
Mocha([ˈmoʊkə] 摩卡)是一个单元测试框架/库,它可以用来写测试用例
步骤
1. 安装各种工具
npm i -D karma karma-chrome-launcher karma-mocha karma-sinon-chai mocha sinon sinon-chai karma-chai karma-chai-spies
2. 创建 karma 配置
// 新建 karma.conf.js,内容如下
module.exports = function (config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['mocha', 'sinon-chai'],
client: {
chai: {
includeStack: true
}
},
// list of files / patterns to load in the browser
files: [
'dist/**/*.test.js',
'dist/**/*.test.css'
],
// list of files / patterns to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['ChromeHeadless'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity
})
}
3. 创建 test/button.test.js 文件
const expect = chai.expect;
import Vue from 'vue'
import Button from '../src/button'
Vue.config.productionTip = false
Vue.config.devtools = false
describe('Button', () => {
it('存在.', () => {
expect(Button).to.be.ok
})
it('可以设置icon.', () => {
const Constructor = Vue.extend(Button)
const vm = new Constructor({
propsData: {
icon: 'settings'
}
}).$mount()
const useElement = vm.$el.querySelector('use')
expect(useElement.getAttribute('xlink:href')).to.equal('#i-settings')
vm.$destroy()
})
it('可以设置loading.', () => {
const Constructor = Vue.extend(Button)
const vm = new Constructor({
propsData: {
icon: 'settings',
loading: true
}
}).$mount()
const useElements = vm.$el.querySelectorAll('use')
expect(useElements.length).to.equal(1)
expect(useElements[0].getAttribute('xlink:href')).to.equal('#i-loading')
vm.$destroy()
})
it('icon 默认的 order 是 1', () => {
const div = document.createElement('div')
document.body.appendChild(div)
const Constructor = Vue.extend(Button)
const vm = new Constructor({
propsData: {
icon: 'settings',
}
}).$mount(div)
const icon = vm.$el.querySelector('svg')
expect(getComputedStyle(icon).order).to.eq('1')
vm.$el.remove()
vm.$destroy()
})
it('设置 iconPosition 可以改变 order', () => {
const div = document.createElement('div')
document.body.appendChild(div)
const Constructor = Vue.extend(Button)
const vm = new Constructor({
propsData: {
icon: 'settings',
iconPosition: 'right'
}
}).$mount(div)
const icon = vm.$el.querySelector('svg')
expect(getComputedStyle(icon).order).to.eq('2')
vm.$el.remove()
vm.$destroy()
})
it('点击 button 触发 click 事件', () => {
const Constructor = Vue.extend(Button)
const vm = new Constructor({
propsData: {
icon: 'settings',
}
}).$mount()
const callback = sinon.fake();
vm.$on('click', callback)
vm.$el.click()
expect(callback).to.have.been.called
})
})
4. 创建测试脚本
在 package.json 里面找到 scripts 并改写 scripts
"scripts": {
"dev-test": "parcel watch test/* --no-cache & karma start",
"test": "parcel build test/* --no-cache --no-minify && karma start --single-run"
},
5. 运行测试脚本
可以使用npm run test ,他会先把test目录下的所有文件打包,然后不缓存。成功以后,开启karma,只运行一次。
这种情况下,我们每次修改代码,想再次测试,就要重新运行npm run test 一次,能不能让我在修改代码后,就能自动测试呢?
使用npm run dev-test ,但是windows上会报错,分着输入命令:新开一个 Git Bash 窗口运行 npx parcel watch test/* --no-cache
再开一个 Git Bash 窗口运行 npx karma start。这样一来,只需要在一开始输入这两句命令,之后只要修改代码,就能自动测试了。
二. 使用travisci 持续集成
之前我们使用npm run dev-test 能实现一句代码,自动测试。能不能再自动化一点,让我们不需要输入命令,就能自动测试呢?
可以持续集成。使用travisci。前提是在项目的根目录下边,新建一个.travis.yml文件,写入一下内容:
language: node_js
node_js:
- "8"
addons:
chrome: stable
sudo: required
before_script:
- "sudo chown root /opt/google/chrome/chrome-sandbox"
- "sudo chmod 4755 /opt/google/chrome/chrome-sandbox"
然后,登录travisci官网,选择要进行持续集成的项目。
然后把当前代码提交,push到github,在travisci那里就能自动测试。
之后如果修改了代码,只要把代码push到github上,travisci就能自动进行测试,检查有没有错误,这就是持续集成
三. 发布自己的npm包,给别人用
我们使用别人的包,要通过npm下载。那想把自己的代码给别人用,就要把自己的代码上传到npm,让别人通过npm下载。
步骤:
-
确保所有代码都测试通过
npm run test 全部是绿色才行。
-
上传代码到 npmjs.org
首先更新 package.json:
在 package.json 里将版本号改为 0.0.1,等全都做完了再改成 1.0.0
根目录下创建 index.js,在 index.js 里将你想要导出的内容全部导出(想让别人用的东西),比如我们现在只写了三个按钮,那就导出这三个按钮。
import Button from "./src/Button";
import ButtonGroup from "./src/ButtonGroup";
import Icon from "./src/Icon";
export {Button,ButtonGroup,Icon}
这个index.js就是package.json文件里的入口文件,即`main`选项后边的就写`index.js`
去官网 www.npmjs.com/ 注册一个账户,注册后会给我们发邮件,必须打开一下,之后才能发布。
在 要发布的项目根目录运行 npm adduser ,逐步填写用户名,密码,邮箱。
如果错误提示里面含有 registry.npm.taobao.org 则说明我们的 npm 源目前为淘宝源,需要更换为 npm 官方源才行。怎么换呢?先运行npm config list ,会看到配置选项,
发现很多都是淘宝源,我们只需要修改带有
registry这个字段的,找它所在的路径,在我这里就是C:\Users\18742\.npmrc 这个文件,打开这个文件,把registry = "https://registry.npm.taobao.org/" 这一句注释掉,保存。现在就不是淘宝源了。
然后重新npm adduser ,逐步填写用户名,密码,邮箱。此时应该正常了,会显示:正确的官方源:
- 运行
npm publish发布(之前要把所有代码提交,push)。如果成功,会显示:然后别人通过
npm i my_wheel就可以安装我们发布的包了。
成功发布之后,就可以回去再把npm源改成淘宝源,为了以后安装其他包速度快一点(注释去掉)。以后就发布之前用官方源,之后改回淘宝源
假装别人使用自己的包
在桌面建一个tmp目录,在这个目录下安装我们的包:npm i my_wheel ,安装成功后,看到项目结构变成了这样:其实这里并不需要上传我们的所有代码,有一些是可以废弃的。
我们的包是一个Vue的UI框架,所以猜测用户会使用vue-cli 使用我们的包。那我们就假装在使用vue-cli的情况下,看看是否能成功使用我们的包。
去vue-cli 的官网,照着步骤搭建一个项目,
npm install -g @vue/cli
vue create hello-world
cd hello-world
npm run serve
就能用浏览器打开,看到一个最基本的页面。
然后怎么在hello-world这个里用我们的包呢?当然是进入这个目录,
npm i my_wheel 安装。安装好了以后,试试能不能用:在用户的入口文件main.js里
import {Button,ButtonGroup,Icon} from 'my_wheel'
console.log(Button)
console.log(ButtonGroup);
console.log(Icon);
发现浏览器报错了:这是因为我们导出这个包的时候是在index.js里用export语法导出别人要用的东西,所以就需要使用import语法导入。但是问题就在于,目前node还不支持import语法。
解决: 用 babel 转译 import。转译好了再给别人用。
在我们的轮子项目里:
npx parcel build index.js --no-minify(本来不应该加 --no-minify 的,奈何不加会有 bug,HTML 压缩把 slot 标签全删了)。它会生成dist目录下的三个文件:- 将 package.json 的 main 改为 dist/index.js,即导出dist里的index.js,因为只有这个才是转译过的
然后重新npm publish 发布包,注意版本号要变,不能是上一个
然后切换回用户,再次安装这个包,它会自动下载最新的版本。
发现可以正确打印引入的对象了:
然后使用这些组件:
<template>
<div id="app">
<Button>我是一个按钮</Button>
</div>
</template>
<script>
import {Button} from 'my_wheel'
export default {
name: 'App',
components: {
Button
}
}
</script>
用户可以成功使用了!
npm link 简化发布过程
现在我们每修改一次源代码,就要更新pacjage.json里的版本号,npm publish上传一次,然后为了测试是否好用,用户就要随之再下载更新一次。能不能加快这个效率呢?
有一种方法,用于本机上测试的高效的做法:
修改代码后,在项目目录使用 npm link,然后为了自己测试能不能用,在本机上,在使用之处运行 npm link my_wheel,就是最新了
如果使用yarn,就把npm 都换成yarn 就行了。