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

Commit

Permalink
fix(fakeAsync): fix #1050, should only reset patched Date.now until f…
Browse files Browse the repository at this point in the history
…akeAsync exit (#1051)

* chore: release v0.8.21

* fix(fakeAsync): fix #1050, work with fakeAsync
  • Loading branch information
JiaLiPassion authored and mhevery committed Mar 31, 2018
1 parent 6654b69 commit e15d735
Show file tree
Hide file tree
Showing 13 changed files with 311 additions and 262 deletions.
10 changes: 10 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,14 @@ gulp.task('build/sync-test.js', ['compile-esm'], function(cb) {
return generateScript('./lib/zone-spec/sync-test.ts', 'sync-test.js', false, cb);
});

gulp.task('build/zone-async-testing.js', ['compile-esm'], function(cb) {
return generateScript('./lib/testing/async-testing.ts', 'zone-async-testing.js', false, cb);
});

gulp.task('build/zone-fake-async.js', ['compile-esm'], function(cb) {
return generateScript('./lib/testing/fake-async.ts', 'zone-fake-async.js', false, cb);
});

gulp.task('build/rxjs.js', ['compile-esm'], function(cb) {
return generateScript('./lib/rxjs/rxjs.ts', 'zone-patch-rxjs.js', false, cb);
});
Expand Down Expand Up @@ -391,6 +399,8 @@ gulp.task('build', [
'build/async-test.js',
'build/fake-async-test.js',
'build/sync-test.js',
'build/zone-async-testing.js',
'build/zone-fake-async.js',
'build/rxjs.js',
'build/rxjs.min.js',
'build/rxjs-fake-async.js',
Expand Down
4 changes: 3 additions & 1 deletion karma-dist.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ module.exports = function(config) {
config.files.push('dist/proxy.js');
config.files.push('dist/sync-test.js');
config.files.push('dist/task-tracking.js');
config.files.push('dist/wtf.js');
config.files.push('dist/zone-async-testing.js');
config.files.push('dist/zone-fake-async.js');
config.files.push('dist/zone-patch-promise-test.js');
config.files.push('dist/wtf.js');
config.files.push('build/test/main.js');
};
15 changes: 10 additions & 5 deletions lib/jasmine/jasmine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
};
}

function runInTestZone(testBody: Function, queueRunner: any, done?: Function) {
function runInTestZone(testBody: Function, applyThis: any, queueRunner: any, done?: Function) {
const isClockInstalled = !!(jasmine as any)[symbol('clockInstalled')];
const testProxyZoneSpec = queueRunner.testProxyZoneSpec;
const testProxyZone = queueRunner.testProxyZone;
Expand All @@ -121,16 +121,21 @@
const _fakeAsyncTestZoneSpec = new FakeAsyncTestZoneSpec();
lastDelegate = (testProxyZoneSpec as any).getDelegate();
(testProxyZoneSpec as any).setDelegate(_fakeAsyncTestZoneSpec);
_fakeAsyncTestZoneSpec.lockDatePatch();
}
}
try {
if (done) {
return testProxyZone.run(testBody, this, [done]);
return testProxyZone.run(testBody, applyThis, [done]);
} else {
return testProxyZone.run(testBody, this);
return testProxyZone.run(testBody, applyThis);
}
} finally {
if (isClockInstalled) {
const _fakeAsyncTestZoneSpec = testProxyZoneSpec.getDelegate();
if (_fakeAsyncTestZoneSpec) {
_fakeAsyncTestZoneSpec.unlockDatePatch();
}
(testProxyZoneSpec as any).setDelegate(lastDelegate);
}
}
Expand All @@ -146,9 +151,9 @@
// 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: Function) {
return runInTestZone(testBody, this.queueRunner, done);
return runInTestZone(testBody, this, this.queueRunner, done);
} : function() {
return runInTestZone(testBody, this.queueRunner);
return runInTestZone(testBody, this, this.queueRunner);
}));
}
interface QueueRunner {
Expand Down
175 changes: 87 additions & 88 deletions lib/testing/async-testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,97 +6,96 @@
* found in the LICENSE file at https://angular.io/license
*/

const _global: any =
typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global;

/**
* Wraps a test function in an asynchronous test zone. The test will automatically
* complete when all asynchronous calls within this zone are done.
*/
export function asyncTest(fn: Function): (done: any) => any {
// If we're running using the Jasmine test framework, adapt to call the 'done'
// function when asynchronous activity is finished.
if (_global.jasmine) {
// Not using an arrow function to preserve context passed from call site
return function(done: any) {
if (!done) {
// if we run beforeEach in @angular/core/testing/testing_internal then we get no done
// fake it here and assume sync.
done = function() {};
done.fail = function(e: any) {
throw e;
};
}
runInTestZone(fn, this, done, (err: any) => {
if (typeof err === 'string') {
return done.fail(new Error(<string>err));
} else {
done.fail(err);
Zone.__load_patch('asynctest', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
/**
* Wraps a test function in an asynchronous test zone. The test will automatically
* complete when all asynchronous calls within this zone are done.
*/
(Zone as any)[api.symbol('asyncTest')] = function asyncTest(fn: Function): (done: any) => any {
// If we're running using the Jasmine test framework, adapt to call the 'done'
// function when asynchronous activity is finished.
if (global.jasmine) {
// Not using an arrow function to preserve context passed from call site
return function(done: any) {
if (!done) {
// if we run beforeEach in @angular/core/testing/testing_internal then we get no done
// fake it here and assume sync.
done = function() {};
done.fail = function(e: any) {
throw e;
};
}
runInTestZone(fn, this, done, (err: any) => {
if (typeof err === 'string') {
return done.fail(new Error(<string>err));
} else {
done.fail(err);
}
});
};
}
// Otherwise, return a promise which will resolve when asynchronous activity
// is finished. This will be correctly consumed by the Mocha framework with
// it('...', async(myFn)); or can be used in a custom framework.
// Not using an arrow function to preserve context passed from call site
return function() {
return new Promise<void>((finishCallback, failCallback) => {
runInTestZone(fn, this, finishCallback, failCallback);
});
};
}
// Otherwise, return a promise which will resolve when asynchronous activity
// is finished. This will be correctly consumed by the Mocha framework with
// it('...', async(myFn)); or can be used in a custom framework.
// Not using an arrow function to preserve context passed from call site
return function() {
return new Promise<void>((finishCallback, failCallback) => {
runInTestZone(fn, this, finishCallback, failCallback);
});
};
}

function runInTestZone(
fn: Function, context: any, finishCallback: Function, failCallback: Function) {
const currentZone = Zone.current;
const AsyncTestZoneSpec = (Zone as any)['AsyncTestZoneSpec'];
if (AsyncTestZoneSpec === undefined) {
throw new Error(
'AsyncTestZoneSpec is needed for the async() test helper but could not be found. ' +
'Please make sure that your environment includes zone.js/dist/async-test.js');
}
const ProxyZoneSpec = (Zone as any)['ProxyZoneSpec'] as {
get(): {setDelegate(spec: ZoneSpec): void; getDelegate(): ZoneSpec;};
assertPresent: () => void;
};
if (ProxyZoneSpec === undefined) {
throw new Error(
'ProxyZoneSpec is needed for the async() test helper but could not be found. ' +
'Please make sure that your environment includes zone.js/dist/proxy.js');
function runInTestZone(
fn: Function, context: any, finishCallback: Function, failCallback: Function) {
const currentZone = Zone.current;
const AsyncTestZoneSpec = (Zone as any)['AsyncTestZoneSpec'];
if (AsyncTestZoneSpec === undefined) {
throw new Error(
'AsyncTestZoneSpec is needed for the async() test helper but could not be found. ' +
'Please make sure that your environment includes zone.js/dist/async-test.js');
}
const ProxyZoneSpec = (Zone as any)['ProxyZoneSpec'] as {
get(): {setDelegate(spec: ZoneSpec): void; getDelegate(): ZoneSpec;};
assertPresent: () => void;
};
if (ProxyZoneSpec === undefined) {
throw new Error(
'ProxyZoneSpec is needed for the async() test helper but could not be found. ' +
'Please make sure that your environment includes zone.js/dist/proxy.js');
}
const proxyZoneSpec = ProxyZoneSpec.get();
ProxyZoneSpec.assertPresent();
// We need to create the AsyncTestZoneSpec outside the ProxyZone.
// If we do it in ProxyZone then we will get to infinite recursion.
const proxyZone = Zone.current.getZoneWith('ProxyZoneSpec');
const previousDelegate = proxyZoneSpec.getDelegate();
proxyZone.parent.run(() => {
const testZoneSpec: ZoneSpec = new AsyncTestZoneSpec(
() => {
// Need to restore the original zone.
if (proxyZoneSpec.getDelegate() == testZoneSpec) {
// Only reset the zone spec if it's
// sill this one. Otherwise, assume
// it's OK.
proxyZoneSpec.setDelegate(previousDelegate);
}
currentZone.run(() => {
finishCallback();
});
},
(error: any) => {
// Need to restore the original zone.
if (proxyZoneSpec.getDelegate() == testZoneSpec) {
// Only reset the zone spec if it's sill this one. Otherwise, assume it's OK.
proxyZoneSpec.setDelegate(previousDelegate);
}
currentZone.run(() => {
failCallback(error);
});
},
'test');
proxyZoneSpec.setDelegate(testZoneSpec);
});
return Zone.current.runGuarded(fn, context);
}
const proxyZoneSpec = ProxyZoneSpec.get();
ProxyZoneSpec.assertPresent();
// We need to create the AsyncTestZoneSpec outside the ProxyZone.
// If we do it in ProxyZone then we will get to infinite recursion.
const proxyZone = Zone.current.getZoneWith('ProxyZoneSpec');
const previousDelegate = proxyZoneSpec.getDelegate();
proxyZone.parent.run(() => {
const testZoneSpec: ZoneSpec = new AsyncTestZoneSpec(
() => {
// Need to restore the original zone.
if (proxyZoneSpec.getDelegate() == testZoneSpec) {
// Only reset the zone spec if it's
// sill this one. Otherwise, assume
// it's OK.
proxyZoneSpec.setDelegate(previousDelegate);
}
currentZone.run(() => {
finishCallback();
});
},
(error: any) => {
// Need to restore the original zone.
if (proxyZoneSpec.getDelegate() == testZoneSpec) {
// Only reset the zone spec if it's sill this one. Otherwise, assume it's OK.
proxyZoneSpec.setDelegate(previousDelegate);
}
currentZone.run(() => {
failCallback(error);
});
},
'test');
proxyZoneSpec.setDelegate(testZoneSpec);
});
return Zone.current.runGuarded(fn, context);
}
});
Loading

0 comments on commit e15d735

Please sign in to comment.