You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
12 KiB
JavaScript
258 lines
12 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory() :
|
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
(factory());
|
|
}(this, (function () { 'use strict';
|
|
|
|
/**
|
|
* @license
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
(function () {
|
|
var __extends = function (d, b) {
|
|
for (var p in b)
|
|
if (b.hasOwnProperty(p))
|
|
d[p] = b[p];
|
|
function __() {
|
|
this.constructor = d;
|
|
}
|
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
};
|
|
var _global = typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global;
|
|
// Patch jasmine's describe/it/beforeEach/afterEach functions so test code always runs
|
|
// in a testZone (ProxyZone). (See: angular/zone.js#91 & angular/angular#10503)
|
|
if (!Zone)
|
|
throw new Error('Missing: zone.js');
|
|
if (typeof jasmine == 'undefined')
|
|
throw new Error('Missing: jasmine.js');
|
|
if (jasmine['__zone_patch__'])
|
|
throw new Error("'jasmine' has already been patched with 'Zone'.");
|
|
jasmine['__zone_patch__'] = true;
|
|
var SyncTestZoneSpec = Zone['SyncTestZoneSpec'];
|
|
var ProxyZoneSpec = Zone['ProxyZoneSpec'];
|
|
if (!SyncTestZoneSpec)
|
|
throw new Error('Missing: SyncTestZoneSpec');
|
|
if (!ProxyZoneSpec)
|
|
throw new Error('Missing: ProxyZoneSpec');
|
|
var ambientZone = Zone.current;
|
|
// Create a synchronous-only zone in which to run `describe` blocks in order to raise an
|
|
// error if any asynchronous operations are attempted inside of a `describe` but outside of
|
|
// a `beforeEach` or `it`.
|
|
var syncZone = ambientZone.fork(new SyncTestZoneSpec('jasmine.describe'));
|
|
var symbol = Zone.__symbol__;
|
|
// whether patch jasmine clock when in fakeAsync
|
|
var enableClockPatch = _global[symbol('fakeAsyncPatchLock')] === true;
|
|
// Monkey patch all of the jasmine DSL so that each function runs in appropriate zone.
|
|
var jasmineEnv = jasmine.getEnv();
|
|
['describe', 'xdescribe', 'fdescribe'].forEach(function (methodName) {
|
|
var originalJasmineFn = jasmineEnv[methodName];
|
|
jasmineEnv[methodName] = function (description, specDefinitions) {
|
|
return originalJasmineFn.call(this, description, wrapDescribeInZone(specDefinitions));
|
|
};
|
|
});
|
|
['it', 'xit', 'fit'].forEach(function (methodName) {
|
|
var originalJasmineFn = jasmineEnv[methodName];
|
|
jasmineEnv[symbol(methodName)] = originalJasmineFn;
|
|
jasmineEnv[methodName] = function (description, specDefinitions, timeout) {
|
|
arguments[1] = wrapTestInZone(specDefinitions);
|
|
return originalJasmineFn.apply(this, arguments);
|
|
};
|
|
});
|
|
['beforeEach', 'afterEach', 'beforeAll', 'afterAll'].forEach(function (methodName) {
|
|
var originalJasmineFn = jasmineEnv[methodName];
|
|
jasmineEnv[symbol(methodName)] = originalJasmineFn;
|
|
jasmineEnv[methodName] = function (specDefinitions, timeout) {
|
|
arguments[0] = wrapTestInZone(specDefinitions);
|
|
return originalJasmineFn.apply(this, arguments);
|
|
};
|
|
});
|
|
// need to patch jasmine.clock().mockDate and jasmine.clock().tick() so
|
|
// they can work properly in FakeAsyncTest
|
|
var originalClockFn = (jasmine[symbol('clock')] = jasmine['clock']);
|
|
jasmine['clock'] = function () {
|
|
var clock = originalClockFn.apply(this, arguments);
|
|
if (!clock[symbol('patched')]) {
|
|
clock[symbol('patched')] = symbol('patched');
|
|
var originalTick_1 = (clock[symbol('tick')] = clock.tick);
|
|
clock.tick = function () {
|
|
var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
|
|
if (fakeAsyncZoneSpec) {
|
|
return fakeAsyncZoneSpec.tick.apply(fakeAsyncZoneSpec, arguments);
|
|
}
|
|
return originalTick_1.apply(this, arguments);
|
|
};
|
|
var originalMockDate_1 = (clock[symbol('mockDate')] = clock.mockDate);
|
|
clock.mockDate = function () {
|
|
var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
|
|
if (fakeAsyncZoneSpec) {
|
|
var dateTime = arguments.length > 0 ? arguments[0] : new Date();
|
|
return fakeAsyncZoneSpec.setCurrentRealTime.apply(fakeAsyncZoneSpec, dateTime && typeof dateTime.getTime === 'function' ? [dateTime.getTime()] :
|
|
arguments);
|
|
}
|
|
return originalMockDate_1.apply(this, arguments);
|
|
};
|
|
// for auto go into fakeAsync feature, we need the flag to enable it
|
|
if (enableClockPatch) {
|
|
['install', 'uninstall'].forEach(function (methodName) {
|
|
var originalClockFn = (clock[symbol(methodName)] = clock[methodName]);
|
|
clock[methodName] = function () {
|
|
var FakeAsyncTestZoneSpec = Zone['FakeAsyncTestZoneSpec'];
|
|
if (FakeAsyncTestZoneSpec) {
|
|
jasmine[symbol('clockInstalled')] = 'install' === methodName;
|
|
return;
|
|
}
|
|
return originalClockFn.apply(this, arguments);
|
|
};
|
|
});
|
|
}
|
|
}
|
|
return clock;
|
|
};
|
|
/**
|
|
* Gets a function wrapping the body of a Jasmine `describe` block to execute in a
|
|
* synchronous-only zone.
|
|
*/
|
|
function wrapDescribeInZone(describeBody) {
|
|
return function () {
|
|
return syncZone.run(describeBody, this, arguments);
|
|
};
|
|
}
|
|
function runInTestZone(testBody, applyThis, queueRunner, done) {
|
|
var isClockInstalled = !!jasmine[symbol('clockInstalled')];
|
|
var testProxyZoneSpec = queueRunner.testProxyZoneSpec;
|
|
var testProxyZone = queueRunner.testProxyZone;
|
|
if (isClockInstalled && enableClockPatch) {
|
|
// auto run a fakeAsync
|
|
var fakeAsyncModule = Zone[Zone.__symbol__('fakeAsyncTest')];
|
|
if (fakeAsyncModule && typeof fakeAsyncModule.fakeAsync === 'function') {
|
|
testBody = fakeAsyncModule.fakeAsync(testBody);
|
|
}
|
|
}
|
|
if (done) {
|
|
return testProxyZone.run(testBody, applyThis, [done]);
|
|
}
|
|
else {
|
|
return testProxyZone.run(testBody, applyThis);
|
|
}
|
|
}
|
|
/**
|
|
* Gets a function wrapping the body of a Jasmine `it/beforeEach/afterEach` block to
|
|
* execute in a ProxyZone zone.
|
|
* This will run in `testProxyZone`. The `testProxyZone` will be reset by the `ZoneQueueRunner`
|
|
*/
|
|
function wrapTestInZone(testBody) {
|
|
// The `done` callback is only passed through if the function expects at least one argument.
|
|
// Note we have to make a function with correct number of arguments, otherwise jasmine will
|
|
// think that all functions are sync or async.
|
|
return (testBody && (testBody.length ? function (done) {
|
|
return runInTestZone(testBody, this, this.queueRunner, done);
|
|
} : function () {
|
|
return runInTestZone(testBody, this, this.queueRunner);
|
|
}));
|
|
}
|
|
var QueueRunner = jasmine.QueueRunner;
|
|
jasmine.QueueRunner = (function (_super) {
|
|
__extends(ZoneQueueRunner, _super);
|
|
function ZoneQueueRunner(attrs) {
|
|
var _this = this;
|
|
attrs.onComplete = (function (fn) { return function () {
|
|
// All functions are done, clear the test zone.
|
|
_this.testProxyZone = null;
|
|
_this.testProxyZoneSpec = null;
|
|
ambientZone.scheduleMicroTask('jasmine.onComplete', fn);
|
|
}; })(attrs.onComplete);
|
|
var nativeSetTimeout = _global['__zone_symbol__setTimeout'];
|
|
var nativeClearTimeout = _global['__zone_symbol__clearTimeout'];
|
|
if (nativeSetTimeout) {
|
|
// should run setTimeout inside jasmine outside of zone
|
|
attrs.timeout = {
|
|
setTimeout: nativeSetTimeout ? nativeSetTimeout : _global.setTimeout,
|
|
clearTimeout: nativeClearTimeout ? nativeClearTimeout : _global.clearTimeout
|
|
};
|
|
}
|
|
// create a userContext to hold the queueRunner itself
|
|
// so we can access the testProxy in it/xit/beforeEach ...
|
|
if (jasmine.UserContext) {
|
|
if (!attrs.userContext) {
|
|
attrs.userContext = new jasmine.UserContext();
|
|
}
|
|
attrs.userContext.queueRunner = this;
|
|
}
|
|
else {
|
|
if (!attrs.userContext) {
|
|
attrs.userContext = {};
|
|
}
|
|
attrs.userContext.queueRunner = this;
|
|
}
|
|
// patch attrs.onException
|
|
var onException = attrs.onException;
|
|
attrs.onException = function (error) {
|
|
if (error &&
|
|
error.message ===
|
|
'Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.') {
|
|
// jasmine timeout, we can make the error message more
|
|
// reasonable to tell what tasks are pending
|
|
var proxyZoneSpec = this && this.testProxyZoneSpec;
|
|
if (proxyZoneSpec) {
|
|
var pendingTasksInfo = proxyZoneSpec.getAndClearPendingTasksInfo();
|
|
error.message += pendingTasksInfo;
|
|
}
|
|
}
|
|
if (onException) {
|
|
onException.call(this, error);
|
|
}
|
|
};
|
|
_super.call(this, attrs);
|
|
}
|
|
ZoneQueueRunner.prototype.execute = function () {
|
|
var _this = this;
|
|
var zone = Zone.current;
|
|
var isChildOfAmbientZone = false;
|
|
while (zone) {
|
|
if (zone === ambientZone) {
|
|
isChildOfAmbientZone = true;
|
|
break;
|
|
}
|
|
zone = zone.parent;
|
|
}
|
|
if (!isChildOfAmbientZone)
|
|
throw new Error('Unexpected Zone: ' + Zone.current.name);
|
|
// This is the zone which will be used for running individual tests.
|
|
// It will be a proxy zone, so that the tests function can retroactively install
|
|
// different zones.
|
|
// Example:
|
|
// - In beforeEach() do childZone = Zone.current.fork(...);
|
|
// - In it() try to do fakeAsync(). The issue is that because the beforeEach forked the
|
|
// zone outside of fakeAsync it will be able to escape the fakeAsync rules.
|
|
// - Because ProxyZone is parent fo `childZone` fakeAsync can retroactively add
|
|
// fakeAsync behavior to the childZone.
|
|
this.testProxyZoneSpec = new ProxyZoneSpec();
|
|
this.testProxyZone = ambientZone.fork(this.testProxyZoneSpec);
|
|
if (!Zone.currentTask) {
|
|
// if we are not running in a task then if someone would register a
|
|
// element.addEventListener and then calling element.click() the
|
|
// addEventListener callback would think that it is the top most task and would
|
|
// drain the microtask queue on element.click() which would be incorrect.
|
|
// For this reason we always force a task when running jasmine tests.
|
|
Zone.current.scheduleMicroTask('jasmine.execute().forceTask', function () { return QueueRunner.prototype.execute.call(_this); });
|
|
}
|
|
else {
|
|
_super.prototype.execute.call(this);
|
|
}
|
|
};
|
|
return ZoneQueueRunner;
|
|
})(QueueRunner);
|
|
})();
|
|
|
|
})));
|