I have an Angular Application with Jasmine Testing Framework. The Application has a Service called AuthService
that handles decoding JSON Web Tokens:
auth.service.ts
import * as jwtDecode from 'jwt-decode';
...
@Injectable()
export class AuthService {
...
public getTokenPayload(token) {
return jwtDecode(token);
}
}
Now I would like to stub the module jwtDecode
and return a fake value for the purpose if testing:
auth.service.spec.ts
...
it('should get a token payload', () => {
const fakeToken = 'fake-token';
spyOn(service, 'getTokenPayload').and.callThrough();
const tokenPayload = service.getTokenPayload(fakeToken);
expect(tokenPayload).toBe('fake-token');
});
Because 'fake-token'
is not a valid JSON Web Token, my tests fail with the message:
InvalidTokenError: Invalid token specified: undefined is not an object (evaluating 'str.replace')
This is probably an error generated from the jwt-decode
module, which is expected. I do not want to have to include another module just to create valid JSON Web Tokens for testing purposes. Instead, I'd like to stub the functionality of jwtDecode()
.
What I've tried
1. Using spyOn
on jwtDecode
When I use spyOn
, I need an object with a method. So for the imported jwtDecode
this won't work, since it is a function itself:
spyOn(jwtDecode, '<method?>').and.callFake(() => 'fake-token');
2. Using callFake
on getTokenPayload
I've tried using:
spyOn(service, 'getTokenPayload').and.callFake(() => 'fake-token');
...and that prevents any errors from happening. However, my code coverage report now shows that the function getTokenPayload
is not covered. Moreover, I have other function in the application that use external NPM Modules and I don't want to ignore code coverage since they might have other implementations inside the method that should be tested.
3. Using createSpy
on jwtDecode
I tried overriding the imported jwtDecode
and create a spy:
const jwtDecode = jasmine.createSpy('jwtDecode').and.returnValue('fake-token');
This gives me the same error as above, indicating that jwtDecode
is not overridden inside my actual AuthService
Service.
4. Using the window
as the Object
From this question I read that global modules might be attached to the window
Object. Hence, I tried doing the same thing for jwt-decode
:
inside the test...
console.log(window.jwtDecode); // undefined
console.log(window.jwt_decode); // undefined
Unfortunately, both values are undefined
on the window
Object.
Question
I guess in general the question becomes:
How to stub imported NPM modules? Especially, how to stub them if they are not an object, but a function (without a method to use in Jasmine spyOn
)?