Example:
In my test I need to mock the two calls to the external apis. I can't mock on the second call. With the library 'axios-mock-adapter' and ava I could only mock the first call.
const read = async (req, res) => {
try {
const responseOne = await axios({
method: 'get',
url: 'https://api.example.com/search/repositories',
params: {
q: 'example',
},
})
const resultOne = responseOne.data
if (resultOne) {
let aux = []
const itemsOne = resultOne.items.slice(0, 10)
return Promise.all(
itemsOne.map((p, indexOne) => {
aux = [...aux, { id: p.id, name: p.name, arr: [] }]
return axios({
headers: { Authorization: `Bearer ${SECRET_KEY}` },
method: 'get',
url: 'https://api.example2.com/search/things',
params: { q: p.name },
})
.then(responseTwo =>
responseTwo.data.array.map(i => {
aux[indexOne].arr.push({
id: i.id,
created_at: i.created_at,
text: i.text,
})
})
)
.catch(err => res.status(500).json(err))
})
)
.then(() => res.json({ result: aux }))
.catch(err => res.status(500).json(err))
} else res.status(404).json({ message: 'Example not found' })
} catch (err) {
res.status(500).json(err)
}
}
This is my test read.test.js. Now I am dealing with the 'ava' and 'axios-mock-adapter' libraries. But the second axios call does not working the mock.
import axios from 'axios'
import MockAdapter from 'axios-mock-adapter'
import test from 'ava'
import read from '../read'
var mock = new MockAdapter(axios)
test('GET - /examples', async t => {
mock
.onGet('https://api.example.com/search/repositories, {
params: {
q: 'example',
},
})
.reply(200, {
total_count: 2,
incomplete_results: false,
items: [
{
id: 555,
name: 'exampleOne',
},
{
id: 666,
name: 'exampleTwo',
},
],
})
.onGet('https://api.example2.com/search/things', {
params: { q: 'name' },
headers: { Authorization: `Bearer ${SECRET_KEY}` },
})
.reply(200, {
statuses: [
{
id: 123,
created_at: 'Thu Feb 27 22:54:02 +0000 2020',
text: 'Example one.',
},
{
id: 456,
created_at: 'Wed Feb 26 13:40:20 +0000 2020',
text: 'Example Two',
},
],
})
try {
const res = await read()
t.assert(res.result[0].id.test(555))
} catch (err) {
console.log(`ERROR::: ${err}`)
}
The problem with the mock of the second request is that you are configuring it to respond only if the endpoint is requested with the params { q: 'name' }
. If you want to respond with the same data for all the requests to https://api.example2.com/search/things
it is enough to remove that params atribute:
.onGet('https://api.example2.com/search/things', {
headers: { Authorization: `Bearer ${SECRET_KEY}` },
})
.reply(200, {
statuses: [
{
id: 123,
created_at: 'Thu Feb 27 22:54:02 +0000 2020',
text: 'Example one.',
},
{
id: 456,
created_at: 'Wed Feb 26 13:40:20 +0000 2020',
text: 'Example Two',
},
],
})
There are also other problems present in your test. In the mocked response you are passing the data in a property statuses
but in your actual code you are iterating over an array
property.
Also, the read
method receives two parameters, req
and res
. If you don't provide those objects when calling read
in your test it will break, as you are calling methods of the res
object.
The simplest way to call the method would be by creating fake req
and res
objects and calling the read
method with them. For the sake of simplicity, I will create the mock with the help of sinon spies:
test('GET - /examples', async t => {
mock
.onGet('https://api.example.com/search/repositories, {
params: {
q: 'example',
},
})
.reply(200, {
total_count: 2,
incomplete_results: false,
items: [
{
id: 555,
name: 'exampleOne',
},
{
id: 666,
name: 'exampleTwo',
},
],
})
.onGet('https://api.example2.com/search/things', {
headers: { Authorization: `Bearer ${SECRET_KEY}` },
})
.reply(200, {
array: [
{
id: 123,
created_at: 'Thu Feb 27 22:54:02 +0000 2020',
text: 'Example one.',
},
{
id: 456,
created_at: 'Wed Feb 26 13:40:20 +0000 2020',
text: 'Example Two',
},
],
})
const res = {
status: sinon.stub().returnsThis(),
json: sinon.stub().returnsThis(),
};
try {
await read({}, res);
const data = res.json.firstCall.args[0];
t.is(data.result[0].id, 555)
} catch (err) {
console.log(`ERROR::: ${err}`)
}
});
Note that I'm mocking the request object by passing an empty object, since the read
method does not use any property of the request.