mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
ci: fix flakey defer test (#60461)
This uses a fake timer scheduler implementation to ensure timer tests do not cause flakiness, similar to the incremental hydration tests. PR Close #60461
This commit is contained in:
committed by
Pawel Kozlowski
parent
7e65b9f6c0
commit
c7cacbf523
@@ -48,6 +48,7 @@ import {getInjectorResolutionPath} from '@angular/core/src/render3/util/injector
|
||||
import {ActivatedRoute, provideRouter, Router, RouterOutlet} from '@angular/router';
|
||||
import {ChainedInjector} from '@angular/core/src/render3/chained_injector';
|
||||
import {global} from '../../src/util/global';
|
||||
import {TimerScheduler} from '@angular/core/src/defer/timer_scheduler';
|
||||
|
||||
/**
|
||||
* Clears all associated directive defs from a given component class.
|
||||
@@ -94,15 +95,6 @@ function allPendingDynamicImports() {
|
||||
return dynamicImportOf(null, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke a callback function after a specified amount of time (in ms).
|
||||
*/
|
||||
function timer(delay: number): Promise<void> {
|
||||
return new Promise<void>((resolve) => {
|
||||
setTimeout(() => resolve(), delay);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to verify behavior of defer blocks by providing a set of
|
||||
* [time, expected output] pairs. Also allows to provide a function
|
||||
@@ -129,6 +121,22 @@ async function verifyTimeline(
|
||||
}
|
||||
}
|
||||
|
||||
class FakeTimerScheduler {
|
||||
cbs: VoidFunction[] = [];
|
||||
add(delay: number, callback: VoidFunction) {
|
||||
this.cbs.push(callback);
|
||||
}
|
||||
remove(callback: VoidFunction) {
|
||||
/* noop */
|
||||
}
|
||||
|
||||
invoke() {
|
||||
for (const cb of this.cbs) {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a template, creates a component fixture and returns
|
||||
* a set of helper functions to trigger rendering of prefetching
|
||||
@@ -3161,9 +3169,14 @@ describe('@defer', () => {
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{provide: ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR, useValue: deferDepsInterceptor}],
|
||||
providers: [
|
||||
{provide: ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR, useValue: deferDepsInterceptor},
|
||||
{provide: TimerScheduler, useClass: FakeTimerScheduler},
|
||||
],
|
||||
});
|
||||
|
||||
const fakeScheduler = TestBed.inject(TimerScheduler) as unknown as FakeTimerScheduler;
|
||||
|
||||
clearDirectiveDefs(RootCmp);
|
||||
|
||||
const fixture = TestBed.createComponent(RootCmp);
|
||||
@@ -3176,7 +3189,7 @@ describe('@defer', () => {
|
||||
// Make sure loading function is not yet invoked.
|
||||
expect(loadingFnInvokedTimes).toBe(0);
|
||||
|
||||
await timer(1000);
|
||||
fakeScheduler.invoke();
|
||||
await allPendingDynamicImports(); // fetching dependencies of the defer block
|
||||
fixture.detectChanges();
|
||||
|
||||
@@ -3218,24 +3231,26 @@ describe('@defer', () => {
|
||||
})
|
||||
class RootCmp {}
|
||||
|
||||
TestBed.configureTestingModule({});
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{provide: TimerScheduler, useClass: FakeTimerScheduler}],
|
||||
});
|
||||
const fakeScheduler = TestBed.inject(TimerScheduler) as unknown as FakeTimerScheduler;
|
||||
|
||||
clearDirectiveDefs(RootCmp);
|
||||
|
||||
const fixture = TestBed.createComponent(RootCmp);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.outerHTML).toContain('placeholder[top]');
|
||||
|
||||
await timer(110);
|
||||
fixture.detectChanges();
|
||||
fakeScheduler.invoke();
|
||||
await allPendingDynamicImports(); // fetching dependencies of the defer block
|
||||
|
||||
// Verify primary blocks content after triggering top-level @defer.
|
||||
expect(fixture.nativeElement.outerHTML).toContain('primary[top]');
|
||||
expect(fixture.nativeElement.outerHTML).toContain('placeholder[nested]');
|
||||
|
||||
await timer(110);
|
||||
fixture.detectChanges();
|
||||
fakeScheduler.invoke();
|
||||
await allPendingDynamicImports(); // fetching dependencies of the defer block
|
||||
|
||||
// Verify that nested @defer block was triggered as well.
|
||||
expect(fixture.nativeElement.outerHTML).toContain('primary[top]');
|
||||
@@ -3282,9 +3297,14 @@ describe('@defer', () => {
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{provide: ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR, useValue: deferDepsInterceptor}],
|
||||
providers: [
|
||||
{provide: ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR, useValue: deferDepsInterceptor},
|
||||
{provide: TimerScheduler, useClass: FakeTimerScheduler},
|
||||
],
|
||||
});
|
||||
|
||||
const fakeScheduler = TestBed.inject(TimerScheduler) as unknown as FakeTimerScheduler;
|
||||
|
||||
clearDirectiveDefs(RootCmp);
|
||||
|
||||
const fixture = TestBed.createComponent(RootCmp);
|
||||
@@ -3297,7 +3317,7 @@ describe('@defer', () => {
|
||||
// Make sure loading function is not yet invoked.
|
||||
expect(loadingFnInvokedTimes).toBe(0);
|
||||
|
||||
await timer(200);
|
||||
fakeScheduler.invoke();
|
||||
await allPendingDynamicImports(); // fetching dependencies of the defer block
|
||||
fixture.detectChanges();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user