Skip to content

Instantly share code, notes, and snippets.

@tomazzaman
Created January 21, 2016 15:12
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tomazzaman/790bc607eb7ca3fd347f to your computer and use it in GitHub Desktop.
Save tomazzaman/790bc607eb7ca3fd347f to your computer and use it in GitHub Desktop.

Integration testing

While you should always strive for 100% test coverage, it's sometimes impractical and time consuming to test every single bit of your code, which is why we sometimes tend to skip the small, seemingly unbreakable parts.

I've pushed code to production in the past that broke the whole application just because I untroduced a syntax error in one of the small helper files by mistake and rendered the whole application unusable.

To avoid making the same mistake again, I decided to write one single integration test that loads the whole application (as it was opened in a browser) and checks whether it actually loads. Then, to take it jsut a bit furher, it tries to log in (Because the login screen is what appears first when the app loads). All of this in the terminal.

Here's the test, and it doesn't require AVA to run, just use

$ NODE_ENV=test babel-node test/integration/login.scenario.js

Here's the script:

import path from 'path';
import assert from 'assert';
import proxyquire from 'proxyquire';
import nock from 'nock';
import jsdom from 'jsdom';
import mockLocalStorage from '../mockLocalStorage.js';

process.env.NODE_PATH = path.resolve(__dirname, '..', '..', '..', 'client', 'js');
require('module').Module._initPaths();

const markup = '<!doctype html><html><body><div id="root"></div></body></html>';
const virtualConsole = jsdom.createVirtualConsole().sendTo(console);
const document = jsdom.jsdom(markup, { virtualConsole });
const win = document.defaultView;

mockLocalStorage(win, document);

((window) => {
  for (const key in window) {
    if (! window.hasOwnProperty(key)) continue;
    if (key in global) continue;
    global[ key ] = window[ key ];
  }
})(win);

const noCallThru = {
  '@noCallThru': true,
  '@global': true,
};

const config = Object.assign({}, noCallThru, {
  apiUrl: 'http://test.com',
});

const stubs = {
  '../../../img/logo.svg': noCallThru,
  '../../img/logo.svg': noCallThru,
  '../../img/modal-close.svg': noCallThru,
  '../scss/styles.scss': noCallThru,
  'config': config,
}

nock(config.apiUrl)
  .defaultReplyHeaders({ 'Content-Type': 'application/json' })
  .post('/user/login')
  .replyWithFile(200, 'mocks/user/login.json');

nock(config.apiUrl)
  .defaultReplyHeaders({ 'Content-Type': 'application/json' })
  .get('/user/performance')
  .replyWithFile(200, 'mocks/user/performance.json');

window.doneRendering = function() {
  const root = document.getElementById('root');
  const emailInput = document.querySelector('#email');
  const button = document.querySelector('button');

  // Some manualy work, just like we'd to it in browser
  emailInput.value = 'john@test.com';
  button.click();

  // Wait a reasonable amount so that React can re-render properly
  setTimeout(function() {
    const header = document.querySelector('h1');
    assert.equal(header.innerHTML, 'Showing performance for last 30 days');
    nock.cleanAll();

    console.log('Integration test complete. Passed with flying colors!');
  }, 100);
};

proxyquire('../../js/index.js', stubs);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment