3
votes

My question is similar to this question. I'm trying to write a test that checks the existence of a route in Angular. The main difference to the linked question, as that I'm using lazy loading modules instead of components.

I have a file app.routes.ts that contains the routes:

import { Routes } from '@angular/router';

export const routes: Routes = [
    {
        path: '',
        loadChildren: () => import('./main/main.module').then(m => m.MainModule)
    }
];

In the test file app.routes.spec.ts, I expect that this route exists:

import { routes } from './app.routes';

describe('app.routes', () => {
    it('should contain a route for /', () => {
        expect(routes).toContain({
            path: '',
            loadChildren: () => import('./main/main.module').then(m => m.MainModule)
        });
    });
});

When I run this, the test is not passing.

Expected [ Object({ path: '', loadChildren: Function }) ] to contain Object({ path: '', loadChildren: Function }). Error: Expected [ Object({ path: '', loadChildren: Function }) ] to contain Object({ path: '', loadChildren: Function }). at at UserContext. (http://localhost:9876/_karma_webpack_/src/app/app.routes.spec.ts:5:24) at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:365:1) at ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-testing.js:305:1)

How can I fix this unit test, and make sure that the existence of lazy loaded routes can be tested? Thank you!

DISCLAIMER: I know that some people don't think this should be part of unit testing, and that routing should be tested in e2e testing. Personally I like the idea to check if all my routes exist, and there are no typos. The idea that if somebody would comment out a route for whatever reason and forgets to undo it, and automated testing catches this, makes me feel a bit safer.

2
did you check solution below?Aakash Garg

2 Answers

1
votes

I found a generic solution for my problem to test lazy loaded routes, based on the answer of Aakash Garg. I'm sharing my solution, in case it might help somebody with the same problem. This solution works for me, but I'm not claiming that this is the perfect way to do this.

Basically, I added a custom matcher for jasmine to test equality of routes.

The source code file equal-route-matcher.ts:

import MatchersUtil = jasmine.MatchersUtil;
import CustomMatcherFactories = jasmine.CustomMatcherFactories;
import CustomEqualityTester = jasmine.CustomEqualityTester;
import CustomMatcher = jasmine.CustomMatcher;
import CustomMatcherResult = jasmine.CustomMatcherResult;

function replacer(key: any, value: any) {
    if (typeof value === 'function') {
        value = value.toString();
    }
    return value;
  }

export const EqualRouteMatcher: CustomMatcherFactories = {
    toEqualRoute: (util: MatchersUtil, customEqualityTester: CustomEqualityTester[]): CustomMatcher => {
        return {
            compare: (actual: any, expected: any): CustomMatcherResult => {
                let actualstring: string, expectedstring: string;
                actualstring = JSON.stringify(actual, replacer).replace(/(\\t|\\n)/g,'');
                expectedstring = JSON.stringify(expected, replacer).replace(/(\\t|\\n)/g,'');
                if (actualstring === expectedstring) {
                    return {
                        pass: true,
                        message: 'Routes are equal'
                    };
                } else {
                    return {
                        pass: false,
                        message: 'Expected route ' + actualstring + ' to equal route ' + expectedstring
                    };
                }
            }
        };
    }
};

The type definition file equal-route-matcher-type.d.ts:

declare namespace jasmine {
    interface Matchers<T> {
        toEqualRoute(expected: any, expectationFailOutput?: any): boolean;
    }
}

Finally, you can import the custom matcher in your unit test file, and use it like this:

import { routes } from './app.routes';
import { EqualRouteMatcher } from './equal-route-matcher.ts';

describe('app.routes', () => {
    beforeEach(() => {
        jasmine.addMatchers(EqualRouteMatcher);
    });

    it('should contain a route for /', () => {
      expect(routes.length).toEqual(1);
      expect(routes[0]).toEqualRoute({path: '',loadChildren: () => import('./main/main.module').then(m => m.MainModule)});
    });
});
0
votes

Check It Like :-

    expect(routes.find((route) => JSON.stringify(route,function(key, value) {
  if (typeof value === "function") {
    return "/Function(" + value.toString() + ")/";
  }
  return value;
}) === JSON.stringify({"path":"","loadChildren":"/Function(() => import('./main/main.module').then(m => m.MainModule))/"}))).toBeTruthy();

Screenshot of it working :-

enter image description here