Reputation: 489
I currently have an object that is used to interact with my API api.js
:
export var Auth = (function () {
var Login = async function(username, password) {
//Async login code for interacting with the API
};
return {
Login: Login
}
});
And this object is imported inside another file, login.js
:
import * as API from './api';
export var LoginRequestHandler = function() {
//processess user input, then calls:
try {
await API.Auth().Login(username, password);
} catch(e) {
throw new Error(e);
}
This is my jest test:
import * as API from '../api';
import * as User from '../user';
jest.mock('../api');
const spy = jest.spyOn(API.Auth(), 'Login');
User.LoginRequestHandler().then(() => {
expect(spy).toHaveBeenLastCalledWith('theUsername', 'thePassword');
}).catch(error => console.log(error));
This is my mock file, __mock__/api.js
:
export var Auth = (function () {
var Login = async function(username, password) {
return Promise.resolve(true);
};
return {
Login: Login
}
});
I retrieve theUsername
and thePassword
through document.getElementId()
in the LoginRequestHandler
and create my own DOM for the test above.
Adding console.log(username)
in the LoginRequestHandler
reveals that it is being called and is able to get the right values. Furthermore, adding a console.log(username)
in API.Auth().Login
also reveals that it is getting the right values as well. However, when I look at my test logs, I see: Number of calls: 0
for the mock function and the test results in errors.
I assume that I am trying to spy on the wrong function, and is there anyway that I can fix this?
Upvotes: 1
Views: 2879
Reputation: 102597
Every time you call API.Auth()
, it will return a new object which has a Login
method. So, the object created in LoginRequestHandler
function and created by jest.spyOn(API.Auth(), 'Login')
statement in your test case are different. The spy is only added to the later one. The Login
method in LoginRequestHandler
function is not spied.
So, here I am going to use jest.mock()
to mock the api.js
module without putting mocked object to __mocks__
directory. E.g.
api.js
:
export var Auth = function () {
var Login = async function (username, password) {};
return {
Login: Login,
};
};
user.js
:
import * as API from './api';
export var LoginRequestHandler = async function () {
const username = 'theUsername';
const password = 'thePassword';
try {
await API.Auth().Login(username, password);
} catch (e) {
throw new Error(e);
}
};
user.test.js
:
import * as API from './api';
import * as User from './user';
jest.mock('./api', () => {
const auth = { Login: jest.fn() };
return {
Auth: jest.fn(() => auth),
};
});
describe('61643983', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('should login', () => {
expect.assertions(2);
return User.LoginRequestHandler().then(() => {
expect(API.Auth).toBeCalledTimes(1);
expect(API.Auth().Login).toHaveBeenLastCalledWith('theUsername', 'thePassword');
});
});
it('should throw error', () => {
expect.assertions(4);
const mError = new Error('user not found');
API.Auth().Login.mockRejectedValueOnce(mError);
return User.LoginRequestHandler().catch((e) => {
expect(API.Auth).toBeCalled();
expect(API.Auth().Login).toHaveBeenLastCalledWith('theUsername', 'thePassword');
expect(e).toBeInstanceOf(Error);
expect(e.message).toMatch(/user not found/);
});
});
});
unit test results with 100% coverage:
PASS stackoverflow/61643983/user.test.js (11.507s)
61643983
✓ should login (5ms)
✓ should throw error (3ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
user.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 13.023s
source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/61643983
Upvotes: 1