In short:
- When doing normal calls,
nockworks perfectly - But when testing a request that triggers
axios-retry,nockfails when the first retry attempt happens (based on logging)
Does nock support retries? If so, how should the test be setup?
Client:
const getClient = (authorizationToken: string | undefined, target: ApiParams) =>
axios.create({
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
...(!!authorizationToken && { Authorization: `Bearer ${authorizationToken}` }),
'x-api-key': target.apiKey || 'missing',
},
timeout: API_TIMEOUT_MILLISECONDS,
});
export const sendRequest = ({ someParams }) => {
const client = getClient(authorizationToken, target);
axiosRetry(client, {
retries: API_MAX_RETRIES,
retryDelay: (retryCount) => {
logger.info('retrying request', retryCount);
return retryCount * API_RETRY_INTERVAL_MS;
},
retryCondition: (error) => {
// There's more in this, but it's not relevant for the question
return Number(error.response.status) >= 500;
},
});
}
Simplified implementation that I test:
export const upsertExclusionList = async () => {
const response: ApiClientResult = sendRequest({ someParams });
if (response.data) {
return response.data;
} else {
throw Error('No data');
}
}
Test that works:
it('processes valid request', async () => {
nock(serverBaseUrl).put('/exclusion-lists', { some: 'data' }).query({ callerId: 'Tester', role: 'Tester' }).reply(200, { success: true });
const response: ExclusionList = await upsertExclusionList({ someParams });
expect(response).toEqual({ some: 'thing' });
});
Test that fails (this test triggers retries):
it('handles a 500 response from the API', async () => {
nock(serverBaseUrl).put('/exclusion-lists', { some: 'data' }).query({ callerId: 'Tester', role: 'Tester' }).reply(500, { error: 'Some error' });
await expect(upsertExclusionList({ someParams }).toBeCalledTimes(4);
// Also did this:
// await expect(upsertExclusionList({ someParams }).rejects.toEqual('No data');
});
But what happens is I get this:
Attempted to log "Call to put exclusion list API (https://api.example.com/exclusion-lists?callerId=Tester&role=Tester) failed: Nock: No match for request {
"method": "PUT",
"url": "https://api.example.com/exclusion-lists?callerId=Tester&role=Tester",
"headers": {
"accept": "application/json",
"content-type": "application/json",
"authorization": "Bearer unit-test",
"x-api-key": "xxx",
"user-agent": "axios/1.2.0-alpha.1",
"content-length": "93",
"accept-encoding": "gzip, deflate, br"
},
"body": "{\"some\":\"data\"}"
} (2080 ms)".
Versions:
node 18.13.0
"axios-retry": "3.3.1",
"nock": "13.3.0",
"jest": "28.1.3",
"ts-jest": "28.0.8",
"typescript": "4.3.5"
So, how can I get nock to work with axios-retry?
When you nock a request, the default behavior is that Nock will only intercept a single request. After the single request, that interceptor is removed from the stack so any further requests creates an error. Nock provides two methods to change this behavior.
.times(), which allows a single interceptor to act on n requests back to back..persist(), which will stop an interceptor from removing itself from the stack after being used. Therefore being able to be reused over and over for any request.If you're writing a test that covers the fault tolerance of your code, say with Axios config that is setup to retry four times. You could create one Nock that returns a 500 three times then returns a 200 on the four attempt. Or mix and match as needed.