Skip to main content

ยท 8 min read

We are pleased to announce that we now have support for CucumberJS in WebdriverIO V5!!!! This has been a great challenge for the project committers so we're all very thankful for the time and effort they put into this. So normally we would say

npm install @wdio/cucumber-framework --save-dev

and go with the flow, but this time it is different. When you upgrade to the latest version of the Cucumber framework you also need to upgrade to the latest version of WebdriverIO. In this blog post we want to give you some guidelines on how to do that.

Where to start

Upgrading to the latest version of the Cucumber framework isn't that simple, because as said, you also need to migrate to version 5 of WebdriverIO. To understand what you need to do we have created some steps you might want to follow which will make the migration a lot easier for you. But before we explain the steps, you first need to understand the differences between WebdriverIO V4 and WebdriverIO V5.

NodeJS support

WebdriverIO now needs NodeJS 8 or higher. Be aware that NodeJS 8 will end it's LTS support at the end of 2019, so upgrading to 10 would be better. If you want to know more about the NodeJS LTS support check this. This might help you convince your colleagues / DEVOPS engineers to upgrade you NodeJS instances.

As a side note, if you want to know what is supported by NodeJS by default you can check node.green and follow all upcoming changes.

W3C support

WebdriverIO is now fully supporting the W3C protocol, this has a lot of advantages, but for your existing scripts some minor downsides. One of the downsides might be that you are using methods that are based on the JSONWire Protocol, that are not supported by the newest drivers like for example ChromeDriver 74+. This might result in errors like for example browser.positionClick() is not a function. If you see this error you are using a not supported method for the W3C supported Driver. See the API documentation here to see which command is a WebDriver Protocol (W3C) or a JSONWire protocol command.

Just a little side note, we tried to keep all browser and element commands, see the link above, agnostic to the protocol. Nothing changed here for you. To provide you some insight on how this works please check for example the keys command, you will find the support for both protocols here.

If you want to use W3C with cloud vendors, like for example Sauce Labs or Browserstack, you need to use a vendor specific prefix in your capabilities. Please check the websites of the vendors to see what you need to do.

But, you always need to end with the advantages. So, with W3C you will now see that the browsers follow a common web standard for web automation. This helps WebdriverIO to build a reliable framework on top of it. And last but not least, with W3C support from all browser vendors we now also get better support for Appium, check the latest post of Apple here. So, W3C is a major step for us all!!

Command changes

Over the years WebdriverIO added more and more commands for different automation protocols without applying a pattern to it which resulted in having a bunch of duplication and inconsistent naming. Even though the list looks exhausting, most of the commands that have changed were used internally. Please check the changelog of V5 to see all the changes.

Breaking changes

When creating a better product and thus releasing a major version, you will always have breaking changes. We can't repeat it enough but please check the changelog of V5 to see all the breaking changes.

Don't only read the changes in the V5.0.0 release, but also read the rest of the changes!

It's not only WebdriverIO who evolved!

When you are going to use the latest version of the @wdio/cucumber-framework, you'll also get the latest version of Cucumber. This means you also need to look at the breaking changes between CucumberJS 2 and CucumberJS 5. Please check the changelog of CucumberJS from version 3 till 5 to see what changed in CucumberJS.

Migration steps

So enough about the differences between V4 and V5, please follow the steps below to make the migration a little bit smoother. The idea behind these steps is to migrate with small baby steps. The advantage of doing it in small baby steps is that you also have some time to look at your code again and maybe refactor it or remove duplicate and ugly not needed code.

1. Start with a clean project

We advise you to create a fresh new project which you can easily copy to your old project and migrate 1 feature file and it's steps per scenario. When you do this you can easily disable scenario's in your old project, and run the new migrated tests in the new project, maybe even embed it in your pipeline.

Before installing dependencies, we need to initialize an empty NPM project (this will allow us to the cli to install needed dependencies to our local project). To do this, run:

