1. 程式人生 > >對vue-cli(增加/進行)單元測試,所遇到的問題及解決方法。 dom節點為null等

對vue-cli(增加/進行)單元測試,所遇到的問題及解決方法。 dom節點為null等

1、用vue-cli生成一個新的專案,把單元測試需要的檔案直接複製到你現有的專案中

2.增加啟動入口

"unit": "karma start test/unit/karma.conf.js --single-run"

3.安裝單元測試需要的外掛

npm i -D karma karma-webpack phantomjs-prebuilt karma-phantomjs-launcher karma-phantomjs-shim karma-chrome-launcher karma-sourcemap-loader mocha karma-mocha sinon chai sinon-chai karma-sinon-chai karma-spec-reporter karma-coverage

4.複製vue-cli生成helloWorld.vue檔案到現有專案

執行 npm run unit 

這是測試通過的截圖。

採坑1、 網上找到解決方法

採坑2、執行各種出錯!汗...

在karma.conf.js檔案裡把 PhantomJS 換為 Chrome

採坑2、點選事件及事件封裝方法。

未封裝前:

封裝後:

封裝的util.js採用elementUI專案的原始碼並稍微改動,如createTest函式

util.js貼在本頁最底下。

採坑3、vm.$el.querySelector('xxx') 為 null 等情況.

vm.$el為本元件的dom節點,只能獲取元件內的dom

全域性彈窗等在元件外生成dom,需要從document/html下獲取對應dom

如有引入element等第三方外掛,需要引入

最後建議:github上下載elementUI專案的原始碼進行參考。

util.js:

import Vue from 'vue';
import ElementUI from 'element-ui';

Vue.use(ElementUI);

let id = 0;

const createElm = function() {
    const elm = document.createElement('div');

    elm.id = 'app' + ++id;
    document.body.appendChild(elm);

    return elm;
};

/**
 * 回收 vm
 * @param {Object} vm vm
 */

const destroyVM = function(vm) {
    vm.$destroy && vm.$destroy();
    vm.$el &&
    vm.$el.parentNode &&
    vm.$el.parentNode.removeChild(vm.$el);
};

/**
 * 建立一個 Vue 的例項物件
 * @param  {Object|String} Compo   元件配置,可直接傳 template
 * @param  {Boolean=false} mounted 是否新增到 DOM 上
 * @return {Object} vm
 */

const createVue = function(Compo, mounted = false) {
    if (Object.prototype.toString.call(Compo) === '[object String]') {
        Compo = { template: Compo };
    }
    return new Vue(Compo).$mount(mounted === false ? null : createElm());
};

/**
 * 建立一個測試元件例項
 * @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
 */

const createTest = function(Compo, propsData = {}, mounted = false) {
    if (propsData === true || propsData === false) {
        mounted = propsData;
        propsData = {};
    }
    const elm = createElm();
    const Ctor = Vue.extend(Compo);
    return new Ctor({ propsData }).$mount(mounted === false ? null : elm);
};

/**
 * 觸發一個事件
 * mouseenter, mouseleave, mouseover, keyup, change, click 等
 * @param  {Element} elm
 * @param  {String} name
 * @param  {*} opts
 */

const triggerEvent = function(elm, name, ...opts) {
    let eventName;

    if (/^mouse|click/.test(name)) {
        eventName = 'MouseEvents';
    } else if (/^key/.test(name)) {
        eventName = 'KeyboardEvent';
    } else {
        eventName = 'HTMLEvents';
    }
    const evt = document.createEvent(eventName);

    evt.initEvent(name, ...opts);
    elm.dispatchEvent
        ? elm.dispatchEvent(evt)
        : elm.fireEvent('on' + name, evt);

    return elm;
};

/**
 * 觸發 “mouseup” 和 “mousedown” 事件
 * @param {Element} elm
 * @param {*} opts
 */

const triggerClick = function(elm, ...opts) {
    exports.triggerEvent(elm, 'mousedown', ...opts);
    exports.triggerEvent(elm, 'mouseup', ...opts);

    return elm;
};

/**
 * 觸發 keydown 事件
 * @param {Element} elm
 * @param {keyCode} int
 */

const triggerKeyDown = function(el, keyCode) {
    const evt = document.createEvent('Events');
    evt.initEvent('keydown', true, true);
    evt.keyCode = keyCode;
    el.dispatchEvent(evt);
};

export {
    destroyVM,
    createVue,
    createTest,
    triggerEvent,
    triggerClick,
    triggerKeyDown
};