jasmine angular 4 unit test router.url
Asked Answered
A

2

18

I am unit testing a function in angular 4 project using jasmine which a switch statement like mentioned below:

    switch(this.router.url) {

    case 'firstpath': {
               // some code
            }
        break;
    case 'secondpath': {
               // some more code
            }
       break;
    default:
        break;

    }

In my spec.ts file. I can't stub or change the value of router.url.I want my cases to execute but default is executing. I tried different ways to set or spyOn and return value, but everytime url is '/'. Every suggestion or solution will be welcomed.

Acoustic answered 15/11, 2018 at 7:14 Comment(0)
K
39

First you need to mock router in your testing module:

TestBed.configureTestingModule({
  ...
  providers: [
    {
       provide: Router,
       useValue: {
          url: '/path'
       } // you could use also jasmine.createSpyObj() for methods
    } 
  ]
});

You can also change the url in the test and run your tested method:

const router = TestBed.inject(Router);
// @ts-ignore: force this private property value for testing.
router.url = '/path/to/anything';
// now you can run your tested method:
component.testedFunction();

As you mention spyOn doesnt work because it works only for methods/functions. But url is a property.

Kevakevan answered 15/11, 2018 at 8:14 Comment(10)
@martin you are my savior! I tried using spyOnProperty(spyRouter, 'url', 'get').and.returnValue('test'); But it did not workout quiet so well.Shit
I'm getting an error "TypeError: Cannot set property url of [object Object] which has only a getter" when using router.url = '/path/to/anything'Upkeep
TestBed should return any type so you shouldn't get this error. Maybe you do const router: Router = TestBed.get(Router); instead?Kevakevan
If you're getting the error that is in Christoper Grigg's comment the router may not be mocked our properly. You can try the spyOnProperty and use it as spyOnProperty(router, 'url', 'get').and.returnValue('yourUrl')Galliard
can we do similar thing using RouterTestingModule ?Superfluous
@MartinNuc,really thanks for your answer.It also solved my router juni test problem.Kone
TestBed.get is deprecated by TestBed.Inject. Unfortunately, the URL becomes get only when switching to .Inject.Pimentel
@Pimentel You could probably always fall back to any: `(router as any).url = '/path/to/anything';Kevakevan
Updated the answer to reflect on read-only property when using TestBed.inject on newer Angular versions.Kevakevan
doesn't work: TypeError: Cannot set property url of [object Object] which has only a getterSexism
H
8

For people using Angular 9 and above property url is now a readonly property and so spyOnProperty will not work. It's also confusing as you won't get an error, but you won't see any "spying" either.

To solve this, use the following code:

const mockUrlTree = routerSpy.parseUrl('/mynewpath/myattribute');
// @ts-ignore: force this private property value for testing.
routerSpy.currentUrlTree = mockUrlTree;

Thanks to Rob on this post here for the answer:

https://mcmap.net/q/669263/-angular-4-router-url-unit-testing

Hamhung answered 26/1, 2021 at 11:16 Comment(1)
Not possible anymore in Angular 17, currentUrlTree is readonly as well.Paulie

© 2022 - 2024 — McMap. All rights reserved.