Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit 41a9047

Browse files
nordingmhevery
authored andcommitted
feat: add mocha support
1 parent c5130a6 commit 41a9047

17 files changed

+512
-37
lines changed

Diff for: .travis.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ before_script:
2222
- ./scripts/sauce/sauce_connect_block.sh
2323

2424
script:
25-
- node_modules/.bin/karma start karma-sauce.conf.js --single-run
25+
- node_modules/.bin/karma start karma-sauce-jasmine.conf.js --single-run
26+
- node_modules/.bin/karma start karma-sauce-mocha.conf.js --single-run
2627
- node_modules/.bin/gulp test/node

Diff for: gulpfile.js

+10
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ gulp.task('build/jasmine-patch.min.js', ['compile-esm'], function(cb) {
9191
return generateScript('./lib/jasmine/jasmine.ts', 'jasmine-patch.min.js', true, cb);
9292
});
9393

94+
gulp.task('build/mocha-patch.js', ['compile-esm'], function(cb) {
95+
return generateScript('./lib/mocha/mocha.ts', 'mocha-patch.js', false, cb);
96+
});
97+
98+
gulp.task('build/mocha-patch.min.js', ['compile-esm'], function(cb) {
99+
return generateScript('./lib/mocha/mocha.ts', 'mocha-patch.min.js', true, cb);
100+
});
101+
94102
gulp.task('build/long-stack-trace-zone.js', ['compile-esm'], function(cb) {
95103
return generateScript('./lib/zone-spec/long-stack-trace.ts', 'long-stack-trace-zone.js', false, cb);
96104
});
@@ -142,6 +150,8 @@ gulp.task('build', [
142150
'build/zone-node.js',
143151
'build/jasmine-patch.js',
144152
'build/jasmine-patch.min.js',
153+
'build/mocha-patch.js',
154+
'build/mocha-patch.min.js',
145155
'build/long-stack-trace-zone.js',
146156
'build/long-stack-trace-zone.min.js',
147157
'build/proxy-zone.js',

Diff for: karma-jasmine.conf.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
module.exports = function (config) {
3+
require('./karma.conf')(config);
4+
5+
config.plugins.push(require('karma-jasmine'));
6+
config.frameworks.push('jasmine');
7+
};

Diff for: karma-mocha.conf.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
module.exports = function (config) {
3+
require('./karma.conf')(config);
4+
5+
config.plugins.push(require('karma-mocha'));
6+
config.frameworks.push('mocha');
7+
config.client.mocha = {
8+
timeout: 5000 // copied timeout for Jasmine in WebSocket.spec (otherwise Mochas default timeout at 2 sec is to low for the tests)
9+
};
10+
};

Diff for: karma-sauce-jasmine.conf.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
module.exports = function (config) {
10+
require('./karma.conf')(config);
11+
require('./karma-jasmine.conf')(config);
12+
require('./sauce.conf')(config);
13+
};

Diff for: karma-sauce.conf.js renamed to karma-sauce-mocha.conf.js

+1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@
88

99
module.exports = function (config) {
1010
require('./karma.conf')(config);
11+
require('./karma-mocha.conf')(config);
1112
require('./sauce.conf')(config);
1213
};

Diff for: karma.conf.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ module.exports = function (config) {
2222
plugins: [
2323
require('karma-chrome-launcher'),
2424
require('karma-firefox-launcher'),
25-
require('karma-jasmine'),
26-
require('karma-sourcemap-loader'),
25+
require('karma-sourcemap-loader')
2726
],
2827

2928
preprocessors: {
@@ -42,7 +41,6 @@ module.exports = function (config) {
4241
logLevel: config.LOG_INFO,
4342

4443
browsers: ['Firefox'],
45-
frameworks: ['jasmine'],
4644

4745
captureTimeout: 60000,
4846

Diff for: lib/mocha/mocha.ts

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
'use strict';
2+
3+
((context: any) => {
4+
var Mocha = context.Mocha;
5+
6+
if (typeof Mocha === 'undefined') {
7+
throw new Error('Missing Mocha.js');
8+
}
9+
10+
if (typeof Zone === 'undefined') {
11+
throw new Error('Missing Zone.js');
12+
}
13+
14+
const ProxyZoneSpec = Zone['ProxyZoneSpec'];
15+
const SyncTestZoneSpec = Zone['SyncTestZoneSpec'];
16+
17+
if (!ProxyZoneSpec) {
18+
throw new Error('Missing ProxyZoneSpec');
19+
}
20+
21+
if(Mocha['__zone_patch__']){
22+
throw new Error('"Mocha" has already been patched with "Zone".');
23+
}
24+
25+
Mocha['__zone_patch__'] = true;
26+
27+
const rootZone = Zone.current;
28+
const syncZone = rootZone.fork(new SyncTestZoneSpec('Mocha.describe'));
29+
let testZone = null;
30+
const suiteZone = rootZone.fork(new ProxyZoneSpec());
31+
32+
const mochaOriginal = {
33+
after: Mocha.after,
34+
afterEach: Mocha.afterEach,
35+
before: Mocha.before,
36+
beforeEach: Mocha.beforeEach,
37+
describe: Mocha.describe,
38+
it: Mocha.it
39+
};
40+
41+
function modifyArguments(args: IArguments, syncTest: Function, asyncTest?: Function): any[] {
42+
for (let i = 0; i < args.length; i++) {
43+
let arg = args[i];
44+
if (typeof arg === 'function') {
45+
// The `done` callback is only passed through if the function expects at
46+
// least one argument.
47+
// Note we have to make a function with correct number of arguments,
48+
// otherwise mocha will
49+
// think that all functions are sync or async.
50+
args[i] = (arg.length === 0) ? syncTest(arg) : asyncTest(arg);
51+
// Mocha uses toString to view the test body in the result list, make sure we return the correct function body
52+
args[i].toString = function(){
53+
return arg.toString();
54+
};
55+
}
56+
}
57+
58+
return args as any;
59+
}
60+
61+
function wrapDescribeInZone(args: IArguments): any[] {
62+
const syncTest: any = function(fn){
63+
return function(){
64+
return syncZone.run(fn, this, arguments as any as any[]);
65+
};
66+
};
67+
68+
return modifyArguments(args, syncTest);
69+
}
70+
71+
function wrapTestInZone(args: IArguments): any[] {
72+
const asyncTest = function(fn){
73+
return function(done){
74+
return testZone.run(fn, this, [done]);
75+
};
76+
};
77+
78+
const syncTest: any = function(fn){
79+
return function(){
80+
return testZone.run(fn, this);
81+
};
82+
};
83+
84+
return modifyArguments(args, syncTest, asyncTest);
85+
}
86+
87+
function wrapSuiteInZone(args: IArguments): any[] {
88+
const asyncTest = function(fn){
89+
return function(done){
90+
return suiteZone.run(fn, this, [done]);
91+
};
92+
};
93+
94+
const syncTest: any = function(fn){
95+
return function(){
96+
return suiteZone.run(fn, this);
97+
};
98+
};
99+
100+
return modifyArguments(args, syncTest, asyncTest);
101+
};
102+
103+
context.describe = context.suite = Mocha.describe = function() {
104+
return mochaOriginal.describe.apply(this, wrapDescribeInZone(arguments));
105+
};
106+
107+
context.xdescribe = context.suite.skip = Mocha.describe.skip = function() {
108+
return mochaOriginal.describe.skip.apply(this, wrapDescribeInZone(arguments));
109+
};
110+
111+
context.describe.only = context.suite.only = Mocha.describe.only = function() {
112+
return mochaOriginal.describe.only.apply(this, wrapDescribeInZone(arguments));
113+
};
114+
115+
context.it = context.specify = context.test = Mocha.it = function() {
116+
return mochaOriginal.it.apply(this, wrapTestInZone(arguments));
117+
};
118+
119+
context.xit = context.xspecify = Mocha.it.skip = function() {
120+
return mochaOriginal.it.skip.apply(this, wrapTestInZone(arguments));
121+
};
122+
123+
context.it.only = context.test.only = Mocha.it.only = function() {
124+
return mochaOriginal.it.only.apply(this, wrapTestInZone(arguments));
125+
};
126+
127+
context.after = context.suiteTeardown = Mocha.after = function(){
128+
return mochaOriginal.after.apply(this, wrapSuiteInZone(arguments));
129+
};
130+
131+
context.afterEach = context.teardown = Mocha.afterEach = function(){
132+
return mochaOriginal.afterEach.apply(this, wrapTestInZone(arguments));
133+
};
134+
135+
context.before = context.suiteSetup = Mocha.before = function(){
136+
return mochaOriginal.before.apply(this, wrapSuiteInZone(arguments));
137+
};
138+
139+
context.beforeEach = context.setup = Mocha.beforeEach = function(){
140+
return mochaOriginal.beforeEach.apply(this, wrapTestInZone(arguments));
141+
};
142+
143+
((originalRunTest, originalRun) => {
144+
Mocha.Runner.prototype.runTest = function(fn){
145+
Zone.current.scheduleMicroTask('mocha.forceTask', () => {
146+
originalRunTest.call(this, fn);
147+
});
148+
};
149+
150+
Mocha.Runner.prototype.run = function(fn){
151+
this.on('test', (e) => {
152+
if(Zone.current !== rootZone){
153+
throw new Error('Unexpected zone: '+ Zone.current.name);
154+
}
155+
testZone = rootZone.fork(new ProxyZoneSpec());
156+
});
157+
158+
return originalRun.call(this, fn);
159+
};
160+
161+
162+
})(Mocha.Runner.prototype.runTest, Mocha.Runner.prototype.run);
163+
164+
})(window);

Diff for: package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
"ws-server": "node ./test/ws-server.js",
1919
"tsc": "tsc",
2020
"tsc:w": "tsc -w",
21-
"test": "npm run tsc && concurrently \"npm run tsc:w\" \"npm run ws-server\" \"karma start karma.conf.js\"",
21+
"test": "npm run tsc && concurrently \"npm run tsc:w\" \"npm run ws-server\" \"karma start karma-jasmine.conf.js\"",
2222
"test-node": "gulp test/node",
23+
"test-mocha": "npm run tsc && concurrently \"npm run tsc:w\" \"npm run ws-server\" \"karma start karma-mocha.conf.js\"",
2324
"serve": "python -m SimpleHTTPServer 8000"
2425
},
2526
"repository": {
@@ -52,9 +53,11 @@
5253
"karma-chrome-launcher": "^0.2.1",
5354
"karma-firefox-launcher": "^0.1.4",
5455
"karma-jasmine": "^0.3.6",
56+
"karma-mocha": "^1.2.0",
5557
"karma-safari-launcher": "^0.1.1",
5658
"karma-sauce-launcher": "^0.2.10",
5759
"karma-sourcemap-loader": "^0.3.6",
60+
"mocha": "^3.1.2",
5861
"nodejs-websocket": "^1.2.0",
5962
"pump": "^1.0.1",
6063
"systemjs": "^0.19.37",

Diff for: test/browser-zone-setup.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
// Must be loaded before zone loads, so that zone can detect WTF.
10+
import './wtf_mock';
11+
12+
// Setup tests for Zone without microtask support
13+
import '../lib/zone';
14+
import '../lib/browser/browser';
15+
import '../lib/zone-spec/async-test';
16+
import '../lib/zone-spec/fake-async-test';
17+
import '../lib/zone-spec/long-stack-trace';
18+
import '../lib/zone-spec/proxy';
19+
import '../lib/zone-spec/sync-test';
20+
import '../lib/zone-spec/task-tracking';
21+
import '../lib/zone-spec/wtf';

Diff for: test/browser/WebSocket.spec.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ if (!window['soucelabs']) {
2121

2222
beforeEach(function(done) {
2323
socket = new WebSocket(TEST_SERVER_URL);
24-
socket.addEventListener('open', done);
24+
socket.addEventListener('open', function(){
25+
done();
26+
});
2527
socket.addEventListener('error', function() {
2628
fail(
2729
'Can\'t establish socket to ' + TEST_SERVER_URL +
@@ -31,9 +33,10 @@ if (!window['soucelabs']) {
3133
}, TIMEOUT);
3234

3335
afterEach(function(done) {
34-
socket.addEventListener('close', done);
36+
socket.addEventListener('close', function(){
37+
done();
38+
});
3539
socket.close();
36-
done();
3740
}, TIMEOUT);
3841

3942

Diff for: test/browser_entry_point.ts

+1-17
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,6 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
// Must be loaded before zone loads, so that zone can detect WTF.
10-
import './wtf_mock';
11-
12-
// Setup tests for Zone without microtask support
13-
import '../lib/zone';
14-
import '../lib/browser/browser';
15-
import '../lib/zone-spec/async-test';
16-
import '../lib/zone-spec/fake-async-test';
17-
import '../lib/zone-spec/long-stack-trace';
18-
import '../lib/zone-spec/proxy';
19-
import '../lib/zone-spec/sync-test';
20-
import '../lib/zone-spec/task-tracking';
21-
import '../lib/zone-spec/wtf';
22-
23-
// Setup test environment
24-
import './test-env-setup';
25-
269
// List all tests here:
2710
import './common_tests';
2811
import './browser/browser.spec';
@@ -35,3 +18,4 @@ import './browser/requestAnimationFrame.spec';
3518
import './browser/WebSocket.spec';
3619
import './browser/XMLHttpRequest.spec';
3720
// import './browser/geolocation.spec.manual';
21+
import './mocha-patch.spec';

Diff for: test/main.ts

+20-11
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,28 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
declare var __karma__: {loaded: Function, start: Function
9+
declare var __karma__: {
10+
loaded: Function, start: Function
1011
error: Function
1112
};
1213

13-
__karma__.loaded = function() {};
14-
(window as any).global = window;
14+
__karma__.loaded = function () { };
15+
(window as any).global = window;
1516

16-
System.config({defaultJSExtensions: true});
17-
System.import('/base/build/test/browser_entry_point')
17+
System.config({ defaultJSExtensions: true });
18+
19+
System.import('/base/build/test/browser-zone-setup').then(() => {
20+
let testFrameworkPatch = typeof (window as any).Mocha !== 'undefined' ? '/base/build/test/test-env-setup-mocha'
21+
: '/base/build/test/test-env-setup-jasmine';
22+
// Setup test environment
23+
System.import(testFrameworkPatch).then(() => {
24+
System.import('/base/build/test/browser_entry_point')
1825
.then(
19-
() => {
20-
__karma__.start();
21-
},
22-
(error) => {
23-
console.error(error.stack || error);
24-
});
26+
() => {
27+
__karma__.start();
28+
},
29+
(error) => {
30+
console.error(error.stack || error);
31+
});
32+
});
33+
});

0 commit comments

Comments
 (0)