Testing Piscosour

There are to ways to test piscosour recipes: unit testing and functional testing (integration). Both could be functional but the main difference is that unit testing runs as a node library inside the test and functional testing (integration) runs the recipe as a system executable using require('child_process').exec.

  1. Unit Testing
  2. Functional Testing (integration)

Unit testing

  1. Testing steps
  2. Testing plugins
  3. Testing contexts

Needed to test steps, plugins (coming soon) and contexts (coming soon)

Testing steps

Steps only need dependency to piscosour on devDependencies. Add dependencies to mocha and chai too.

NOTE: If you need a context definition for the step execution, then the dependency to the context has to be on devDependencies too. for example pisco-contexts

package.json:

{
  "...":"...",
  "scripts": {
    "deps": "npm install",
    "test": "node_modules/.bin/mocha -u tdd --recursive"
  },
  "devDependencies": {
    "chai": "*",
    "mocha": "*",
    "piscosour": "^1.0.0"
  },
  "...":"..."
}

Writing a test for piscosour. First require stepTester

 const tester = require('piscosour/lib/tests/stepTester');
  1. command object
  2. setLoggerLevel(level) method
  3. loadStep(command) method
  4. runStep(command) method

command object.

The command object is the configuration parameter that piscosour uses to run the test.

Param Type Optional Description
name String No The name of the step
context Array Yes Array of the contexts runned
baseDir String Yes Folder where the step is going to be runned. Default is the root of the recipe.
params Object Yes All params passed for the execution

setLoggerLevel(level) method

logger.setLoggerLevel(level) set logger level for piscosour. See logger for more information

Param Type Optional Description
level Number No 0...5 log levels

loadStep(command) method

logger.loadStep(command) Load local step with all plugins and all piscosour configuration. Returns step object with all piscosour features loaded.

Param Type Optional Description
command Object No See command object

runStep(command) method

logger.runStep(command) Run one local step from the recipe. Returns a promise with the execution of the step.

Param Type Optional Description
command Object No See command object

This is a example of an entire test file.

'use strict';

const path = require('path');
const tester = require('piscosour/lib/tests/stepTester');
const expect = require('chai').expect;
const assert = require('assert');

/* global define, it, describe, before, beforeEach, afterEach, after */

// configure

tester.setLoggerLevel(0);

// constants

const stepName = 'askHello';
const contexts = ['world'];
const message = 'Unit Framework hola!';

describe('Unit testing framework for askHello step', () => {
  it('Should return the step to test', (done) => {
    const step = tester.loadStep({
      name: stepName,
      context: contexts
    });
    expect(step).not.equal(null);
    expect(step.name).to.equal(stepName);
    done();
  });
  it('Should run the step to test', (done) => {
    tester.setLoggerLevel(0);
    tester.runStep({
        name: stepName,
        context: contexts,
        baseDir: path.join(__dirname, 'world'),
        params: {
          paramInquire: message
        }
      })
      .then(() => {
        done();
      })
      .catch((err) => {
        done(err);
      })
  });
  it('Should run the step with plugins to test', (done) => {
    tester.setLoggerLevel(0);
    tester.runStep({
        name: 'emittingHello',
        context: contexts,
        baseDir: path.join(__dirname, 'world'),
        params: {
          paramInquire: message
        }
      })
      .then(() => {
        done();
      })
      .catch((err) => {
        done(err);
      })
  });
});

Testing plugins

(comming soon)

Testing contexts

(comming soon)

Functional testing (integration)

  1. Configure the recipe
  2. Writing tests
  3. Running tests

The functional testing features are:

Configuring the recipe for testing

  1. Add "test" : "bin/pisco.js -ft" to the scripts object in package.json.
  2. Add dependencies to one or more functional-testing modules.

Fragment of package.json of a recipe.

{
  "scripts": {
    "deps": "npm install",
    "test": "bin/pisco.js -ft"
  },
  "keywords": [
    "piscosour-recipe"
  ],
  "bin": {
    "cells": "bin/pisco.js"
  },
  "dependencies": {
    "piscosour": "^1.1.0"
  },
  "devDependencies": {
    "pisco-functional-tests": "^1.0.1-beta"
  },
  "...":"..."
}

Writing the tests (the functional testing module)

Fragment of package.json of the functional testing module:

{
  "...":"...",
  "keywords": [
    "functional-tests"
  ],
  "dependencies": {
    "chai": "*",
    "mocha": "*"
  },
  "...":"..."
}

Now tests must execute the command piscoExec that is injected as an environment variable.

This is an example of tests that we can be written. This test proves the creation of an app using cells-cli recipe.

'use strict';

const pctp = require('pisco-callback-to-promise');
const u = require('../utils');

const fs = require('fs-extra');
const path = require('path');
const exec = require('child_process').exec;

/* global define, it, describe, before, beforeEach, afterEach, after */

// constants

const baseApp = `${__dirname}/../tmp`;

// ---- Tests --------

describe('Run cells app:create', function() {

  const allOk = '[ create ] finished';
  this.timeout(6000);

  it(`Should create a list of apps and say "${allOk}" on all apps`, function(done) {
    pctp.c2p(fs.ensureDir, baseApp)
      .then(() => pctp.c2p(exec, `${process.env.piscoExec} app:create --scaffoldDir scaffold --appName test-app`, {cwd: baseApp}))
      .catch((err) => pctp.logError(err, done));
  });
  afterEach('Should delete the tmp directory', (done) => {
    u.remove([ baseApp ])
      .then(() => done());
  });
});

Let's see this example:

Running functional tests

export piscoExec="node /Users/sbonacho/projects/cells-cli/bin/pisco.js"
mocha -u tdd --recursive test --timeout 5000 --grep "Unit testing framework for askHello step"

NOTE: Is possible to test docker by changing piscoExec value:

export piscoExec="docker run -ti --rm -p 8000-8100:8000-8100 -p 3000-3100:3000-3100 -v ~/.gradle:/home/pisco/.gradle -v ~/.bowerrc:/home/pisco/.bowerrc -v ~/.npmrc:/home/pisco/.npmrc -v ~/.netrc:/home/pisco/.netrc -v ~/.ssh:/home/pisco/.ssh -v `pwd`:/home/pisco/workspace piscosour/cells-bundle"

The execution of pisco -ft or pisco --functionalTests starts with these messages on stdout. Showing the number of functional testing modules in the recipe, theirs names and versions.


[14:32:49] Number of functional testing modules detected:  1
[14:32:49] Executing piscosour functional tests from pisco-functional-tests ( 1.0.15 )


  Pisco context world validation
    ✓ Should return ....