HomeSoftware TestingSmart Home
 
  

Adding Custom Commands to Nightwatch TypeScript Projects

April 21, 2023

It's been about a year since my last post about using Nightwatch test automation with TypeScript (instead of the JavaScript default). The Nightwatch developers have added significant features in that time making it even more convenient to get the benefits of TypeScript when working in Nightwatch Test Automation.

This post will cover adding custom commands, one of the less documented areas, when working in a TypeScript Nightwatch project rather than a JS one. This is a bit trickier than when working in JavaScript because JavaScript has no type-checking whereas TypeScript does so one needs to append any custom commands not part of the Nightwatch API to the type definitions.

In addition, this article will serve as an update to the original Nightwatch TypeScript how-to post with some of convenient new updates since the article was written. For example,

  • Automatic project scaffolding
  • Execution of .ts tests without requiring tsc transpiling first.

Creating a TypeScript Nightwatch Test Suite (with npm init)

One can now do a "choose-your-own-adventure" type of project setup when creating new Nightwatch projects through their scaffolding command npm init nightwatch@latest. Where one can answer what kind of test project they want to create, which browsers to run on, and if they are doing so using a cloud test provider like SauceLabs or BrowserStack. Everything is automatically downloaded and configured, including the nightwatch.conf.js file, to their selections.

Here is an example of it getting a new TypeScript project setup from scratch in under 60 seconds.

Steps

  1. At a command line type npm init nightwatch@latest
  2. Affirmatively answer to proceed.
  3. Select TypeScript
===============================
Nightwatch Configuration Wizard
===============================
Setting up Nightwatch in C:\test-automation\nightwatch-typescript...
? Select testing type to setup for your project End-to-End testing
? Select language + test runner variant
JavaScript / default
> TypeScript / default
JavaScript / Mocha
JavaScript / CucumberJS

Differing from my earlier article, the new recommended project structure has all the tests, page objects, custom commands, and so on under the /nightwatch folder.

nightwatch.config.js
/nightwatch
└───tsconfig.json
└───/page-objects
│ │
│ └───testPage1.ts
│ └───testPage2.ts
└───/tests
│ │
│ └───test1.ts
│ └───test2.ts
└───/commands
│ │
│ └───customWait.ts
└───/types
nightwatch.d.ts

Default sample tests are included and don't need to be transpiled with tsc to JavaScript before running. To execute tests when setup in this project structure you can simply run npx nightwatch to run all your tests or npx nightwatch -t ./nightwatch/tests/your-test-here.ts for a specific test.

Writing Custom Commands in a Nightwatch TypeScript project

One of the nice features about Nightwatch is how easy it is to extend the API with ones own custom commands. Commands in the directory that one adds in the path of their custom_commands_path property of nightwatch.conf.js will automatically be available on the browser object as browser.yourCommandHere() when writing their tests. This takes advantage of the fact JavaScript doesn't do type checking. However, TypeScript is more structured in that it does type-checking which creates a conflict here since "yourCommand" is not part of @types/nightwatch so TypeScript alerts that the command does not exist. To correct this, one can leverage an overriding definition file like nightwatch.d.ts that would append the custom command to the existing Nightwatch types.

Step 1: Create your custom command

The structure is very similar to the existing custom command documentation, but adds some types as shown in this simple example

// nightwatch/commands/waitForLoadScreen.ts
import { NightwatchCLient, NightwatchExpectedResult } from 'nightwatch'
export default class WaitForLoadScreen {
async command(
this: NightwatchClient,
maxWaitInMs: number
): Promise<NightwatchExpectResult> {
return this.api.expect
.element('#loadScreenOverlay')
.to.not.be.visible.before(maxWaitInMs);
}
}

This file should be stored in the ./nightwatch/commands folder with nightwatch.conf.js set to

// nightwatch.conf.js
//...
custom_commands_path: ['nightwatch/commands'],
//...

If there was no type-checking, one would be able to use browser.waitForLoadScreen(5000), but since waitForLoadScreen is not a typed method of the Nightwatch API TypeScript will display an error alerting one that waitForLoadScreen does not exist on the browser object. So in step 2, let's fix that.

Step 2: Add a definition for your Custom Command

In the nightwatch/types folder create a file called nightwatch.d.ts. This will append your command to the existing NightwatchCustomCommands type definitions.

// nightwatch/types/nightwatch.d.ts
declare module 'nightwatch' {
export interface NightwatchCustomCommands {
waitForLoadScreen(maxWaitInMs: number): Awaitable<this, null>;
}
}

Open the ./nightwatch/tsconfig.json (there is one in the root project directory as well--leave that outer one alone)

// nightwatch/tsconfig.json
"compilerOptions": {
// excluded for brevity
},
"files": ["/types/nightwatch.d.ts"]

Append the files property under compilerOptions as shown with the path to the definition file. Once all three steps are complete the custom command should be available to use without any TypeScript warnings.

Final Thoughts

The Nightwatch TypeScript implementation has matured very nicely over the past year and should continue to progress with Nightwatch 3.0 right around the corner. Stay tuned for updates on their Nightwatch GitHub Releases page for the latest.

If you are a Nightwatch beginner be sure to watch my Software Testing Playlist

Please share the link to this article if you enjoyed it and if you have any questions or comments please reach out through my social links below 👇

Photo of David Mello

David Mello

Breaker of software, geek, meme enthusiast.

 

DavidMello.com © 2023