Add API Testing to your Nightwatch Test Automation
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
- From a command line run
npm init nightwatch@latest
- During the guided setup select end-to-end testing and TypeScript
- Continue through accepting defaults for the remaining prompts.
- 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.
- Remove the sample tests out of
./nightwatch/
, but leavetsconfig.json
- Create a folder
./nightwatch/tests
- Edit
./nightwatch.conf.js
- Change
src_folders
tosrc_folders: ['nightwatch/tests'],
- Change
plugins
toplugins: ['@nightwatch/apitest'],
- 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.
- Create a file called petStore.ts under
./nightwatch/tests/
// petStore.tsimport { NightwatchBrowser, NightwatchTests } from "nightwatch";// This line will add the api testing command types to the Nightwatch APIimport '@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.
The results also present nicely in the improved 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 typesnow 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!)