npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

a

v4.0.8

Published

Mocking framework

Readme

a

Mocking framework

CI coverage

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

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

import a from 'a';

var original = function() {
	return 'realValue';
}

var mock = a.mock(original);
original = mock;
mock.expect().return('fake');

mock(); //returns 'fake'
mock(); //returns 'realValue'

Note: Consumers do not need to provide a thisArg. It is optional and only used to force a specific this when the original fallback is called (low-level partial mock usage).

Strict mock

import a from 'a';

var mock = a.mock();
mock.expect().return('fake');

mock(); //returns 'fake'
mock(); //throws unexpected arguments

Expecting arguments

import a from 'a';

var mock = 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

import a from 'a';

var mock = 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

import a from 'a';

var mock = 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

import a from 'a';

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

mock({a : 'x'}); //throws unexpected arguments
mock({a : 1}); //returns 'fake1'
mock({a : 2}); //returns 'fake2'
mock({a : 2, b : {c : 'foo', d : ['me', 'too']}}); //returns 'fake3'
mock(obj);  //returns 'fake4'
mock({});  //throws unexpected arguments

Note: Struct matching is strict on leaf properties. All leaf property values must be equal to match, and an empty object does not match a non-empty expected struct.

Ignoring a single argument

import a from 'a';

var mock = a.mock();
mock.ignore().expect('foo').return('fake1');

mock('ignore me', 'foo'); //returns 'fake1'
mock(); //throws unexpected arguments

Ignoring all arguments

import a from 'a';

var mock = a.mock();
mock.ignoreAll().return('fake1'); //same as expectAnything

mock('someRandomValue', 'whatever'); //returns 'fake1'
mock(); //throws unexpected arguments

Repeats

import a from 'a';

var mock = a.mock();
mock.expect().return('fake').repeat(2);

mock(); //returns 'fake'
mock(); //returns 'fake'
mock(); //throws unexpected arguments

Infinite repeats

import a from 'a';

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

mock(); //returns 'fake'
mock(); //returns 'fake'
mock(); //returns 'fake'...

Throwing exceptions

import a from 'a';

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

mock(); //throws error
mock(); //returns 'fake'

Intercepting

import a from 'a';

var mock = a.mock();
mock.expect('testValue').whenCalled(onCalled).return('fake1');

function onCalled(arg) {
	//arg == 'testValue'
}

mock('testValue'); //returns 'fake1'
mock(); //throws unexpected arguments

Verify (fail)

import a from 'a';

var mock = 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)

import a from 'a';

var mock = 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)

import a from 'a';

var mock = 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 ..

import a from 'a';

var mock = 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

import a from 'a';

var original = function() {
	return 'realValue';
}

var mock = a.mock(original);
mock.expect().return('fake');
mock.reset();

mock(); //returns 'realValue'

Returning resolved promise

import a from 'a';

var mock = a.mock();
mock.expect('foo').resolve('fake');

mock('foo').then(function(returned){
	//returned == 'fake'
}); 

Returning rejected promise

import a from 'a';

var mock = a.mock();
mock.expect('foo').reject('fake');

mock('foo').then(null, function(returned){
	//returned == 'fake'
}); 

Strict mock - advanced scenario

import a from 'a';

var mock = 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 an object

Partial object mock

import a from 'a';

function newCustomer(_name) {
	var c = {};

	c.getName = function ()
	{
		return _name;
	};

	return c;
}

var customer = newCustomer('Alfonzo The Real');
var customerMock = a.mock(customer);

customerMock.getName.expect().return('Johnny Fake');

customer.getName(); //returns Johnny Fake
customer.getName(); //returns Alfonzo The Real
customerMock.verify(); //returns true

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 promises

Mocking resolve

import a from 'a';

var promise = a.promise(); //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)

import a from 'a';

var promise = a.promise(); //mocked promise

promise.then(success,error);
promise('success');

function success(arg) {
	console.log(arg);//success
}

function error(e) {
	//will not happen
}

Mocking reject

import a from 'a';

var promise = a.promise();

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)

import a from 'a';

var promise = a.promise();

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

From version 3.0.0 this is in a separate package: npmjs.com/package/a_test
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, 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. The SUT currently has that folder structure. Suite names are generated based on their filenames. As a result, there will be many small test files without nested test suites instead of a few big test files with nested test suites.

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 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 the current and sub-directories.

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

import a from 'a';

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

counter_specs/when_new.js

import a from 'a';

var c = {}; //test context object
var when = 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

import a from 'a';

var c = {};
var when = 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 files should look like this:

import a from 'a';

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

or

import a from 'a';

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

Test file should look like this:

import a from 'a';
var when = a.when;
var c = {};

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