Security News
pnpm 10.0.0 Blocks Lifecycle Scripts by Default
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.
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.
To install:
npm install a
If you want the test framework, install it globally too:
npm install a -g
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({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
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
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
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 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
}
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
The test runner ( a ) will search for all files named 'when*.js' in the current and sub-directories.
Given the following file structure
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
Modified act files should look 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();
});
3.0.0
2.1.2
2.1.0
2.0.13
2.0.12
2.0.11
2.0.10
2.0.9
2.0.8
2.0.7
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
BREAKING CHANGE: Support async testing.
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);
FAQs
Mocking framework
The npm package a receives a total of 14,953 weekly downloads. As such, a popularity was classified as popular.
We found that a demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.
Product
Socket now supports uv.lock files to ensure consistent, secure dependency resolution for Python projects and enhance supply chain security.
Research
Security News
Socket researchers have discovered multiple malicious npm packages targeting Solana private keys, abusing Gmail to exfiltrate the data and drain Solana wallets.