HomeSoftware TestingSmart Home
 
  

Add API Testing to your Nightwatch Test Automation

January 13, 2023

When the software being tested exposes REST API endpoints it can be more efficient to test the APIs directly instead of going through the UI. If the business logic is in the API you can cut out the middle man, the browser, and make the calls directly--eliminating flakiness due to page load times for example. There are many solutions for testing REST APIs including.

  • Postman
  • SuperTest
  • RestAssured
  • SoapUI

Testing REST APIs from your Selenium Test Projects

The downside of these tools is they didn't, until recently, integrate with one's existing selenium UI automated test suite. The API tests would live in a separate framework or solution. Being able to test and interact with one's APIs from one's UI tests offers several advantages including

  • Better organization of one's tests, everything in one place
  • Setup of pre/post conditions (state) for the UI tests through the API
  • Assert results of UI interaction more efficiently at the API layer

So, one can write test cases where it makes sense to, as pure API tests, or mix in API checks and calls within one's selenium tests.

Nightwatch 2.5.2 integrated SuperTest into its selenium test framework allowing one to use SuperTest in their existing test suites. This tutorial will explore how Nightwatch and SuperTest work in practice when compared to other frameworks that offer similar capabilities, like Playwright.

Initial Thoughts

I've used SuperTest off and on for years so I was happy to learn Nightwatch integrated it into its framework to add API testing. It's easy to use and has a nice fluent assertion style.

I don't like the fact it needs to be imported as a plugin (@nightwatch/apitesting). I feel this should be a more core feature and included as default. In addition, when working with TypeScript, the Nightwatch plugin system and TypeScript types are still having growing pains.

Importing the plugin and adding custom types is not difficult. This article will go over both, but it's something that just works out of the box with competing frameworks like Playwright. Still, this is a nice addition of functionality for quality engineers with an existing Nightwatch test suite and I'm happy to see continuous innovation being made.

So, let's get started API testing.

API Testing in Nightwatch Selenium Projects

This tutorial will go through creating a Nightwatch TypeScript selenium test project, import the API Testing plugin, add type definitions for TypeScript support, and write example tests against some practice REST APIs.

Initial Installation

  1. From a command line run npm init nightwatch@latest
  2. During the guided setup select end-to-end testing and TypeScript
  3. Continue through accepting defaults for the remaining prompts.
  4. Add the API testing plugin by running npm install @nightwatch/apitesting @types/supertest --save-dev

This will create a default working Nightwatch TypeScript test project with sample tests under /nightwatch/

They can be executed using npx nightwatch

Configuring the Test Project

Now that there is a working test project we can add custom TypeScript types for API testing(edit 1/24/22 now included in v0.2.2), remove the sample tests, and create our own API tests.

  1. Remove the sample tests out of ./nightwatch/, but leave tsconfig.json
  2. Create a folder ./nightwatch/tests
  3. Edit ./nightwatch.conf.js
  4. Change src_folders to src_folders: ['nightwatch/tests'],
  5. Change plugins to plugins: ['@nightwatch/apitest'],
  6. Optionally, to prevent a browser from launching, useful in a pure API test suite, one can modify the start_session and start_process values to false.
// nightwatch.conf.js
// ...
test_settings: {
default: {
// ...
start_session: false,
webdriver: {
start_process: false,
server_path: ''
},
},
}

You can checkout the example solution with this preconfigured from my GitHub under nightwatchTutorials/apiTesting to follow along. I'll try to keep this repository updated as updates occur to the API testing plugin over time.

Writing your first API Test

The example test solution has example tests written against the Swagger PetStore and Restful Booker test playground APIs (see more on Best Websites to Practice Test Automation).

First, let's create a test against /store/inventory.

  1. Create a file called petStore.ts under ./nightwatch/tests/
// petStore.ts
import { NightwatchBrowser, NightwatchTests } from "nightwatch";
// This line will add the api testing command types to the Nightwatch API
import '@nightwatch/apitesting';
const petStoreTests: NightwatchTests = {
};
export default petStoreTests;

This will be the shell of your tests against the pet store API. It brings in the TypeScript types applicable for Nightwatch API tests. Now, let's create the test.

import { NightwatchBrowser, NightwatchTests } from "nightwatch";
import '@nightwatch/apitesting';
const petStoreTests: NightwatchTests = {
// You pass supertest into the test through the object. The test must be async/awaited
'can GET count of sold inventory': async ({ supertest }: NightwatchBrowser) => {
await supertest
// Request can take a a baseUrl for a remote API or the entry point of a REST API, like Express()
.request('https://petstore.swagger.io/v2')
// After request, the syntax exactly matches supertest and chai
.get('/store/inventory/')
.expect(200)
.expect('Content-Type', /json/)
.then((response) => {
expect(response.body.sold).to.be.greaterThan(0);
});
},
};
export default petStoreTests;

