A Mind United

Development notes, docs, and scribbles.

Nightwatch VRT Setup

August 1, 2019

npm Install


npm install nightwatch nightwatch-vrt nightwatch-vrt-reporter concurrently selenium-standalone wait-on chromedriver --save-dev

Add Run scripts:

    "selenium:install": "selenium-standalone install",
    "selenium:start": "selenium-standalone start & echo $! > selenium.pid",
    "selenium:stop": "kill $(< selenium.pid); rm selenium.pid",
    "nightwatch:chrome": "nightwatch -c ./nightwatch.conf.js -e chrome -r ./node_modules/nightwatch-vrt-reporter/lib/index.js",
    "vrt:runner": "npm run selenium:start ; sleep 2 ; npm run nightwatch:chrome; npm run selenium:stop",
    "vrt": "concurrently 'npm run start' '$(npm bin)/wait-on http://localhost:4200 && npm run vrt:runner' --kill-others --success first",
    "vrt:accept": "rm -rf ./visual-regression/screens/baseline; npm run vrt"

Create a config for Nightwatch:

touch nightWatch.conf.js && cat nightWatch.conf.js <<EOL
const SCREENSHOT_PATH = './visual-regression/screens/';

// we use a nightwatch.conf.js file so we can include comments and helper functions
module.exports = {
  src_folders: [ './visual-regression/tests' ],
  output_folder: './visual-regression/report',
  selenium: {
    start_process: false, // tells nightwatch to start/stop the selenium process
    host: '127.0.0.1',
    port: 4444, // standard selenium port
  },
  globals_path : "./visual-regression/nightwatchGlobals.js",
  custom_commands_path: [ 'node_modules/nightwatch-vrt/commands', './visual-regression/commands' ],
  custom_assertions_path: [ 'node_modules/nightwatch-vrt/assertions' ],
  test_settings: {
    default: {
      silent: true,
      globals: {
        waitForConditionTimeout: 5000, // sometimes internet is slow so wait.
        visual_regression_settings: {
          latest_screenshots_path: "./visual-regression/screens/latest",
          baseline_screenshots_path: "./visual-regression/screens/baseline",
          diff_screenshots_path: "./visual-regression/screens/diff",
          threshold: 0.05,
          prompt: false,
          always_save_diff_screenshot: false
        }
      }
    },
    chrome: {
      desiredCapabilities: {
        browserName: "chrome",
        chromeOptions: { args: [ "--headless", "--disable-gpu", "--window-size=800,600" ] },
        javascriptEnabled: true // turn off to test progressive enhancement
      }
    },
    firefox: {
      desiredCapabilities: {
        browserName: 'firefox',
        acceptInsecureCerts: true,
        "moz:firefoxOptions": {
          args: ["--headless"]
        },
        javascriptEnabled: true // turn off to test progressive enhancement
      }
    }
  }
}
EOL

Create a visual-regression directory in your project root


mkdir visual-regression && cd $_ && mkdir commands && mkdir screens && mkdir screens/diff && mkdir screens/baseline && mkdir screens/latest && mkdir tests

Add a utils script

(still in the visual-regression directory)

touch utils.js && cat utils.js <<EOL
module.exports =  {
  globalThreshold: 0.001,
  getBrowser(config) {
    if (config.test_settings.chrome && config.test_settings.chrome.output) {
      return 'chrome';
    } else if (config.test_settings.firefox && config.test_settings.firefox.output) {
      return 'firefox';
    } else {
      return 'unknown';
    }
  }
}
EOL

Setup Globals

(still in the visual-regression directory)

touch nightwatchGlobals.js && cat nightwatchGlobals.js <<EOL
module.exports =  {
  // before : function(cb) {
  //   console.log('GLOBAL BEFORE')
  //   cb();
  // },

  // beforeEach : function(browser, cb) {
    // console.log('GLOBAL beforeEach')
    // cb();
  // },

  // after : function(cb) {
    // console.log('GLOBAL AFTER')
    // cb();
  // },

  afterEach : function(browser, cb) {
    browser.perform(function() {
      console.log('GLOBAL afterEach')
      cb();
    })
  }
}
EOL

Create some example commands:

(still in the visual-regression directory)

** also this cat command doesn’t work :(


touch commands/testIndexPage.js && cat commands/testIndexPage.js <<EOL
var util = require('util');
var EventEmitter = require('events');

function TestIndexPage() {
  EventEmitter.call(this);
}

util.inherits(TestIndexPage, EventEmitter);

TestIndexPage.prototype.command = function(screenWidth, browserName, cb) {
  browser = this;
  if (!screenWidth || !browserName) {
    return browser;
  }
  // Replace '.my-element' with a reference for your page
  browser.api.waitForElementPresent('.my-element', 10000);
  browser.api.resizeWindow(screenWidth, 1080)
    .pause(3000)
    .verify.screenshotIdenticalToBaseline('body', `${screenWidth}/body/${browserName}`, {threshold: 0.05})

  setTimeout(function() {
    // if we have a callback, call it right before the complete event
    if (cb) {
      cb.call(browser.client.api);
    }

    browser.emit('complete');
  }, 100);

  return browser;
};

module.exports = TestIndexPage;
EOL


Create an example test

cat tests/example-page.js <<EOL
let utils = require('../utils');
let config = require('../../nightwatch.conf.js');

module.exports = { // adapted from: https://git.io/vodU0
  'All Components page': function(browser) {
    browser.url('http://localhost:8080/')
      .testIndexPage(320, browser.capabilities.browserName)
      .testIndexPage(600, browser.capabilities.browserName)
      .testIndexPage(1080, browser.capabilities.browserName)
      .end();
  }
}

EOL

Setup Selenuim (you’ll have to do this in your CI too)

npm run selenium:install