fix(core): In Testability.whenStable update callback, pass more complete (#25010)

data about tasks.

When building a list of pending tasks for callers of whenStable(),
Testability will copy data about the task into a new object, in order to
avoid leaking references to tasks.

This change copies more properties from Tasks into the list of pending
tasks, as well as a reference to Task.data to give callers more
information about the tasks that are pending.

Specifically, this also copies runCount and task ID, which are needed in
order for callers to know when a given task is repeating.

PR Close #25010
This commit is contained in:
Michael Giambalvo 2018-07-20 13:24:31 -07:00 committed by Kara Erickson
parent 3355502f2f
commit 16c03c0f38
3 changed files with 16 additions and 14 deletions

View File

@ -25,10 +25,15 @@ export declare interface PublicTestability {
// Angular internal, not intended for public API. // Angular internal, not intended for public API.
export interface PendingMacrotask { export interface PendingMacrotask {
source: string; source: string;
isPeriodic: boolean;
delay?: number;
creationLocation: Error; creationLocation: Error;
xhr?: XMLHttpRequest; runCount?: number;
data: TaskData;
}
export interface TaskData {
target?: XMLHttpRequest;
delay?: number;
isPeriodic?: boolean;
} }
// Angular internal, not intended for public API. // Angular internal, not intended for public API.
@ -152,17 +157,14 @@ export class Testability implements PublicTestability {
return []; return [];
} }
// Copy the tasks data so that we don't leak tasks.
return this.taskTrackingZone.macroTasks.map((t: Task) => { return this.taskTrackingZone.macroTasks.map((t: Task) => {
return { return {
source: t.source, source: t.source,
isPeriodic: t.data.isPeriodic,
delay: t.data.delay,
// From TaskTrackingZone: // From TaskTrackingZone:
// https://github.com/angular/zone.js/blob/master/lib/zone-spec/task-tracking.ts#L40 // https://github.com/angular/zone.js/blob/master/lib/zone-spec/task-tracking.ts#L40
creationLocation: (t as any).creationLocation as Error, creationLocation: (t as any).creationLocation as Error,
// Added by Zones for XHRs data: t.data
// https://github.com/angular/zone.js/blob/master/lib/browser/browser.ts#L133
xhr: (t.data as any).target
}; };
}); });
} }

View File

@ -143,9 +143,9 @@ class MockNgZone extends NgZone {
const tasks = execute.calls.mostRecent().args[1] as PendingMacrotask[]; const tasks = execute.calls.mostRecent().args[1] as PendingMacrotask[];
expect(tasks.length).toEqual(1); expect(tasks.length).toEqual(1);
expect(tasks[0].delay).toEqual(1000); expect(tasks[0].data.delay).toEqual(1000);
expect(tasks[0].source).toEqual('setTimeout'); expect(tasks[0].source).toEqual('setTimeout');
expect(tasks[0].isPeriodic).toEqual(false); expect(tasks[0].data.isPeriodic).toEqual(false);
clearTimeout(id); clearTimeout(id);
})); }));
@ -207,11 +207,11 @@ class MockNgZone extends NgZone {
expect(execute).toHaveBeenCalled(); expect(execute).toHaveBeenCalled();
const update1 = updateCallback.calls.all()[0].args[0] as PendingMacrotask[]; const update1 = updateCallback.calls.all()[0].args[0] as PendingMacrotask[];
expect(update1[0].delay).toEqual(500); expect(update1[0].data.delay).toEqual(500);
const update2 = updateCallback.calls.all()[1].args[0] as PendingMacrotask[]; const update2 = updateCallback.calls.all()[1].args[0] as PendingMacrotask[];
expect(update2[0].delay).toEqual(500); expect(update2[0].data.delay).toEqual(500);
expect(update2[1].delay).toEqual(300); expect(update2[1].data.delay).toEqual(300);
})); }));
it('cancels the done callback if the update callback returns true', fakeAsync(() => { it('cancels the done callback if the update callback returns true', fakeAsync(() => {

View File

@ -30,7 +30,7 @@ describe('testability example', () => {
browser.driver.executeAsyncScript(waitWithResultScript).then((result: any[]) => { browser.driver.executeAsyncScript(waitWithResultScript).then((result: any[]) => {
let pendingTask = result[0]; let pendingTask = result[0];
expect(pendingTask.delay).toEqual(5000); expect(pendingTask.data.delay).toEqual(5000);
expect(pendingTask.source).toEqual('setTimeout'); expect(pendingTask.source).toEqual('setTimeout');
expect(element(by.css('.status')).getText()).not.toContain('done'); expect(element(by.css('.status')).getText()).not.toContain('done');
done(); done();