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

fix(fakeAsync): fix #1050, should only reset patched Date.now until fakeAsync exit #1051

Merged
merged 3 commits into from
Mar 31, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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