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)?