robzolkos
robzolkos

Reputation: 2276

Integration/Acceptance testing of a ReactJS App

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.

Upvotes: 10

Views: 3415

Answers (2)

Abhinaba
Abhinaba

Reputation: 424

you can now use protractor-react-selector to identify web elements by react's component, props, and state. This will automatically wait to load REACT in your app and then identify the web elements. It can save you from doing an extra ton of workarounds.

You can identify your target element by:

const myElement = element(
    by.react('MyComponent', { someBooleanProp: true }, { someBooleanState: true })
);

Find out some sample tests here

Let me know if this helps!

Upvotes: 1

Hayo
Hayo

Reputation: 149

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.

Upvotes: 3

Related Questions