qingwei.li 8 жил өмнө
parent
commit
ff6803924d

+ 1 - 0
.gitignore

@@ -9,3 +9,4 @@ lib
 examples/element-ui
 fe.element/element-ui
 .npmrc
+coverage

+ 24 - 0
build/config.js

@@ -28,3 +28,27 @@ exports.alias = {
 };
 
 exports.jsexclude = /node_modules|utils\/popper\.js|utils\/date.\js/;
+
+exports.postcss = function(webapck) {
+  return [
+    require('postcss-salad')({
+      browser: ['ie > 8', 'last 2 version'],
+      features: {
+        'partialImport': {
+          addDependencyTo: webapck
+        },
+        'bem': {
+          'shortcuts': {
+            'component': 'b',
+            'modifier': 'm',
+            'descendent': 'e'
+          },
+          'separators': {
+            'descendent': '__',
+            'modifier': '--'
+          }
+        }
+      }
+    })
+  ];
+};

+ 1 - 23
build/cooking.demo.js

@@ -28,29 +28,7 @@ cooking.set({
   sourceMap: true,
   alias: config.alias,
   extends: ['vue2', 'lint'],
-  postcss: function(webapck) {
-    return [
-      require('postcss-salad')({
-        browser: ['ie > 8', 'last 2 version'],
-        features: {
-          'partialImport': {
-            addDependencyTo: webapck
-          },
-          'bem': {
-            'shortcuts': {
-              'component': 'b',
-              'modifier': 'm',
-              'descendent': 'e'
-            },
-            'separators': {
-              'descendent': '__',
-              'modifier': '--'
-            }
-          }
-        }
-      })
-    ];
-  }
+  postcss: config.postcss
 });
 
 cooking.add('loader.md', {

+ 25 - 0
build/cooking.test.js

@@ -0,0 +1,25 @@
+var path = require('path');
+var cooking = require('cooking');
+var config = require('./config');
+var projectRoot = path.resolve(__dirname, '../');
+var ProgressBarPlugin = require('progress-bar-webpack-plugin');
+
+cooking.set({
+  entry: './src/index.js',
+  extends: ['vue2'],
+  minimize: false,
+  alias: config.alias,
+  postcss: config.postcss,
+  sourceMap: '#inline-source-map'
+});
+
+cooking.add('vue.loaders.js', 'isparta');
+cooking.add('loader.js.exclude', config.jsexclude);
+cooking.add('preLoader.js', {
+  test: /\.js$/,
+  loader: 'isparta-loader',
+  include: path.resolve(projectRoot, 'src')
+});
+
+cooking.add('plugins.process', new ProgressBarPlugin());
+module.exports = cooking.resolve();

+ 5 - 1
examples/docs/zh-cn/development.md

@@ -25,7 +25,11 @@ npm run bootstrap
 registry=https://registry.npm.taobao.org
 ```
 
-然后再运行 `npm run bootstrap` 安装依赖。
+然后再运行
+
+```shell
+PHANTOMJS_CDNURL=http://npm.taobao.org/mirrors/phantomjs npm run bootstrap
+```
 
 ### 启动开发环境
 

+ 19 - 1
package.json

@@ -20,7 +20,9 @@
     "pub:all": "npm run dist:all && lerna publish",
     "build:utils": "babel src/utils --out-dir lib/utils",
     "clean": "rimraf lib && rimraf packages/*/lib",
-    "lint": "eslint src/**/*.js packages/**/*.{js,vue} build/**/*.js --quiet"
+    "lint": "eslint src/**/*.js test/**/*.js packages/**/*.{js,vue} build/**/*.js --quiet",
+    "test:watch": "karma start test/unit/karma.conf.js",
+    "test": "karma start test/unit/karma.conf.js --single-run"
   },
   "repository": {
     "type": "git",
@@ -43,6 +45,7 @@
     "babel-plugin-syntax-jsx": "^6.8.0",
     "babel-plugin-transform-vue-jsx": "^3.1.0",
     "babel-preset-es2015": "^6.14.0",
+    "chai": "^3.5.0",
     "cheerio": "^0.18.0",
     "cooking": "^1.1.0",
     "cooking-lint": "^0.1.3",
@@ -57,16 +60,31 @@
     "highlight.js": "^9.3.0",
     "html-loader": "^0.4.3",
     "html-webpack-plugin": "^2.22.0",
+    "inject-loader": "^3.0.0-beta2",
+    "isparta-loader": "^2.0.0",
     "json-loader": "^0.5.4",
     "json-templater": "^1.0.4",
+    "karma": "^1.3.0",
+    "karma-coverage": "^1.1.1",
+    "karma-mocha": "^1.2.0",
+    "karma-phantomjs-launcher": "^1.0.2",
+    "karma-sinon-chai": "^1.2.4",
+    "karma-sourcemap-loader": "^0.3.7",
+    "karma-spec-reporter": "0.0.26",
+    "karma-webpack": "^1.8.0",
     "lerna": "2.0.0-beta.18",
+    "lolex": "^1.5.1",
     "markdown-it": "^6.1.1",
     "markdown-it-container": "^2.0.0",
+    "mocha": "^3.1.1",
     "object-assign": "^4.1.0",
+    "phantomjs-prebuilt": "^2.1.13",
     "postcss": "^5.1.2",
     "postcss-loader": "^0.11.1",
     "postcss-salad": "^1.0.5",
     "rimraf": "^2.5.4",
+    "sinon": "^1.17.6",
+    "sinon-chai": "^2.8.0",
     "style-loader": "^0.13.1",
     "theaterjs": "^3.0.0",
     "uppercamelcase": "^1.1.0",

+ 9 - 0
test/unit/.eslintrc

@@ -0,0 +1,9 @@
+{
+  "env": {
+    "mocha": true
+  },
+  "globals": {
+    "expect": true,
+    "sinon": true
+  }
+}

+ 14 - 0
test/unit/index.js

@@ -0,0 +1,14 @@
+// Polyfill fn.bind() for PhantomJS
+/* eslint-disable no-extend-native */
+Function.prototype.bind = require('function-bind');
+require('packages/theme-default/src/index.css');
+
+// require all test files (files that ends with .spec.js)
+const testsContext = require.context('./specs', true, /\.spec$/);
+testsContext.keys().forEach(testsContext);
+
+// require all src files except main.js for coverage.
+// you can also change this to match only the subset of files that
+// you want coverage for.
+const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/);
+srcContext.keys().forEach(srcContext);

+ 31 - 0
test/unit/karma.conf.js

@@ -0,0 +1,31 @@
+var webpackConfig = require('../../build/cooking.test');
+
+// no need for app entry during tests
+delete webpackConfig.entry;
+
+module.exports = function(config) {
+  config.set({
+    // to run in additional browsers:
+    // 1. install corresponding karma launcher
+    //    http://karma-runner.github.io/0.13/config/browsers.html
+    // 2. add it to the `browsers` array below.
+    browsers: ['PhantomJS'],
+    frameworks: ['mocha', 'sinon-chai'],
+    reporters: ['spec', 'coverage'],
+    files: ['./index.js'],
+    preprocessors: {
+      './index.js': ['webpack', 'sourcemap']
+    },
+    webpack: webpackConfig,
+    webpackMiddleware: {
+      noInfo: true
+    },
+    coverageReporter: {
+      dir: './coverage',
+      reporters: [
+        { type: 'lcov', subdir: '.' },
+        { type: 'text-summary' }
+      ]
+    }
+  });
+};

+ 60 - 0
test/unit/specs/timeselect.spec.js

@@ -0,0 +1,60 @@
+import { createTest, createVue } from '../util';
+import TimeSelect from 'packages/time-select';
+import Vue from 'vue';
+
+describe('TimeSelect', () => {
+  it('should render correct contents', done => {
+    const vm = createTest(TimeSelect, {
+      pickerOptions: {
+        start: '08:30',
+        step: '00:15',
+        end: '18:30'
+      },
+      placeholder: 'test'
+    }, true);
+    vm.$el.querySelector('input').blur();
+    vm.$el.querySelector('input').focus();
+    vm.$el.querySelector('input').blur();
+
+    Vue.nextTick(_ => {
+      expect(vm.picker.start).to.equal('08:30');
+      expect(vm.picker.end).to.equal('18:30');
+      expect(vm.picker.step).to.equal('00:15');
+      expect(vm.$el.querySelector('input').getAttribute('placeholder')).to.equal('test');
+      done();
+    });
+  });
+
+  it('click time', done => {
+    const vm = createVue({
+      template: `
+        <div>
+          <el-time-select ref="compo" v-model="value">
+          </el-time-select>
+        </div>
+      `,
+
+      data() {
+        return {
+          value: ''
+        };
+      }
+    }, true);
+
+    vm.$el.querySelector('input').blur();
+    vm.$el.querySelector('input').focus();
+    vm.$el.querySelector('input').blur();
+
+    Vue.nextTick(_ => {
+      const items = vm.$refs.compo.picker.$el.querySelectorAll('.time-select-item');
+      const target = items[4];
+      const time = target.textContent.trim();
+
+      target.click();
+      Vue.nextTick(_ => {
+        expect(vm.value).to.equal(time);
+        done();
+      });
+    });
+  });
+});

+ 40 - 0
test/unit/util.js

@@ -0,0 +1,40 @@
+import Vue from 'vue/dist/vue';
+import Element from 'main/index.js';
+
+Vue.use(Element);
+
+let id = 0;
+
+const createElm = function() {
+  const elm = document.createElement('div');
+
+  elm.id = 'app' + ++id;
+  document.body.appendChild(elm);
+
+  return elm;
+};
+
+/**
+ * 创建一个 Vue 的实例对象
+ * @param  {Object}  Compo   组件配置
+ * @param  {Boolean=false} mounted 是否添加到 DOM 上
+ * @return {Object} vm
+ */
+exports.createVue = function(Compo, mounted = false) {
+  const elm = createElm();
+  return new Vue(Compo).$mount(mounted === false ? null : elm);
+};
+
+/**
+ * 创建一个测试组件实例
+ * @link http://vuejs.org/guide/unit-testing.html#Writing-Testable-Components
+ * @param  {Object}  Compo          - 组件对象
+ * @param  {Object}  propsData      - props 数据
+ * @param  {Boolean=false} mounted  - 是否添加到 DOM 上
+ * @return {Object} vm
+ */
+exports.createTest = function(Compo, propsData = {}, mounted = false) {
+  const elm = createElm();
+  const Ctor = Vue.extend(Compo);
+  return new Ctor({ propsData }).$mount(mounted === false ? null : elm);
+};