LISBON 2018 DRUPAL DEVELOPER DAYS Browser Testing with Nightwatch.js Salvador Molina - @salva_bg www.adevfromtheplains.com
Diamond Sponsor
Platinum Sponsors
Gold Sponsors
About me... Salva Molina • PHP Developer. • Drupal.org (slv_): field_type_generator, nodejs_chat, entityreference_autocomplete… • Working as freelance: • Drupal & Symfony. • Security Audits. • Devops.
About me...
Nightwatch.js • Introduction & Motivation • 4 Artifacts to rule them all • Tips & Tricks
Motivation aka The Watermelon Effect
Deploying to production (no tests)
Introduction
Introduction
• 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
"src_folders" : [ "./tests/nightwatch/tests/" ], "output_folder" : "./tests/nightwatch/reports", "custom_commands_path" : "./tests/nightwatch/commands", "custom_assertions_path" : "./tests/nightwatch/assertions", "page_objects_path" : [ "./tests/nightwatch/pages/example" ], "globals_path" : "./tests/nightwatch/data/global.js", First Stop: Nightwatch.json (I)
"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 (II)
First Stop: Nightwatch.json (III) "dev" : { "launch_url" : "http://127.0.0.1:8000", "selenium_port" : 9515, "selenium_host" : "127.0.0.1", "default_path_prefix" : "", "desiredCapabilities": { "browserName": "chrome" } }
Bonus! - Nightwatch.conf.js 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'));
4 Artifacts to rule them all
• Commands. • Page Objects. • Asserts. • Global data. Artifacts Tests.
● Generic Actions across the site: ○ .closeWindow(). ○ .getValue(). ○ .saveScreenshot(). ○ .useXpath(). ● Custom commands. 2 Types: ○ Function-style. ○ Class-style. Commands
Function-Style (commands/myCommand.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; };
● Simple Test Demo 1
– 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)
● Simple Test - (With Page Objects) Demo 2
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.
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' }, Global Data (data/global.js)
Dependencies in remote Server: Demo 3: Remote Testing via Jenkins
Scenario
Scenario 1
Scenario 1 2
Scenario 1 2 3
Scenario 1 2 4 3
Scenario
Scenario
CI "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"] } } }
"test_workers": { "enabled": true, "workers": 2 } Tips & Tricks: Parallel exec
nightwatch --env chrome,firefox Tips & Tricks: Parallel exec (II)
"ci" : { "desiredCapabilities": { "browserName": "chrome", "chromeOptions": { "args": ["--headless", "window-size=1400,1000"] } } } Tips & Tricks: Remote, Headless
Tips & Tricks: Resources ● Official Docs: nightwatchjs.org. ● Starter Repo: https://github.com/salvamomo/nightwatch-starter. ● API CODE: https://github.com/nightwatchjs/nightwatch/tree/master/lib/api.
● All dependencies retrievable through npm. ● 4 Artifacts to rule them all. ● Good bye Selenium (mostly). ● Remote testing: Chrome + Nightwatch + Node. ● Almost fully extensible architecture. Recap...
Nightwatch 1.0 is coming
Questions? @Salva_bg salva.momo[at]gmail.com www.adevfromtheplains.com
Obrigado! @Salva_bg salva.momo[at]gmail.com www.adevfromtheplains.com

Browser testing with nightwatch.js