How to test API routes in NextJS
June 06, 2020
I'm currently working on a NextJS project where we're using api
folder for all sort of calls: fetching data, authorization... Well, basically that's it for now, we're just starting. :)
So I had some questions on how to approach it, and thanks to Mason's post and a few stack overflow issues, I was able to construct something that wokred for our case.
In that case, I needed to test
- API function accepts and sends back the same headers (e.g. session key)
- API responds with a certain status (e.g.
200
) - API responds with a pre-defined object structure (e.g. it had to be
data: {}
)
For that I've used
nock
to mock the http server andnode-mocks-http
for mocking 'http'res
andreq
objects
This is how it all came together in our .test.ts
file
import nock from 'nock'
import nodeMocks from 'node-mocks-http'
import auth from '../auth'
describe('API function', () => {
// We create req and res mocks
const req = nodeMocks.createRequest()
const res = nodeMocks.createResponse()
// We're using the same headers and we're mocking .status and .end function,
// because we're going to see how many times they've called
// and what they've called with
beforeEach(() => {
req.headers = { username: 'test', password: 'test123' }
res.status = jest.fn(function () {
return this
})
res.end = jest.fn()
})
// We need to reset mocks after every test so that we could reuse them in another
afterEach(() => {
jest.resetAllMocks()
nock.restore()
})
it('sends data with session key on successful call', async () => {
// This is what server sends to us as a response to our requests.
// So we create a similar object here for mocking purposes.
const successReply = {
result: 1,
session: 'testsessionId',
text: 'Auth ok',
}
// We instruct nock to send that object/reply and status 200 when our
// API route is called
nock(process.env.BASE_API_URL)
.post(/authenticate$/)
.reply(200, successReply)
// Using async/await here to wait for the response
await auth(req, res)
// And here we're checking our mocks that we created in beforeEach function
expect(res.status).toHaveBeenCalledTimes(1)
expect(res.status).toHaveBeenCalledWith(200)
expect(res.end).toHaveBeenCalledTimes(1)
expect(res.end).toHaveBeenCalledWith(
JSON.stringify({ data: { session: successReply.session } }),
)
})
})
That is basically it. 🎉
I also blog about my professional life in @british_frontend (на Русском).