How to unit test a Angular 4 component which uses router.paramMap
Asked Answered
M

6

19

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

Monosymmetric answered 19/10, 2017 at 5:11 Comment(0)
P
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})) }
}
Prudery answered 19/10, 2017 at 12:35 Comment(1)
Didn't know that the convertToParamMap method existed. Saved me a bunch of time having to stub the class itself. Thanks!Ranunculus
C
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})
        }
      }
}
Callboard answered 24/10, 2018 at 19:15 Comment(0)
H
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', () => {
            //...
        });
    });
});
Hamamelidaceous answered 29/3, 2019 at 19:46 Comment(0)
A
0

we're currently using this:

    { provide: ActivatedRoute, useValue: { 'params': Observable.from([{ 'id': '1'}]) } },
Annamarieannamese answered 19/10, 2017 at 5:44 Comment(2)
Thanks @Lotte Lemmens for your answer but i ran into one more issue - TypeError: params.get is not a function, any solution?Monosymmetric
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 aboveAnnamarieannamese
G
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((....) => {
            ....
        })
}
Garin answered 19/10, 2017 at 7:9 Comment(0)
A
0

im using this code :

this.activatedRoute.paramMap.subscribe((params: ParamMap) => {
            const id = params.get('id') || '000000000000';
        });
    

the way i found for test is this :

providers: [
                {
                    provide: ActivatedRoute,
                    useValue: {
                        paramMap: of({
                            get: (key: string) => 'mock-id',
                        }),
                    },
                },
            ],

the reason that your test didnt work well is this :

" The paramMap in ActivatedRoute is an Observable, so it needs to be mocked with an Observable. of() creates an Observable that emits the values you provide and then completes."

Abner answered 27/5 at 13:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.