Closed mimajka closed 1 year ago
I had the same issue and saw in the example test that they used RouterTestingModule instead of RouterModule. Adding a global replacement fixed it for me:
Shallow.alwaysReplaceModule(RouterModule, RouterTestingModule);
Thank you @mfrey-WELL for your comment. I know about using RouterTestingModule instead of RouterModule, however it dosn't work for all tests in my project. For example when I subscribe to Router events in a component and want to mock these events in a test, it's not doable with RouterTestingModule or at least I have no idea how I could do it 😉
Is your error gone with the line alwaysReplaceModule(RouterModule, RouterTestingModule)
@Mimajka ?
For testing Router events, you could inject a custom Mock - something like:
it('should do something on NavigationEnd event', async () => {
const mockEvent = new NavigationEnd(...);
const mockRouter = { events: of(mockEvent) };
const { inject } = await shallow.provide({ provide: Router, useValue: mockRouter }).render();
....
});
});
@getsaf Brandon, did you see this one? we're hitting up against it as we migrate to Angular 14. could you take a look? thx!
I've never tried to write any specs against the non-test RouterModule
. I would guess that things wouldn't go well w/out manually providing some suitable mocks for it (or using the RouterTestingModule
as @mfrey-WELL suggested).
You may want to try avoiding mocking the actual RouterModule
and RouterOutlet
with
shallow.dontMock(RouterModule, RouterOutlet)
If for some reason this doesn't work and you can't use Angular's RouterTestingModule
, @floisloading's solution sounds good too.
If neither of those solutions work, you may need to try a TestBed-only spec.
fast-follow:
I did just try modifying the routing tests in the shallow-render
repo and it worked:
describe('component with routing', () => {
let shallow: Shallow<GoHomeLinkComponent>;
beforeEach(() => {
shallow = new Shallow(GoHomeLinkComponent, GoHomeModule).dontMock(
RouterModule,
RouterOutlet,
);
});
it('uses the route', async () => {
const { fixture, find, inject } = await shallow.render();
const location = inject(Location);
find('a').triggerEventHandler('click', {});
await fixture.whenStable();
expect(location.path()).toMatch(/\/home$/);
});
});
For us it didn't work to provide a mock for Router
using shallow.provide({ provide: Router, useValue: mockRouter })
as suggested by @floisloading. Because when adding dontMock(RouterModule)
e.g. the RouterLinkWithHref
directive seemed to need some of the other methods on Router
(TypeError: Cannot read properties of undefined (reading 'subscribe') at new RouterLinkWithHref
). If we don't add dontMock(RouterModule)
we get errors like described above: MockOfRouterOutlet does not have a module def (ɵmod property)
. Similar problems for using replaceModule(RouterModule, RouterTestingModule)
.
But we could fix the problem by only mocking a single method on the Router
like this:
const rendering = await shallow
// [...] mocks etc. for router unrelated things
.dontMock(RouterModule, ActivatedRoute)
.provide({provide: ActivatedRoute, useValue: {
data: activatedRouteData.asObservable(),
queryParams: activatedRouteQueryParams.asObservable()
}})
.render();
router = rendering.inject(Router);
spyOn(router, "navigate").and.callFake((commands: any[], extras?: NavigationExtras) => {
activatedRouteQueryParams.next(extras?.queryParams || {});
return Promise.resolve(true);
});
This looks solved :-)
In the process of updating my project to angular 14, in which I am using Jest and Shallow-render for unit tests, I noticed a problem with mocking of RouterModule. Unit tests failed with the following error message.
Minimal reproduction of the problem
You can reproduce the issue by running
ng test
for the project in my repo where you find a simple Angular 14 project with Jest 28 (added with @angular-builders/jest) and Shallow-render 14.