1 | 'use strict';
|
---|
2 | /**
|
---|
3 | * @license Angular v12.0.0-next.0
|
---|
4 | * (c) 2010-2020 Google LLC. https://angular.io/
|
---|
5 | * License: MIT
|
---|
6 | */
|
---|
7 | /**
|
---|
8 | * @license
|
---|
9 | * Copyright Google LLC All Rights Reserved.
|
---|
10 | *
|
---|
11 | * Use of this source code is governed by an MIT-style license that can be
|
---|
12 | * found in the LICENSE file at https://angular.io/license
|
---|
13 | */
|
---|
14 | Zone.__load_patch('jasmine', (global, Zone, api) => {
|
---|
15 | const __extends = function (d, b) {
|
---|
16 | for (const p in b)
|
---|
17 | if (b.hasOwnProperty(p))
|
---|
18 | d[p] = b[p];
|
---|
19 | function __() {
|
---|
20 | this.constructor = d;
|
---|
21 | }
|
---|
22 | d.prototype = b === null ? Object.create(b) : ((__.prototype = b.prototype), new __());
|
---|
23 | };
|
---|
24 | // Patch jasmine's describe/it/beforeEach/afterEach functions so test code always runs
|
---|
25 | // in a testZone (ProxyZone). (See: angular/zone.js#91 & angular/angular#10503)
|
---|
26 | if (!Zone)
|
---|
27 | throw new Error('Missing: zone.js');
|
---|
28 | if (typeof jest !== 'undefined') {
|
---|
29 | // return if jasmine is a light implementation inside jest
|
---|
30 | // in this case, we are running inside jest not jasmine
|
---|
31 | return;
|
---|
32 | }
|
---|
33 | if (typeof jasmine == 'undefined' || jasmine['__zone_patch__']) {
|
---|
34 | return;
|
---|
35 | }
|
---|
36 | jasmine['__zone_patch__'] = true;
|
---|
37 | const SyncTestZoneSpec = Zone['SyncTestZoneSpec'];
|
---|
38 | const ProxyZoneSpec = Zone['ProxyZoneSpec'];
|
---|
39 | if (!SyncTestZoneSpec)
|
---|
40 | throw new Error('Missing: SyncTestZoneSpec');
|
---|
41 | if (!ProxyZoneSpec)
|
---|
42 | throw new Error('Missing: ProxyZoneSpec');
|
---|
43 | const ambientZone = Zone.current;
|
---|
44 | // Create a synchronous-only zone in which to run `describe` blocks in order to raise an
|
---|
45 | // error if any asynchronous operations are attempted inside of a `describe` but outside of
|
---|
46 | // a `beforeEach` or `it`.
|
---|
47 | const syncZone = ambientZone.fork(new SyncTestZoneSpec('jasmine.describe'));
|
---|
48 | const symbol = Zone.__symbol__;
|
---|
49 | // whether patch jasmine clock when in fakeAsync
|
---|
50 | const disablePatchingJasmineClock = global[symbol('fakeAsyncDisablePatchingClock')] === true;
|
---|
51 | // the original variable name fakeAsyncPatchLock is not accurate, so the name will be
|
---|
52 | // fakeAsyncAutoFakeAsyncWhenClockPatched and if this enablePatchingJasmineClock is false, we also
|
---|
53 | // automatically disable the auto jump into fakeAsync feature
|
---|
54 | const enableAutoFakeAsyncWhenClockPatched = !disablePatchingJasmineClock &&
|
---|
55 | ((global[symbol('fakeAsyncPatchLock')] === true) ||
|
---|
56 | (global[symbol('fakeAsyncAutoFakeAsyncWhenClockPatched')] === true));
|
---|
57 | const ignoreUnhandledRejection = global[symbol('ignoreUnhandledRejection')] === true;
|
---|
58 | if (!ignoreUnhandledRejection) {
|
---|
59 | const globalErrors = jasmine.GlobalErrors;
|
---|
60 | if (globalErrors && !jasmine[symbol('GlobalErrors')]) {
|
---|
61 | jasmine[symbol('GlobalErrors')] = globalErrors;
|
---|
62 | jasmine.GlobalErrors = function () {
|
---|
63 | const instance = new globalErrors();
|
---|
64 | const originalInstall = instance.install;
|
---|
65 | if (originalInstall && !instance[symbol('install')]) {
|
---|
66 | instance[symbol('install')] = originalInstall;
|
---|
67 | instance.install = function () {
|
---|
68 | const originalHandlers = process.listeners('unhandledRejection');
|
---|
69 | const r = originalInstall.apply(this, arguments);
|
---|
70 | process.removeAllListeners('unhandledRejection');
|
---|
71 | if (originalHandlers) {
|
---|
72 | originalHandlers.forEach(h => process.on('unhandledRejection', h));
|
---|
73 | }
|
---|
74 | return r;
|
---|
75 | };
|
---|
76 | }
|
---|
77 | return instance;
|
---|
78 | };
|
---|
79 | }
|
---|
80 | }
|
---|
81 | // Monkey patch all of the jasmine DSL so that each function runs in appropriate zone.
|
---|
82 | const jasmineEnv = jasmine.getEnv();
|
---|
83 | ['describe', 'xdescribe', 'fdescribe'].forEach(methodName => {
|
---|
84 | let originalJasmineFn = jasmineEnv[methodName];
|
---|
85 | jasmineEnv[methodName] = function (description, specDefinitions) {
|
---|
86 | return originalJasmineFn.call(this, description, wrapDescribeInZone(specDefinitions));
|
---|
87 | };
|
---|
88 | });
|
---|
89 | ['it', 'xit', 'fit'].forEach(methodName => {
|
---|
90 | let originalJasmineFn = jasmineEnv[methodName];
|
---|
91 | jasmineEnv[symbol(methodName)] = originalJasmineFn;
|
---|
92 | jasmineEnv[methodName] = function (description, specDefinitions, timeout) {
|
---|
93 | arguments[1] = wrapTestInZone(specDefinitions);
|
---|
94 | return originalJasmineFn.apply(this, arguments);
|
---|
95 | };
|
---|
96 | });
|
---|
97 | ['beforeEach', 'afterEach', 'beforeAll', 'afterAll'].forEach(methodName => {
|
---|
98 | let originalJasmineFn = jasmineEnv[methodName];
|
---|
99 | jasmineEnv[symbol(methodName)] = originalJasmineFn;
|
---|
100 | jasmineEnv[methodName] = function (specDefinitions, timeout) {
|
---|
101 | arguments[0] = wrapTestInZone(specDefinitions);
|
---|
102 | return originalJasmineFn.apply(this, arguments);
|
---|
103 | };
|
---|
104 | });
|
---|
105 | if (!disablePatchingJasmineClock) {
|
---|
106 | // need to patch jasmine.clock().mockDate and jasmine.clock().tick() so
|
---|
107 | // they can work properly in FakeAsyncTest
|
---|
108 | const originalClockFn = (jasmine[symbol('clock')] = jasmine['clock']);
|
---|
109 | jasmine['clock'] = function () {
|
---|
110 | const clock = originalClockFn.apply(this, arguments);
|
---|
111 | if (!clock[symbol('patched')]) {
|
---|
112 | clock[symbol('patched')] = symbol('patched');
|
---|
113 | const originalTick = (clock[symbol('tick')] = clock.tick);
|
---|
114 | clock.tick = function () {
|
---|
115 | const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
|
---|
116 | if (fakeAsyncZoneSpec) {
|
---|
117 | return fakeAsyncZoneSpec.tick.apply(fakeAsyncZoneSpec, arguments);
|
---|
118 | }
|
---|
119 | return originalTick.apply(this, arguments);
|
---|
120 | };
|
---|
121 | const originalMockDate = (clock[symbol('mockDate')] = clock.mockDate);
|
---|
122 | clock.mockDate = function () {
|
---|
123 | const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
|
---|
124 | if (fakeAsyncZoneSpec) {
|
---|
125 | const dateTime = arguments.length > 0 ? arguments[0] : new Date();
|
---|
126 | return fakeAsyncZoneSpec.setFakeBaseSystemTime.apply(fakeAsyncZoneSpec, dateTime && typeof dateTime.getTime === 'function' ? [dateTime.getTime()] :
|
---|
127 | arguments);
|
---|
128 | }
|
---|
129 | return originalMockDate.apply(this, arguments);
|
---|
130 | };
|
---|
131 | // for auto go into fakeAsync feature, we need the flag to enable it
|
---|
132 | if (enableAutoFakeAsyncWhenClockPatched) {
|
---|
133 | ['install', 'uninstall'].forEach(methodName => {
|
---|
134 | const originalClockFn = (clock[symbol(methodName)] = clock[methodName]);
|
---|
135 | clock[methodName] = function () {
|
---|
136 | const FakeAsyncTestZoneSpec = Zone['FakeAsyncTestZoneSpec'];
|
---|
137 | if (FakeAsyncTestZoneSpec) {
|
---|
138 | jasmine[symbol('clockInstalled')] = 'install' === methodName;
|
---|
139 | return;
|
---|
140 | }
|
---|
141 | return originalClockFn.apply(this, arguments);
|
---|
142 | };
|
---|
143 | });
|
---|
144 | }
|
---|
145 | }
|
---|
146 | return clock;
|
---|
147 | };
|
---|
148 | }
|
---|
149 | // monkey patch createSpyObj to make properties enumerable to true
|
---|
150 | if (!jasmine[Zone.__symbol__('createSpyObj')]) {
|
---|
151 | const originalCreateSpyObj = jasmine.createSpyObj;
|
---|
152 | jasmine[Zone.__symbol__('createSpyObj')] = originalCreateSpyObj;
|
---|
153 | jasmine.createSpyObj = function () {
|
---|
154 | const args = Array.prototype.slice.call(arguments);
|
---|
155 | const propertyNames = args.length >= 3 ? args[2] : null;
|
---|
156 | let spyObj;
|
---|
157 | if (propertyNames) {
|
---|
158 | const defineProperty = Object.defineProperty;
|
---|
159 | Object.defineProperty = function (obj, p, attributes) {
|
---|
160 | return defineProperty.call(this, obj, p, Object.assign(Object.assign({}, attributes), { configurable: true, enumerable: true }));
|
---|
161 | };
|
---|
162 | try {
|
---|
163 | spyObj = originalCreateSpyObj.apply(this, args);
|
---|
164 | }
|
---|
165 | finally {
|
---|
166 | Object.defineProperty = defineProperty;
|
---|
167 | }
|
---|
168 | }
|
---|
169 | else {
|
---|
170 | spyObj = originalCreateSpyObj.apply(this, args);
|
---|
171 | }
|
---|
172 | return spyObj;
|
---|
173 | };
|
---|
174 | }
|
---|
175 | /**
|
---|
176 | * Gets a function wrapping the body of a Jasmine `describe` block to execute in a
|
---|
177 | * synchronous-only zone.
|
---|
178 | */
|
---|
179 | function wrapDescribeInZone(describeBody) {
|
---|
180 | return function () {
|
---|
181 | return syncZone.run(describeBody, this, arguments);
|
---|
182 | };
|
---|
183 | }
|
---|
184 | function runInTestZone(testBody, applyThis, queueRunner, done) {
|
---|
185 | const isClockInstalled = !!jasmine[symbol('clockInstalled')];
|
---|
186 | const testProxyZoneSpec = queueRunner.testProxyZoneSpec;
|
---|
187 | const testProxyZone = queueRunner.testProxyZone;
|
---|
188 | if (isClockInstalled && enableAutoFakeAsyncWhenClockPatched) {
|
---|
189 | // auto run a fakeAsync
|
---|
190 | const fakeAsyncModule = Zone[Zone.__symbol__('fakeAsyncTest')];
|
---|
191 | if (fakeAsyncModule && typeof fakeAsyncModule.fakeAsync === 'function') {
|
---|
192 | testBody = fakeAsyncModule.fakeAsync(testBody);
|
---|
193 | }
|
---|
194 | }
|
---|
195 | if (done) {
|
---|
196 | return testProxyZone.run(testBody, applyThis, [done]);
|
---|
197 | }
|
---|
198 | else {
|
---|
199 | return testProxyZone.run(testBody, applyThis);
|
---|
200 | }
|
---|
201 | }
|
---|
202 | /**
|
---|
203 | * Gets a function wrapping the body of a Jasmine `it/beforeEach/afterEach` block to
|
---|
204 | * execute in a ProxyZone zone.
|
---|
205 | * This will run in `testProxyZone`. The `testProxyZone` will be reset by the `ZoneQueueRunner`
|
---|
206 | */
|
---|
207 | function wrapTestInZone(testBody) {
|
---|
208 | // The `done` callback is only passed through if the function expects at least one argument.
|
---|
209 | // Note we have to make a function with correct number of arguments, otherwise jasmine will
|
---|
210 | // think that all functions are sync or async.
|
---|
211 | return (testBody && (testBody.length ? function (done) {
|
---|
212 | return runInTestZone(testBody, this, this.queueRunner, done);
|
---|
213 | } : function () {
|
---|
214 | return runInTestZone(testBody, this, this.queueRunner);
|
---|
215 | }));
|
---|
216 | }
|
---|
217 | const QueueRunner = jasmine.QueueRunner;
|
---|
218 | jasmine.QueueRunner = (function (_super) {
|
---|
219 | __extends(ZoneQueueRunner, _super);
|
---|
220 | function ZoneQueueRunner(attrs) {
|
---|
221 | if (attrs.onComplete) {
|
---|
222 | attrs.onComplete = (fn => () => {
|
---|
223 | // All functions are done, clear the test zone.
|
---|
224 | this.testProxyZone = null;
|
---|
225 | this.testProxyZoneSpec = null;
|
---|
226 | ambientZone.scheduleMicroTask('jasmine.onComplete', fn);
|
---|
227 | })(attrs.onComplete);
|
---|
228 | }
|
---|
229 | const nativeSetTimeout = global[Zone.__symbol__('setTimeout')];
|
---|
230 | const nativeClearTimeout = global[Zone.__symbol__('clearTimeout')];
|
---|
231 | if (nativeSetTimeout) {
|
---|
232 | // should run setTimeout inside jasmine outside of zone
|
---|
233 | attrs.timeout = {
|
---|
234 | setTimeout: nativeSetTimeout ? nativeSetTimeout : global.setTimeout,
|
---|
235 | clearTimeout: nativeClearTimeout ? nativeClearTimeout : global.clearTimeout
|
---|
236 | };
|
---|
237 | }
|
---|
238 | // create a userContext to hold the queueRunner itself
|
---|
239 | // so we can access the testProxy in it/xit/beforeEach ...
|
---|
240 | if (jasmine.UserContext) {
|
---|
241 | if (!attrs.userContext) {
|
---|
242 | attrs.userContext = new jasmine.UserContext();
|
---|
243 | }
|
---|
244 | attrs.userContext.queueRunner = this;
|
---|
245 | }
|
---|
246 | else {
|
---|
247 | if (!attrs.userContext) {
|
---|
248 | attrs.userContext = {};
|
---|
249 | }
|
---|
250 | attrs.userContext.queueRunner = this;
|
---|
251 | }
|
---|
252 | // patch attrs.onException
|
---|
253 | const onException = attrs.onException;
|
---|
254 | attrs.onException = function (error) {
|
---|
255 | if (error &&
|
---|
256 | error.message ===
|
---|
257 | 'Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.') {
|
---|
258 | // jasmine timeout, we can make the error message more
|
---|
259 | // reasonable to tell what tasks are pending
|
---|
260 | const proxyZoneSpec = this && this.testProxyZoneSpec;
|
---|
261 | if (proxyZoneSpec) {
|
---|
262 | const pendingTasksInfo = proxyZoneSpec.getAndClearPendingTasksInfo();
|
---|
263 | try {
|
---|
264 | // try catch here in case error.message is not writable
|
---|
265 | error.message += pendingTasksInfo;
|
---|
266 | }
|
---|
267 | catch (err) {
|
---|
268 | }
|
---|
269 | }
|
---|
270 | }
|
---|
271 | if (onException) {
|
---|
272 | onException.call(this, error);
|
---|
273 | }
|
---|
274 | };
|
---|
275 | _super.call(this, attrs);
|
---|
276 | }
|
---|
277 | ZoneQueueRunner.prototype.execute = function () {
|
---|
278 | let zone = Zone.current;
|
---|
279 | let isChildOfAmbientZone = false;
|
---|
280 | while (zone) {
|
---|
281 | if (zone === ambientZone) {
|
---|
282 | isChildOfAmbientZone = true;
|
---|
283 | break;
|
---|
284 | }
|
---|
285 | zone = zone.parent;
|
---|
286 | }
|
---|
287 | if (!isChildOfAmbientZone)
|
---|
288 | throw new Error('Unexpected Zone: ' + Zone.current.name);
|
---|
289 | // This is the zone which will be used for running individual tests.
|
---|
290 | // It will be a proxy zone, so that the tests function can retroactively install
|
---|
291 | // different zones.
|
---|
292 | // Example:
|
---|
293 | // - In beforeEach() do childZone = Zone.current.fork(...);
|
---|
294 | // - In it() try to do fakeAsync(). The issue is that because the beforeEach forked the
|
---|
295 | // zone outside of fakeAsync it will be able to escape the fakeAsync rules.
|
---|
296 | // - Because ProxyZone is parent fo `childZone` fakeAsync can retroactively add
|
---|
297 | // fakeAsync behavior to the childZone.
|
---|
298 | this.testProxyZoneSpec = new ProxyZoneSpec();
|
---|
299 | this.testProxyZone = ambientZone.fork(this.testProxyZoneSpec);
|
---|
300 | if (!Zone.currentTask) {
|
---|
301 | // if we are not running in a task then if someone would register a
|
---|
302 | // element.addEventListener and then calling element.click() the
|
---|
303 | // addEventListener callback would think that it is the top most task and would
|
---|
304 | // drain the microtask queue on element.click() which would be incorrect.
|
---|
305 | // For this reason we always force a task when running jasmine tests.
|
---|
306 | Zone.current.scheduleMicroTask('jasmine.execute().forceTask', () => QueueRunner.prototype.execute.call(this));
|
---|
307 | }
|
---|
308 | else {
|
---|
309 | _super.prototype.execute.call(this);
|
---|
310 | }
|
---|
311 | };
|
---|
312 | return ZoneQueueRunner;
|
---|
313 | })(QueueRunner);
|
---|
314 | });
|
---|