美文网首页
[日记]Angular Unit Test(mocha&chai

[日记]Angular Unit Test(mocha&chai

作者: 刘开心_8a6c | 来源:发表于2019-03-12 22:52 被阅读0次

    主要参考这篇博客,配置了mocha,对文中废弃的写法进行了修改,并用一个demo做了component的单元测试,包含input、button的相关行为,写法其实与Angular自带的jasmine+Karma一样,只是换了一个测试框架。

    install:

    • mocha (test runner)
    • mocha-webpack (build the tests with Webpack before running them)
    • chai (assertion library)
    • @types/chai (TypeScript definitions for chai)
    • sinon (mocking library)
    • @types/sinon (TypeScript definitions for sinon)
    • webpack-node-externals (exclude server-side node modules from the build)
    • jsdom (provides stubs for DOM API required by Angular - HTMLElement, XMLHttpRequest)
    npm install --save-dev mocha mocha-webpack chai @types/chai sinon @types/sinon webpack-node-externals jsdom
    

    目前mocha-webpack只支持mocha5以下,所以可能会提示:

    npm WARN mocha-webpack@1.1.0 requires a peer of mocha@>=2.4.5 <=5 but none is installed. You must install peer dependencies yourself.
    npm WARN mocha-webpack@1.1.0 requires a peer of webpack@^2.0.0 || ^3.0.0 but none is installed. You must install peer dependencies yourself.
    

    手动把设mocha-webpack与mocha的版本为:

     "mocha": "5.0.0",
     "mocha-webpack": "2.0.0-beta.0",
    

    config

    1. 在项目目录中添加config文件夹,与src同级,创建下面四个文件:
    • helpers.js
    • mocha-test-shim.js
    • webpack-mocha.js
    • webpack-test.js
    1. helpers.js:
    var path = require('path');
    var _root = path.resolve(__dirname, '..');
    function root(args) {
      args = Array.prototype.slice.call(arguments, 0);
      return path.join.apply(path, [_root].concat(args));
    }
    exports.root = root;
    
    
    1. mocha-test-shim.js
      这个文件改动较大。改动如下:
    • 注意顺序,require一定要放在最前面,zone的顺序最好不要乱,否则可能报错,而且测试中不能用async,否则会报ProxZone之类的错,所以对于async的测试怎么办还需要想办法;
    • 原来的require('zone.js/dist/zone')需要换成require('zone.js/dist/zone-node'),否则会报Zone 的reference error;
    • jsdom的写法改变了,测试文件中用的document、node、event等全部要在这里设定,通过global.xxx = window.xxx的方式,否则会出现xxx is not defined的错误。
      改动后的内容为:
    require('core-js/es6');
    require('core-js/es7/reflect');
    
    require('zone.js/dist/zone-node');
    require('zone.js/dist/long-stack-trace-zone');
    require('zone.js/dist/proxy');
    require('zone.js/dist/sync-test');
    require('zone.js/dist/async-test');
    require('zone.js/dist/fake-async-test');
    
    var jsdom = require('jsdom')
    const { JSDOM } = jsdom;
    var document = new JSDOM('<!doctype html><html><body></body></html>');
    
    global.window = document.window;
    global.document = document.window.document;
    global.HTMLElement = window.HTMLElement;
    global.XMLHttpRequest = window.XMLHttpRequest;
    global.Node = window.Node;
    global.Event = window.Event;
    // global.Text = window.Text;
    // global.DOMTokenList = window.DOMTokenList;
    
    var testing = require('@angular/core/testing');
    var browser = require('@angular/platform-browser-dynamic/testing');
    
    testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting());
    
    1. webpack-test.js
      这个文件也有改动:
    • loaders换成rules;
    • 所有的loader都要写全称,并且用npm进行安装;
      npm install --save awesome-typescript-loader angular2-template-loader html-loader null-loader raw-loade
      改动后的内容如下:
    var helpers = require('./helpers');
    
    module.exports = {
      devtool: 'cheap-module-source-map',
    
      resolve: {
        extensions: ['*', '.ts', '.js']
      },
    
      module: {
        rules: [
          {
            test: /\.ts$/,
            loader: ['awesome-typescript-loader', 'angular2-template-loader']
          },
          {
            test: /\.html$/,
            loader: 'html-loader'
          },
          {
            test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
            loader: 'null-loader'
          },
          {
            test: /\.css$/,
            exclude: helpers.root('src', 'app'),
            loader: 'null-loader'
          },
          {
            test: /\.css$/,
            include: helpers.root('src', 'app'),
            loader: 'raw-loader'
          }
        ]
      }
    }
    
    
    1. 在与src同级的目录中新建mocha-webpack.opts文件,主要用来设置webpack的,这样就不需要每次在命令行里输入所传的参数。文件内容如下:
    --webpack-config config/webpack.mocha.js webpack --mode=development
    --require config/mocha-test-shim.js
    src/**/*.spec.ts
    

    在scripts中加入:

    "scripts": {
        ...
        "test": "mocha-webpack",
        ...
      },
    

    demo

    使用与Angular Form中相同的demo,在其基础上添加测试,这里主要抽象出对于input以及button等控件的测试,具体代码可以到repo来看。

    设置TestBed,需要把用到的Module写到imports中

    beforeEach((() => {
        TestBed.configureTestingModule({
          declarations: [
            AppComponent
          ],
          imports: [
            ReactiveFormsModule,
            FormsModule,
          ],
        }).compileComponents();
      }));
    
      afterEach(() => {
        getTestBed().resetTestingModule();
      });
    

    获取fixture以及component

    也可以写在before里,复用,根据需求来。

    const fixture = TestBed.createComponent(AppComponent);
    const component = fixture.componentInstance;
    

    获取html的dom元素:

    querySelector中获取元素的方式与css一样,css的selector都可以用。

     const nameInput = fixture.nativeElement.querySelector('#nameInput');
     const zodiacSignInput = fixture.nativeElement.querySelector('#zodiacSignInput');
    

    每次对内容进行修改后,记得fixture.detectChanges

    有时候测试挂掉是因为没有detectChanges或者detectChanges的位置没有放对。

    ...
    component.editMode = true;
    fixture.detectChanges();
    ...
    

    写断言

    这里用的chai。

     expect(showNameInput.value).to.equal('Kate');
    

    创建Event来模拟用户输入

    注意,如果这里有Event,就要在mocha-test-shim.js中加global.Event=window.Event

    ...
    const event = new Event('input');
    nameInput.value = 'Kate';
    zodiacSignInput.value = 'Cancer';
    nameInput.dispatchEvent(event);
    zodiacSignInput.dispatchEvent(event);
    fixture.detectChanges();
    ...
    

    常见Error:

    1. "before each" hook for "xxx":
      ** Error: Expected to be running in 'ProxyZone', but it was not found.**


      ProxZone problem

      解决:检查test中是否有async,如果有,删掉。

    2. Zone.__load_patch('ZoneAwarePromise', function (global, Zone, api) {
      ^
      ReferenceError: Zone is not defined
      解决:将mocha-test-shim.js文件中所有require的移动到最上边,zone换成zone-node
    3. ReferenceError: Event is not defined

    ​ at Context.<anonymous> (.tmp/mocha-webpack/1552397596789/webpack:/src/app/app.component.spec.ts:92:1)
    解决:在mocha-test-shim.js中加global.Event=window.Event

    repo:https://github.com/LiuKaixinHappy/angular-form-demo


    好的mock store的博客:

    相关文章

      网友评论

          本文标题:[日记]Angular Unit Test(mocha&chai

          本文链接:https://www.haomeiwen.com/subject/ebvopqtx.html