REST API tests

In this guide, we learn how to write tests against an API server. If you are new testing with AdonisJs or in general, make sure to read the getting started guide.

Basic example

Let’s get started with a basic example to test an endpoint that returns a list of posts in JSON.

Upcoming example assumes that you have database tables set up with a Post model.

Let’s start by creating a functional test since we are testing the API endpoint like an end-user.

adonis make:test Post

Output

create: test/functional/post.spec.js

Let’s open the test file and paste following code inside it.

test/functional/post.spec.js
const { test, trait } = use('Test/Suite')('Post')
const Post = use('App/Models/Post')

trait('Test/ApiClient')

test('get list of posts', async ({ client }) => {
  await Post.create({
    title: 'Adonis 101',
    body: 'Blog post content'
  })

  const response = await client.get('/posts').end()

  response.assertStatus(200)
  response.assertJSONSubset([{
    title: 'Adonis 101',
    body: 'Blog post content'
  }])
})

Now if we run adonis test, hopefully, the test passes. Also, let’s talk about how everything works in a nutshell.

  1. Very first we register the Test/ApiClient trait, which gives us an HTTP client to make requests on a URL.

  2. We create a dummy post before hitting the posts URL.

  3. Finally, we run assertions to make sure the return HTTP status is 200 with one post having the same title and body.

Congratulations 👏   You have got your first test passing.

Client methods

Below is the list of available methods you can call when making HTTP requests.

get(url)

Make an HTTP GET request to a given url.

client.get('posts')

Just like get, you can use other methods like post, put, delete to make HTTP requests.

header(key, value)

Set key/value pair as an header when making the HTTP request.

client
  .get('posts')
  .header('accept', 'application/json')

send(body)

Send request body when making the HTTP request.

client
  .post('posts')
  .send({
    title: 'Adonis 101',
    body: 'Post content'
  })

query(queryObject)

Set query string

client
  .get('posts')
  .query({ order: 'desc', page: 1 })

type(type)

Set request content type.

client
  .get('posts')
  .type('json')

accept(type)

Set the data type you want to accept from the server.

client
  .get('posts')
  .accept('json')

Set request cookies. Since all cookies are encrypted in AdonisJs, this method makes sure to encrypt the values properly, so that AdonisJs server can parse them.

client
  .get('posts')
  .cookie('name', 'virk')

plainCookie(key, value)

Set a cookie which doesn’t get encrypted

client
  .get('posts')
  .plainCookie('name', 'virk')

end

The end method ends the HTTP request chain and returns the response. Make sure always to call the 'end' method.

const response = await client.get('posts').end()

Multipart requests

The API client also makes it possible to make multipart requests and send files as part of the request body.

await client
  .post('posts')
  .field('title', 'Adonis 101')
  .attach('cover_image', Helpers.tmpPath('cover-image.jpg'))
  .end()

Also, you can set HTML form style field names to send an array of data.

await client
  .post('user')
  .field('user[name]', 'Virk')
  .field('user[email]', '[email protected]')
  .end()

Sessions

When writing tests, you may want to set sessions beforehand, and same can be done by using the Session/Client trait.

Make sure you have installed the session provider before you can take advantage of the Session/Client trait.
const { test, trait } = use('Test/Suite')('Post')

trait('Test/ApiClient')
trait('Session/Client')

test('get list of posts', async ({ client }) => {
  const response = await client
    .get('posts')
    .session('adonis-auth', 1)
    .end()
})

Authentication

Also, you can authenticate users beforehand by using the Auth/Client trait.

const { test, trait } = use('Test/Suite')('Post')

trait('Test/ApiClient')
trait('Session/Client')
trait('Auth/Client')

test('get list of posts', async ({ client }) => {
  const user = await User.find(1)

  const response = await client
    .get('posts')
    .loginVia(user)
    .end()
})

Alternatively, you can pass a custom scheme to be used for authenticating users.

client
  .get('posts')
  .loginVia(user, 'jwt')

Moreover, for a basic auth, you must pass the username and the password to log in the user.

client
  .get('posts')
  .loginVia(username, password, 'basic')

Assertions

Below is the list of assertions you can run when using the API client.

assertStatus

Assert response status

response.assertStatus(200)

assertJSON

Response the response body to deepEqual the expected value.

response.assertJSON({
})

assertJSONSubset

Assert subset of JSON. This assertion tests a subset of objects, which is quite helpful when some keys inside an object are not determinable. For example: timestamps

response.assertJSONSubset({
  title: 'Adonis 101',
  body: 'Some content'
})

assertText

Assert plain text returned by the server

response.assertText('Hello world')

assertError

Assert the error received as response

response.assertError([
  {
    message: 'username is required',
    field: 'username',
    validation: 'required'
  }
])

assertCookie

Assert that the server set a cookie with value

response.assertCookie('key', 'value')

assertPlainCookie

Assert plain cookie

response.assertPlainCookie('key', 'value')

assertHeader

Assert that the server sent a header.

response.assertHeader('content-type', 'application/json')

assertRedirect

Assert that the request was redirected to a given URL.

response.assertRedirect('/there')