I need your help with this issue that I am having while unit testing a Got client hook where I do logging of HTTP requests. I am using Jest. I am getting an expectations error that is seeing the argument to .toBeCalledWith as object whereas it is a string when I console log it. Maybe I am doing something wrong here. Please let me know.
got-client.js below
const http = require('http');
const https = require('https');
const got = require('got');
const _ = require('lodash');
const { name: packageName, version: packageVersion } = require('../../package.json');
const keepAliveOptions = { keepAlive: true, keepAliveMsecs: 20000 };
let clients = {};
const allowedHeaders = ['user-agent', 'x-forwarded-for', 'referer', 'content-length'];
const filterHeaders = headers => _.pick(headers, allowedHeaders);
const gotLoggingHooks = (name, logger) => ({
hooks: {
beforeRequest: [
options => {
const { url, method, headers } = options;
logger.debug({
message: `${name} request ${options.method} ${options.url}`,
http_request: {
method,
target: url,
direction: 'OUT',
headers: filterHeaders(headers)
},
request: _.pick(options, ['url', 'method', 'headers', 'body', 'json'])
});
}
],
beforeRetry: [
(options, error, retryCount) => {
const {
response: { statusCode, ip } = {},
request: { options: { method, headers = {} } = {}, requestUrl: url } = {},
timings: {
// eslint-disable-next-line camelcase
phases: { total: duration_ms } = {}
} = {}
} = error;
logger.warn({
message: `${name} will retry request, attempt ${retryCount}/${options.retry.limit} ${method} ${url} (${error.code} ${error.message})`,
err: error,
http_request: {
method,
target: url,
status: statusCode,
server_ip: ip,
duration_ms,
direction: 'OUT',
protocol: headers.via,
headers: filterHeaders(headers)
}
});
}
],
beforeError: [
error => {
const {
response: { statusCode, ip } = {},
request: { options: { method, headers } = {}, requestUrl: url } = {},
timings: {
// eslint-disable-next-line camelcase
phases: { total: duration_ms } = {}
} = {}
} = error;
if (!statusCode) {
logger.error({
message: `${name} request error ${method} ${url} (${error.code} ${error.message})`,
err: error,
http_request: {
method,
target: url,
status: statusCode,
server_ip: ip,
duration_ms,
direction: 'OUT',
protocol: headers.via,
headers: filterHeaders(headers)
}
});
}
// eslint-disable-next-line no-param-reassign
error.serviceName = name;
return error;
}
],
afterResponse: [
response => {
const {
statusCode,
body,
url,
ip,
headers = {},
request: { options: { method } = {} } = {},
timings: {
// eslint-disable-next-line camelcase
phases: { total: duration_ms } = {}
} = {},
retryCount
} = response;
logger.debug({
message: `${name} response ${method} ${url}`,
response: { body, retryCount, headers },
http_request: {
method,
target: url,
status: statusCode,
server_ip: ip,
duration_ms,
direction: 'OUT',
protocol: headers.via,
headers: filterHeaders(_.get(response, 'request.options.headers'))
}
});
return response;
}
]
}
});
const gotClient = ({ name, logger, keepAlive = true, gotOptions = {} }) => {
if (!clients[name]) {
clients[name] = got
.extend({
headers: {
'user-agent': `${packageName} ${packageVersion}`
},
...(keepAlive && {
agent: {
http: new http.Agent(keepAliveOptions),
https: new https.Agent(keepAliveOptions)
}
}),
responseType: 'json',
timeout: 5000
})
.extend(gotLoggingHooks(name, logger))
.extend(gotOptions);
}
return clients[name];
};
gotClient.clearAll = () => {
clients = {};
};
module.exports = gotClient;
got-client.spec.js below
const nock = require('nock');
const { name: packageName, version: packageVersion } = require('../../../package.json');
const gotClient = require('../../../src/lib/got-client');
const BASE_URL = 'https://subdomain.domain.com/';
const BASE_ENDPOINT = 'path';
const logger = {
error: jest.fn(),
debug: jest.fn(),
info: jest.fn(),
log: jest.fn(),
warn: jest.fn(),
};
describe('got client', () => {
afterEach(gotClient.clearAll);
test('should log requests', async () => {
const client = gotClient({
name: 'test',
logger,
gotOptions: {
prefixUrl: BASE_URL,
},
});
nock(BASE_URL).get(`/${BASE_ENDPOINT}`).reply(200, { success: true });
await client.get(BASE_ENDPOINT);
// console.log('mock call 0', logger.debug.mock.calls[0][0]);
// TODO: match message
expect(logger.debug).toBeCalled();
expect(logger.debug).toBeCalledWith(
expect.objectContaining({
message: expect.stringContaining(`request GET ${BASE_URL}${BASE_ENDPOINT}`),
})
);
expect(logger.debug).toBeCalledWith(
expect.objectContaining({
message: expect.stringContaining(`response GET ${BASE_URL}${BASE_ENDPOINT}`),
})
);
nock(BASE_URL).get(`/${BASE_ENDPOINT}/error`).reply(500, { success: false });
try {
await client.get(`${BASE_ENDPOINT}/error`, { retry: 0 });
} catch (e) {}
expect(logger.error).toBeCalledWith(
expect.objectContaining({
message: expect.stringContaining(`request error GET ${BASE_URL}${BASE_ENDPOINT}/error`),
})
);
});
});
Failing Test Error below
Error: expect(jest.fn()).toBeCalledWith(...expected)
Expected: ObjectContaining {"message": StringContaining "request error GET https://subdomain.domain.com/path/error"}
Number of calls: 0
at Object.<anonymous> (/Users/user/Documents/company/teams/team/project/test/unit/lib/got-clients.spec.js:62:26)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
I will really appreciate help with this. Thank you very much in advance.