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

aroma-mock

v0.1.6

Published

CoffeeScript automatic Mock objects with Scenarios: test *exactly* what you want

Readme

AromaMock - Mocking Framework for JavaScript and CoffeeScript

Aroma is a CoffeeScript Mock Framework. This of course means that it can be used to test and develop JavaScript, but in this document, I will address CoffeeScript, because I like it better. It provides a useful scenario-expectations construct and easy, on the fly mock object generation.

The scenario verifies the exact expected function call sequence including the function arguments. Scenarios are specified before the code is run, making the tests well organized, readable and more explicit.

The scenario abstraction verifies that things happen exactly as specified: i.e. we do not only verify that some mock function was called with specific paramenter, we verify that it has not been called more times that it should have been, with some other parameters.

Original concepts were carried over from Voodoo-Mock, a C++/Python unit test framework.

Installation

$ npm install aroma-mock

You will also probably want to

$ npm install mocha coffee-script

Running CoffeeScript Tests with Mocha

In the following examples I use Mocha for a test runner. In order for Mocha to work with CoffeeScript you must use it like this:

$ mocha --compilers coffee:coffee-script/register [tests...]

Using Aroma-Mock with JavaScript

Aroma-Mock is written in CoffeeScript. It can be used in JavaScript by requiring the coffee-script/register in your test code, and then requiring aroma-mock:

Quick Start

Here's an example test, that mocks the jQuery $ symbol and tests that it is used as expected. Before reading the entire thing, let's just look at the call expectation:

call( '$', [ "#input_element" ], fakeObject( 'element', ['val'] ) )

expresses our expectation that the tested code will call $ with "#input_element" as its first argument. We also arrange that the return value of this call will be a Mock Object called element.

We then expect that this element object's val method will be called with one argument, the string '123'. This is expressed in the expectation:

call( 'element.val', [ '123' ] )

Since we don't care about the return value from this call, we leave it unspecified. We can also use null

call( 'element.val', [ '123' ], null )

Since jQuery expectations are commonplace, we can use the shorthand expect_$ for this 2-call expectation - this is demonstrated below.

Another thing to note is the use of capture and captured to test functions called with callbacks. E.g., if our code calls fs.mkdir( 'somepath', onCreated ), we want to later call this onCreated function. We therefore use the capture feature of Aroma-Mock to get at it:

call( 'fs.mkdir', [ 'somepath', capture( 'onCreatedCallback' ) ] )

and later call it via the captured API:

captured.onCreatedCallback()

I hope this makes the following, complete listing, clear.

require 'aroma-mock' # import the Aroma-Mock framework
example = require '../example'

fakeGlobal( '$', [ 'getJSON', 'ajax' ] )
fakeGlobal( 'Point', [] )

describe 'example of aroma mocking framework', ->
	it 'should get JSON with jQuery', ->
		tested = new example.Example()
		scenario = new Scenario()
		scenario.expect call( '$.getJSON', [ 'www.google.com', {a:1, b:2}, capture( 'doneCallback' ) ], null )

		tested.getSomeJSON()
		scenario.end()

		captured.doneCallback()

	it 'should use jQuery on the DOM', ->
		tested = new example.Example()
		scenario = new Scenario()
		scenario.expect call( '$', [ "#input_element" ], fakeObject( 'element', ['val'] ) )
		scenario.expect call( 'element.val', [ '123' ], null )
		tested.useJQueryOnDOM( '123' )
		scenario.end()

	it 'should use jQuery on the DOM: example of expect_$ shorthand notation', ->
		tested = new example.Example()
		scenario = new Scenario()
		scenario.expect_$( '#input_element', 'val', [ '456' ], null )
		tested.useJQueryOnDOM( '456' )
		scenario.end()

here's the code that passes this test:

class Example
	useJQueryOnDOM: ( text ) =>
		$("#input_element").val( text )

	getSomeJSON: =>
		$.getJSON 'www.google.com', {a:1,b:2}, this._mycallback

	_mycallback: =>
		console.log( 'my callback called!' )

exports.Example = Example

Asynchronous Ajax JSON Retrieval Example

The AjaxTest class allows testing for an asynchronous ajax call. We define the parameters of the ajax call, the data supposedly returned from the server, and what we expect should happen on success.

Here's an asynchronous ajax test:


# we don't use getJSON in this example, but this is how to create a fake object
# with multiple methods.
fakeGlobal( '$', [ 'getJSON', 'ajax' ] )

