这是一个配置教程,关于 karma 和 jasmine 的知识请参考 karma doc 和 jasmine doc 。
开始之前先看一下我们的目录结构
1 2 3 4 5 6 7 8 9 10 11 12 13 ├── angular-cli.json ├── config.xml ├── ionic.config.json ├── node_modules ├── package.json ├── resources ├── src ├── tests ├── tsconfig.json ├── tslint.json ├── typings ├── typings.json └── www
这是一个直接使用 ionic-cli
创建的 ionic3.x
项目
step1 在项目的 package.json
的 devDependencies
中添加如下内容,然后执行 npm i
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 "@angular/cli": "^1.3.2", "@ionic/app-scripts": "2.1.3", "@types/jasmine": "^2.5.54", "@types/node": "^8.0.26", "codelyzer": "^3.1.2", "jasmine": "^2.8.0", "jasmine-core": "^2.8.0", "jasmine-spec-reporter": "^4.2.1", "karma": "^1.7.1", "karma-chrome-launcher": "^2.2.0", "karma-cli": "^1.0.1", "karma-coverage-istanbul-reporter ": "^1.3.0", "karma-jasmine": "^1.1.0", "karma-jasmine-html-reporter": "^0.2.2", "karma-mocha-reporter": "^2.2.4", "karma-remap-istanbul": "^0.6.0",
在 typings.json
(如果没有就创建一个) 文件中添加以下内容,然后执行 typings install
1 2 3 4 5 { "globalDependencies": { "jasmine": "registry:dt/jasmine#2.5.2+20170317130948" } }
在 angular-cli.json
(如果没有就创建一个)文件中添加以下内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 { "project": { "version": "1.0.0", "name": "app name" }, "apps": [ { "root": "src", "outDir": "dist", "assets": [ "assets" ], "index": "index.html", "main": "./app/main.ts", "polyfills": "../tests/polyfills.ts", "test": "../tests/test.ts", "tsconfig": "../tests/tsconfig.spec.json", "prefix": "app", "mobile": false, "styles": [ "styles.css" ], "scripts": [], "environmentSource": "../tests/environments/environment.ts", "environments": { "dev": "../tests/environments/environment.ts", "prod": "../tests/environments/environment.prod.ts" } } ], "addons": [], "packages": [], "test": { "karma": { "config": "./karma.conf.js" } }, "defaults": { "styleExt": "css", "prefixInterfaces": false, "inline": { "style": false, "template": false }, "spec": { "class": false, "component": true, "directive": true, "module": false, "pipe": true, "service": true } } }
step2 在根目录下创建 karma.conf.js
文件,内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 module.exports = function (config) { config.set({ basePath: '', frameworks: ['jasmine', '@angular/cli'], plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), require('karma-remap-istanbul'), require('karma-mocha-reporter'), require('@angular/cli/plugins/karma') ], files: [ { pattern: './src/test.ts', watched: false } ], preprocessors: { './tests/test.ts': ['@angular/cli'] }, mime: { 'text/x-typescript': ['ts','tsx'] }, remapIstanbulReporter: { reports: { html: 'coverage', lcovonly: './coverage/coverage.lcov' } }, angularCli: { config: './angular-cli.json', environment: 'dev' }, reporters: config.angularCli && config.angularCli.codeCoverage ? ['mocha', 'karma-remap-istanbul'] : ['mocha'], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false }); };
step3 在 tests 目录下面创建 tsconfig.spec.json
文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 { "compilerOptions": { "baseUrl": "", "declaration": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, "lib": [ "es6", "dom" ], "mapRoot": "./", "module": "es6", "moduleResolution": "node", "outDir": "../dist/out-tsc", "sourceMap": true, "target": "es5", "typeRoots": [ "../node_modules/@types" ] } }
step4 在 tests 目录下面创建 polyfills.ts
文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import 'core-js/es6/symbol'; import 'core-js/es6/object'; import 'core-js/es6/function'; import 'core-js/es6/parse-int'; import 'core-js/es6/parse-float'; import 'core-js/es6/number'; import 'core-js/es6/math'; import 'core-js/es6/string'; import 'core-js/es6/date'; import 'core-js/es6/array'; import 'core-js/es6/regexp'; import 'core-js/es6/map'; import 'core-js/es6/set'; import 'core-js/es6/reflect'; import 'core-js/es7/reflect'; import 'reflect-metadata'; import 'zone.js';
step5 在 tests 目录下面创建 test.ts
文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 import './polyfills'; import 'zone.js/dist/long-stack-trace-zone'; import 'zone.js/dist/proxy.js'; import 'zone.js/dist/sync-test'; import 'zone.js/dist/jasmine-patch'; import 'zone.js/dist/async-test'; import 'zone.js/dist/fake-async-test'; import {getTestBed, TestBed} from '@angular/core/testing'; import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing'; // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. declare let __karma__: any; declare let require: any; // Prevent Karma from running prematurely. __karma__.loaded = function (): void { // noop }; // First, initialize the Angular testing environment. getTestBed().initTestEnvironment( BrowserDynamicTestingModule, platformBrowserDynamicTesting() ); // Then we find all the tests. let context: any = require.context('./', true, /\.spec\.ts/); // And load the modules. context.keys().map(context); // Finally, start Karma to run the tests. __karma__.start();
step6 在 tests
目录下面创建 environments
目录,在这个目录中创建两个文件,内容分别如下
environment.ts
1 2 3 export const environment: any = { production: false, };
environment.prod.ts
1 2 3 export const environment: any = { production: true, };
Final step 在 package.json
中添加一个 scripts
至此,karma + jasmine 的测试环境已经配置完成了,执行 npm test
就可以开始执行测试用例了。
测试用例要放到 tests
目录下。我为我项目中的一个管道写的测试用例类似这个样子:
message-date.spec.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import {MessageDatePipe} from "../../src/pipes/message-date/message-date"; import {DATE_UNIT} from "../../src/constants/date-cons"; import moment = require("moment"); describe('test all cases of message date', () => { let messageDatePipe: MessageDatePipe; const today = moment(); const oneMinuteAgo = today.clone().add(-1, DATE_UNIT.MINUTES).format('x'); const oneDayAgo = today.clone().add(-1, DATE_UNIT.DAYS).format('x'); const oneWeekAgo = today.clone().add(-7, DATE_UNIT.DAYS).format('x'); beforeEach(() => { messageDatePipe = new MessageDatePipe(); }); it('one week ago', () => { expect(messageDatePipe.transform(oneWeekAgo)).toMatch(/[0-9]{4}-[0-9]{2}-[0-9]{2}/); }); it('one day ago', () => { expect(messageDatePipe.transform(oneDayAgo)).toMatch(/[0-9]{2}-[0-9]{2}/); }); it('within current day', () => { expect(messageDatePipe.transform(oneMinuteAgo)).toMatch(/(A|P)M [0-9]{2}:[0-9]{2}/); }); it('one week ago num', () => { expect(messageDatePipe.transform(parseInt(oneWeekAgo))).toMatch(/[0-9]{4}-[0-9]{2}-[0-9]{2}/); }); it('one day ago num', () => { expect(messageDatePipe.transform(parseInt(oneDayAgo))).toMatch(/[0-9]{2}-[0-9]{2}/); }); it('within current day num', () => { expect(messageDatePipe.transform(parseInt(oneMinuteAgo))).toMatch(/(A|P)M [0-9]{2}:[0-9]{2}/); }); });
运行后结果如图所示