Introduction

The idea behind gremlins testing is pretty simple: any user action on your application should not have throw a runtime error. It's like a smoke test with lots of random user's actions. This should be helpful when your project has unit tests but you're not ready yet for end to end tests.

Implementation

  • Install the lib: yarn add gremlins.js -D
  • Copy gremlins to hosted directory (e.g. dist) cp node_modules/gremlins.js/dist/gremlins.min.js dist
  • Open your app in a browser
  • In the browser console add gremlins to DOM const s = document.createElement('script'); s.src='gremlins.min.js'; document.head.appendChild(s);
  • Run the gremlins gremlins.createHorde().unleash()
  • In result gremlins will execute buch od random events

Image description

If in console there's no error test passes

Automatisation

Of course we can not run it manually each time. To automate it we can use the puppeteer, it's a nodeJS chromium driver. After installation yarn add puppeteer -D do something like this:

// run-gremlins.js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  const errors = [];
  page.on('pageerror', (error) => {
    browserErrors.push(error);
  });
  await page.goto('localhost:4200');
  if (browserErrors.length !== 0) {
    errors.forEach((e) => {
      console.error('e2e error: ', e);
    });
    process.exit(1);
  }

  // TODO: insert gremlins
  // TODO: run gremlins
  // TODO: wait 5s

  await browser.close();
})();
Enter fullscreen mode Exit fullscreen mode

This code will run a browser (in incognito mode to have cookies cleared), open new a page on localhost:4200, run gremlins like in the previous part and if any page error appears process will close with falsy status.

missing parts:

module.exports.insertGremlins = async (page) => {
  await page.evaluate(() => {
    const s = document.createElement('script');
    s.src='gremlins.min.js'; 
    document.head.appendChild(s);
  });
};

module.exports.runGremlins = async (page) => {
  await page.evaluate(() => {
    window.gremlins.createHorde().unleash()
  });
};

module.exports.wait = (time) =>
  new Promise((resolve) => {
    setTimeout(resolve, time);
  });
Enter fullscreen mode Exit fullscreen mode

Verification

To be sure that gremlins are gonna catch an error, add something like this to the app: setTimeout(() => { throw new Error('debug'); }, 3000); . If command node run-gremlins.js will exit with falsy code then the tester works correctly :)

Run on docker

Best way to be sure that tester is working on other environment (like CI) is wrap it into a docker container. Unfortunately we need to install some dependencies in the container.

FROM node:16.13.1 # Specific version, not the lastest

RUN ["apt-get", "update"]
RUN apt-get install gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils -y
RUN apt-get update 
     && apt-get install -y wget --no-install-recommends 
     && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - 
     && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' 
     && apt-get update 
     && apt-get install -y google-chrome-unstable --no-install-recommends 
     && rm -rf /var/lib/apt/lists/* 
     && wget --quiet https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh -O /usr/sbin/wait-for-it.sh 
     && chmod +x /usr/sbin/wait-for-it.sh
Enter fullscreen mode Exit fullscreen mode

To allow root user run puppeteer add --no-sandbox flag into run-gremlins.js file:

const browser = await puppeteer.launch({
  args: ['--no-sandbox'],
});
Enter fullscreen mode Exit fullscreen mode

In this case your local web application has to run in the same container, however you can add --network=host to the previous command to allow gremlin-tester to communicate with a localhost.

I'm using it, it saves a lot of my time. Maybe someone else will to take advantage of it.