1

Here is my component code that i want to test:

allpages: Array<Page> = [
  { name: 'Home', url: '/home' },
];

constructor(private router: Router) {
    this.$routerEvent = this.router.events.subscribe((event: Event) => {
      if (event instanceof NavigationEnd) {
        let route = event.url !== '/' ? event.url : event.urlAfterRedirects;
        this.currentPage = this.allpages.find(
          (page) => page.url === route
        );
      }
    });
  }

Here is my test:

beforeEach(async () => {
  TestBed.configureTestingModule({
    declarations: [NavigationBarComponent],
    imports: [MatIconModule, RouterTestingModule],
  }).compileComponents();

  fixture = TestBed.createComponent(NavigationBarComponent);
  component = fixture.componentInstance;
  fixture.detectChanges();
});

it('should set home page as current page', inject([Router], (router: Router) => {
  router.initialNavigation();
  expect(component.currentPage).toEqual({ name: 'Home', url: '/home' });
}));

Test fails because component.currentPage = undefined.

I have read that navigation is an async operation, how do i properly should implement the test, or maybe i went absolutely incorrect way?

Developer
  • 4,158
  • 5
  • 34
  • 66

1 Answers1

3

To test router events, we need to mock the router service object. In the test session configuration, we will replace events property of router as an Observable object. To have access to the events observable object, we create a separate variable of ReplaySubject<RouterEvent>.

 const eventSubject = new ReplaySubject<RouterEvent>(1);

Crate a router mock

const routerMock = {
     events: eventSubject.asObservable(),
 };

While using mock object do not use RouterTestingModule
Explanation:Angular 2 Final Release Router Unit Test

beforeEach(async () => {
  TestBed.configureTestingModule({
    declarations: [NavigationBarComponent],
    imports: [MatIconModule],
    providers: [
        {provide: Router, useValue: routerMock} <-- Override with mock object
    ]

  }).compileComponents();

  fixture = TestBed.createComponent(NavigationBarComponent);
  component = fixture.componentInstance;
  fixture.detectChanges();
});

it('should set home page as current page', () => {
   // simulate the navigation end events
    eventSubject.next(new NavigationEnd(1, '/home', '/urlAfterRedirect'));
    expect(app.currentPage).toEqual({ name: 'Home', url: '/home' });
});

Ref:Approach using Jasmine
More

Vikas
  • 11,859
  • 7
  • 45
  • 69
  • Thanks for your reply. I have added the code you provided and now all my tests fail with: "TypeError: Cannot read properties of undefined (reading 'root')". Seems like the mock config is a bit incorrect – Developer Nov 29 '22 at 08:05
  • I found what caused it. The google says that you cannot use the RouterTestingModule along with the routerMock. This will lead to my error. But without RouterTestingModule i get testing warnings that 'Can't bind to 'routerLink' since it isn't a known property of 'a'. How to bypass this? – Developer Nov 29 '22 at 10:35
  • `schemas: [NO_ERRORS_SCHEMA]` in ngModule schemas array – Vikas Nov 29 '22 at 10:47
  • `import { NO_ERRORS_SCHEMA } from '@angular/core';` – Vikas Nov 29 '22 at 10:47
  • `beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [AppComponent], providers: [ {provide: Router, useValue: routerMock} ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); });` – Vikas Nov 29 '22 at 10:48