Search code examples
angulartypescriptangular-unit-testangular-activatedroute

Error as Cannot read property 'subscribe' . for activated route in angular 7 while unit testing


I am getting error as Cannot read property 'subscribe' of undefined for activated route in angular 7 while unit testing .I have tried it in multiple way kindly help .

Observer.of is not working for me as i have rx.js version 6.3.3

here is my compnent file ChildComponent.ts

import { Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';

@Component({
    selector: 'app-child',
    template: `
        <h1>Enter your name</h1>
        <form
              [formGroup]="nameForm"
              (ngSubmit)="submitForm(nameForm)"
        >
            <input
                   type="text"
                   formControlName="firstName"
                   placeholder="first"
            >
            <input
                   type="text"
                   formControlName="lastName"
                   placeholder="last"
            >
            <button type="submit">launch to space</button>
        </form>
    `,
    styleUrls: ['./child.component.css']
})
export class ChildComponent {
    @Input() nameForm: FormGroup;
    private abc: number;
    constructor(
        public route: ActivatedRoute,
       ) {

        this.route.queryParams.subscribe(params => {
          this.abc = params['abc'];
        });

      }

    submitForm(form: FormGroup) {
        console.log(form);
        // really you would be using an event emitter
    }
}

here is my unit test file for child component unit test case


import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule, FormBuilder } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { ActivatedRoute, Router, Data, Params } from '@angular/router';
import { Observable, of } from 'rxjs';
import { BehaviorSubject } from 'rxjs';


export class MockActivatedRoute {
    private paramsSubject = new BehaviorSubject(this.testParams);
    private _testParams: {};

    params  = this.paramsSubject.asObservable();

    get testParams() {
        return this._testParams;
    }
    set testParams(newParams: any) {
        this._testParams = newParams;
        this.paramsSubject.next(newParams);
    }
}


import { ChildComponent } from './child.component';


describe('StaticComponent', () => {
    let component: ChildComponent;
    let fixture: ComponentFixture<ChildComponent>;

    class MockActivatedRoute1 extends ActivatedRoute {
    constructor() {
        super();
        this.params = of({id: "5"});
    }
  }

    // create new instance of FormBuilder
    const formBuilder: FormBuilder = new FormBuilder();
    let activeRoute: MockActivatedRoute;  


    beforeEach(() => {
        activeRoute = new MockActivatedRoute();
    });


    beforeEach(
        async(() => {
            TestBed.configureTestingModule({
                declarations: [
                    ChildComponent
                ],
                imports: [
                    CommonModule,
                    ReactiveFormsModule,
                    //AppModule
                ],
                providers: [
                    // reference the new instance of formBuilder from above
                    { provide: FormBuilder, useValue: formBuilder },
                    {
                        provide: ActivatedRoute,
                        useValue: {
                            params: {
                                subscribe: (fn: (value: Data) => void) => fn({
                                    abc: 1
                                })
                            }
                        }
                    }
                ]
            }).compileComponents();
        })
    );

    beforeEach(() => {
        fixture = TestBed.createComponent(ChildComponent);
        component = fixture.componentInstance;

        // pass in the form dynamically
        component.nameForm = formBuilder.group({
            firstName: null,
            lastName: null
        });
        fixture.detectChanges();
    });

    it('should be created', () => {
        expect(component).toBeTruthy();
    });
});

Solution

  • You were very close! To get your test to pass, I mocked the ActivatedRoute like this:

    const mockActivatedRoute = { 
      queryParams: of({ abc: 'testABC' }) 
    };
    

    And then used it in the providers array of the TestBed like this:

    providers: [
        ...
        { provide: ActivatedRoute, useValue: mockActivatedRoute }
    ]
    

    Here is a working Stackblitz. In the Stackblitz, I also commented out all the other code that is no longer needed.