Custom Commands with WebdriverIO

Custom WebdriverIO Commands

Custom commands are a convenient way of extending the browser object with new functionalities to improve test stability, to enhance test maintenance, and to reduce code duplication.

Webdriver.io allows to add new helper functions, and to overwrite existing commands in the browser instance.

To extend the browser instance with your own set of commands there is a method called addCommand available from the browser object.

This results in several benefits:

  • Mochas it() (test case) statement is cleaner and easier to read.
  • Removal of code duplication as several steps are encapsulated into one command.
  • Reduce programming errors as frequently used actions are optimised in one place.
  • Tests become less about the specific implementation and more about what you actually want to do.

The following example shows how to add a new command that checks if an element is existing and enabled before it clicks on it.

First, we add a new custom command to Webdriver using the addCommand method.

/**
* addCommand handler for async or standalone mode
* @param {String}   fnName         function name
* @param {Function} fn             function
* @param {Boolean}  forceOverwrite if true it can overwrite existing commands
*/

The first attribute is the function name with which we can use it later.

The second is the functionality being executed on each call. The third will be important later-on.

client.addCommand('waitAndClick', WebdriverHelper.clickElement);

This example extends the normal click event.

We want to be extra careful before clicking on something, so we wait until the element exists and it is enabled. Otherwise, the click would fail.

public static clickElement(elementId: string) {
    return WebdriverHelper.client
      .waitForExist(elementId)
      .waitForEnabled(elementId)
      .click(elementId);
}

The result of your custom command will be the result of the promise you return.

Custom commands, like all WebdriverIO commmands, can only be called inside a test hook or it() block.

You can define custom commands at any point in your test suite.

The onPrepare or before hook can be a good place to include your commands (see the discussion on stackoverflow on Where do I add custom commands).

The custom command can be used in your test as follows.

it('should click on button with custom command', () => {
   browser.waitAndClick(Selectors.SUBMIT);
}

You can chain custom commands with other commands as you would normally do.

it('should login user with valid credentials', () => {
   browser
      .click(Selectors.TAB_LOGIN_PAGE)
      .setValue(Selectors.USERNAME_INPUT, Data.USER)
      .setValue(Selectors.PASSWORD_INPUT, DATA.PASSWORD)
      .waitAndClick(Selectors.SUBMIT);
}

In case you end up with a lot of custom commands, a good idea might be structure them into different categories, such as action, navigation, and validation commands.

Instead of writing a new custom command, you can also overwrite an existing command, such as click().

browser.addCommand("click", selector => {
   // my implementation
}, true);

By default WebdriverIO will throw an error if you try to overwrite an existing command. Notice the third property of addCommand which is set to true. This is needed to let WebdriverIO know that we intend to override an existing command.