mkdir webdriverio-test && cd webdriverio-test
npm init -y

The -y will answer 'yes' to all the prompts, giving us a standard NPM project. Feel free to omit the -y if you'd like to specify your own project details.

2. Install WebdriverIO CLI

We recommend using the test runner because it comes with a lot of useful features that makes your life easier. With WebdriverIO v5 and up, the testrunner has moved into the @wdio/cli NPM package.

Now we need to install the cli. Do that by running:

npm i --save-dev @wdio/cli

3. Generate Configuration File

We'll next want to generate a configuration file that stores all of our WebdriverIO settings. To do that just run the configuration utility:

npx wdio config

A question interface pops up. It will help to create the config easy and fast and install all needed dependencies. Check the file and read the comments, some things changed so reading them might help you understand what changed in the configuration file.

NOTE: If you were using a compiler in your cucumberOpts you need to be aware of the fact that CucumberJS removed the compiler. This means that WebdriverIO can't provide you with this option, but, as you might expect from our hard working contributors, there is a different solution. Please check Babel or TypeScript for the new way of using a compiler.

4. Create the same folder structure

Now that everything has been set up, it's best to create the same folder structure you now have in your project.

DON'T COPY THE FILE, ONLY THE FOLDER STRUCTURE

5. Migrate feature file per feature file

When you have the folder structure, copy 1 feature file to the new project. Start with the easiest file and if you have more than 1 scenario in it, comment out all scenario's and leave 1 active. Now make sure you migrate the steps that belong to that specific scenario, including all pageobjects that belong to the implementation, to the new project. Keep in mind that there are breaking changes in WebdriverIO in selecting elements and so on, see above. If you were using the defineSupportCode from CucumberJS, please check the CucumberJS changelog for V4. That is deprecated now.

Do this for each scenario, migrate it step by step, if you face issues, fix them and proceed. And don't forget to clean up the coding mess you, or your colleagues, might have made in the past.

6. When you're done

Because you created a clean project you can now easily do the following:

  1. Remove all WebdriverIO V4 dependencies in your old project.
  2. Copy all dependencies from the new project to the old project.
  3. Remove all test related files.
  4. Copy all new test related files to your project.

And you're done, time to party.

Support

If you need support you can find us on the WebdriverIO- Gitter channel by clicking on this link Gitter chat. When you ask for support we only have 1 question for you, please provide us a detailed description of your issue, what you already did and so on. Otherwise you ask us to find a needle in a haystack and trust me, that will be very hard for us.

Happy testing!

Grtz,

The Blue Guy

ยท 4 min read

Testing an upload scenario in the browser is a rare but not uncommon case in the automation testing space. It is always important to evaluate the importance of such a test because in many situations you end up testing the browser more than your application. So always keep in mind how much additional functionality your frontend application puts on top of the default upload behavior of the browser. If for example most of the magic happens in the backend it makes much more sense to mimik an upload using a simple Node.js POST request using packages like request or axios.

Find and expose file inputs

Let's say our frontend app does a lot of things on top of just uploading a file (e.g. validation or some other frontend side manipulation of the file that is about to be uploaded). Now the first thing we should do is to find the input elements from type file. Be aware that apps build in React, Angular or other frameworks often hide these elements as there are hard to style using pure CSS. Therefore they hide the elements and mimic the input with a div or other more styleable HTML tags.

// Two hidden input elements, 1 for single file upload 1 for multiple.
<input class="upload-data-file-input hidden" type="file">
<input class="upload-data-file-input-multiple hidden" type="file">

In order to become capable to modify the value of this element we need to make it visible. The WebDriver spec defines input elements to be interactable in order to change their value. So let's do that:

/**
* The css class name "upload-data-file-input hidden" is just an example
* and you can replace with your app.
*/
const fileUpload = $('.upload-data-file-input');
browser.execute(
// assign style to elem in the browser
(el) => el.style.display = 'block',
// pass in element so we don't need to query it again in the browser
fileUpload
);
fileUpload.waitForDisplayed();

