Image

Drupal 8 Javascript tests with Nightwatch.js and Docker

JavaScript Browser testing with Drupal 8

Drupal 8.6 introduced the Nightwatch.js browser automation tool to perform browser and JavaScript testing. That's a good news because current PHPUnit based javascript tests are prone to failure on ci and writing JavaScript tests in PHP is a bit... confusing.

It's part of the Drupal 8 Modernize Drupal's JavaScript initiative and let be honest, I am not very familiar with the Node.js ecosystem but it's always a good idea to use existing robust tools!

When you search on Google we can say that the hype is starting, but since Drupal 8 has been released it's often hard to avoid the roller coaster of emotions... wahoo what a great new way/tool/initiative in Drupal 8! Oh but we miss a UI, some documentation, some crucial features from Drupal 7....

For now Nightwatch.js with Drupal documentation is pretty light, you can find some information to setup and run tests in /core/tests/README.md and on the manual page JavaScript testing using Nightwatch.js.

This end-to-end tool integration in Drupal 8.6 is just starting and will not be fully usable on a production project before 8.7 as you can see with this issue.
Currently it support only Chromedriver even if Nightwatch.js should allow more drivers and there is still some work going on Nightwatch.js Commands to help running all JavaScript tests with Drupal.

For this article I am using this patch adding a Support install profile and language code params in drupalInstall Nightwatch command to have enough to test any website with an profile!

If you still want to start and see what's going on quickly without installing a full development stack, just keep reading.

Using Gitlab Ci with Drupal 8 to run Nightwatch.js tests

To run Nightwatch.js tests in Gitlab Ci you can use my configuration project Gitlab Ci for Drupal 8, it include Nightwatch.js test job, basically it run the test using Drupal 8 core web/core/package.json.

I use a custom Docker image that include Node, Yarn and Gitlab Ci services with Mariadb database because it's much more faster than SQLite.

Unfortunately currently services in Gitlab Ci do not let us use Selenium standalone Chrome driver properly, because the service can not access the host, see Accessing a Docker container service from another container service.

There is a bunch of workaround but all a bit tricky and adding too much complexity, so the solution for now is to include the service (Selenium server) in the image used to run the tasks. Luckily This issue could be resolved soon if this MR pass.

So here is a summary of the Gitlab CI configuration to run Nightwatch.js

Nightwatch Js:
  image: mogtofu33/drupal8ci:8.6-selenium
  /** ... Build + setup actions ... **/
  services:
    - mariadb:latest
  script:
    - cp .gitlab-ci/.env.ci ${WEB_ROOT}/core/.env || true
    - cd ${WEB_ROOT}/core
    - yarn install
    - yarn test:nightwatch --skiptags core
  variables:
    MYSQL_ALLOW_EMPTY_PASSWORD: "1"
    MYSQL_DATABASE: "drupal"

That's working nicely with Gitlab Ci as you can see in this job result. But what if you want to run this locally without installing all the tools: Webserver, database, Node, Yarn and even Drupal 8?

Test Drupal 8 locally with Docker

To run everything locally without any installation, the solution is to use Docker with Docker-compose to get all our tools shipped together to write and run tests locally.

I am using Ubuntu so it works fine there, should be good on Mac, but for Windows probably not.

I created a Drupal image based on the official Docker Drupal image with some tweaks, tools we need for our tests and more. The goal is to have something fast to create, reliable and easy to maintain.

With or without a local Drupal

The Docker image include Drupal 8.6, a variant include Selenium server to fit a custom module only test, when without Drupal you need a local Drupal 8 installed with composer, I suggest to use the Drupal template project.

If you just have your custom code, the Drupal 8.6 included is patched with Support install profile and language code params in drupalInstall Nightwatch command.

Get the needed files

On my Gitlab CI for Drupal 8 project, you can find a Docker compose files to have everything ready, it must be placed side of your custom module code in a web/modules/custom folder or your Drupal in a ./drupal folder for next part we will suppose you are just adding your custom code.

Grab the whole project and replace web/... with your custom module or use the included example.

Launch the Drupal 8 stack

The stack is based on official Docker images for Mariadb and Selenium/standalone-chrome.

To launch the stack we use Docker compose

docker-compose up -d

You can test the webserver is working properly by visiting

And test Chromedriver by visiting

Use Nightwatch.js to run JavaScript tests

You can run Nightwatch.js test, for example from core with Docker, optionally add --verbose flag to have more information

docker exec -it ci-drupal yarn test:nightwatch tests/Drupal/Nightwatch/Tests/exampleTest.js

And of course best now is to run your tests, note that the docker container working directory is ./core, you can use sample test from the project, it rely on a Drupal installation with profile Standard and give you some screenshots

docker exec -it ci-drupal yarn test:nightwatch ../modules/custom/my_d8_module/tests/src/Nightwatch/Tests/exampleTest.js

Or an other good approach is to use a specific @tag on your modules, so you can use it to run all your tests

docker exec -it ci-drupal yarn test:nightwatch --tag my_module

Or run all tests except core with --skiptags

docker exec -it ci-drupal yarn test:nightwatch --skiptags core

Result will be saved in ./reports folder.

Some tips for using Nightwatch.js test with Drupal 8

First you can edit core/.env file to change the base resolution for Chromedriver (My image is set with screen resolution to 1920*1080, the default Selenium standalone is 1360 x 1020 (?))

During the test you can resize the browser to have a screenshot on different viewport with browser.resizeWindow(375, 812). And taking a screenshot is pretty easy with browser.saveScreenshot(`${browser.screenshotsPath}/my_screenshot.jpg`)

For a more advanced usage check Nightwatch.js API, Nightwatch.js commands and Drupal sample tests is a good source of inspiration.

Any suggestion? Feel free to add a comment.

If you need some help to implement this kind of testing on your project, I can provide you some Drupal 8 expertise, just contact me with the form at the bottom of this page.

Comments