www.drupaleurope.org
Salva Molina
Browser Testing
Session URL: https://www.drupaleurope.org/session/browser-testing-nightwatchjs
with Nightwatch.js
13/9/2018
Salva Molina
PHP Engineer
@salva_bg
Drupal.org: slv_
Freelance
Drupal & Symfony.
Security Audits.
Devops.
Me
Nightwatch.js
A somewhat familiar Friday for every developer.
The watermelon effect
“
“
Deploying to production (no tests)
Introduction
What’s Nightwatch.js
Introduction
What’s Nightwatch.js
Test Runner with parallel execution support.
JUnit-compliant XML reports.
assert-like and expect-like validations.
Hooks: before, beforeEach, after, afterEach.
Unit Testing support.
Main Features
The bread and butter
"src_folders" : [
"./tests/nightwatch/tests/"
],
"output_folder" : "{...}/reports",
"custom_commands_path" : "{...}/commands",
"custom_assertions_path" : "{...}/assertions",
"page_objects_path" : [
"{...}/pages/example"
],
"globals_path" : "{...}/global.js",
First Stop: Nightwatch.json
Paths
"selenium" : {
"start_process" : true,
"server_path" : "./tests/bin/selenium-server-standalone-3.13.0.jar",
"log_path" : "",
"port" : 34567,
"cli_args" : {
"webdriver.chrome.driver" : "./tests/bin/chromedriver"
}
},
First Stop: Nightwatch.json
Selenium and Webdrivers
"dev" : {
"launch_url" : "http://127.0.0.1:8000",
"selenium_port" : 9515,
"selenium_host" : "127.0.0.1",
"default_path_prefix" : "",
"desiredCapabilities": {
"browserName": "chrome"
}
}
First Stop: Nightwatch.json
Environments
var selenium = require('selenium-server');
var chromedriver = require('chromedriver');
module.exports = (function(settings) {
settings.selenium.server_path = selenium.path;
settings.selenium.cli_args["webdriver.chrome.driver"] = chromedriver.path;
return settings;
})(require('./nightwatch.json'));
Fully-customized setup
Nightwatch.conf.js
Main header
Subtitle
4 Artifacts to rule them all
Commands.
Page Objects.
Asserts.
Global Data.
Artifacts
Tests.
Many provided by default, like:
.closeWindow.
.setValue.
.saveScreenshot.
.click.
Commands
Generic actions to perform across the site
Custom Commands
commands/clickWithMessage.js
exports.command = function (selector, message) {
// Click and display a message for the action.
this.click(selector, function() {
if (this.globals.test_settings.disable_colors === true) {
console.log(' ✔ ' + message);
}
else {
console.log('\033[92m ✔ \033[0m' + message);
}
});
return this;
};
Martin Fowler.
Page objects are a classic example of encapsulation - they hide the details of the UI structure and widgetry from other components (the tests).
“
“
Page Objects
pages/myPage.js
Page Objects
pages/myPage.js
Page Objects
pages/myPage.js
Page Objects
pages/myPage.js
Assertions
assertions/myAssertion.js
exports.assertion = function(selector, comparedValue, msg) {
this.message = msg || util.format('Testing if value of <%s> does not equal: "%s".', selector, comparedValue);
this.expected = comparedValue;
this.command = function(callback) {};
this.value = function(result) {};
this.pass = function(value) {};
};
BDD Expect Assertions
checkFieldAttribute: function(fieldName, attr, Value) {
this
.expect.element(fieldName).to.have.attribute(attr).equals(Value);
return this;
},
Language Chains: to, be, been, is, that, which, and, has, have, with, at, does, of.
Global Data
data/globals.js
user: {
username: 'test3',
password: 'AcceptableUserPassword_-',
},
unexisting_user: {
username: 'nightwatch_' + Date.now(),
firstname: 'NW_First',
display_name: 'NW_First' + 'Surname' + Date.now(),
email: 'nightwatch_' + Date.now() + '@.example.net'
},
Simple Test with & w/o Page Objects.
Demo 1
Remote testing via Jenkins
Dependencies on the remote Server
Scenario
1
Scenario
1
2
Scenario
1
2
3
Scenario
Scenario
1
2
4
3
CI Configuration
"ci" : {
"launch_url" : "http://{http_auth_user}:{http_auth_pass}@127.0.0.1:8000",
"selenium_port" : 9515,
"selenium_host" : "127.0.0.1",
"default_path_prefix" : "",
"selenium" : {
"start_process": false
},
"desiredCapabilities": {
"browserName": "chrome",
"chromeOptions": {
"args": ["--headless"]
}
}
}
LIVE DEMO:�Graphical representation
Remote Testing via Jenkins
Demo 2
Drupal commands
Nightwatch & Drupal
CreateRole, CreateUser, Login, Logout, RelativeURL, UserIsLoggedIn.
Commands
Available in 8.6.0
Install, LoginAsAdmin, Uninstall.
Script-based
Web-based
Don’t need to go through any Nightwatch documentation.
Very simple and fast setup. No custom package.json needed:
yarn install
yarn test:nightwatch
Drupal Setup
Pros
Page Objects not supported yet.
Some use cases not covered (no multiple env setup).
Need to download some other npm dependencies that you might not want for remote testing.
Still lots to do. Can’t easily enable modules, place blocks, etc.
Drupal Setup
Cons
Module developer: YES! or… yes?
For customer sites: I would not.
Instead: Use your own setup, and simply point its config to the commands provided by core that are somewhat usable outside of core testing.
Commands
So, should I use Core commands for my tests?
Why Nightwatch?
Why Nightwatch?
Official Docs!
Quick install: https://github.com/salvamomo/nightwatch-starter.
Resources
Some links, tools and interesting reads
DevOps + Infrastructure
13/9/2018
TRACK SUPPORTED BY
Questions?
Danke fürs Kommen
@salva_bg
salva.momo[at]gmail.com
www.adevfromtheplains.com