mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
1342 lines
44 KiB
TypeScript
1342 lines
44 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.dev/license
|
|
*/
|
|
|
|
const noop = function () {};
|
|
let log: {zone: string; taskZone: undefined | string; toState: TaskState; fromState: TaskState}[] =
|
|
[];
|
|
const detectTask = Zone.current.scheduleMacroTask('detectTask', noop, undefined, noop, noop);
|
|
const originalTransitionTo = detectTask.constructor.prototype._transitionTo;
|
|
// patch _transitionTo of ZoneTask to add log for test
|
|
const logTransitionTo: Function = function (
|
|
this: Task & {_state: TaskState},
|
|
toState: TaskState,
|
|
fromState1: TaskState,
|
|
fromState2?: TaskState,
|
|
) {
|
|
log.push({
|
|
zone: Zone.current.name,
|
|
taskZone: this.zone && this.zone.name,
|
|
toState: toState,
|
|
fromState: this._state,
|
|
});
|
|
originalTransitionTo.apply(this, arguments);
|
|
};
|
|
|
|
function testFnWithLoggedTransitionTo(testFn: Function) {
|
|
return function (this: unknown) {
|
|
detectTask.constructor.prototype._transitionTo = logTransitionTo;
|
|
testFn.apply(this, arguments);
|
|
detectTask.constructor.prototype._transitionTo = originalTransitionTo;
|
|
};
|
|
}
|
|
|
|
describe('task lifecycle', () => {
|
|
describe('event task lifecycle', () => {
|
|
beforeEach(() => {
|
|
log = [];
|
|
});
|
|
|
|
it(
|
|
'task should transit from notScheduled to scheduling then to scheduled state when scheduleTask',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testEventTaskZone'}).run(() => {
|
|
Zone.current.scheduleEventTask('testEventTask', noop, undefined, noop, noop);
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from scheduling to unknown when zoneSpec onScheduleTask callback throw error',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current
|
|
.fork({
|
|
name: 'testEventTaskZone',
|
|
onScheduleTask: (delegate, currZone, targetZone, task) => {
|
|
throw Error('error in onScheduleTask');
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
Zone.current.scheduleEventTask('testEventTask', noop, undefined, noop, noop);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'unknown', fromState: 'scheduling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from scheduled to running when task is invoked then from running to scheduled after invoke',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testEventTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleEventTask('testEventTask', noop, undefined, noop, noop);
|
|
task.invoke();
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'scheduled', fromState: 'running'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from scheduled to canceling then from canceling to notScheduled when task is canceled before running',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testEventTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleEventTask('testEventTask', noop, undefined, noop, noop);
|
|
Zone.current.cancelTask(task);
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from running to canceling then from canceling to notScheduled when task is canceled in running state',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testEventTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleEventTask(
|
|
'testEventTask',
|
|
() => {
|
|
Zone.current.cancelTask(task);
|
|
},
|
|
undefined,
|
|
noop,
|
|
noop,
|
|
);
|
|
task.invoke();
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'canceling', fromState: 'running'},
|
|
{toState: 'notScheduled', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from running to scheduled when task.callback throw error',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testEventTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleEventTask(
|
|
'testEventTask',
|
|
() => {
|
|
throw Error('invoke error');
|
|
},
|
|
undefined,
|
|
noop,
|
|
noop,
|
|
);
|
|
try {
|
|
task.invoke();
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'scheduled', fromState: 'running'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from canceling to unknown when zoneSpec.onCancelTask throw error before task running',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testEventTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleEventTask(
|
|
'testEventTask',
|
|
noop,
|
|
undefined,
|
|
noop,
|
|
() => {
|
|
throw Error('cancel task');
|
|
},
|
|
);
|
|
try {
|
|
Zone.current.cancelTask(task);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'unknown', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from canceling to unknown when zoneSpec.onCancelTask throw error in running state',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testEventTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleEventTask(
|
|
'testEventTask',
|
|
noop,
|
|
undefined,
|
|
noop,
|
|
() => {
|
|
throw Error('cancel task');
|
|
},
|
|
);
|
|
try {
|
|
Zone.current.cancelTask(task);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'unknown', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from notScheduled to scheduled if zoneSpec.onHasTask throw error when scheduleTask',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current
|
|
.fork({
|
|
name: 'testEventTaskZone',
|
|
onHasTask: (delegate, currZone, targetZone, hasTaskState) => {
|
|
throw Error('hasTask Error');
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
Zone.current.scheduleEventTask('testEventTask', noop, undefined, noop, noop);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit to notScheduled state if zoneSpec.onHasTask throw error when task is canceled',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
let task: Task;
|
|
Zone.current
|
|
.fork({
|
|
name: 'testEventTaskZone',
|
|
onHasTask: (delegate, currZone, targetZone, hasTaskState) => {
|
|
if (task && task.state === 'canceling') {
|
|
throw Error('hasTask Error');
|
|
}
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
task = Zone.current.scheduleEventTask('testEventTask', noop, undefined, noop, noop);
|
|
Zone.current.cancelTask(task);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
});
|
|
|
|
describe('non periodical macroTask lifecycle', () => {
|
|
beforeEach(() => {
|
|
log = [];
|
|
});
|
|
|
|
it(
|
|
'task should transit from notScheduled to scheduling then to scheduled state when scheduleTask',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testMacroTaskZone'}).run(() => {
|
|
Zone.current.scheduleMacroTask('testMacroTask', noop, undefined, noop, noop);
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from scheduling to unknown when zoneSpec onScheduleTask callback throw error',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current
|
|
.fork({
|
|
name: 'testMacroTaskZone',
|
|
onScheduleTask: (delegate, currZone, targetZone, task) => {
|
|
throw Error('error in onScheduleTask');
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
Zone.current.scheduleMacroTask('testMacroTask', noop, undefined, noop, noop);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'unknown', fromState: 'scheduling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from scheduled to running when task is invoked then from running to noScheduled after invoke',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testMacroTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleMacroTask('testMacroTask', noop, undefined, noop, noop);
|
|
task.invoke();
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'running'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from scheduled to canceling then from canceling to notScheduled when task is canceled before running',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testMacroTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleMacroTask('testMacrotask', noop, undefined, noop, noop);
|
|
Zone.current.cancelTask(task);
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from running to canceling then from canceling to notScheduled when task is canceled in running state',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testMacroTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleMacroTask(
|
|
'testMacroTask',
|
|
() => {
|
|
Zone.current.cancelTask(task);
|
|
},
|
|
undefined,
|
|
noop,
|
|
noop,
|
|
);
|
|
task.invoke();
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'canceling', fromState: 'running'},
|
|
{toState: 'notScheduled', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from running to noScheduled when task.callback throw error',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testMacroTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleMacroTask(
|
|
'testMacroTask',
|
|
() => {
|
|
throw Error('invoke error');
|
|
},
|
|
undefined,
|
|
noop,
|
|
noop,
|
|
);
|
|
try {
|
|
task.invoke();
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'running'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from canceling to unknown when zoneSpec.onCancelTask throw error before task running',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testMacroTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleMacroTask(
|
|
'testMacroTask',
|
|
noop,
|
|
undefined,
|
|
noop,
|
|
() => {
|
|
throw Error('cancel task');
|
|
},
|
|
);
|
|
try {
|
|
Zone.current.cancelTask(task);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'unknown', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from canceling to unknown when zoneSpec.onCancelTask throw error in running state',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testMacroTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleMacroTask(
|
|
'testMacroTask',
|
|
noop,
|
|
undefined,
|
|
noop,
|
|
() => {
|
|
throw Error('cancel task');
|
|
},
|
|
);
|
|
try {
|
|
Zone.current.cancelTask(task);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'unknown', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from notScheduled to scheduling then to scheduled if zoneSpec.onHasTask throw error when scheduleTask',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current
|
|
.fork({
|
|
name: 'testMacroTaskZone',
|
|
onHasTask: (delegate, currZone, targetZone, hasTaskState) => {
|
|
throw Error('hasTask Error');
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
Zone.current.scheduleMacroTask('testMacroTask', noop, undefined, noop, noop);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit to notScheduled state if zoneSpec.onHasTask throw error after task.callback being invoked',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
let task: Task;
|
|
Zone.current
|
|
.fork({
|
|
name: 'testMacroTaskZone',
|
|
onHasTask: (delegate, currZone, targetZone, hasTaskState) => {
|
|
if (task && task.state === 'running') {
|
|
throw Error('hasTask Error');
|
|
}
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
task = Zone.current.scheduleMacroTask('testMacroTask', noop, undefined, noop, noop);
|
|
task.invoke();
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'running'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit to notScheduled state if zoneSpec.onHasTask throw error when task is canceled before running',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
let task: Task;
|
|
Zone.current
|
|
.fork({
|
|
name: 'testMacroTaskZone',
|
|
onHasTask: (delegate, currZone, targetZone, hasTaskState) => {
|
|
if (task && task.state === 'canceling') {
|
|
throw Error('hasTask Error');
|
|
}
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
task = Zone.current.scheduleMacroTask('testMacroTask', noop, undefined, noop, noop);
|
|
Zone.current.cancelTask(task);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
});
|
|
|
|
describe('periodical macroTask lifecycle', () => {
|
|
let task: Task | null;
|
|
beforeEach(() => {
|
|
log = [];
|
|
task = null;
|
|
});
|
|
afterEach(() => {
|
|
task &&
|
|
task.state !== 'notScheduled' &&
|
|
task.state !== 'canceling' &&
|
|
task.state !== 'unknown' &&
|
|
task.zone.cancelTask(task);
|
|
});
|
|
|
|
it(
|
|
'task should transit from notScheduled to scheduling then to scheduled state when scheduleTask',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testPeriodicalTaskZone'}).run(() => {
|
|
task = Zone.current.scheduleMacroTask(
|
|
'testPeriodicalTask',
|
|
noop,
|
|
{isPeriodic: true},
|
|
noop,
|
|
noop,
|
|
);
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from scheduling to unknown when zoneSpec onScheduleTask callback throw error',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current
|
|
.fork({
|
|
name: 'testPeriodicalTaskZone',
|
|
onScheduleTask: (delegate, currZone, targetZone, task) => {
|
|
throw Error('error in onScheduleTask');
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
task = Zone.current.scheduleMacroTask(
|
|
'testPeriodicalTask',
|
|
noop,
|
|
{isPeriodic: true},
|
|
noop,
|
|
noop,
|
|
);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'unknown', fromState: 'scheduling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from scheduled to running when task is invoked then from running to scheduled after invoke',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testPeriodicalTaskZone'}).run(() => {
|
|
task = Zone.current.scheduleMacroTask(
|
|
'testPeriodicalTask',
|
|
noop,
|
|
{isPeriodic: true},
|
|
noop,
|
|
noop,
|
|
);
|
|
task.invoke();
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'scheduled', fromState: 'running'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from scheduled to canceling then from canceling to notScheduled when task is canceled before running',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testPeriodicalTaskZone'}).run(() => {
|
|
task = Zone.current.scheduleMacroTask(
|
|
'testPeriodicalTask',
|
|
noop,
|
|
{isPeriodic: true},
|
|
noop,
|
|
noop,
|
|
);
|
|
Zone.current.cancelTask(task);
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from running to canceling then from canceling to notScheduled when task is canceled in running state',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testPeriodicalTaskZone'}).run(() => {
|
|
task = Zone.current.scheduleMacroTask(
|
|
'testPeriodicalTask',
|
|
() => {
|
|
Zone.current.cancelTask(task!);
|
|
},
|
|
{isPeriodic: true},
|
|
noop,
|
|
noop,
|
|
);
|
|
task.invoke();
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'canceling', fromState: 'running'},
|
|
{toState: 'notScheduled', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from running to scheduled when task.callback throw error',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testPeriodicalTaskZone'}).run(() => {
|
|
task = Zone.current.scheduleMacroTask(
|
|
'testPeriodicalTask',
|
|
() => {
|
|
throw Error('invoke error');
|
|
},
|
|
{isPeriodic: true},
|
|
noop,
|
|
noop,
|
|
);
|
|
try {
|
|
task.invoke();
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'scheduled', fromState: 'running'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from canceling to unknown when zoneSpec.onCancelTask throw error before task running',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testPeriodicalTaskZone'}).run(() => {
|
|
task = Zone.current.scheduleMacroTask(
|
|
'testPeriodicalTask',
|
|
noop,
|
|
{isPeriodic: true},
|
|
noop,
|
|
() => {
|
|
throw Error('cancel task');
|
|
},
|
|
);
|
|
try {
|
|
Zone.current.cancelTask(task);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'unknown', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from canceling to unknown when zoneSpec.onCancelTask throw error in running state',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testPeriodicalTaskZone'}).run(() => {
|
|
task = Zone.current.scheduleMacroTask(
|
|
'testPeriodicalTask',
|
|
noop,
|
|
{isPeriodic: true},
|
|
noop,
|
|
() => {
|
|
throw Error('cancel task');
|
|
},
|
|
);
|
|
try {
|
|
Zone.current.cancelTask(task);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'unknown', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from notScheduled to scheduled if zoneSpec.onHasTask throw error when scheduleTask',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current
|
|
.fork({
|
|
name: 'testPeriodicalTaskZone',
|
|
onHasTask: (delegate, currZone, targetZone, hasTaskState) => {
|
|
throw Error('hasTask Error');
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
task = Zone.current.scheduleMacroTask(
|
|
'testPeriodicalTask',
|
|
noop,
|
|
{isPeriodic: true},
|
|
noop,
|
|
noop,
|
|
);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit to notScheduled state if zoneSpec.onHasTask throw error when task is canceled',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current
|
|
.fork({
|
|
name: 'testPeriodicalTaskZone',
|
|
onHasTask: (delegate, currZone, targetZone, hasTaskState) => {
|
|
if (task && task.state === 'canceling') {
|
|
throw Error('hasTask Error');
|
|
}
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
task = Zone.current.scheduleMacroTask(
|
|
'testPeriodicalTask',
|
|
noop,
|
|
{isPeriodic: true},
|
|
noop,
|
|
noop,
|
|
);
|
|
Zone.current.cancelTask(task);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
});
|
|
|
|
describe('microTask lifecycle', () => {
|
|
beforeEach(() => {
|
|
log = [];
|
|
});
|
|
|
|
it(
|
|
'task should transit from notScheduled to scheduling then to scheduled state when scheduleTask',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testMicroTaskZone'}).run(() => {
|
|
Zone.current.scheduleMicroTask('testMicroTask', noop, undefined, noop);
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from scheduling to unknown when zoneSpec onScheduleTask callback throw error',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current
|
|
.fork({
|
|
name: 'testMicroTaskZone',
|
|
onScheduleTask: (delegate, currZone, targetZone, task) => {
|
|
throw Error('error in onScheduleTask');
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
Zone.current.scheduleMicroTask('testMicroTask', noop, undefined, noop);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'unknown', fromState: 'scheduling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from scheduled to running when task is invoked then from running to noScheduled after invoke',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testMicroTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleMicroTask('testMicroTask', noop, undefined, noop);
|
|
task.invoke();
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'running'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'should throw error when try to cancel a microTask',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testMicroTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleMicroTask('testMicroTask', () => {}, undefined, noop);
|
|
expect(() => {
|
|
Zone.current.cancelTask(task);
|
|
}).toThrowError('Task is not cancelable');
|
|
});
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from running to notScheduled when task.callback throw error',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testMicroTaskZone'}).run(() => {
|
|
const task = Zone.current.scheduleMicroTask(
|
|
'testMicroTask',
|
|
() => {
|
|
throw Error('invoke error');
|
|
},
|
|
undefined,
|
|
noop,
|
|
);
|
|
try {
|
|
task.invoke();
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'running'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit from notScheduled to scheduling then to scheduled if zoneSpec.onHasTask throw error when scheduleTask',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current
|
|
.fork({
|
|
name: 'testMicroTaskZone',
|
|
onHasTask: (delegate, currZone, targetZone, hasTaskState) => {
|
|
throw Error('hasTask Error');
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
Zone.current.scheduleMicroTask('testMicroTask', noop, undefined, noop);
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should transit to notScheduled state if zoneSpec.onHasTask throw error after task.callback being invoked',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
let task: Task;
|
|
Zone.current
|
|
.fork({
|
|
name: 'testMicroTaskZone',
|
|
onHasTask: (delegate, currZone, targetZone, hasTaskState) => {
|
|
if (task && task.state === 'running') {
|
|
throw Error('hasTask Error');
|
|
}
|
|
},
|
|
})
|
|
.run(() => {
|
|
try {
|
|
task = Zone.current.scheduleMicroTask('testMicroTask', noop, undefined, noop);
|
|
task.invoke();
|
|
} catch (err) {}
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'running', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'running'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'task should not run if task transite to notScheduled state which was canceled',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
let task: Task;
|
|
Zone.current.fork({name: 'testCancelZone'}).run(() => {
|
|
const task = Zone.current.scheduleEventTask('testEventTask', noop, undefined, noop, noop);
|
|
Zone.current.cancelTask(task);
|
|
task.invoke();
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'canceling'},
|
|
]);
|
|
}),
|
|
);
|
|
});
|
|
|
|
// Test specific to https://github.com/angular/angular/issues/45711
|
|
it('should not throw an error when the task has been canceled previously and is attempted to be canceled again', () => {
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'testCancelZone'}).run(() => {
|
|
const task = Zone.current.scheduleEventTask('testEventTask', noop, undefined, noop, noop);
|
|
Zone.current.cancelTask(task);
|
|
Zone.current.cancelTask(task);
|
|
});
|
|
expect(
|
|
log.map((item) => {
|
|
return {toState: item.toState, fromState: item.fromState};
|
|
}),
|
|
).toEqual([
|
|
{toState: 'scheduling', fromState: 'notScheduled'},
|
|
{toState: 'scheduled', fromState: 'scheduling'},
|
|
{toState: 'canceling', fromState: 'scheduled'},
|
|
{toState: 'notScheduled', fromState: 'canceling'},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('reschedule zone', () => {
|
|
let callbackLogs: ({pos: string; method: string; zone: string; task: string} | HasTaskState)[];
|
|
const newZone = Zone.root.fork({
|
|
name: 'new',
|
|
onScheduleTask: (delegate, currZone, targetZone, task) => {
|
|
callbackLogs.push({
|
|
pos: 'before',
|
|
method: 'onScheduleTask',
|
|
zone: currZone.name,
|
|
task: task.zone.name,
|
|
});
|
|
return delegate.scheduleTask(targetZone, task);
|
|
},
|
|
onInvokeTask: (delegate, currZone, targetZone, task, applyThis, applyArgs) => {
|
|
callbackLogs.push({
|
|
pos: 'before',
|
|
method: 'onInvokeTask',
|
|
zone: currZone.name,
|
|
task: task.zone.name,
|
|
});
|
|
return delegate.invokeTask(targetZone, task, applyThis, applyArgs);
|
|
},
|
|
onCancelTask: (delegate, currZone, targetZone, task) => {
|
|
callbackLogs.push({
|
|
pos: 'before',
|
|
method: 'onCancelTask',
|
|
zone: currZone.name,
|
|
task: task.zone.name,
|
|
});
|
|
return delegate.cancelTask(targetZone, task);
|
|
},
|
|
onHasTask: (delegate, currZone, targetZone, hasTaskState) => {
|
|
(hasTaskState as any)['zone'] = targetZone.name;
|
|
callbackLogs.push(hasTaskState);
|
|
return delegate.hasTask(targetZone, hasTaskState);
|
|
},
|
|
});
|
|
const zone = Zone.root.fork({
|
|
name: 'original',
|
|
onScheduleTask: (delegate, currZone, targetZone, task) => {
|
|
callbackLogs.push({
|
|
pos: 'before',
|
|
method: 'onScheduleTask',
|
|
zone: currZone.name,
|
|
task: task.zone.name,
|
|
});
|
|
task.cancelScheduleRequest();
|
|
task = newZone.scheduleTask(task);
|
|
callbackLogs.push({
|
|
pos: 'after',
|
|
method: 'onScheduleTask',
|
|
zone: currZone.name,
|
|
task: task.zone.name,
|
|
});
|
|
return task;
|
|
},
|
|
onInvokeTask: (delegate, currZone, targetZone, task, applyThis, applyArgs) => {
|
|
callbackLogs.push({
|
|
pos: 'before',
|
|
method: 'onInvokeTask',
|
|
zone: currZone.name,
|
|
task: task.zone.name,
|
|
});
|
|
return delegate.invokeTask(targetZone, task, applyThis, applyArgs);
|
|
},
|
|
onCancelTask: (delegate, currZone, targetZone, task) => {
|
|
callbackLogs.push({
|
|
pos: 'before',
|
|
method: 'onCancelTask',
|
|
zone: currZone.name,
|
|
task: task.zone.name,
|
|
});
|
|
return delegate.cancelTask(targetZone, task);
|
|
},
|
|
onHasTask: (delegate, currZone, targetZone, hasTaskState) => {
|
|
(<any>hasTaskState)['zone'] = targetZone.name;
|
|
callbackLogs.push(hasTaskState);
|
|
return delegate.hasTask(targetZone, hasTaskState);
|
|
},
|
|
});
|
|
|
|
beforeEach(() => {
|
|
callbackLogs = [];
|
|
});
|
|
|
|
it(
|
|
'should be able to reschedule zone when in scheduling state, after that, task will completely go to new zone, has nothing to do with original one',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
zone.run(() => {
|
|
const t = Zone.current.scheduleMacroTask(
|
|
'testRescheduleZoneTask',
|
|
noop,
|
|
undefined,
|
|
noop,
|
|
noop,
|
|
);
|
|
t.invoke();
|
|
});
|
|
|
|
expect(callbackLogs).toEqual([
|
|
{pos: 'before', method: 'onScheduleTask', zone: 'original', task: 'original'},
|
|
{pos: 'before', method: 'onScheduleTask', zone: 'new', task: 'new'},
|
|
{microTask: false, macroTask: true, eventTask: false, change: 'macroTask', zone: 'new'},
|
|
{pos: 'after', method: 'onScheduleTask', zone: 'original', task: 'new'},
|
|
{pos: 'before', method: 'onInvokeTask', zone: 'new', task: 'new'},
|
|
{microTask: false, macroTask: false, eventTask: false, change: 'macroTask', zone: 'new'},
|
|
]);
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'should not be able to reschedule task in notScheduled / running / canceling state',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
Zone.current.fork({name: 'rescheduleNotScheduled'}).run(() => {
|
|
const t = Zone.current.scheduleMacroTask(
|
|
'testRescheduleZoneTask',
|
|
noop,
|
|
undefined,
|
|
noop,
|
|
noop,
|
|
);
|
|
Zone.current.cancelTask(t);
|
|
expect(() => {
|
|
t.cancelScheduleRequest();
|
|
}).toThrow(
|
|
Error(
|
|
`macroTask 'testRescheduleZoneTask': can not transition to ` +
|
|
`'notScheduled', expecting state 'scheduling', was 'notScheduled'.`,
|
|
),
|
|
);
|
|
});
|
|
|
|
Zone.current
|
|
.fork({
|
|
name: 'rescheduleRunning',
|
|
onInvokeTask: (delegate, currZone, targetZone, task, applyThis, applyArgs) => {
|
|
expect(() => {
|
|
task.cancelScheduleRequest();
|
|
}).toThrow(
|
|
Error(
|
|
`macroTask 'testRescheduleZoneTask': can not transition to ` +
|
|
`'notScheduled', expecting state 'scheduling', was 'running'.`,
|
|
),
|
|
);
|
|
},
|
|
})
|
|
.run(() => {
|
|
const t = Zone.current.scheduleMacroTask(
|
|
'testRescheduleZoneTask',
|
|
noop,
|
|
undefined,
|
|
noop,
|
|
noop,
|
|
);
|
|
t.invoke();
|
|
});
|
|
|
|
Zone.current
|
|
.fork({
|
|
name: 'rescheduleCanceling',
|
|
onCancelTask: (delegate, currZone, targetZone, task) => {
|
|
expect(() => {
|
|
task.cancelScheduleRequest();
|
|
}).toThrow(
|
|
Error(
|
|
`macroTask 'testRescheduleZoneTask': can not transition to ` +
|
|
`'notScheduled', expecting state 'scheduling', was 'canceling'.`,
|
|
),
|
|
);
|
|
},
|
|
})
|
|
.run(() => {
|
|
const t = Zone.current.scheduleMacroTask(
|
|
'testRescheduleZoneTask',
|
|
noop,
|
|
undefined,
|
|
noop,
|
|
noop,
|
|
);
|
|
Zone.current.cancelTask(t);
|
|
});
|
|
}),
|
|
);
|
|
|
|
it(
|
|
'can not reschedule a task to a zone which is the descendants of the original zone',
|
|
testFnWithLoggedTransitionTo(() => {
|
|
const originalZone = Zone.root.fork({
|
|
name: 'originalZone',
|
|
onScheduleTask: (delegate, currZone, targetZone, task) => {
|
|
callbackLogs.push({
|
|
pos: 'before',
|
|
method: 'onScheduleTask',
|
|
zone: currZone.name,
|
|
task: task.zone.name,
|
|
});
|
|
task.cancelScheduleRequest();
|
|
task = rescheduleZone.scheduleTask(task);
|
|
callbackLogs.push({
|
|
pos: 'after',
|
|
method: 'onScheduleTask',
|
|
zone: currZone.name,
|
|
task: task.zone.name,
|
|
});
|
|
return task;
|
|
},
|
|
});
|
|
const rescheduleZone = originalZone.fork({name: 'rescheduleZone'});
|
|
expect(() => {
|
|
originalZone.run(() => {
|
|
Zone.current.scheduleMacroTask('testRescheduleZoneTask', noop, undefined, noop, noop);
|
|
});
|
|
}).toThrowError(
|
|
'can not reschedule task to rescheduleZone which is descendants of the original zone originalZone',
|
|
);
|
|
}),
|
|
);
|
|
});
|
|
});
|