Reputation: 4309
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?
Upvotes: 24
Views: 24866
Reputation: 8267
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);
}));
});
Upvotes: 16
Reputation: 21
import createSpyObj = jasmine.createSpyObj;
let route = createSpyObj('Route', ['']);
route.params = {
nameOfParam: 'test'
}
Upvotes: 2
Reputation: 41
Note you can also simply cast your object as an ActivatedRouteSnapshot if you like:
const mockRoute = {paramMap: convertToParamMap({'id': '123'})} as
ActivatedRouteSnapshot;
resolver.resolve(mockRoute);
Upvotes: 2
Reputation: 123
for my purposes, this was the easiest thing to do (which also allowed me to write to the 'parent' property which is normally read-only:
const route = Object.assign({}, ActivatedRouteSnapshot.prototype, {
params: {
myParam: 'some_value'
},
parent: {
params: {
myParentParam: 'some_other_value'
}
}
});
then you just call your resolver with 'route' like so:
it('should do something with my activated route params', (done) => {
const route = Object.assign({}, ActivatedRouteSnapshot.prototype, {
params: {
myParam: 'some_value'
},
parent: {
params: {
myParentParam: 'some_other_value'
}
}
});
service.resolve(route).subscribe(res => {
expect( ... )
done();
});
});
Upvotes: 1
Reputation: 40732
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);
...
});
Upvotes: 3
Reputation: 505
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'
}
Upvotes: 8