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
- http://localhost:88 (Should show the Drupal install page)
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.