Automate UI testing with Mocha and Puppeteer (Updated)

Github: https://github.com/railsstudent/image-gallery-native-js

1) yarn add puppeteer mocha chai

yarn add puppeteer mocha chai

2) Create bootstrap.js file to share global variables among tests. Expose chai.expect, chai.assert and an instance of browser

'use strict';
 
const puppeteer = require('puppeteer');
const chai = require('chai');
const expect = chai.expect;
const globalVariables = { 
    browser: global.browser,
    expect: global.expect
};
 
// puppeteer options
const opts = {
  headless: true,
  slowMo: 150,
  timeout: 50000
};
 
// expose variables
before (async function () {
  global.expect = expect;
  global.browser = await puppeteer.launch(opts);
});
 
// close browser and reset global variables
after (function () {
  global.browser.close();
 
  global.browser = globalVariables.browser;
  global.expect = globalVariables.expect;
});

3) Puppeteer creates a headless browser that timeout after 50 seconds and slow down operation by 150 milliseconds.

// puppeteer options
const opts = {
  headless: true,
  slowMo: 150,
  timeout: 50000
};

4) Set up npm script commands in package.json to load the variables in bootstrap.js and execute all UI test cases in test/gallery.test.js directory

 "scripts": {
    "serve:test": "gulp build && http-server dist/ -p 8000",
    "puppeteer": "rm ./test/*.png; SCREEN_SHOT=false mocha test/bootstrap.js test/gallery.test.js",
    "puppeteer-screenshot": "rm ./test/*.png; SCREEN_SHOT=true mocha test/bootstrap.js test/gallery.test.js"
 }

5) Write mocha test case in test file.

describe('gallery test', function() {
  let page;
  this.timeout(TIMEOUT);
 
  before(async () => {
    try {
      page = await browser.newPage();
      await page.goto('http://localhost:8000/');
    } catch (e) {
      console.error(e);
    }
  });
 
  after(async () => {
    await page.close();
  });
 
 it('Shows first image src is not blank and has correct caption and visible buttons', 
     async () => {
    try {
      await page.waitForSelector('.image:nth-child(1)', { visible: true, timeout: 0 });
      await page.screenshot( {
        path: './test/test4.png'
      });
 
      const imageElement = await page.$('.image:nth-child(1)');
      await imageElement.click(); 
      await page.screenshot( {
        path: './test/test5.png'
      });
 
      const modalHandle = await page.$('.modal.show');
      const imageSrc = await page.evaluate((modal) => 
                modal.querySelector('#modal-image').src, modalHandle);
      const caption = await page.evaluate((modal) => 
                modal.querySelector('#caption').innerText, modalHandle);
      const [btnCloseDisplay, btnCloseOpacity,
        btnLeftDisplay, btnLeftOpacity,
        btnRightDisplay, btnRightOpacity
      ] = await page.evaluate((modal) => { 
        const { opacity: closeOpacity, display: closeDisplay } 
             = window.getComputedStyle(modal.querySelector('.close'));
        const { opacity: leftOpacity, display: leftDisplay } 
             = window.getComputedStyle(modal.querySelector('.left-arrow'));
        const { opacity: rightOpacity, display: rightDisplay } 
             = window.getComputedStyle(modal.querySelector('.right-arrow'));
        return [
          closeDisplay, closeOpacity,  
          leftDisplay, leftOpacity,
          rightDisplay, rightOpacity 
        ];
      }, modalHandle);
 
      expect(imageSrc).to.not.equal('');
      expect(caption).to.equal(`1 of ${NUM_IMAGES}`);
      expect(btnCloseDisplay).to.equal('inline-block');
      expect(btnRightDisplay).to.equal('inline-block');
      expect(btnLeftDisplay).to.be.equal('block');
      expect(btnCloseOpacity).to.equal('1');
      expect(btnRightOpacity).to.equal('1');
      expect(btnLeftOpacity).to.equal('0');
 
      const closeHandle = await page.$('.modal.show .close');
      await closeHandle.click();      
      closeHandle.dispose();
      modalHandle.dispose();
    } catch (e) {
      console.error(e);
      throw e;
    }
  });
});

6) Build development version and serve website at http://localhost:8000

yarn serve:test

7) Run UI test cases without creating screen shots

yarn puppeteer

8) Run UI test cases that creates screen shots

yarn puppeteer-screenshot

Finally, we are done.

Projects built in July, 2018

Angular

Vanilla JS, SCSS, HTML

Import bootstrap, ng-bootstrap and font-awesome in angular app

1) yarn add bootstrap @ng-bootstrap/ng-bootstrap font-awesome

yarn add bootstrap @ng-bootstrap/ng-bootstrap font-awesome

2) In style.scss, import bootstrap and font-awesome

  1. @import "~bootstrap/scss/bootstrap";
  2. $fa-font-path : '../node_modules/font-awesome/fonts';
  3. @import "~font-awesome/scss/font-awesome";

4) type ng serve to launch application in development mode. Index page should open at url http://localhost:4200.

ng serve