With the execute we can simply modify the element properties to either remove the hidden class or give the element displayedness.

Uploading the file

Unfortunately the mechanism to upload a file with a browser highly depends on your test setup. At the end of the day the browser needs to be able to access the file that you want tp upload. For the local scenario it is super simple. Since you run the browser on your local machine and the file that you want to upload also exists on your local machine, all you need to do is to set the value of the file path to the input element:

/**
* it is recommended to always use the absolute path of the file as it ensures
* that it can be found by the browser.
*/
const path = require('path');
const filePath = path.join(__dirname, 'path/to/your/file');
fileUpload.setValue(filePath);

If you automate a browser that is running on a remote machine this approach won't work anymore because the file that is located locally (or wherever the tests are running) does not exist on the remote machine where the browser is running. For these scenarios the Selenium project created a file that is currently only supported when running Chrome or using a Selenium Grid with the Selenium standalone server. The command expects the file payload to be passed in as base64 string. Since this is quite inconvenient to use WebdriverIO has implemented an upload command that allows you to pass in just the file name and the framework takes care of parsing it properly. The upload example will now look like:

const path = require('path');
const filePath = path.join(__dirname, 'path/to/your/file');

const remoteFilePath = browser.uploadFile(filePath);
$('.upload-data-file-input').setValue(remoteFilePath);

Note that the remote file name is different from your local filename. Therefore you need to set the value based on the remote file name you get from the uploadFile command.

That was it!!! Happy Uploading ๐Ÿ˜‰๐Ÿ™Œ๐Ÿป โค๏ธ

ยท 5 min read

We are pleased to announce that we now have a new Visual Regression service for WebdriverIO V5 called wdio-image-comparison-service.

What can it do?

wdio-image-comparison-service is a lightweight WebdriverIO service for browsers / mobile browsers / hybrid apps to do image comparison on screens, elements or full page screens.

You can:

  • save or compare screens / elements / full page screens against a baseline
  • automatically create a baseline when no baseline is there
  • blockout custom regions and even automatically exclude a status and or tool bars (mobile only) during a comparison
  • increase the element dimensions screenshots
  • use different comparison methods
  • and much more, see the options here

The module is now based on the power of the new webdriver-image-comparison module. This is a lightweight module to retrieve the needed data and screenshots for all browsers / devices. The comparison power comes from ResembleJS. If you want to compare images online you can check the online tool.

It can be used for:

  • desktop browsers (Chrome / Firefox / Safari / Internet Explorer 11 / Microsoft Edge)
  • mobile / tablet browsers (Chrome / Safari on emulators / real devices) via Appium
  • Hybrid apps via Appium

For versions check below:

Sauce Test Status

Installation

Install this module locally with the following command to be used as a (dev-)dependency:

npm install --save-dev wdio-image-comparison-service

Instructions on how to install WebdriverIO can be found here.

Usage

wdio-image-comparison-service supports NodeJS 8 or higher

Configuration

wdio-image-comparison-service is a service so it can be used as a normal service. You can set it up in your wdio.conf.js file with the following:

const { join } = require('path');

// wdio.conf.js
exports.config = {
// ...
// =====
// Setup
// =====
services: [
['image-comparison',
// The options
{
// Some options, see the docs for more
baselineFolder: join(process.cwd(), './tests/sauceLabsBaseline/'),
formatImageName: '{tag}-{logName}-{width}x{height}',
screenshotPath: join(process.cwd(), '.tmp/'),
savePerInstance: true,
autoSaveBaseline: true,
blockOutStatusBar: true,
blockOutToolBar: true,
// ... more options
}],
],
// ...
};

More plugin options can be found here.

Writing tests

