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

Commit e15d735

Browse files
JiaLiPassionmhevery
authored andcommitted
fix(fakeAsync): fix #1050, should only reset patched Date.now until fakeAsync exit (#1051)
* chore: release v0.8.21 * fix(fakeAsync): fix #1050, work with fakeAsync
1 parent 6654b69 commit e15d735

13 files changed

+311
-262
lines changed

gulpfile.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,14 @@ gulp.task('build/sync-test.js', ['compile-esm'], function(cb) {
319319
return generateScript('./lib/zone-spec/sync-test.ts', 'sync-test.js', false, cb);
320320
});
321321

322+
gulp.task('build/zone-async-testing.js', ['compile-esm'], function(cb) {
323+
return generateScript('./lib/testing/async-testing.ts', 'zone-async-testing.js', false, cb);
324+
});
325+
326+
gulp.task('build/zone-fake-async.js', ['compile-esm'], function(cb) {
327+
return generateScript('./lib/testing/fake-async.ts', 'zone-fake-async.js', false, cb);
328+
});
329+
322330
gulp.task('build/rxjs.js', ['compile-esm'], function(cb) {
323331
return generateScript('./lib/rxjs/rxjs.ts', 'zone-patch-rxjs.js', false, cb);
324332
});
@@ -391,6 +399,8 @@ gulp.task('build', [
391399
'build/async-test.js',
392400
'build/fake-async-test.js',
393401
'build/sync-test.js',
402+
'build/zone-async-testing.js',
403+
'build/zone-fake-async.js',
394404
'build/rxjs.js',
395405
'build/rxjs.min.js',
396406
'build/rxjs-fake-async.js',

karma-dist.conf.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ module.exports = function(config) {
2020
config.files.push('dist/proxy.js');
2121
config.files.push('dist/sync-test.js');
2222
config.files.push('dist/task-tracking.js');
23-
config.files.push('dist/wtf.js');
23+
config.files.push('dist/zone-async-testing.js');
24+
config.files.push('dist/zone-fake-async.js');
2425
config.files.push('dist/zone-patch-promise-test.js');
26+
config.files.push('dist/wtf.js');
2527
config.files.push('build/test/main.js');
2628
};

lib/jasmine/jasmine.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
};
111111
}
112112

