I'm pretty sure this has something to do with the call being async but that's about as far as my brain can get.
The calling function is:
const { messageNodeResponse } = require('../../../app/lib/message-node-response');
jest.mock('../../../app/lib/am-api.js');
describe('message node response', () => {
it('should check for message node prompt.', async () => {
const req = {
session:
{
payload: {
callbacks: [{
type: 'NameCallback',
output: [{ name: 'prompt', value: 'resendExpiredOTP' }],
input: [{ name: 'IDToken1', value: '' }],
},
{
type: 'NameCallback',
output: [{ name: 'prompt', value: 0 }],
input: [{ name: 'IDToken2', value: '' }],
}],
},
},
};
const res = await messageNodeResponse(req, 'registration');
expect(res.statusCode).toEqual(200);
});
});
The function being tested (in message-node-response.js):
const messageNodeResponse = (req, api) => {
const requestBody = req.session.payload;
requestBody.callbacks[1].input[0].value = 0;
const apiCall = assignApi(api);
return apiCall(req, requestBody)
.then((result) => {
logger.debug(result.data);
req.session.payload = result.data;
}).catch((err) => {
throw err;
});
};
module.exports = { messageNodeResponse };
Running the unit test gives me the following error: "TypeError: Cannot read property 'then' of undefined" referring to the line "return apiCall(req, requestBody)".
As requested, am-api.js:
const axios = require('axios');
const { v1: uuid } = require('uuid');
const post = async (url, data, req) => axios.post(
url,
data,
{
headers: {
'Content-Type': 'application/json',
'Accept-API-Version': 'protocol=1.0,resource=2.1',
language: req.cookies.lng ? req.cookies.lng : 'en',
...(req.session.clientId) && { 'client-id': req.session.clientId },
...(req.session.id) && { 'session-id': req.session.id },
...((req.headers['correlation-id']) && { 'correlation-id': req.headers['correlation-id'] }) || { 'correlation-id': uuid() },
...(req.headers['user-agent']) && { 'User-Agent': req.headers['user-agent'] },
...(req.headers['x-forwarded-for']) && { 'X-Forwarded-For': req.headers['x-forwarded-for'] },
},
},
);
const registrationApi = async (req, data) => {
const url = `${process.env.AM_API_URL}${process.env.AM_REALM_PATH}/authenticate?service=${process.env.AM_REGISTRATION_TREE_NAME}&authIndexType=service&authIndexValue=${process.env.AM_REGISTRATION_TREE_NAME}`;
return post(url, data, req);
};
const authenticationApi = async (req, data) => {
const url = `${process.env.AM_API_URL}${process.env.AM_REALM_PATH}/authenticate?service=${process.env.AM_AUTHENTICATION_TREE_NAME}&authIndexType=service&authIndexValue=${process.env.AM_AUTHENTICATION_TREE_NAME}`;
return post(url, data, req);
};
const passwordResetApi = async (req, data) => {
const url = `${process.env.AM_API_URL}${process.env.AM_REALM_PATH}/authenticate?service=${process.env.AM_PASSWORD_RESET_TREE_NAME}&authIndexType=service&authIndexValue=${process.env.AM_PASSWORD_RESET_TREE_NAME}`;
return post(url, data, req);
};
const accountRecoveryApi = async (req, data) => {
const url = `${process.env.AM_API_URL}${process.env.AM_REALM_PATH}/authenticate?service=${process.env.AM_ACCOUNT_RECOVERY_TREE_NAME}&authIndexType=service&authIndexValue=${process.env.AM_ACCOUNT_RECOVERY_TREE_NAME}`;
return post(url, data, req);
};
module.exports = {
registrationApi,
authenticationApi,
passwordResetApi,
accountRecoveryApi,
};
CodePudding user response:
the current jest implementation (v27.5) does only use the synchronous function definitions when auto-mocking.
furthermore, the default returning value is undefined
for the mocked functions.
to define your mocks correctly it's possible to use the second jest.mock()
function argument which is the module factory.
jest.mock('../../../app/lib/am-api.js', () => ({
registrationApi: () => Promise.resolve({ data: 42 }),
authenticationApi: () => Promise.resolve({ data: 42 }),
passwordResetApi: () => Promise.resolve({ data: 42 }),
accountRecoveryApi: () => Promise.resolve({ data: 42 })
}));
the other option for you is to use the mockAxios
module without mockinп your api file itself.