Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock ActivatedRouteSnapshot when unit testing a Resolver

I want to write a unit test for my resolver, which needs to take ActivatedRouteSnapshot in its constructor like so:

export class MyResolver {
  constructor () {
    // ...
  }

  resolve (private route: ActivatedRouteSnapshot) {
    callFoo(route.params.val);
  }
};

But in my unit test, what's the best way to provide an activated route snapshot with mock data? When I try to create an object with just the properties I need, I get an error that it cannot be cast to ActivatedRouteSnapshot:

it('should call foo', inject([MyResolver], async (myResolver: MyResolver) => {
  const mockRoute = {
    params: {
      val: '1234'
    };
  };

  sinon.spy(callFoo);
  myResolver.resolve(mockRoute); // This is the line that errors
  expect(callFoo.calledWith('1234')).to.be.true;
}));

Error:

Type '{ params: { val: string; }; }' cannot be converted to type 'ActivatedRouteSnapshot'.

How can I provide a mock ActivatedRouteSnapshot to pass to my resolver?

like image 410
A. Duff Avatar asked Jan 22 '18 19:01

A. Duff


3 Answers

You have to provide the active route like this:

import {TestBed} from '@angular/core/testing';
import {SomeResolver} from './some.resolver';
import {ActivatedRoute, convertToParamMap} from '@angular/router';
import {of} from 'rxjs';

describe('SomeResolver', () => {
  let someResolver: SomeResolver;
  let route: ActivatedRoute;

  TestBed.configureTestingModule({
    providers: [
      {
        provide: ActivatedRoute,
        useValue: {snapshot: {paramMap: convertToParamMap({id: 'one-id'})}}
      },
      SomeResolver
    ]
  });

  beforeEach(() => {
    heroResolver = TestBed.get(HeroResolver);
    route = TestBed.get(ActivatedRoute);
  });

  it('should resolve', (() => {
    someResolver.resolve(route.snapshot);
  }));
});

Check a more complex example here.

like image 143
ismaestro Avatar answered Oct 19 '22 02:10

ismaestro


I'm not sure if this is the prettiest solution, but you can mock the route like this:

let route = createSpyObj('Route', ['']);
route.params = {
  val: '1234'
}
like image 40
Janneman96 Avatar answered Oct 19 '22 01:10

Janneman96


If the purpose is just to pass the mock to the resolver, it's not necessary to use createSpyObj, as suggested in other answers. Also, it would be better to add type safety to the solution:

const mock = <T, P extends keyof T>(obj: Pick<T, P>): T => obj as T;

it('should call foo', () => {
    const route = mock<ActivatedRouteSnapshot, 'params'>({
        params: {
            val: '1234'
        }
    });

    const resolver = createTheResolver();
    const resolverParams = resolver.resolve(route);
    ...
});
like image 2
Valeriy Katkov Avatar answered Oct 19 '22 01:10

Valeriy Katkov