wdio-image-comparison-service is framework agnostic, meaning that you can use it with all the frameworks WebdriverIO supports like Jasmine|Mocha. You can use it like this:

describe('Example', () => {
beforeEach(() => {
browser.url('https://webdriver.io');
});

it('should save some screenshots', () => {
// Save a screen
browser.saveScreen('examplePaged', { /* some options*/ });

// Save an element
browser.saveElement($('#element-id'), 'firstButtonElement', { /* some options*/ });

// Save a full page screens
browser.saveFullPageScreen('fullPage', { /* some options*/ });
});

it('should compare successful with a baseline', () => {
// Check a screen
expect(browser.checkScreen('examplePaged', { /* some options*/ })).toEqual(0);

// Check an element
expect(browser.checkElement($('#element-id'), 'firstButtonElement', { /* some options*/ })).toEqual(0);

// Check a full page screens
expect(browser.checkFullPageScreen('fullPage', { /* some options*/ })).toEqual(0);
});
});

If you run for the first time without having a baseline the check-methods will reject the promise with the following warning:

#####################################################################################
Baseline image not found, save the actual image manually to the baseline.
The image can be found here:
/Users/wswebcreation/Git/wdio-image-comparison-service/.tmp/actual/desktop_chrome/examplePage-chrome-latest-1366x768.png
If you want the module to auto save a non existing image to the baseline you
can provide 'autoSaveBaseline: true' to the options.
#####################################################################################

This means that the current screenshot is saved in the actual folder and you manually need to copy it to your baseline. If you instantiate wdio-image-comparison-service with autoSaveBaseline: true the image will automatically be saved into the baseline folder.

Nice new feature

When you create a fullpage screenshot you might have some elements that stay in the view, like a stickyheader or a chatbox. These elements normally mess up the screenshot like you can see on the left side of the below image.

But you can now add elements that need to be hidden after the first scroll which will give you a result as you can see in the right side of the below image. This can be done by adding this property to your test:

browser.checkFullPageScreen('fullPage', {
hideAfterFirstScroll: [
$('nav-bar'),
$('chat-box'),
],
});

fullpage-example

Test result outputs

The save(Screen/Element/FullPageScreen) methods will provide the following information after the method has been executed:

const saveResult = {
// The device pixel ratio of the instance that has run
devicePixelRatio: 1,
// The formatted filename, this depends on the options `formatImageName`
fileName: 'examplePage-chrome-latest-1366x768.png',
// The path where the actual screenshot file can be found
path: '/Users/wswebcreation/Git/wdio-image-comparison-service/.tmp/actual/desktop_chrome',
};

See the Save output section in the output docs for the images.

By default the check(Screen/Element/FullPageScreen) methods will only provide a mismatch percentage like 1.23, but when the plugin has the options returnAllCompareData: true the following information is provided after the method has been executed:

const checkResult = {
// The formatted filename, this depends on the options `formatImageName`
fileName: 'examplePage-chrome-headless-latest-1366x768.png',
folders: {
// The actual folder and the file name
actual: '/Users/wswebcreation/Git/wdio-image-comparison-service/.tmp/actual/desktop_chrome/examplePage-chrome-headless-latest-1366x768.png',
// The baseline folder and the file name
baseline: '/Users/wswebcreation/Git/wdio-image-comparison-service/localBaseline/desktop_chrome/examplePage-chrome-headless-latest-1366x768.png',
// This following folder is optional and only if there is a mismatch
// The folder that holds the diffs and the file name
diff: '/Users/wswebcreation/Git/wdio-image-comparison-service/.tmp/diff/desktop_chrome/examplePage-chrome-headless-latest-1366x768.png',
},
// The mismatch percentage
misMatchPercentage: 2.34
};

See the Check output on failure section in the output docs for the images.

Support

If you need support you can find me on the wdio-image-comparison-service- Gitter channel, or click on this link Gitter chat

Happy testing!

Grtz,

The Blue Guy