Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integration/Acceptance testing of a ReactJS App

Tags:

reactjs

I've read the documentation about Jest. However this seems to imply unit testing of individual components.

How does one test integration of components, or acceptance testing a feature of a web app written with React JS (with Flux).

eg Testing the checkout flow in an e-commerce React app.

  1. User can login
  2. User can browse the product catalogue
  3. User can add product to cart
  4. User can checkout

Angular has e2e testing with Protractor, Ember also has end to end acceptance testing. I cannot find anything for React apps.

like image 418
robzolkos Avatar asked Apr 02 '15 15:04

robzolkos


People also ask

What is integration acceptance testing?

Integration testing focuses on ensuring various components within a program or system can function together well. Acceptance testing focuses on the client's use of the system and how it functions as a whole unit, rather than on the specific interaction between different aspects.

What is the best testing framework for Reactjs?

For web apps that are based on React, Jest is the preferred framework. Apart from React, Jest supports unit testing of Angular, VueJS, NodeJS, and others.

What types of tests can be applied to a React application?

Types of Testing in React As the React documentation states, there are essentially two types of testing for React components — rendering component trees, and end-to-end testing for an app.


1 Answers

The way I solved the problem is to start several processes or services in order to test e2e with mocha:

  1. Webserver: I start a simple webserver (like express) that provides the webpack build packages (https://www.npmjs.com/package/express)
  2. Selenium: for controlling the browser (https://www.npmjs.com/package/selenium-standalone)
  3. mocha within a 'child_process' fork

This looks in my test_runner.js file following which I start with 'node test_runner.js':

 var async = require('async');
 var web_runner = require('./web_server');'
 //... and other runner scripts

 var start = function () {
   console.log('Starting services:');
   async.series([
       function (callback) {
          web_runner.start(args[0], callback);
       },
       function (callback) {
           selenium_runner.start(callback);
       },
       function (callback) {
            mocha_runner.start(args[0], args[1], callback);
       },
       function (callback) {
            selenium_runner.stop(callback_stop, 0);
            mock_runner.stop(callback_stop);
            web_runner.stop(callback_stop);
            callback();
       }
   ]);
};
start();

Once the test is done the function stops all services.

The webserver should be no problem to start. I had some difficilises with the selenium start and found a nice way here: https://github.com/nkbt/nightwatch-autorun/blob/master/index.js

var selenium = require('selenium-standalone');

function onSeleniumStarted(err, seleniumChild) {
  if (err) {
      process.exit(1);
  }
  process.on('uncaughtException', err2 => {
     console.error(err2.stack);
     seleniumChild.kill('SIGINT');
     process.exit(1);
  });
  startServer(onServerStarted(seleniumChild));
}

function onSeleniumInstalled(err) {
  if (err) {
     console.error(err.stack);
     process.exit(1);
   }
   selenium.start({seleniumArgs: ['-debug']}, onSeleniumStarted);
}

selenium.install({}, onSeleniumInstalled);

The mocha is then basically a node process that starts and looks like this in javascript:

module.exports = {
    start: function (env, test_path, callback) {
        var env_mocha = {env: process.env.ENV = env};
        console.log('Start mocha with:', env_mocha, mocha, test_path);
        cp.fork(mocha,
            [
                test_path
            ], [
                env_mocha
            ])
            .on('error', function (error) {
                runner.stop(error);
                return process.exit(1);
            })
            .on('close', function (code) {
                callback();
            });
    },
    stop: function (reason) {
        return process.exit(reason);
    }
}

Now the test cases have to use a selenium driver. I choose webdriverIO, but there are other alternatives (see here: http://www.slant.co/topics/2814/~node-js-selenium-webdriver-client-libraries-bindings)

var env = process.env.ENV;
var webdriverio = require('webdriverio');
var assert = require('assert');

describe('File: some_test_spec', function () {

    var client = {};

    before(function (done) {
        client = webdriverio.remote({desiredCapabilities: {browserName: 'chrome'}});
        client.init(done);
    });

    after(function (done) {
        client.end(done);
    });

    describe('Login success', function () {
            before(function (done) {
                // user needs to be logged in 
                client
                    .url(url_start)
                    .waitForVisible('#comp\\.user\\.login\\.button', 1000)
                    .setValue('#comp\\.user\\.login\\.email', '[email protected]')
                    .setValue('#comp\\.user\\.login\\.password', 'mysecret')
                    .click('#comp\\.user\\.login\\.button')
                    .waitForVisible('#comp\\.user\\.home', 1000)
                    .call(done);
            });
     });
});

Last note: Phantomjs does not work with the .bind(this) function of react, therefore the Phantomjs Browser is no option at the moment. Reason is explained here: https://groups.google.com/forum/#!msg/phantomjs/r0hPOmnCUpc/uxusqsl2LNoJ

Hope this helped ;) Good luck.

like image 56
Hayo Avatar answered Oct 24 '22 14:10

Hayo