Cookies concent notice

This site uses cookies from Google to deliver its services and to analyze traffic.
Learn more
Skip to main content
This site is no longer updated.Head to Angular.devHome
/

This is the archived documentation for Angular v17. Please visit angular.dev to see this page for the current version of Angular.

RouterTestingHarness

A testing harness for the Router to reduce the boilerplate needed to test routes and routed components.

      
      class RouterTestingHarness {
  static create(initialUrl?: string): Promise<RouterTestingHarness>
  fixture: ComponentFixture<unknown>
  routeDebugElement: DebugElement | null
  routeNativeElement: HTMLElement | null
detectChanges(): void
navigateByUrl<T>(url: string, requiredRoutedComponentType?: Type<T>): Promise<T | null>
navigateByUrl(url: string): Promise<null | {}>
navigateByUrl<T>(url: string, requiredRoutedComponentType: Type<T>): Promise<T> }

Static methods

Creates a RouterTestingHarness instance.

      
      static create(initialUrl?: string): Promise<RouterTestingHarness>
    
Parameters
initialUrl string

The target of navigation to trigger before returning the harness.

Optional. Default is undefined.

Returns

Promise<RouterTestingHarness>

The RouterTestingHarness also creates its own root component with a RouterOutlet for the purposes of rendering route components.

Throws an error if an instance has already been created. Use of this harness also requires destroyAfterEach: true in the ModuleTeardownOptions

Properties

Property Description
fixture: ComponentFixture<unknown> Read-Only

Fixture of the root component of the RouterTestingHarness

routeDebugElement: DebugElement | null Read-Only

The DebugElement of the RouterOutlet component. null if the outlet is not activated.

routeNativeElement: HTMLElement | null Read-Only

The native element of the RouterOutlet component. null if the outlet is not activated.

Methods

Instructs the root fixture to run change detection.

      
      detectChanges(): void
    
Parameters

There are no parameters.

Returns

void

Triggers a Router navigation and waits for it to complete.

      
      navigateByUrl(url: string): Promise<null | {}>
    
Parameters
url string

The target of the navigation. Passed to Router.navigateByUrl.

Returns

Promise<null | {}>: The activated component instance of the RouterOutlet after navigation completes (null if the outlet does not get activated).

Triggers a router navigation and waits for it to complete.

      
      navigateByUrl<T>(url: string, requiredRoutedComponentType: Type<T>): Promise<T>
    
Parameters
url string

The target of the navigation. Passed to Router.navigateByUrl.

requiredRoutedComponentType Type<T>

After navigation completes, the required type for the activated component of the RouterOutlet. If the outlet is not activated or a different component is activated, this function will throw an error.

Returns

Promise<T>: The activated component instance of the RouterOutlet after navigation completes.

The root component with a RouterOutlet created for the harness is used to render Route components.

      
      it('navigates to routed component', async () => {
  @Component({standalone: true, template: 'hello {{name}}'})
  class TestCmp {
    name = 'world';
  }

  TestBed.configureTestingModule({
    providers: [provideRouter([{path: '', component: TestCmp}])],
  });

  const harness = await RouterTestingHarness.create();
  const activatedComponent = await harness.navigateByUrl('/', TestCmp);
  expect(activatedComponent).toBeInstanceOf(TestCmp);
  expect(harness.routeNativeElement?.innerHTML).toContain('hello world');
});
    

The root component is reused within the same test in subsequent calls to navigateByUrl.

This function also makes it easier to test components that depend on ActivatedRoute data.

      
      @Component({
  standalone: true,
  imports: [AsyncPipe],
  template: `search: {{ (route.queryParams | async)?.query }}`,
})
class SearchCmp {
  constructor(
    readonly route: ActivatedRoute,
    readonly router: Router,
  ) {}

  async searchFor(thing: string) {
    await this.router.navigate([], {queryParams: {query: thing}});
  }
}

TestBed.configureTestingModule({
  providers: [provideRouter([{path: 'search', component: SearchCmp}])],
});

const harness = await RouterTestingHarness.create();
const activatedComponent = await harness.navigateByUrl('/search', SearchCmp);
await activatedComponent.searchFor('books');
harness.detectChanges();
expect(TestBed.inject(Router).url).toEqual('/search?query=books');
expect(harness.routeNativeElement?.innerHTML).toContain('books');
    

The root component with a RouterOutlet created for the harness is used to render Route components. The root component is reused within the same test in subsequent calls to navigateForTest.

When testing Routes with a guards that reject the navigation, the RouterOutlet might not be activated and the activatedComponent may be null.

      
      let isLoggedIn = false;
const isLoggedInGuard: CanActivateFn = () => {
  return isLoggedIn ? true : inject(Router).parseUrl('/login');
};

TestBed.configureTestingModule({
  providers: [
    provideRouter([
      {path: 'admin', canActivate: [isLoggedInGuard], component: AdminComponent},
      {path: 'login', component: LoginComponent},
    ]),
  ],
});

const harness = await RouterTestingHarness.create('/admin');
expect(TestBed.inject(Router).url).toEqual('/login');
isLoggedIn = true;
await harness.navigateByUrl('/admin');
expect(TestBed.inject(Router).url).toEqual('/admin');