Js.Edgar
Lightweight Spy/Mock Library for JavaScript
Why choose this name?
This library is meant to create, manage, and direct spies for testing JavaScript. As such, it only seemed natural to name it after one of the most infamous intelligence directors in history, J. Edgar Hoover.
Using Js.Edgar
Install with npm:
npm install js.edgar
Install with bower:
bower install js.edgar
Install with jam:
jam install js.edgar
Install with jspm:
jspm install js.edgar
Make sure to add Js.Edgar to the devDependencies of your project where applicable.
Once installed, simply add the edgar.js script to your html:
Or reference the script within a build tool file, such as Brocfile.js
Js.Edgar is supported as an AMD module, Node.js export, or browser global, depending on what your project is using. You can now reference/import "Edgar" anywhere within your test files!
Supported Testing Frameworks
Js.Edgar is built to be lightweight and flexible; it should work with any testing framework. Specifically, the tests for this library are written in QUnit, so integration with that framework has been well-documented. As such, all major examples will show how to utilize Js.Edgar within QUnit.
Some major frameworks, such as Jasmine, come with their own Spy solution, so no testing has been done around that integration. For other frameworks, though, we've tried to make things easy by utilizing their testing hooks to provide automatic cleanup for Js.Edgar. QUnit's testDone and Mocha's afterEach hooks will be called if those frameworks are in use, and every Spy managed by Js.Edgar will be released and removed.
Creating Spies
Creating a Spy is easy, and our API attempts to intelligently configure the Spy to your needs with as little configuration as possible. A basic Spy will track all calls to the spied method, including arguments and return values, and it will prevent the actual method from being executed.
var obj;module'QUnit Spies' { obj = { return 'bar'; } ; }; ;
You'll note two things happened here:
- Js.Edgar tracked that foo was called (
called()
actually returns the number of calls, as you'll see later, butok
is a perfectly fine assertion if you only want to make sure it was called). - The method
foo()
was mocked and the return value wasundefined
.
Mocking Return Values
So far, this is pretty basic, but we can easily expand our capabilities to provide a mocked return value:
;
In the above example, we added a third parameter to createSpy()
, which Js.Edgar used to mock a return value when foo()
was called. This parameter can be any valid javascript object or primitive, including functions!
If you need to change the Spy's return value for subsequent assertions or to setup mocking after executing the live method previously (see below), you can call startMocking()
(or its alias andMock()
).
;
startMocking
takes an optional parameter that allows you to set the return value or invoke method (see below) for the Spy if you have not yet done so.
Invoking Mock Methods
Now, let's say that you have a more complicated scenario, and you want your mocked return value to be different depending on what it gets passed. Well, that's easy, too!
;
The key here was chaining the andInvoke()
method onto your spy creation, telling Js.Edgar that the function you passed was to be invoked, rather than simply returned intact. You can also set this up after creating the spy, if you'd like.
;
startInvoking()
is interchangeable with andInvoke
, we just provided both method names so that your code is more readable regardless of which pattern you choose.
Executing Original Functionality
Now you might be asking yourself, what if I actually want the method I'm spying on to execute? Well, don't worry, we've thought of that!
;
By calling andExecute()
or its alias startExecuting()
, you can tell Js.Edgar to let the original method be executed within the appropriate scope while still tracking all calls made to the method!
Tracking Arguments
Js.Edgar can easily tell you what arguments were passed to each individual call. Spy.calledWith()
will return the arguments array of the most recent call made to the method, regardless of whether you are using the mock, invoke, or execute strategies.
;
Of course, you can also track multiple calls and obtain the arguments by passing the id of call you want (in order):
;
Tracking Return Values
The exact same API exists for tracking values returned from each method call; just call returnedWith()
!
; ; ;
Tracking Call Context
Spies also track and pass the context of this
when the spied method is called:
; ;
The above examples show that the context is passed to both executed and invoked methods, regardless of whether call()
or apply()
(or neither) were used.
For the purposes of testing, you can use Spy.getContext()
to assert that the method was called with the proper value of this
, which can be helpful if you are using call()
or apply()
yourself.
; ;
As with the previous APIs, passing a call id to getContext is optional; it will return the most recent call by default.
Cleanup
Since spies override existing objects in your code (especially if you are messing with globals), it's important to make sure they get cleaned up after each test completes. As mentioned previously, Js.Edgar will proactively release all spies between QUnit or Mocha tests. If QUnit or mocha are not accessible as global variables in your project, you can call the following methods and pass them the object accordingly:
Edgar; Edgar;
If you are using another testing framework and need to integrate it, please submit a pull request to enable it in Js.Edgar! Simply call the following methods in the post-test hook (or after an individual test to cleanup all spies):
Edgar;Edgar;
Releasing Spies
All spies have a release()
method that allow you to cleanup an individual spy
;
After release()
is called, no further calls to the method will be tracked and it will execute normally, as if the Spy had never been created. The Spy will still have any data it collected up to that point, in case you should need it.
Resetting Spies
You can reset a Spy and wipe out its tracked calls by calling reset()
. Once reset has been called, any further calls to the spies method will still be tracked, but previous calls will have been lost.
;
Resuming Spies
If you have released a Spy, you can resume spying on the method by simply calling resume()
.
;
Running Js.Edgar's Unit Tests
Run the following command:
npm test
License
- Copyright © 2014 Jordan Hawker
- MIT License (see LICENSE.txt or http://opensource.org/licenses/MIT)