Description
Which @angular/* package(s) are relevant/related to the feature request?
router
Description
TL;DR: When using RouterTestingHarness
, navigations triggered using RouterTestingHarness
are triggering change detection but subsequent navigations (i.e. triggered through routerLink clicks or Router.navigate()
etc...) are not. Developers must then explicitly trigger change detection which can be tricky (e.g. some guard might add some delay etc...). This makes tests more fragile and complex and kind of defeats the purpose of RouterTestingHarness
.
More precisely, while RouterTestingHarness
triggers change detection when explicitly calling navigateByUrl()
or implicitly by passing an initial URL to create()
...
angular/packages/router/testing/src/router_testing_harness.ts
Lines 135 to 138 in dedac8d
... it doesn't trigger it when navigation is triggered otherwise.
Thanks to @tomalaforge for raising questions on testing + routing in Cypress.
Thanks to @atscott for the quick feedback and help to pinpoint this.
Proposed solution
RouterTestingHarness
should trigger change detection after each navigation.
This can be done by subscribing to Router.events
and triggering change detection on each NavigationEnd
.
@Injectable({providedIn: 'root'})
export class RootFixtureService {
// ...
private subscription?: Subscription;
createHarness(): RouterTestingHarness {
if (this.harness) {
throw new Error('Only one harness should be created per test.');
}
this.harness = new RouterTestingHarness(this.getRootFixture());
this.subscription = TestBed.inject(Router).events
.pipe(filter(e => e instanceof NavigationEnd))
.subscribe(() => this.harness.detectChanges());
return this.harness;
}
ngOnDestroy() {
this.subscription?.unsubscribe();
}
// ...
}
I'd be happy to submit a PR.
Alternatives considered
Meanwhile, here is a temporary workaround one can use.
async function createHarness(initialUrl: string) {
const harness = await RouterTestingHarness.create(initialUrl);
autoDetectChanges(harness);
return harness;
}
function autoDetectChanges(harness: RouterTestingHarness) {
TestBed.inject(Router)
.events.pipe(filter((e) => e instanceof NavigationEnd))
.subscribe(() => harness.detectChanges());
}