For those used to supertest this is very familiar. The one oddity I found was the await returns an @nightwatch_element response instead of the supertest response which requires one to do assertions against the response in the then block.

POST requests are very similar and one can easily put a JSON object inside the .send method as shown.

'can POST a pet to the store': async ({ supertest }: NightwatchBrowser) => {
await supertest
.request('https://petstore.swagger.io/v2')
.post('/store/order')
.send({
id: 0,
petId: 31337,
quantity: 1,
shipDate: '2022-12-30T14:55:04.147Z',
status: 'placed',
complete: true,
})
.expect(200)
.expect('Content-Type', /json/)
.then((response) => {
expect(response.body.id).to.be.greaterThan(0);
expect(response.body.quantity).to.equal(1);
expect(response.body.status).to.equal('placed');
});
},

More Advanced API Testing

The Restful Booker has a more realistic stateful database (that gets wiped every 10 minutes) so it is better to construct scenario-based API tests against. I have examples under /apiTesting/nightwatch/tests/restfulBooker.ts that illustrate that including partial updates using the PATCH verb.

'Can partially update booking': async ({ supertest }: NightwatchBrowser) => {
await supertest
.request(baseUrl)
.patch(`/booking/${bookingId}`)
.set('Content-type', 'application/json')
.set('Cookie', `token=${authToken.token}`)
.accept('application/json')
.send({
totalprice: 200,
depositpaid: false,
bookingdates: {
checkin: '2023-03-31',
checkout: '2023-04-15',
},
additionalneeds: 'an even-numbered floor',
})
.then((response: any) => {
expect(response.body).to.have.property('depositpaid', false);
expect(response.body).to.have.property(
'additionalneeds',
'an even-numbered floor'
);
expect(response.body).to.have.property('totalprice', 200);
expect(response.body.bookingdates).to.have.property(
'checkin',
'2023-03-31'
);
expect(response.body.bookingdates).to.have.property(
'checkout',
'2023-04-15'
);
});
},

Another oddity, I found (as of writing) was no documented way of using supertest in the before pretest hook to do something like grab and store an authentication token to use in the tests later. I ended up importing superagent to do that in this test suite which worked out, but didn't seem polished.

import { NightwatchBrowser, NightwatchTests } from 'nightwatch';
import superagent from 'superagent';
//...
let authToken: token;
const bookerTests: NightwatchTests = {
before: async () => {
authToken = (
await superagent.post(`${baseUrl}/auth`).send({
username: 'admin',
password: 'password123',
})
).body;
},
//...

1/13/23 Update - I learned you can use it in the before test hook off of the Nightwatch API object (aka browser or client). So one could rewrite the above example removing the need to import superagent using the style below.

const bookerTests: NightwatchTests = {
before: async (client: NightwatchBrowser) => {
await client.supertest
.request(baseUrl)
.post('/auth')
.send({
username: 'admin',
password: 'password123',
})
.expect(200)
.expect('Content-type', 'application/json; charset=utf-8')
.then((response: any) => {
authToken = response.body;
});
},

Last, you can load up your API locally into supertest by passing it the entry point of your Express() application (or NestJS) which is useful for local testing. An example of that can be found under, apiTesting/nightwatch/tests/restfulBookerLocal.ts.

const server = require('../../restfulBooker/restful-booker/app');
// ...
'Can GET ping': async ({ supertest }: NightwatchBrowser) => {
await supertest.request(server).get('/ping').expect(201);
},

Executing the tests

To run the tests, you can run all or specific tests using the standard Nightwatch command line syntax.

  • npx nightwatch

  • npx nightwatch --test testPathHere

You get the same nice test reporting that was added in Nightwatch 2.0.

Nightwatch API Test Output

The results also present nicely in the improved Nightwatch HTML test report.

Nightwatch HTML Test Report

Final Thoughts

Nightwatch has been rapidly releasing interesting new features throughout 2022 and now into 2023 such as visual regression testing, component testing, enhancements to reporting and debugging, and improved mobile testing. Their implementation of API Testing is one of the newer additions and I think it shows promise, but it feels like it needs more polish compared to other popular frameworks like Playwright.

Playwright's API testing

  • Is included by default (not a plugin)
  • Has included TypeScript types now included in the Nightwatch plugin as well
  • Has better documentation
  • Has a handy test.use that let's you default tedious settings like baseUrl, headers, and authorization

What Nightwatch does better

  • Better assertion style
  • Nicer test output/HTML report
  • Perhaps better support for local testing/mocking API requests

Overall, the API testing capability added to Nightwatch is a useful addition and will hopefully improve in coming iterations.

For further learning consider checking out some API testing books

As an Amazon Associate I earn from qualifying purchases made through links on this site (which helps support it, thank you!)

Photo of David Mello

David Mello

Breaker of software, geek, meme enthusiast.

 

DavidMello.com © 2023