describe 'example of aroma ajax mocking', ->
	it 'aroma can test asynchronous AJAX', ->
		tested = new example.Example()
		scenario = new Scenario()
		ajaxTest = new AjaxTest( scenario )
		ajaxTest.expect( { url: '/path/to/return_keys.json', data: { a: 1, b: 2 }, type: 'POST' } )
		ajaxTest.returnFromServer( { status: 'ok', answer: [ 'a', 'b' ] } )
		ajaxTest.onSuccessScenario = =>
			scenario.expect_$( "#status", 'val', [ 'ok' ], null )
			scenario.expect_$( "#output_element", 'val', [ [ 'a', 'b' ] ], null )

		tested.doAsyncAjax( { a: 1, b: 2 } )
		ajaxTest.verify()
		scenario.end()

this is the code that passes it

class Example
	doAsyncAjax: ( data ) =>
		success = (data) =>
			$("#status").val( data.status )
			$("#output_element").val( data.answer )
		$.ajax { url: '/path/to/return_keys.json', data: data, type: 'POST', success: success }

a test that checks the response to an error can also be written


# we don't use getJSON in this example, but this is how to create a fake object
# with multiple methods.
fakeGlobal( '$', [ 'getJSON', 'ajax' ] )

describe 'example of aroma ajax mocking', ->
	it 'aroma asynchronous AJAX error example', ->
		tested = new example.Example()
		scenario = new Scenario()
		ajaxTest = new AjaxTest( scenario )
		ajaxTest.expect( { url: '/path/to/return_keys.json', data: { a: 1, b: 2 }, type: 'POST' } )
		ajaxTest.errorFromServer( null, 'error text 123', null )
		ajaxTest.onErrorScenario = =>
			scenario.expect_$( "#status", 'val', [ 'error text 123' ], null )
			scenario.expect_$( "#output_element", 'val', [ [] ], null )

		tested.doAsyncAjax( { a: 1, b: 2 } )
		ajaxTest.verify( 'error' )
		scenario.end()

This code passes the test, as well as the previous one:

class Example
	doAsyncAjax: ( data ) =>
		success = (data) =>
			$("#status").val( data.status )
			$("#output_element").val( data.answer )
		error = ( unused, text, unused2 ) =>
			$("#status").val( text )
			$("#output_element").val( [] )
			
		$.ajax { 	url: '/path/to/return_keys.json',\
					data: data,
					type: 'POST',
					success: success,
					error: error }

The Callback Cascade Pattern

When writing JavaScript code, it often happens that we get a cascade of callback functions, since almost everything is done asynchronously. For example, say we want to check if some directory exists, and if not, create it, and then run some subprocess in the directory. If the directory already exists, we don't need to create it.

The callback cascade here is

fs.exists => fs.mkdir => childProcess.exec

We can use capture for this, but it gets ugly really fast. If the callback argument for each function in our cascade is the last one, which is often the case, e.g.

fs.exists(path, callback)

We can use the cascade pattern:

rewire = require 'rewire'

describe 'cascade of callbacks', ->
    beforeEach ->
        cascadeModule.__set__( 'fs', fakeObject( 'fs', [ 'exists', 'mkdir' ] ) )
        cascadeModule.__set__( 'childProcess', fakeObject( 'childProcess', [ 'exec' ] ) )

    it 'should work', ->
        myCallback = fakeObject( 'myCallback' )
        scenario.expectCascade [    cascade( 'fs.exists', [ 'some_path' ], null, [false] ),
                                    cascade( 'fs.mkdir', [ 'some_path' ] ),
                                    cascade( 'childProcess.exec', [ 'some command', {cwd: 'some_path'} ], null, [ null, "output string", "error string" ] ),
                                    call( 'myCallback', [ "output string" ] ) ]

        tested = new cascadeModule.Cascade()

        tested.go( 'some_path', myCallback )
        scenario.end()
        

NOTE the use of rewire to mock objects inside the module.

This expresses the expectation that the code will call fs.exists - passing it some_path. The fs.exists cascade specifies that fs.exists will return null, and then call its callback with the arguments specified in a list, in this case [false], so just one argument.

What happens when fs.exists's callback is called? Since the directory does not exist (we made fs.exists pass false to its callback, remember?) we expect it to call fs.mkdir, which will the call its callback.

We then demand that this callback call childProcess.exec and we specify the output and error strings passed to its callback, which should, finally, call the user's callback.

NOTE the last call in the cascade is a call, not a cascade - since we don't want it to automatically call a callback.

The code that passes this test would be:

fs = require 'fs'
childProcess = require 'child_process'

class Cascade
    go: ( path, callback ) =>
        @callback = callback
        fs.exists path, (exists) =>
            if exists
                this._runChild( path )
            else
                fs.mkdir path, =>
                    this._runChild( path )

    _runChild: ( path ) =>
        childProcess.exec 'some command', { cwd: path }, (err, output, error) =>
            @callback( output )

exports.Cascade = Cascade