angularunit-testingangular-routerangular-router-events

Write unit test for "ActivationEnd" event from router.events.subscribe in angular


I need help in order to write unit tests for router.events.subscribe. I used ActivationEnd to use snapshot object which has properties which I need for my application. No other events from router provide these so I have to stick to this ActivationEnd. But I did not get anything so far as to how to mock this snapshot object.

Below is my code snippet.

ngOnInit() {
    this.router.events.subscribe(e => {
      if (e instanceof ActivationEnd) {
        this.section = e.snapshot.data.title;
        this.dynamicSubNavLabel = e.snapshot.routeConfig?.data?.label;
      }
    });
  }

Can you please help me what could I do to achieve unit tests for this or any alternatives ?

Regards, Alpesh


Solution

  • Let say, you have a component like this:

    import { Component, OnInit } from '@angular/core';
    import { ActivationEnd, Router } from '@angular/router';
    
    @Component({
      selector: 'app-test-router',
      templateUrl: './test-router.component.html',
      styleUrls: ['./test-router.component.css']
    })
    export class TestRouterComponent implements OnInit {
      section = '';
      dynamicSubNavLabel = '';
      constructor(private router: Router) { }
    
      ngOnInit() {
        this.router.events.subscribe(e => {
          if (e instanceof ActivationEnd) {
            this.section = e.snapshot.data.title;
            this.dynamicSubNavLabel = e.snapshot.routeConfig?.data?.label;
          }
        });
      }
    
    }
    

    Because Router.events is a Subject<Event> already. We can do this:

    import { ComponentFixture, TestBed } from '@angular/core/testing';
    import { ActivatedRouteSnapshot, ActivationEnd, Event, Router } from '@angular/router';
    import { RouterTestingModule } from '@angular/router/testing';
    import { Subject } from 'rxjs';
    
    import { TestRouterComponent } from './test-router.component';
    
    describe('TestRouterComponent', () => {
      let component: TestRouterComponent;
      let fixture: ComponentFixture<TestRouterComponent>;
      let router: Router;
    
      beforeEach(async () => {
        await TestBed.configureTestingModule({
          imports: [RouterTestingModule],
          declarations: [ TestRouterComponent ]
        })
        .compileComponents();
      });
    
      beforeEach(() => {
        fixture = TestBed.createComponent(TestRouterComponent);
        component = fixture.componentInstance;
        router = TestBed.inject(Router);
        fixture.detectChanges();
      });
    
      it('should create', () => {
        expect(component).toBeTruthy();
      });
    
      it('should update data from router', () => {
        const events$ = router.events as Subject<Event>;
        const mockSnapshot = {
          data: {
            title: 'some heading'
          },
          routeConfig: {
            data: {
              label: 'some text'
            }
          }
        } as unknown as ActivatedRouteSnapshot;
        events$.next(new ActivationEnd(mockSnapshot));
        expect(component.section).toBeTruthy();
        expect(component.dynamicSubNavLabel).toBeTruthy();
      })
    });
    

    Source code from Angular: https://github.com/angular/angular/blob/75a3c778b1f7be913f0287423d40fade68ee9adc/packages/router/src/router.ts#L461