Commit 9b6ff1ce28f5b85b86a886986ee8d5de7bb87fd9
1 parent
c9c5e751
add test and update webpack config
[new] add test config [new] add breadcrumb test [change] update package.json [new] util.js copied from element [unresolved] see test/unit/index.js @todo
Showing
10 changed files
with
222 additions
and
4 deletions
Show diff stats
.gitignore
build/webpack.base.config.js
@@ -2,6 +2,10 @@ | @@ -2,6 +2,10 @@ | ||
2 | * 公共配置 | 2 | * 公共配置 |
3 | */ | 3 | */ |
4 | var webpack = require('webpack'); | 4 | var webpack = require('webpack'); |
5 | +var path = require('path'); | ||
6 | +function resolve (dir) { | ||
7 | + return path.join(__dirname, '..', dir) | ||
8 | +} | ||
5 | 9 | ||
6 | module.exports = { | 10 | module.exports = { |
7 | // 加载器 | 11 | // 加载器 |
@@ -55,6 +59,10 @@ module.exports = { | @@ -55,6 +59,10 @@ module.exports = { | ||
55 | ] | 59 | ] |
56 | }, | 60 | }, |
57 | resolve: { | 61 | resolve: { |
58 | - extensions: ['.js', '.vue'] | 62 | + extensions: ['.js', '.vue'], |
63 | + alias: { | ||
64 | + 'vue': 'vue/dist/vue.esm.js', | ||
65 | + '@': resolve('src'), | ||
66 | + } | ||
59 | } | 67 | } |
60 | }; | 68 | }; |
build/webpack.dev.config.js
@@ -8,6 +8,7 @@ var webpack = require('webpack'); | @@ -8,6 +8,7 @@ var webpack = require('webpack'); | ||
8 | var HtmlWebpackPlugin = require('html-webpack-plugin'); | 8 | var HtmlWebpackPlugin = require('html-webpack-plugin'); |
9 | var merge = require('webpack-merge') | 9 | var merge = require('webpack-merge') |
10 | var webpackBaseConfig = require('./webpack.base.config.js'); | 10 | var webpackBaseConfig = require('./webpack.base.config.js'); |
11 | +var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') | ||
11 | 12 | ||
12 | 13 | ||
13 | module.exports = merge(webpackBaseConfig, { | 14 | module.exports = merge(webpackBaseConfig, { |
@@ -35,6 +36,7 @@ module.exports = merge(webpackBaseConfig, { | @@ -35,6 +36,7 @@ module.exports = merge(webpackBaseConfig, { | ||
35 | inject: true, | 36 | inject: true, |
36 | filename: path.join(__dirname, '../examples/dist/index.html'), | 37 | filename: path.join(__dirname, '../examples/dist/index.html'), |
37 | template: path.join(__dirname, '../examples/index.html') | 38 | template: path.join(__dirname, '../examples/index.html') |
38 | - }) | 39 | + }), |
40 | + new FriendlyErrorsPlugin() | ||
39 | ] | 41 | ] |
40 | }); | 42 | }); |
1 | +/** | ||
2 | + * 用于单元测试 | ||
3 | + */ | ||
4 | + | ||
5 | +var webpack = require('webpack') | ||
6 | +var merge = require('webpack-merge') | ||
7 | +var webpackBaseConfig = require('./webpack.base.config.js'); | ||
8 | + | ||
9 | + | ||
10 | +var webpackConfig = merge(webpackBaseConfig, { | ||
11 | + // use inline sourcemap for karma-sourcemap-loader | ||
12 | + devtool: '#inline-source-map', | ||
13 | + plugins: [ | ||
14 | + new webpack.DefinePlugin({ | ||
15 | + 'process.env': { | ||
16 | + NODE_ENV: '"testing"' | ||
17 | + } | ||
18 | + }) | ||
19 | + ] | ||
20 | +}) | ||
21 | + | ||
22 | +// no need for app entry during tests | ||
23 | +delete webpackConfig.entry | ||
24 | + | ||
25 | +module.exports = webpackConfig |
package.json
@@ -25,7 +25,8 @@ | @@ -25,7 +25,8 @@ | ||
25 | "dist:prod": "webpack --config build/webpack.dist.prod.config.js", | 25 | "dist:prod": "webpack --config build/webpack.dist.prod.config.js", |
26 | "dist": "npm run dist:style && npm run dist:dev && npm run dist:prod", | 26 | "dist": "npm run dist:style && npm run dist:dev && npm run dist:prod", |
27 | "lint": "eslint --fix --ext .js,.vue src", | 27 | "lint": "eslint --fix --ext .js,.vue src", |
28 | - "test": "npm run dist && npm run lint", | 28 | + "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run", |
29 | + "test": "npm run unit", | ||
29 | "prepublish": "npm run dist" | 30 | "prepublish": "npm run dist" |
30 | }, | 31 | }, |
31 | "repository": { | 32 | "repository": { |
@@ -54,11 +55,14 @@ | @@ -54,11 +55,14 @@ | ||
54 | "babel-plugin-transform-runtime": "^6.12.0", | 55 | "babel-plugin-transform-runtime": "^6.12.0", |
55 | "babel-preset-es2015": "^6.9.0", | 56 | "babel-preset-es2015": "^6.9.0", |
56 | "babel-runtime": "^6.11.6", | 57 | "babel-runtime": "^6.11.6", |
58 | + "chai": "^3.5.0", | ||
59 | + "cross-env": "^3.1.4", | ||
57 | "css-loader": "^0.23.1", | 60 | "css-loader": "^0.23.1", |
58 | "eslint": "^3.12.2", | 61 | "eslint": "^3.12.2", |
59 | "eslint-plugin-html": "^1.7.0", | 62 | "eslint-plugin-html": "^1.7.0", |
60 | "extract-text-webpack-plugin": "^2.0.0", | 63 | "extract-text-webpack-plugin": "^2.0.0", |
61 | "file-loader": "^0.8.5", | 64 | "file-loader": "^0.8.5", |
65 | + "friendly-errors-webpack-plugin": "^1.6.1", | ||
62 | "gulp": "^3.9.1", | 66 | "gulp": "^3.9.1", |
63 | "gulp-autoprefixer": "^3.1.1", | 67 | "gulp-autoprefixer": "^3.1.1", |
64 | "gulp-clean-css": "^2.0.13", | 68 | "gulp-clean-css": "^2.0.13", |
@@ -66,8 +70,21 @@ | @@ -66,8 +70,21 @@ | ||
66 | "gulp-rename": "^1.2.2", | 70 | "gulp-rename": "^1.2.2", |
67 | "html-loader": "^0.3.0", | 71 | "html-loader": "^0.3.0", |
68 | "html-webpack-plugin": "^2.28.0", | 72 | "html-webpack-plugin": "^2.28.0", |
73 | + "karma": "^1.4.1", | ||
74 | + "karma-coverage": "^1.1.1", | ||
75 | + "karma-mocha": "^1.3.0", | ||
76 | + "karma-phantomjs-launcher": "^1.0.2", | ||
77 | + "karma-sinon-chai": "^1.2.4", | ||
78 | + "karma-sourcemap-loader": "^0.3.7", | ||
79 | + "karma-spec-reporter": "0.0.26", | ||
80 | + "karma-webpack": "^2.0.2", | ||
69 | "less": "^2.7.1", | 81 | "less": "^2.7.1", |
70 | "less-loader": "^2.2.3", | 82 | "less-loader": "^2.2.3", |
83 | + "lolex": "^1.5.2", | ||
84 | + "mocha": "^3.2.0", | ||
85 | + "phantomjs-prebuilt": "^2.1.13", | ||
86 | + "sinon": "^1.17.7", | ||
87 | + "sinon-chai": "^2.8.0", | ||
71 | "style-loader": "^0.13.1", | 88 | "style-loader": "^0.13.1", |
72 | "url-loader": "^0.5.7", | 89 | "url-loader": "^0.5.7", |
73 | "vue": "^2.2.1", | 90 | "vue": "^2.2.1", |
@@ -80,5 +97,9 @@ | @@ -80,5 +97,9 @@ | ||
80 | "webpack": "^2.2.1", | 97 | "webpack": "^2.2.1", |
81 | "webpack-dev-server": "^2.4.1", | 98 | "webpack-dev-server": "^2.4.1", |
82 | "webpack-merge": "^3.0.0" | 99 | "webpack-merge": "^3.0.0" |
100 | + }, | ||
101 | + "engines": { | ||
102 | + "node": ">= 4.0.0", | ||
103 | + "npm": ">= 3.0.0" | ||
83 | } | 104 | } |
84 | } | 105 | } |
test deleted
1 | +import Vue from 'vue'; | ||
2 | +Vue.config.productionTip = false; | ||
3 | + | ||
4 | +// Polyfill fn.bind() for PhantomJS | ||
5 | +/* eslint-disable no-extend-native */ | ||
6 | +Function.prototype.bind = require('function-bind'); | ||
7 | + | ||
8 | +// require all test files (files that ends with .spec.js) | ||
9 | +const testsContext = require.context('./specs', true, /\.spec$/); | ||
10 | +testsContext.keys().forEach(testsContext); | ||
11 | + | ||
12 | +// require all src files except main.js for coverage. | ||
13 | +// you can also change this to match only the subset of files that | ||
14 | +// you want coverage for. | ||
15 | +// const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/); | ||
16 | +// @todo | ||
17 | +const srcContext = require.context('../../src/components/breadcrumb', true, /^\.\/(?!styles.*?(\.less)?$)/); | ||
18 | +srcContext.keys().forEach(srcContext); |
1 | +// This is a karma config file. For more details see | ||
2 | +// http://karma-runner.github.io/0.13/config/configuration-file.html | ||
3 | +// we are also using it with karma-webpack | ||
4 | +// https://github.com/webpack/karma-webpack | ||
5 | + | ||
6 | +var webpackConfig = require('../../build/webpack.test.config.js'); | ||
7 | + | ||
8 | +module.exports = function (config) { | ||
9 | + config.set({ | ||
10 | + // to run in additional browsers: | ||
11 | + // 1. install corresponding karma launcher | ||
12 | + // http://karma-runner.github.io/0.13/config/browsers.html | ||
13 | + // 2. add it to the `browsers` array below. | ||
14 | + browsers: ['PhantomJS'], | ||
15 | + frameworks: ['mocha', 'sinon-chai'], | ||
16 | + reporters: ['spec', 'coverage'], | ||
17 | + files: ['./index.js'], | ||
18 | + preprocessors: { | ||
19 | + './index.js': ['webpack', 'sourcemap'] | ||
20 | + }, | ||
21 | + webpack: webpackConfig, | ||
22 | + webpackMiddleware: { | ||
23 | + noInfo: true, | ||
24 | + }, | ||
25 | + coverageReporter: { | ||
26 | + dir: './coverage', | ||
27 | + reporters: [ | ||
28 | + { type: 'lcov', subdir: '.' }, | ||
29 | + { type: 'text-summary' }, | ||
30 | + ] | ||
31 | + }, | ||
32 | + }); | ||
33 | +}; |
1 | +import { createVue, destroyVM } from '../util'; | ||
2 | + | ||
3 | +describe('Breadcrumb.vue', () => { | ||
4 | + let vm; | ||
5 | + afterEach(() => { | ||
6 | + destroyVM(vm); | ||
7 | + }); | ||
8 | + it('create', done => { | ||
9 | + vm = createVue(` | ||
10 | + <Breadcrumb separator="<b class='demo-breadcrumb-separator'>=></b>"> | ||
11 | + <Breadcrumb-item href="/">Home4</Breadcrumb-item> | ||
12 | + <Breadcrumb-item href="/components/breadcrumb">Components</Breadcrumb-item> | ||
13 | + <Breadcrumb-item>Breadcrumb</Breadcrumb-item> | ||
14 | + </Breadcrumb> | ||
15 | + `); | ||
16 | + expect(vm.$el.querySelectorAll('.ivu-breadcrumb-item-link').length).to.equal(3); | ||
17 | + | ||
18 | + vm.$nextTick(_ => { | ||
19 | + // console.log(vm.$el.querySelector('.ivu-breadcrumb-item-separator').innerHTML); | ||
20 | + expect(vm.$el.querySelector('.ivu-breadcrumb-item-separator').innerHTML).to.equal('<b class="demo-breadcrumb-separator">=></b>'); | ||
21 | + done(); | ||
22 | + }); | ||
23 | + }); | ||
24 | +}); | ||
0 | \ No newline at end of file | 25 | \ No newline at end of file |
1 | +import Vue from 'vue'; | ||
2 | +import iView from '../../src/index'; | ||
3 | + | ||
4 | +Vue.use(iView); | ||
5 | + | ||
6 | +let id = 0; | ||
7 | + | ||
8 | +const createElm = function() { | ||
9 | + const elm = document.createElement('div'); | ||
10 | + | ||
11 | + elm.id = 'app' + ++id; | ||
12 | + document.body.appendChild(elm); | ||
13 | + | ||
14 | + return elm; | ||
15 | +}; | ||
16 | + | ||
17 | +/** | ||
18 | + * 回收 vm | ||
19 | + * @param {Object} vm | ||
20 | + */ | ||
21 | +exports.destroyVM = function(vm) { | ||
22 | + vm.$el && | ||
23 | + vm.$el.parentNode && | ||
24 | + vm.$el.parentNode.removeChild(vm.$el); | ||
25 | +}; | ||
26 | + | ||
27 | +/** | ||
28 | + * 创建一个 Vue 的实例对象 | ||
29 | + * @param {Object|String} Compo 组件配置,可直接传 template | ||
30 | + * @param {Boolean=false} mounted 是否添加到 DOM 上 | ||
31 | + * @return {Object} vm | ||
32 | + */ | ||
33 | +exports.createVue = function(Compo, mounted = false) { | ||
34 | + const elm = createElm(); | ||
35 | + | ||
36 | + if (Object.prototype.toString.call(Compo) === '[object String]') { | ||
37 | + Compo = { template: Compo }; | ||
38 | + } | ||
39 | + return new Vue(Compo).$mount(mounted === false ? null : elm); | ||
40 | +}; | ||
41 | + | ||
42 | +/** | ||
43 | + * 创建一个测试组件实例 | ||
44 | + * @link http://vuejs.org/guide/unit-testing.html#Writing-Testable-Components | ||
45 | + * @param {Object} Compo - 组件对象 | ||
46 | + * @param {Object} propsData - props 数据 | ||
47 | + * @param {Boolean=false} mounted - 是否添加到 DOM 上 | ||
48 | + * @return {Object} vm | ||
49 | + */ | ||
50 | +exports.createTest = function(Compo, propsData = {}, mounted = false) { | ||
51 | + if (propsData === true || propsData === false) { | ||
52 | + mounted = propsData; | ||
53 | + propsData = {}; | ||
54 | + } | ||
55 | + const elm = createElm(); | ||
56 | + const Ctor = Vue.extend(Compo); | ||
57 | + return new Ctor({ propsData }).$mount(mounted === false ? null : elm); | ||
58 | +}; | ||
59 | + | ||
60 | +/** | ||
61 | + * 触发一个事件 | ||
62 | + * mouseenter, mouseleave, mouseover, keyup, change, click 等 | ||
63 | + * @param {Element} elm | ||
64 | + * @param {String} name | ||
65 | + * @param {*} opts | ||
66 | + */ | ||
67 | +exports.triggerEvent = function(elm, name, ...opts) { | ||
68 | + let eventName; | ||
69 | + | ||
70 | + if (/^mouse|click/.test(name)) { | ||
71 | + eventName = 'MouseEvents'; | ||
72 | + } else if (/^key/.test(name)) { | ||
73 | + eventName = 'KeyboardEvent'; | ||
74 | + } else { | ||
75 | + eventName = 'HTMLEvents'; | ||
76 | + } | ||
77 | + const evt = document.createEvent(eventName); | ||
78 | + | ||
79 | + evt.initEvent(name, ...opts); | ||
80 | + elm.dispatchEvent | ||
81 | + ? elm.dispatchEvent(evt) | ||
82 | + : elm.fireEvent('on' + name, evt); | ||
83 | + | ||
84 | + return elm; | ||
85 | +}; |