113-
function runInTestZone(testBody: Function, queueRunner: any, done?: Function) {
113+
function runInTestZone(testBody: Function, applyThis: any, queueRunner: any, done?: Function) {
114114
const isClockInstalled = !!(jasmine as any)[symbol('clockInstalled')];
115115
const testProxyZoneSpec = queueRunner.testProxyZoneSpec;
116116
const testProxyZone = queueRunner.testProxyZone;
@@ -121,16 +121,21 @@
121121
const _fakeAsyncTestZoneSpec = new FakeAsyncTestZoneSpec();
122122
lastDelegate = (testProxyZoneSpec as any).getDelegate();
123123
(testProxyZoneSpec as any).setDelegate(_fakeAsyncTestZoneSpec);
124+
_fakeAsyncTestZoneSpec.lockDatePatch();
124125
}
125126
}
126127
try {
127128
if (done) {
128-
return testProxyZone.run(testBody, this, [done]);
129+
return testProxyZone.run(testBody, applyThis, [done]);
129130
} else {
130-
return testProxyZone.run(testBody, this);
131+
return testProxyZone.run(testBody, applyThis);
131132
}
132133
} finally {
133134
if (isClockInstalled) {
135+
const _fakeAsyncTestZoneSpec = testProxyZoneSpec.getDelegate();
136+
if (_fakeAsyncTestZoneSpec) {
137+
_fakeAsyncTestZoneSpec.unlockDatePatch();
138+
}
134139
(testProxyZoneSpec as any).setDelegate(lastDelegate);
135140
}
136141
}
@@ -146,9 +151,9 @@
146151
// Note we have to make a function with correct number of arguments, otherwise jasmine will
147152
// think that all functions are sync or async.
148153
return (testBody && (testBody.length ? function(done: Function) {
149-
return runInTestZone(testBody, this.queueRunner, done);
154+
return runInTestZone(testBody, this, this.queueRunner, done);
150155
} : function() {
151-
return runInTestZone(testBody, this.queueRunner);
156+
return runInTestZone(testBody, this, this.queueRunner);
152157
}));
153158
}
154159
interface QueueRunner {

lib/testing/async-testing.ts

Lines changed: 87 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -6,97 +6,96 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
const _global: any =
10-
typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global;
11-
12-
/**
13-
* Wraps a test function in an asynchronous test zone. The test will automatically
14-
* complete when all asynchronous calls within this zone are done.
15-
*/
16-
export function asyncTest(fn: Function): (done: any) => any {
17-
// If we're running using the Jasmine test framework, adapt to call the 'done'
18-
// function when asynchronous activity is finished.
19-
if (_global.jasmine) {
20-
// Not using an arrow function to preserve context passed from call site
21-
return function(done: any) {
22-
if (!done) {
23-
// if we run beforeEach in @angular/core/testing/testing_internal then we get no done
24-
// fake it here and assume sync.
25-
done = function() {};
26-
done.fail = function(e: any) {
27-
throw e;
28-
};
29-
}
30-
runInTestZone(fn, this, done, (err: any) => {
31-
if (typeof err === 'string') {
32-
return done.fail(new Error(<string>err));
33-
} else {
34-
done.fail(err);
9+
Zone.__load_patch('asynctest', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
10+
/**
11+
* Wraps a test function in an asynchronous test zone. The test will automatically
12+
* complete when all asynchronous calls within this zone are done.
13+
*/
14+
(Zone as any)[api.symbol('asyncTest')] = function asyncTest(fn: Function): (done: any) => any {
15+
// If we're running using the Jasmine test framework, adapt to call the 'done'
16+
// function when asynchronous activity is finished.
17+
if (global.jasmine) {
18+
// Not using an arrow function to preserve context passed from call site
19+
return function(done: any) {
20+
if (!done) {
21+
// if we run beforeEach in @angular/core/testing/testing_internal then we get no done
22+
// fake it here and assume sync.
23+
done = function() {};
24+
done.fail = function(e: any) {
25+
throw e;
26+
};
3527
}
28+
runInTestZone(fn, this, done, (err: any) => {
29+
if (typeof err === 'string') {
30+
return done.fail(new Error(<string>err));
31+
} else {
32+
done.fail(err);
33+
}
34+
});
35+
};
36+
}
37+
// Otherwise, return a promise which will resolve when asynchronous activity
38+
// is finished. This will be correctly consumed by the Mocha framework with
39+
// it('...', async(myFn)); or can be used in a custom framework.
40+
// Not using an arrow function to preserve context passed from call site
41+
return function() {
42+
return new Promise<void>((finishCallback, failCallback) => {
43+
runInTestZone(fn, this, finishCallback, failCallback);
3644
});
3745
};
38-
}
39-
// Otherwise, return a promise which will resolve when asynchronous activity
40-
// is finished. This will be correctly consumed by the Mocha framework with
41-
// it('...', async(myFn)); or can be used in a custom framework.
42-
// Not using an arrow function to preserve context passed from call site
43-
return function() {
44-
return new Promise<void>((finishCallback, failCallback) => {
45-
runInTestZone(fn, this, finishCallback, failCallback);
46-
});
4746
};
48-
}
4947

50-
function runInTestZone(
51-
fn: Function, context: any, finishCallback: Function, failCallback: Function) {
52-
const currentZone = Zone.current;
53-
const AsyncTestZoneSpec = (Zone as any)['AsyncTestZoneSpec'];
54-
if (AsyncTestZoneSpec === undefined) {
55-
throw new Error(
56-
'AsyncTestZoneSpec is needed for the async() test helper but could not be found. ' +
57-
'Please make sure that your environment includes zone.js/dist/async-test.js');
58-
}
59-
const ProxyZoneSpec = (Zone as any)['ProxyZoneSpec'] as {
60-
get(): {setDelegate(spec: ZoneSpec): void; getDelegate(): ZoneSpec;};
61-
assertPresent: () => void;
62-
};
63-
if (ProxyZoneSpec === undefined) {
64-
throw new Error(
65-
'ProxyZoneSpec is needed for the async() test helper but could not be found. ' +
66-
'Please make sure that your environment includes zone.js/dist/proxy.js');
48+
function runInTestZone(
49+
fn: Function, context: any, finishCallback: Function, failCallback: Function) {
50+
const currentZone = Zone.current;
51+
const AsyncTestZoneSpec = (Zone as any)['AsyncTestZoneSpec'];
52+
if (AsyncTestZoneSpec === undefined) {
53+
throw new Error(
54+
'AsyncTestZoneSpec is needed for the async() test helper but could not be found. ' +
55+
'Please make sure that your environment includes zone.js/dist/async-test.js');
56+
}
57+
const ProxyZoneSpec = (Zone as any)['ProxyZoneSpec'] as {
58+
get(): {setDelegate(spec: ZoneSpec): void; getDelegate(): ZoneSpec;};
59+
assertPresent: () => void;
60+
};
61+
if (ProxyZoneSpec === undefined) {
62+
throw new Error(
63+
'ProxyZoneSpec is needed for the async() test helper but could not be found. ' +
64+
'Please make sure that your environment includes zone.js/dist/proxy.js');
65+
}
66+
const proxyZoneSpec = ProxyZoneSpec.get();
67+
ProxyZoneSpec.assertPresent();
68+
// We need to create the AsyncTestZoneSpec outside the ProxyZone.
69+
// If we do it in ProxyZone then we will get to infinite recursion.
70+
const proxyZone = Zone.current.getZoneWith('ProxyZoneSpec');
71+
const previousDelegate = proxyZoneSpec.getDelegate();
72+
proxyZone.parent.run(() => {
73+
const testZoneSpec: ZoneSpec = new AsyncTestZoneSpec(
74+
() => {
75+
// Need to restore the original zone.
76+
if (proxyZoneSpec.getDelegate() == testZoneSpec) {
77+
// Only reset the zone spec if it's
78+
// sill this one. Otherwise, assume
79+
// it's OK.
80+
proxyZoneSpec.setDelegate(previousDelegate);
81+
}
82+
currentZone.run(() => {
83+
finishCallback();
84+
});
85+
},
86+
(error: any) => {
87+
// Need to restore the original zone.
88+
if (proxyZoneSpec.getDelegate() == testZoneSpec) {
89+
// Only reset the zone spec if it's sill this one. Otherwise, assume it's OK.
90+
proxyZoneSpec.setDelegate(previousDelegate);
91+
}
92+
currentZone.run(() => {
93+
failCallback(error);
94+
});
95+
},
96+
'test');
97+
proxyZoneSpec.setDelegate(testZoneSpec);
98+
});
99+
return Zone.current.runGuarded(fn, context);
67100
}
68-
const proxyZoneSpec = ProxyZoneSpec.get();
69-
ProxyZoneSpec.assertPresent();
70-
// We need to create the AsyncTestZoneSpec outside the ProxyZone.
71-
// If we do it in ProxyZone then we will get to infinite recursion.
72-
const proxyZone = Zone.current.getZoneWith('ProxyZoneSpec');
73-
const previousDelegate = proxyZoneSpec.getDelegate();
74-
proxyZone.parent.run(() => {
75-
const testZoneSpec: ZoneSpec = new AsyncTestZoneSpec(
76-
() => {
77-
// Need to restore the original zone.
78-
if (proxyZoneSpec.getDelegate() == testZoneSpec) {
79-
// Only reset the zone spec if it's
80-
// sill this one. Otherwise, assume
81-
// it's OK.
82-
proxyZoneSpec.setDelegate(previousDelegate);
83-
}
84-
currentZone.run(() => {
85-
finishCallback();
86-
});
87-
},
88-
(error: any) => {
89-
// Need to restore the original zone.
90-
if (proxyZoneSpec.getDelegate() == testZoneSpec) {
91-
// Only reset the zone spec if it's sill this one. Otherwise, assume it's OK.
92-
proxyZoneSpec.setDelegate(previousDelegate);
93-
}
94-
currentZone.run(() => {
95-
failCallback(error);
96-
});
97-
},
98-
'test');
99-
proxyZoneSpec.setDelegate(testZoneSpec);
100-
});
101-
return Zone.current.runGuarded(fn, context);
102-
}
101+
});

0 commit comments

Comments
 (0)