Skip to content

RouterTestingHarness should trigger change detection after any navigation #49398

Closed as not planned
@yjaaidi

Description

@yjaaidi

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()...

afterNextNavigation(TestBed.inject(Router), resolveFn);
await router.navigateByUrl(url);
await redirectTrackingPromise;
this.fixture.detectChanges();

... 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());
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: routerarea: testingIssues related to Angular testing features, such as TestBedarea: zonesIssues related to zone.jsfeatureIssue that requests a new featurefeature: insufficient votesLabel to add when the not a sufficient number of votes or comments from unique authors

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions