Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jasmine angular 4 unit test router.url

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.

like image 714
Punj324 Avatar asked Nov 15 '18 07:11

Punj324


People also ask

How can you set up a router for testing Angular?

We can test routing in Angular by using RouterTestingModule instead of RouterModule to provide our routes. This uses a spy implementation of Location which doesn't trigger a request for a new URL but does let us know the target URL which we can use in our test specs.

What is RouterTestingModule?

RouterTestingModulelink Sets up the router to be used for testing. class RouterTestingModule { static withRoutes(routes: Routes, config?: ExtraOptions): ModuleWithProviders<RouterTestingModule> }

What does detectChanges do in Angular Jasmine tests?

detectChanges(). Delayed change detection is intentional and useful. It gives the tester an opportunity to inspect and change the state of the component before Angular initiates data binding and calls lifecycle hooks.


2 Answers

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.

like image 197
Martin Nuc Avatar answered Oct 05 '22 11:10

Martin Nuc


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://stackoverflow.com/a/63623284/1774291

like image 43
PeterS Avatar answered Oct 05 '22 13:10

PeterS