18

I m new to angular 4 and trying to test one of the angular 4 feature router.paramMap from unit tests, Reading route params in fallowing way and working as expected in my application.

constructor(private router:Router, private actRoute:ActivatedRoute) {
}

ngOnInit() {
    this.router.paramMap.subscribe(params => {
        params.get(id);
    })
......
}

But while running unit test, i m getting error which says cannot call subscribe method of undefined even though i m passing passing route param as below.

{
  provide: ActivatedRoute,
  useValue: { params: Observable.of({id: 1}) }
}

Please suggest

Tatarao voleti
  • 513
  • 3
  • 7
  • 23

5 Answers5

38

You need to provide paramMap instead of params. paramMap should be of type ParamMap from @angular/router, so normal object can be converted to ParamMap using the method convertToParamMap() from @angular/routing.

You can provide the mock ActivatedRoute like below:

import { convertToParamMap} from '@angular/router';
....
.....

{
      provide: ActivatedRoute,
      useValue: { paramMap: Observable.of(convertToParamMap({id: 1})) }
}
xxxxx
  • 1,918
  • 2
  • 17
  • 22
  • 1
    Didn't know that the convertToParamMap method existed. Saved me a bunch of time having to stub the class itself. Thanks! – yoonjesung May 25 '18 at 14:15
14

I am using a slightly different method of getting the params in my component:

this.id = this.route.snapshot.paramMap.get('id');

And this is what worked for me in the jasmine test:

{
      provide: ActivatedRoute,
      useValue: {
        snapshot: {
          paramMap: convertToParamMap({id: 1})
        }
      }
}
333Matt
  • 1,124
  • 2
  • 19
  • 29
3

For anyone needing tests on a component for when it does have a certain route param, and when it does not have it (as in /product and /product/:id ), the following works for me:

The component:

export class PageProductComponent implements OnInit {
    id: string | null = null;

    constructor(private readonly activatedRoute: ActivatedRoute) { }

    ngOnInit(): void {
        this.id = this.activatedRoute.snapshot.paramMap.get('id');
    }
}

The tests:

describe('PageProductComponent ', () => {
    let component: PageProductComponent ;
    let fixture: ComponentFixture<PageProductComponent >;
    let debugEl: DebugElement;

    const makeCompiledTestBed = (provider?: object): void => {
        const moduleDef: TestModuleMetadata = {
            imports: [
                RouterTestingModule,
            ],
            declarations: [ PageProductComponent ],
            providers: [ ]
        };
        if (moduleDef.providers && provider) {
            moduleDef.providers.push(provider);
        }
        TestBed.configureTestingModule(moduleDef).compileComponents();
    };

    const setupTestVars = (): void => {
        fixture = TestBed.createComponent(PageProductComponent );
        component = fixture.componentInstance;
        debugEl = fixture.debugElement;
        fixture.detectChanges();
    };

    describe('When an ID is NOT provided in the URL param', () => {
        beforeEach(async(makeCompiledTestBed));
        beforeEach(setupTestVars);

        it('should list all products', () => {
            //...
        });

    });

    describe('When an ID is provided in the URL param', () => {
        beforeEach(async(() => {
            makeCompiledTestBed({
                provide: ActivatedRoute,
                useValue: {
                    snapshot: {
                        paramMap: convertToParamMap({id: 1234})
                    }
                }
            });
        }));

        beforeEach(setupTestVars);

        it('should show a specific product', () => {
            //...
        });
    });
});
Chris Barr
  • 29,851
  • 23
  • 95
  • 135
0

we're currently using this:

    { provide: ActivatedRoute, useValue: { 'params': Observable.from([{ 'id': '1'}]) } },
Lotte Lemmens
  • 551
  • 5
  • 11
  • 1
    Thanks @Lotte Lemmens for your answer but i ran into one more issue - TypeError: params.get is not a function, any solution? – Tatarao voleti Oct 19 '17 at 06:45
  • Is there an additional value for you to use paramMap? this.router.params.subscribe(par => { const idFromParams = par.id }) This should be testable as mentioned above – Lotte Lemmens Oct 19 '17 at 07:47
0

Your code has a problem, in order to get a param from the URL, you have to write things in a different way.

constructor(private router:Router, private actRoute:ActivatedRoute) {
}

ngOnInit() {
    this.router.paramMap
        .switchMap((params: ParamMap) => {
            params.get(id);
            ....
        })
        .subscribe((....) => {
            ....
        })
}