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

  1. API function accepts and sends back the same headers (e.g. session key)
  2. API responds with a certain status (e.g. 200)
  3. API responds with a pre-defined object structure (e.g. it had to be data: {})

For that I've used

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. 🎉


Telegram
I also blog about my professional life in @british_frontend (на Русском).