How to mock ActivatedRoute in Angular tests
When we are talking about mocking ActivatedRoute
,
we mean a solution to provide stub params in the snapshot of ActivatedRoute
which are used in the component under test.
activatedRoute.snapshot
Let's assume we have the next TargetComponent
component,
which relies on the paramId
of the ActivatedRoute
snapshot.
@Component({
selector: 'target',
template: '{{ param }}',
})
class TargetComponent {
public param: string | null = null;
public constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.param = this.route.snapshot.paramMap.get('paramId');
}
}
In our test as a mock ActivatedRoute
, we would like to provide paramValue
as paramId
.
To do so, we can use MockInstance
.
The first step is to call a spy when someone wants to access snapshot
,
and the second step is to return stub params:
it('works with snapshot from ActivatedRoute', () => {
// for jasmine
// mocking the getter of ActivatedRoute.snapshot
MockInstance(ActivatedRoute, 'snapshot', jasmine.createSpy(), 'get')
// using jasmine.spy.and.returnValue to customize what the getter returns.
.and.returnValue({
paramMap: new Map([['paramId', 'paramValue']]),
});
// for jest
// mocking the getter of ActivatedRoute.snapshot
MockInstance(ActivatedRoute, 'snapshot', jest.fn(), 'get')
// using jest.fn.mockReturnValue to customize what the getter returns.
.mockReturnValue({
paramMap: new Map([['paramId', 'paramValue']]),
});
// the rest of the test
// ...
});
Profit. Now, when someone accesses snapshot
of ActivatedRoute
, the spy will be called,
which returns a stub paramMap
with the params we wanted.
activatedRoute.params
If a component relies on ActivatedRoute.params
and they should be mocked,
then the approach is very similar to be above one:
it('works with params from ActivatedRoute', () => {
// for jasmine
// mocking the getter of ActivatedRoute.snapshot
MockInstance(ActivatedRoute, 'params', jasmine.createSpy(), 'get')
// using jasmine.spy.and.returnValue to customize what the getter returns.
.and.returnValue(of({paramId: 'paramValue'});
// for jest
// mocking the getter of ActivatedRoute.snapshot
MockInstance(ActivatedRoute, 'params', jest.fn(), 'get')
// using jest.fn.mockReturnValue to customize what the getter returns.
.mockReturnValue(of({paramId: 'paramValue'});
// the rest of the test
// ...
});
RouterModule.forRoot
In situation when you want to mock a module which imports RouterModule.forRoot
.
In this case, only the component under test should be kept:
// TargetModule and RouterModule.forRoot will be mocks
beforeEach(() => MockBuilder(
TargetComponent, // keep
TargetModule, // mock
));
RouterModule.forChild
In situation when you want to mock a module which imports RouterModule.forChild
,
you have to add RouterModule.forRoot
to mocks too.
Otherwise, ActivatedRoute
and other dependencies won't be available:
// TargetModule, RouterModule.forChild and RouterModule.forRoot will be mocks
beforeEach(() => MockBuilder(
TargetComponent, // keep
[TargetModule, RouterModule.forRoot([])], // mock, add here RouterModule.forRoot([])
));
Live example how to mock ActivatedRoute
import { Component, NgModule, OnInit } from '@angular/core';
import { ActivatedRoute, RouterModule } from '@angular/router';
import { MockBuilder, MockInstance, MockRender } from 'ng-mocks';
@Component({
selector: 'route',
template: '{{ param }}',
})
class RouteComponent implements OnInit {
public param: string | null = null;
public constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.param = this.route.snapshot.paramMap.get('paramId');
}
}
@NgModule({
declarations: [RouteComponent],
imports: [
RouterModule.forRoot([
{
path: 'test/:paramId',
component: RouteComponent,
},
]),
],
})
class TargetModule {}
describe('MockActivatedRoute', () => {
// Resets customizations after each test, in our case of `ActivatedRoute`.
MockInstance.scope();
// Keeping RouteComponent as it is and mocking all declarations in TargetModule.
beforeEach(() => MockBuilder(RouteComponent, TargetModule));
it('uses paramId from ActivatedRoute', () => {
// Let's set the params of the snapshot.
MockInstance(
ActivatedRoute,
'snapshot',
jasmine.createSpy(),
'get',
).and.returnValue({
paramMap: new Map([['paramId', 'paramValue']]),
});
// // in case of jest.
// MockInstance(
// ActivatedRoute,
// 'snapshot',
// jest.fn(),
// 'get',
// ).mockReturnValue({
// paramMap: new Map([['paramId', 'paramValue']]),
// });
// Rendering RouteComponent.
const fixture = MockRender(RouteComponent);
// Asserting it got the right paramId.
expect(fixture.point.componentInstance.param).toEqual(
'paramValue',
);
});
});