a

    2.1.2 • Public • Published

    a

    Mocking framework + testing framework.

    The mocking framework can be used in any JavaScript testing framework.

    The testing framework has a short and concise bdd syntax - with reusable contexts.

    how to install

    npm install a
    

    if you want the test framework, install it globally too

    npm install a -g
    

    Mocking

    Mocking a function

    partial mock

    var original = function() {
        return 'realValue';
    }
     
    var mock = require('a').mock(original);
    original = mock;
    mock.expect().return('fake');
     
    original(); //returns 'fake'
    original(); //returns 'realValue'

    strict mock

    var mock = require('a').mock();
    mock.expect().return('fake');
     
    mock(); //returns 'fake'
    mock(); //throws unexpected arguments

    expecting arguments

    var mock = require('a').mock();
    mock.expect('testValue1').return('fake1');
    mock.expect('testValue2').return('fake2');
     
    mock('testValue1'); //returns 'fake1'
    mock('testValue2'); //returns 'fake2'
    mock(); //throws unexpected arguments
    mock('foo'); //throws unexpected arguments

    expecting multiple arguments

    var mock = require('a').mock();
    mock.expect('firstArg1', 'secondArg1').return('fake1');
    mock.expect('firstArg2', 'secondArg2').return('fake2');
     
     
    mock('firstArg1', 'secondArg1'); //returns 'fake1'
    mock('firstArg2', 'secondArg2'); //returns 'fake2'
    mock('foo'); //throws unexpected arguments
    mock('foo', 'bar'); //throws unexpected arguments

    expecting array

    var mock = require('a').mock();
    mock.expect(['a','b']).return('fake1');
    mock.expect(['a','b').return('fake2');
    mock.expect(['c','d').return('fake3');
     
    mock(['a','b']); //returns 'fake1'
    mock(['a','b']); //returns 'fake2'
    mock(['c','d']); //returns 'fake3'
    mock(['a','b']); //throws unexpected arguments
    mock(['foo', 'bar']); //throws unexpected arguments

    expecting struct

    var mock = require('a').mock();
    var obj = {};
    mock.expect({: 1}).return('fake1');
    mock.expect({: 2}).return('fake2');
    mock.expect({: 2, b : {: 'foo', d : ['me', 'too']}}).return('fake3');
    mock.expect(obj).return('fake4');
    mock.expect({}).return('will never happen');
     
    mock({: 'x'}); //throws unexpected arguments
    mock({: 1}); //returns 'fake1'
    mock({: 2}); //returns 'fake2'
    mock({: 2, b : {: 'foo', d : ['me', 'too']}}); //returns 'fake3'
    mock(obj);  //returns 'fake4'
    mock({});  //throws unexpected arguments

    repeats

    var mock = require('a').mock();
    mock.expect().return('fake').repeat(2);
     
    mock(); //returns 'fake'
    mock(); //returns 'fake'
    mock(); //throws unexpected arguments

    infinite repeats

    var mock = require('a').mock();
    mock.expect().return('fake').repeatAny();
     
    mock(); //returns 'fake'
    mock(); //returns 'fake'
    mock(); //returns 'fake'...

    ignoring a single argument

    var mock = require('a').mock();
    mock.ignore().expect('foo').return('fake1');
     
    mock('ignore me', 'foo'); //returns 'fake1'
    mock(); //throws unexpected arguments

    ignoring all arguments

    var mock = require('a').mock();
    mock.expectAnything().return('fake1'); //same as expectAnything
     
    mock('someRandomValue', 'whatever'); //returns 'fake1'
    mock(); //throws unexpected arguments

    throwing exceptions

    var mock = require('a').mock();
    var error = new Error('invalid operation');
    mock.expect().throw(error);
    mock.expect().return('fake');
     
    mock(); //throws error
    mock(); //returns 'fake'

    intercepting

    var mock = require('a').mock();
    mock.expect('testValue').whenCalled(onCalled).return('fake1');
     
    function onCalled(arg) {
        //arg == 'testValue'
    }
     
    mock('testValue'); //returns 'fake1'
    mock(); //throws unexpected arguments

    verify (fail)

    var mock = require('a').mock();
    mock.expect('testValue1').return('fake1');
    mock.expect('testValue2').return('fake2');
     
    mock('testValue1'); //returns 'fake1'
    mock.verify(); //throws mock has 1 pending functions

    verify (success)

    var mock = require('a').mock();
    mock.expect('testValue1').return('fake1');
    mock.expect('testValue2').return('fake2');
     
    mock('testValue1'); //returns 'fake1'
    mock('testValue2'); //returns 'fake2'
    mock.verify(); //returns true

    returning void (compact syntax)

    var mock = require('a').mock();
    mock.expect('testValue1');
    mock.expect('testValue2').repeat(2);
     
    mock('testValue1'); //returns undefined
    mock('testValue2'); //returns undefined
    mock('testValue2'); //returns undefined
    mock.verify(); //returns true

    ..is equivalent to ..

    var mock = require('a').mock();
    mock.expect('testValue1').return();
    mock.expect('testValue2').return().repeat(2);
     
    mock('testValue1'); //returns undefined
    mock('testValue2'); //returns undefined
    mock('testValue2'); //returns undefined
    mock.verify(); //returns true

    reset mock

    var original = function() {
        return 'realValue';
    }
     
    var mock = require('a').mock(original);
    original = mock;
    mock.expect().return('fake');
    mock.reset();
     
    original(); //returns 'realValue'

    returning resolved promise

    var mock = require('a').mock();
    mock.expect('foo').resolve('fake');
     
    mock('foo').then(function(returned){
        //returned == 'fake'
    }); 

    returning rejected promise

    var mock = require('a').mock();
    mock.expect('foo').reject('fake');
     
    mock('foo').then(null, function(returned){
        //returned == 'fake'
    }); 

    strict mock - advanced scenario

    var mock = require('a').mock();
    mock.expect('testValue').ignore().whenCalled(onCalled).return('fake1');
     
    function onCalled(arg,callback) {
        //arg == 'testValue'
        //callback == foo
    }
     
    function foo() {
    }
     
     
    mock('testValue', foo); //returns 'fake1'
    mock.verify() //returns true
    mock('testValue',foo); //throws unexpected arguments

    Mocking require

    expectRequire

    var fakeDep = {};
     
    var expectRequire = require('a').expectRequire;
    expectRequire('./realDep').return(fakeDep);
     
    require('./realDep'); //returns fakeDep
    require('./realDep'); //returns realDep (behaves like a partial mock)

    requireMock (compact syntax)

    var requireMock = require('a').requireMock;
    var fakeDep = requireMock('./realDep'); //returns a strict mock
     
    require('./realDep'); //returns fakeDep
    require('./realDep'); //returns realDep

    ..is equivalent to ..

    var mock = require('a').mock();
    var expectRequire = require('a').expectRequire;
     
    var fakeDep = mock;
    expectRequire('./realDep').return(fakeDep);
     
    require('./realDep'); //returns fakeDep
    require('./realDep'); //returns realDep

    reset mocks for require

    var fakeDep = {};
     
    var expectRequire = require('a').expectRequire;
    expectRequire('./realDep').return(fakeDep);
    expectRequire.reset();
     
    require('./realDep'); //returns realDep

    ..is equivalent to ..

    var requireMock = require('a').requireMock;
    var fakeDep = requireMock('./realDep'); //returns a strict mock
    requireMock.reset(); //is an alias for expectRequire.reset()
     
    require('./realDep'); //returns realDep
     

    Mocking an object

    partial object mock

    function newCustomer(_name) {
        var c = {};
     
        c.getName = function ()
        {
            return _name;
        };
     
        return c;
    }
     
    var customer = newCustomer('Alfonzo The Real');
    var customerMock = mock(customer);
     
    customerMock.getName.expect().return('Johnny Fake');
     
    customer.getName(); //returns Johnny Fake
    customer.getName(); //returns Alfonzo The Real
    customerMock.verify(); //returns true

    Mocking promises

    mocking resolve

    var a = require('a');
     
    var promise = a.then(); //mocked promise
     
    promise.then(success,error);
    promise.resolve('success');
     
    function success(arg) {
        console.log(arg);//success
    }
     
    function error(e) {
        //will not happen
    }

    mocking resolve (alternative syntax)

    var a = require('a');
     
    var promise = a.then(); //mocked promise
     
    promise.then(success,error);
    promise('success');
     
    function success(arg) {
        console.log(arg);//success
    }
     
    function error(e) {
        //will not happen
    }

    mocking reject

    var a = require('a');
     
    var promise = a.then();
     
    promise.then(success,error);
    promise.reject(new Error('error'));
     
    function success(arg) {
        //will not happen
    }
     
    function error(e) {
        console.log(e.stack);//will happen
    }

    mocking reject (alternative syntax)

    var a = require('a');
     
    var promise = a.then();
     
    promise.then(success,error);
    promise(null,new Error('error'));
     
    function success(arg) {
        //will not happen
    }
     
    function error(e) {
        console.log(e.stack);//will happen
    }

    A test framework

    A test framework is a simplistic, magic-free library providing unit-testing facilities with a compact, bdd-style syntax.

    In contrast to other bdd-style test frameworks, however, it doesn't allow nesting suites in each other in order to test the SUT(subject under test) in different states. Instead, the framework relies on folder structure to describe the state which the SUT currently is. Suite names are generated based on their filenames. As a result there will be many small test files instead of few big ones with test suites nested in each other.

    Test setup -- the "Arrange-Act" part of suites, is separated from the "Assert" part. This way the same setup can be used across different suites. Test setups can, of course, be chained.

    Examples below can be found here: https://github.com/alfateam/a_demo

    Example

    The test runner ( a ) will search for all files named when*.js in current directory and below.

    Given the following file structure

    • demo/
      • counter.js
      • counter_specs/
        • new/
          • increment.js
          • when_incremented.js
        • new.js
        • when_new.js

    counter.js

    module.exports = function () {
        var counter = {
            value: 0,
            increment: function() { value++; }
        };
     
        return counter;
    }

    counter_specs/new.js

    function act(c) {
        var createCounter = require('../counter');
        c.sut = createCounter();
    }
    module.exports = act;

    counter_specs/when_new.js

    var c = {}; //test context object
    var when = require('a').when;
     
    when('./new', c). //set up
        it('should be an object').
            assertEqual('object', typeof c.sut)
        it('should have value equal to zero').
            assertEqual(0, c.sut.value).
        it('should fail just for fun').
            assertFail('error message');
     

    counter_specs/new/increment.js

    function act(c) {
        c.sut.increment();
    }
    act.base = '../new';
    module.exports = act;

    counter_specs/new/when_incremented.js

    var c = {};
    var when = require('a').when;
     
    when('./increment', c).
        it('should have value equal to 1').
            assertEqual(1, c.sut.value);
     

    In demo directory run a

    user@localhost:~/a_demo $ a
    
     » counter_specs » new
    
      ✓ should be an object
      ✓ should have value equal to zero
      ✘ should fail just for fun
    
     » counter_specs » new » increment
    
      ✓ should have value equal to 1
    
    ========== Summary =============
    
    counter_specs » new
      ✘ should fail just for fun
    
    AssertionError: error message
    	at retval.assertFail (/home/user/a_demo/node_modules/a/when/it.js:14:11)
    	at Object.test (/home/user/a_demo/node_modules/a/when/test_invoker.js:5:3)
    	at Object.retval.assertFail (/home/user/a_demo/node_modules/a/when/it.js:13:5)
    	at Object.<anonymous> (/home/user/a_demo/counter_specs/when_new.js:11:3)
    	at Module._compile (module.js:449:26)
    	at Object.Module._extensions..js (module.js:467:10)
    	at Module.load (module.js:356:32)
    	at Function.Module._load (module.js:312:12)
    	at Module.require (module.js:362:17)
    	at require (module.js:378:17)
    ------------
    
    suites: 2, passed: 3, failed: 1
    

    Async test support

    modified act file should like like this:

     
    function act(c) {
        ...
        return c.sut(c.arguments); //returns promise
    }
     

    or

     
    async function act(c) {
        ...
        await c.sut(c.arguments);
    }
     

    test file should look like this

    var when = require('a').when;
    var c = {};
     
    when(c).then(it => {
        it('....').assertXXXX();
    });
     

    Release Notes

    2.1.2

    2.1.0

    • short hand syntax for returning promises (sync)

    2.0.13

    • a_mock 1.0.4, implements promise mock which is synchronous

    2.0.12

    • assertOk(falsy) would not throw (#21)
    • report suites that cannot be loaded as unrunnable (#20)
    • fix async test result reporting order

    2.0.11

    • README update

    2.0.10

    • disable runtime babel transpiling by default, set A_TEST_BABEL_REGISTER environment variable to enable it.

    2.0.9

    • replace dependency for coloured console output in test runner.

    2.0.8

    • update README

    2.0.7

    • test runner is able to load modules exporting a default function.

    2.0.6

    • test runner reports when a file with tests is not runnable

    2.0.5

    • test runner uses node instead of nodejs

    2.0.4

    • correct reporting of aborted promise mocks

    2.0.3

    • abort Unfulfilled promise mocks after 10secs.

    2.0.2

    • forgotten dependency version

    2.0.1

    • Fix bin section in package.json.
    • Fix memory leak in the test runner

    2.0.0
    BREAKING CHANGE: Support async testing.

    • Tests relying on ability of deferred to resolve synchronously expected to cause problems.
    • Unfulfilled promises will prevent runner from exiting.
    • Runner uses babel-runtime which implies strict mode.

    1.0.1
    ExpectAnything() can be nested - for backwards compatability only.
    1.0.0
    ExpectAnything() no longer expects only one argument, but arbitary number of arguments. Use ignore() if you want to ignore a single argument.
    0.4.8
    Executable test runner "when" is deprecated. Use "a" instead.
    0.4.7
    Inconclusive tests are accounted as failed in exit code.
    0.4.6
    Fixed memory leak in test runner.
    0.4.5
    Display stack trace of inconclusive suites.
    Use dependency deferred instead of promise.
    0.4.4
    Introduced promise mocks.
    Tests with failing setup are reported as inconclusive.
    Bugfix: Test names no longer converted to lowercase.
    0.4.3
    Can reset expectations on mocks by mock.reset.
    Renamed expectRequire.clear to expectRequire.reset. Same goes for for requireMock.
    0.4.2
    Can clear expectations on require by using expectRequire.clear.
    0.4.1
    "When" can accept function instead of separate act file. See example in demo repo.
    0.4.0
    Cleaner output on failed assertions.
    0.3.9
    Can inherit act by convention. See examples in demo repo.
    0.3.8
    Cleaner stack trace on mock errors.
    0.3.7
    Test path can be sent as argument to test runner.
    If no path is specified, the test runner will run from current directory.
    Example: when c:/devel/foo/testFolder
    0.3.6
    Exit code is equal to number of failing tests.
    0.3.5
    Tests files are run in hierarchical order from top to bottom.
    0.3.4
    Cache was cleared at wrong time. This could lead to overflow when running large amount of tests.
    Make sure you update globally (npm update a -g) to get this fix, not only the local dependency.
    0.3.3
    Error in documentation about structs.
    0.3.2
    Mocks can be set up to throw.
    0.3.1
    "when" deletes all cached modules before executing. This ensures tests are isolated.
    ignore is alias for expectAnything.
    "When" can resolve act by camcelCase convention. If test class is named "whenFoo.js", it will assume "foo.js" is the act.

    0.3.0
    expectArray is deprecated, use expect instead.
    expect now handles structs - equality is acheived when same propertyNames and equal leaf properties.

    0.2.9
    "When" can resolve act by convention. If test class is named "when_foo.js", it will assume "foo.js" is the act.
    Example, given when_foo.js:

    var c = {};
    var when = require('a').when;
     
    when(c). //equivalent to: when('./foo',c)....
        it('should have value equal to 1').
            assertEqual(1, c.sut.value);
     

    Install

    npm i a

    DownloadsWeekly Downloads

    2,205

    Version

    2.1.2

    License

    MIT

    Unpacked Size

    17.2 kB

    Total Files

    4

    Last publish

    Collaborators

    • adlanelm
    • lroal