Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

testdouble

testdouble333.4kMIT3.20.2TypeScript support: included

A minimal test double library for TDD with JavaScript

tdd, bdd, mock, stub, spy, test double, double

readme

testdouble.js (AKA td.js)

npmjs unpkg

Welcome! Are you writing JavaScript tests and in the market for a mocking library to fake out real things for you? testdouble.js is an opinionated, carefully-designed test double library maintained by, oddly enough, a software agency that's also named Test Double. (The term "test double" was coined by Gerard Meszaros in his book xUnit Test Patterns.)

If you practice test-driven development, testdouble.js was designed to promote terse, clear, and easy-to-understand tests. There's an awful lot to cover, so please take some time and enjoy our documentation, which is designed to show you how to make the most out of test doubles in your tests.

This library was designed to work for both Node.js and browser interpeters. It's also test-framework agnostic, so you can plop it into a codebase using Jasmine, Mocha, Tape, Jest, or our own teenytest.

Install

$ npm install -D testdouble

If you just want to fetch the browser distribution, you can also curl it from unpkg.

We recommend requiring the library in a test helper and setting it globally for convenience to the shorthand td:

// ES import syntax
import * as td from 'testdouble'

// CommonJS modules (e.g. Node.js)
globalThis.td = require('testdouble')

// Global set in our browser distribution
window.td

(You may need to configure your linter to ignore the td global. Instructions: eslint, standard.)

If you're using testdouble.js in conjunction with another test framework, you may also want to check out one of these extensions:

Getting started

Mocking libraries are more often abused than used effectively, so figuring out how to document a mocking library so as to only encourage healthy uses has proven to be a real challenge. Here are a few paths we've prepared for getting started with testdouble.js:

Of course, if you're unsure of how to approach writing an isolated test with testdouble.js, we welcome you to open an issue on GitHub to ask a question.

API

td.replace() and td.replaceEsm() for replacing dependencies

The first thing a test double library needs to do is give you a way to replace the production dependencies of your subject under test with fake ones controlled by your test.

We provide a top-level function called td.replace() that operates in two different modes: CommonJS module replacement and object-property replacement. Both modes will, by default, perform a deep clone of the real dependency which replaces all functions it encounters with fake test double functions which can, in turn, be configured by your test to either stub responses or assert invocations.

For ES modules, you should use td.replaceEsm(). More details here.

Module replacement with Node.js

td.replace('../path/to/module'[, customReplacement])

If you're using Node.js and don't mind using the CommonJS require() function in your tests (you can still use import/export in your production code, assuming you're compiling it down for consumption by your tests), testdouble.js uses a library we wrote called quibble to monkey-patch require() so that your subject will automatically receive your faked dependencies simply by requiring them. This approach may be familiar if you've used something like proxyquire, but our focus was to enable an even more minimal test setup.

Here's an example of using td.replace() in a Node.js test's setup:

let loadsPurchases, generatesInvoice, sendsInvoice, subject
module.exports = {
  beforeEach: () => {
    loadsPurchases = td.replace('../src/loads-purchases')
    generatesInvoice = td.replace('../src/generates-invoice')
    sendsInvoice = td.replace('../src/sends-invoice')
    subject = require('../src/index')
  }
  //…
  afterEach: function () { td.reset() }
}

In the above example, at the point when src/index is required, the module cache will be bypassed as index is loaded. If index goes on to subsequently require any of the td.replace()'d dependencies, it will receive a reference to the same fake dependencies that were returned to the test.

Because td.replace() first loads the actual file, it will do its best to return a fake that is shaped just like the real thing. That means that if loads-purchases exports a function, a test double function will be created and returned. If generates-invoice exports a constructor, a constructor test double will be returned, complete with test doubles for all of the original's static functions and instance methods. If sends-invoice exports a plain object of function properties, an object will be returned with test double functions in place of the originals' function properties. In every case, any non-function properties will be deep-cloned.

There are a few important things to keep in mind about replacing Node.js modules using td.replace():

  • The test must td.replace() and require() everything in a before-each hook, in order to bypass the Node.js module cache and to avoid pollution between tests
  • Any relative paths passed to td.replace() are relative from the test to the dependency. This runs counter to how some other tools do it, but we feel it makes more sense
  • The test suite (usually in a global after-each hook) must call td.reset() to ensure the real require() function and dependency modules are restored after each test case.
Default exports with ES modules

If your modules are written in the ES module syntax and they specify default exports (e.g. export default function loadsPurchases()), but are actually transpiled to CommonJS, just remember that you'll need to reference .default when translating to the CJS module format.

That means instead of this:

loadsPurchases = td.replace('../src/loads-purchases')

You probably want to assign the fake like this:

loadsPurchases = td.replace('../src/loads-purchases').default

Property replacement

td.replace(containingObject, nameOfPropertyToReplace[, customReplacement])

If you're running tests outside Node.js or otherwise injecting dependencies manually (or with a DI tool like dependable), then you may still use td.replace to automatically replace things if they're referenceable as properties on an object.

To illustrate, suppose our subject depends on app.signup below:

app.signup = {
  onSubmit: function () {},
  onCancel: function () {}
}

If our goal is to replace app.signup during a test of app.user.create(), our test setup might look like this:

let signup, subject
module.exports = {
  beforeEach: function () {
    signup = td.replace(app, 'signup')
    subject = app.user
  }
  // …
  afterEach: function () { td.reset() }
}

td.replace() will always return the newly-created fake imitation, even though in this case it's obviously still referenceable by the test and subject alike with app.signup. If we had wanted to only replace the onCancel function for whatever reason (though in this case, that would smell like a partial mock), we could have called td.replace(app.signup, 'onCancel'), instead.

Remember to call td.reset() in an after-each hook (preferably globally so one doesn't have to remember to do so in each and every test) so that testdouble.js can replace the original. This is crucial to avoiding hard-to-debug test pollution!

Specifying a custom replacement

The library's imitation feature is pretty sophisticated, but it's not perfect. It's also going to be pretty slow on large, complex objects. If you'd like to specify exactly what to replace a real dependency with, you can do so in either of the above modes by providing a final optional argument.

When replacing a Node.js module:

generatesInvoice = td.replace('../generates-invoice', {
  generate: td.func('a generate function'),
  name: 'fake invoices'
})

When replacing a property:

signup = td.replace(app, 'signup', {
  onSubmit: td.func('fake submit handler'),
  onCancel: function () { throw Error('do not call me') }
})

td.func(), td.object(), td.constructor(), td.instance() and td.imitate() to create test doubles

td.replace()'s imitation and injection convenience is great when your project's build configuration allows for it, but in many cases you'll want or need the control to create fake things directly. Each creation function can either imitate a real thing or be specified by passing a bit of configuration.

Each test double creation function is very flexible and can take a variety of inputs. What gets returned generally depends on the number and type of configuration parameters passed in, so we'll highlight each supported usage separately with an example invocation:

td.func()

The td.func() function (also available as td.function()) returns a test double function and can be called in three modes:

  • td.func(someRealFunction) - returns a test double function of the same name, including a deep imitation of all of its custom properties
  • td.func() - returns an anonymous test double function that can be used for stubbing and verifying any calls against it, but whose error messages and debugging output won't have a name to trace back to it
  • td.func('some name') - returns a test double function named 'some name', which will appear in any error messages as well as the debug info returned by passing the returned test double into td.explain()
  • td.func<Type>() - returns a test double function imitating the passed type. Examples and more details can be found in using with TypeScript

td.object()

The td.object() function returns an object containing test double functions, and supports three types of invocations:

  • td.object(realObject) - returns a deep imitation of the passed object, where each function is replaced with a test double function named for the property path (e.g. If realObject.invoices.send() was a function, the returned object would have property invoices.send set to a test double named '.invoices.send')
  • td.object(['add', 'subtract']) - returns a plain JavaScript object containing two properties add and subtract that are both assigned to test double functions named '.add' and '.subtract', respectively
  • td.object('a Person'[, {excludeMethods: ['then']}) - when passed with no args or with a string name as the first argument, returns an ES Proxy. The proxy will automatically intercept any call made to it and shunt in a test double that can be used for stubbing or verification. More details can be found in our full docs
  • td.object<Interface>() - returns an object with methods exposed as test doubles that are typed according to the passed interface. Examples and more details can be found in using with TypeScript

td.constructor()

If your code depends on ES classes or functions intended to be called with new, then the td.constructor() function can replace those dependencies as well.

  • td.constructor(RealConstructor) - returns a constructor whose calls can be verified and whose static and prototype functions have all been replaced with test double functions using the same imitation mechanism as td.func(realFunction) and td.object(realObject)
  • td.constructor(['select', 'save']) - returns a constructor with select and save properties on its prototype object set to test double functions named '#select' and '#save', respectively

When replacing a constructor, typically the test will configure stubbing & verification by directly addressing its prototype functions. To illustrate, that means in your test you might write:

const FakeConstructor = td.constructor(RealConstructor)
td.when(FakeConstructor.prototype.doStuff()).thenReturn('ok')

subject(FakeConstructor)

So that in your production code you can:

const subject = function (SomeConstructor) {
  const thing = new SomeConstructor()
  return thing.doStuff() // returns "ok"
}

td.instance()

As a shorthand convenience, td.instance() function will call td.constructor() and return a new instance of the fake constructor function it returns.

The following code snippets are functionally equivalent:

const fakeObject = td.instance(RealConstructor)
const FakeConstructor = td.constructor(RealConstructor)
const fakeObject = new FakeConstructor()

td.imitate()

td.imitate(realThing[, name])

If you know you want to imitate something, but don't know (or care) whether it's a function, object, or constructor, you can also just pass it to td.imitate() with an optional name parameter.

td.when() for stubbing responses

td.when(__rehearsal__[, options])

Once you have your subject's dependencies replaced with test double functions, you'll want to be able to stub return values (and other sorts of responses) when the subject invokes the test double in the way that the test expects.

To make stubbing configuration easy to read and grep, td.when()'s first argument isn't an argument at all, but rather a placeholder to demonstrate the way you're expecting the test double to be invoked by the subject, like so:

const increment = td.func()
td.when(increment(5)).thenReturn(6)

We would say that increment(5) is "rehearsing the invocation". Note that by default, a stubbing is only satisfied when the subject calls the test double exactly as it was rehearsed. This can be customized with argument matchers, which allow for rehearsals that do things like increment(td.matchers.isA(Number)) or save(td.matchers.contains({age: 21})).

Also note that, td.when() takes an optional configuration object as a second parameter, which enables advanced usage like ignoring extraneous arguments and limiting the number of times a stubbing can be satisfied.

Calling td.when() returns a number of functions that allow you to specify your desired outcome when the test double is invoked as demonstrated by your rehearsal. We'll begin with the most common of these: thenReturn.

td.when().thenReturn()

td.when(__rehearsal__[, options]).thenReturn('some value'[, more, values])

The simplest example is when you want to return a specific value in exchange for a known argument, like so:

const loadsPurchases = td.replace('../src/loads-purchases')
td.when(loadsPurchases(2018, 8)).thenReturn(['a purchase', 'another'])

Then, in the hands of your subject under test:

loadsPurchases(2018, 8) // returns `['a purchase', 'another']`
loadsPurchases(2018, 7) // returns undefined, since no stubbing was satisfied

If you're not used to stubbing, it may seem contrived to think a test will know exactly what argument to pass in and expect back from a dependency, but in an isolated unit test this is not only feasible but entirely normal and expected! Doing so helps the author ensure the test remains minimal and obvious to future readers.

Note as well that subsequent matching invocations can be stubbed by passing additional arguments to thenReturn(), like this:

const hitCounter = td.func()
td.when(hitCounter()).thenReturn(1, 2, 3, 4)

hitCounter() // 1
hitCounter() // 2
hitCounter() // 3
hitCounter() // 4
hitCounter() // 4

td.when().thenResolve() and td.when().thenReject()

td.when(__rehearsal__[, options]).thenResolve('some value'[, more, values])

td.when(__rehearsal__[, options]).thenReject('some value'[, more, values])

The thenResolve() and thenReject() stubbings will take whatever value is passed to them and wrap it in an immediately resolved or rejected promise, respectively. By default testdouble.js will use whatever Promise is globally defined, but you can specify your own like this:

td.config({promiseConstructor: require('bluebird')})`

Because the Promise spec indicates that all promises must tick the event loop, keep in mind that any stubbing configured with thenResolve or thenReject must be managed as an asynchronous test (consult your test framework's documentation if you're not sure).

td.when().thenCallback()

td.when(__rehearsal__[, options]).thenCallback('some value'[,other, args])

The thenCallback() stubbing will assume that the rehearsed invocation has an additional final argument that takes a callback function. When this stubbing is satisfied, testdouble.js will invoke that callback function and pass in whatever arguments were sent to thenCallback().

To illustrate, consider this stubbing:

const readFile = td.replace('../src/read-file')
td.when(readFile('my-secret-doc.txt')).thenCallback(null, 'secrets!')

Then, the subject might invoke readFile and pass an anonymous function:

readFile('my-secret-doc.txt', function (err, contents) {
  console.log(contents) // will print 'secrets!'
})

If the callback isn't in the final position, or if the test double also needs to return something, callbacks can be configured using the td.callback argument matcher.

On one hand, thenCallback() can be a great way to write fast and clear synchronous isolated unit tests of production code that's actually asynchronous. On the other hand, if it's necessary to verify the subject behaves correctly over multiple ticks of the event loop, you can control this with the defer and delay options.

td.when().thenThrow()

td.when(__rehearsal__[, options]).thenThrow(new Error('boom'))

The thenThrow() function does exactly what it says on the tin. Once this stubbing is configured, any matching invocations will throw the specified error.

Note that because rehearsal calls invoke the test double function, it's possible to configure a thenThrow stubbing and then accidentally trigger it when you attempt to configure subsequent stubbings or verifications. In these cases, you'll need to work around it by re-ordering your configurations or catch'ing the error.

td.when().thenDo()

td.when(__rehearsal__[, options]).thenDo(function (arg1, arg2) {})

For everything else, there is thenDo(). thenDo takes a function which will be invoked whenever satisfied with all the arguments and bound to the same this context that the test double function was actually invoked with. Whatever your thenDo function returns will be returned by the test double when the stubbing is satisfied. This configuration is useful for covering tricky cases not handled elsewhere, and may be a potential extension point for building on top of the library's stubbing capabilities.

td.verify() for verifying interactions

td.verify(__demonstration__[, options])

If you've learned how to stub responses with td.when() then you already know how to verify an invocation took place with td.verify()! We've gone out of our way to make the two as symmetrical as possible. You'll find that they have matching function signatures, support the same argument matchers, and take the same options.

The difference, then, is their purpose. While stubbings are meant to facilitate some behavior we want to exercise in our subject, verifications are meant to ensure a dependency was called in a particular expected way. Since td.verify() is an assertion step, it goes at the end of our test after we've invoked the subject under test.

A trivial example might be:

module.exports = function shouldSaveThings () {
  const save = td.replace('../src/save')
  const subject = require('../src/index')

  subject({name: 'dataz', data: '010101'})

  td.verify(save('dataz', '010101'))
}

The above will verify that save was called with the two specified arguments. If the verification fails (say it passed '010100' instead), testdouble.js will throw a nice long error message to explain how the test double function was actually called, hopefully helping you spot the error.

Just like with td.when(), more complex cases can be covered with argument matchers and configuration options.

A word of caution: td.verify() should be needed only sparingly. When you verify a function was called (as opposed to relying on what it returns) you're asserting that your subject has a side effect. Code with lots of side effects is bad, so mocking libraries are often abused to make side-effect heavy code easier to proliferate. In these cases, refactoring each dependency to return values instead is almost always the better design approach. A separate test smell with verifying calls is that sometimes—perhaps in the interest of maximal completeness—a test will verify an invocation that already satisfied a stubbing, but this is almost provably unnecessary.

td.listReplacedModules() for listing the modules that were replaced

td.listReplacedModules()

Use td.listReplacedModules() to list the modules that are replaced. This function will return an array of the modules that are currently being replaced via td.replace() or td.replaceEsm().

The list is in no particular order, and returns the full path to the module that was replaced. The path is returned as a file: URL as is customary in ESM (this is true even if the replaced module was CJS).

For example, if you do this:

td.replace('../src/save')

Then

td.listReplacedModules()

will return something like:

['file:///users/example/code/foo/src/save.js']

Other functions

For other top-level features in the testdouble.js API, consult the docs directory:

changelog

Change Log

3.20.2

  • Fix missinglistReplacedModules #527
  • Update quibble

  • We missed some versions here, sorry.

3.18.0

  • Update quibble to 0.7.0 for Node 20 support quibble#96. Bumping minor for test double because it's a big change to how modules are resolved
  • Update typings for version property #515

3.17.2

  • Loosen typing file to allow non-Error types to be rejected #511

3.17.1

  • Add missing alias to td.function for ESM #509

3.17.0

  • Swap global for globalThis #508
  • Bump quibble to 0.6.17

3.16.8

  • Tweak typings again #500

3.16.7

  • Update typings around replace and related methods #499

3.16.5

  • Improve type definition for stubbing a sequence of promises #481

3.16.4

  • Update quibble

3.16.3

  • Fix replaceEsm for the latest release of Node 16, which changed the loader interface. See #474 and quibble#54

3.16.2

  • Handle cases where deep-cloning arguments fails. If cloneArgs is specified on a stubbing or verification, the error will be propagated and thrown, otherwise it will be swallowed and td.explain will warn the user that clone failed (and therefore its log message may be inaccurate). See #469

3.16.1

  • Upgrade quibble to fix ESM replacement

3.16.0

  • Add new td.instance() method which is a one-liner of FakeFoo = td.constructor(Foo); new FakeFoo() #448

3.15.0

  • Add support for faking native ES modules with td.replaceEsm() #445

3.14.0

3.13.1

  • Fixes cases where test double objects are passed into when or verify #427

Automated changelog (pre-3.13.0) - github_changelog_generator stopped working for us

v3.12.4 (2019-08-21)

Full Changelog

v3.12.3 (2019-08-04)

Full Changelog

Closed issues:

  • Destructuring support fail. #424

Merged pull requests:

  • Add cloneArgs to VerificationConfig type #425 (lumaxis)

v3.12.2 (2019-07-16)

Full Changelog

Merged pull requests:

v3.12.1 (2019-07-03)

Full Changelog

Closed issues:

  • MockService Not Working in Angular 8 #420
  • ReferenceError: td is not defined #418

Merged pull requests:

  • [Issue-370] - Update createTestDoublesForFunctionNames to return an object #421 (bannmoore)

v3.12.0 (2019-06-08)

Full Changelog

Closed issues:

  • Challenges testing mutable objects #416
  • How to stub out instance methods and replace dependencies when writing a request test? #414
  • Mocking Behavior Similar To Rspec: expect to receive and return #413
  • How can I verify a call to a stub which is configured to throw? #412
  • td.replace a double arrow function #411
  • Unable to replace mongoose.model #410
  • Cannot test testdoubles inside .then function. #409
  • How to test a error subscription #408
  • Arguments of mocked functions are saved by reference. #375

Merged pull requests:

  • add cloneArgs option to td.when/td.verify #417 (searls)

v3.11.0 (2019-02-24)

Full Changelog

Merged pull requests:

  • allow for deeply nested test double objects #407 (searls)
  • have the deep nested proxy work with explain #406 (lgandecki)

v3.10.0 (2019-02-02)

Full Changelog

Closed issues:

  • 2 consecutive 'when(...).thenTrow(...)' expectations crashes #403
  • Remove es6-map polyfill #367
  • How to mock typescript abstract class? #356

Merged pull requests:

v3.9.3 (2019-01-16)

Full Changelog

Merged pull requests:

v3.9.2 (2018-12-31)

Full Changelog

Closed issues:

  • Call a Callback Multiple Times #397
  • TypeScript: Update Definition #395

Merged pull requests:

  • allow for creating testdoubles using interface only #400 (lgandecki)

v3.9.1 (2018-11-29)

Full Changelog

Closed issues:

  • td.replace before it vs td.replace inside of it #394
  • Add sticky td.reset.onReset hook #377

Merged pull requests:

  • Add type information for imitation to the exported typings file #396 (lisamai)

v3.9.0 (2018-11-20)

Full Changelog

Closed issues:

  • There are legitimate cases to use td.verify #389
  • TypeError on td.replace('aws-sdk') #388
  • Multiple stubs, count wrong? #387

Merged pull requests:

v3.8.2 (2018-10-08)

Full Changelog

Implemented enhancements:

  • Verifying stubs that return promises without warnings? #245

Closed issues:

  • How do I verify only 1 of 2 stubbed functions was called? #384
  • Fake timers / mock Date #383
  • Getting a not a constructor error when trying to stub an external class dependency #382
  • how to handle async callbacks #380
  • mocking non-direct dependency #379
  • How to replace momentjs ? #378
  • testdouble incompatible with coverage tools? #374
  • td.replaced module still returning stub after a td.reset() #373
  • Awaiting a testdouble function always resolves #371
  • Stub one function and use originals for rest #368
  • td.replace is breaking type definitions from sanctuary.js #327

Merged pull requests:

v3.8.1 (2018-05-05)

Full Changelog

Implemented enhancements:

  • Better verification messages #161

Closed issues:

  • Trouble replacing ES6 classes #365
  • You have a global leak: \_\_core-js\_shared\_\_ #364
  • testdouble causes bluebird to emit Unhandled rejection #168
  • Should style API of chai.js doesn't always work on test doubles since 1.6.2 #134

v3.8.0 (2018-04-29)

Full Changelog

Implemented enhancements:

  • Improve td.replace error message for incorrect module path #355

Closed issues:

  • td.verify(object.function(new Class("param"))) not asserting "param" #362
  • How to Stub a Chained Function #360
  • Critical dependency: the request of a dependency is an expression? #354

Merged pull requests:

  • Better missing module message for td.replace() #363 (searls)

v3.7.0 (2018-03-31)

Full Changelog

Closed issues:

  • Compare dates when using td.matchers.contains #358
  • verifiable thenThrow #288
  • docs: simple page that lists the entire API #253
  • Planning Discussion for a move to TypeScript #252
  • More support for ES Modules #246
  • Consider using _.isObjectLike rather than _.isPlainObject within td.object #224

Merged pull requests:

  • Enhance contains for edge cases, make nesting behave consistently #359 (searls)

v3.6.0 (2018-03-24)

Full Changelog

Closed issues:

  • td.replace a required method? #353

Merged pull requests:

v3.5.2 (2018-02-26)

Full Changelog

Merged pull requests:

v3.5.1 (2018-02-25)

Full Changelog

Closed issues:

  • slow performance when replacing big modules #340
  • Replace method in tested file #339

Merged pull requests:

v3.5.0 (2018-02-11)

Full Changelog

Closed issues:

  • Warn jest users when they call td.replace(moduleName) and point them to testdouble-jest #337
  • td.replace doesn't work with Jest #331

Merged pull requests:

v3.4.0 (2018-02-10)

Full Changelog

Fixed bugs:

  • The webpack example project doesn't work #334

Closed issues:

  • Update Getting Started to pass instance object instead of constructor to td.object() #329

Merged pull requests:

v3.3.4 (2018-02-09)

Full Changelog

Merged pull requests:

v3.3.3 (2018-01-18)

Full Changelog

Fixed bugs:

  • Cannot convert a Symbol value to a string #300

Closed issues:

  • Stubbing function from same module under test not replacing real implementation #325
  • td.replace does not follow node_modules symlinks since v3.3.2 #324
  • td.explain does not work on new instance of td.replace('lib') #323
  • td.object(undefined) allowes to call any method #321
  • td.replace('mongoose') throws exception #316

Merged pull requests:

v3.3.2 (2018-01-16)

Full Changelog

Fixed bugs:

  • td.replace() on an un-parseable source will claim the module is missing instead of printing the parse error #320

Closed issues:

  • thenThrow does not work if stub passed down #319

Merged pull requests:

v3.3.1 (2018-01-05)

Full Changelog

v3.3.0 (2017-12-26)

Full Changelog

Merged pull requests:

v3.2.7 (2017-12-20)

Full Changelog

Fixed bugs:

  • Disallow captors in td.when\(...\) #308

Closed issues:

  • Unexpected output with td.matchers.isA(Function) #307
  • Different objects created using the same constructor function obtained using td.constructor share the same stubs #305
  • Using invocation verification with QUnit #304
  • example tests don't work on latest master #302
  • Error when running install inside testdouble.js #298
  • Can I use test double with enzyme on client end to test if method runs on button click ? #297
  • Node module mocking with td.replace() #294
  • replacing a nested dependency does not get reset correctly #293
  • How to verify the value of "this" keyword on a call? #292
  • How to mock typescript fields #291

Merged pull requests:

v3.2.6 (2017-09-18)

Full Changelog

Merged pull requests:

v3.2.5 (2017-09-07)

Full Changelog

Closed issues:

  • Missing support for async functions? (Node 8) #284
  • redacted #283
  • Stubbing priority #280

Merged pull requests:

v3.2.4 (2017-08-06)

Full Changelog

Closed issues:

  • td.constructor() ReferenceError: td is not defined #279

v3.2.3 (2017-08-01)

Full Changelog

Fixed bugs:

  • Verifying a td.constructor() fails #278

Closed issues:

  • Invocation sequence testing #277
  • Cannot assign to read only property 'constructor' after updating to v3.2.x #271

v3.2.2 (2017-06-30)

Full Changelog

Implemented enhancements:

  • Generator support #273

Merged pull requests:

  • Don't blow up when imitating a thing with generators on it #274 (searls)

v3.2.1 (2017-06-26)

Full Changelog

Closed issues:

  • Tests failing with 'TypeError: Cannot read property 'isPrototypeOf' of null' after updating 3.2.0 #270

v3.2.0 (2017-06-24)

Full Changelog

Implemented enhancements:

  • Single-layer property replacement is inappropriate for ES modules #262

Closed issues:

  • td.constructor() breaks instanceof #267

Merged pull requests:

  • imitate / replace things deeply (instead of shallow) #268 (searls)

v3.1.1 (2017-06-20)

Full Changelog

v3.1.0 (2017-06-18)

Full Changelog

Fixed bugs:

  • td.replace throws with objects created with Object.create #257
  • getters are executed when using td.constructor() #218

Closed issues:

  • Verify that constructor is passed certain values #256
  • Is there any sample code that mock aws sdk? #251
  • Cannot use td.object with "callable objects" #232

Merged pull requests:

  • Allow stubbing of custom instances & Object.create() #264 (searls)
  • Enable tsc in ci pipeline take 2 #260 (duluca)
  • TypeScript typing thenResolve takes variable args #258 (miyu)
  • Test testdouble.js with testdouble.js! #255 (searls)

v3.0.0 (2017-06-02)

Full Changelog

Fixed bugs:

  • Figure out babel+instanceof+constructor problems with class extension #241
  • Mocking a Class #157

Closed issues:

  • td.verify reporting after resolving promises #250
  • Replacing dependency with td.replace(path, replacement) doesn't work #249
  • Verify constructor #248
  • td.replace () breaks the cache in require #244
  • Faking internal calls #243
  • ECMAScript 2015 Classes with td.constructor() #240
  • TypeScript: Better Generic Support for td.object() #236
  • How to Replace Imported Constructor in Another File #235
  • Mocha Spec Reporter #234
  • TypeError: 'x' is not a function #233
  • Inifinite recursion problem #231
  • Invoke callback within object #230
  • Testing Constructor invocations #229
  • Stubbing chained API objects yields a warning #228

Merged pull requests:

  • Stop extending types when replacing constructors #254 (searls)
  • Fix #236; Add another overload and its test #237 (sgtoj)

v2.1.2 (2017-03-29)

Full Changelog

Closed issues:

  • TypeError when used with node -r flag #226
  • When replacing a node library calling it from other modules does not work as expected #225

v2.1.1 (2017-03-28)

Full Changelog

Closed issues:

  • Add td.config() to index.d.ts #222
  • Mocking external dependencies in Express app #221

Merged pull requests:

v2.1.0 (2017-03-25)

Full Changelog

Closed issues:

  • Using td.replace() with external modules #51

Merged pull requests:

  • Add support for third party modules #220 (searls)

v2.0.5 (2017-03-25)

Full Changelog

v2.0.4 (2017-03-23)

Full Changelog

Closed issues:

  • constructor\(someConstructorFunction\) not referenced in associated example #213

Merged pull requests:

v2.0.3 (2017-03-18)

Full Changelog

Merged pull requests:

v2.0.2 (2017-03-17)

Full Changelog

Closed issues:

  • Mocking a constructor function with no prototypes does not correctly mock static methods #208
  • Test td.function() after other td fuction() #202
  • How do I stub a function that being promisify'd by bluebird? #200

Merged pull requests:

v2.0.1 (2017-03-13)

Full Changelog

v2.0.0 (2017-03-13)

Full Changelog

Closed issues:

  • How can I write a test for such situation? #199
  • contains not working against IIFE objects #192
  • td.verify not returning true when true #191
  • Typing definition for td.object doesn't support constructors with arguments #184
  • Replacing methods on window.location #183
  • stub also verified warning when using ignoreExtraArgs #181
  • [BREAKING] Return constructor for td.replace\(\) #166
  • Allow matchers inside objects #160
  • Support invoking callbacks with arbitrary timing #106

Merged pull requests:

v1.11.2 (2017-02-28)

Full Changelog

Closed issues:

  • Stubbing promises with thenResolve does not actually provide for anything in the callback #189
  • sinon.sandbox analog? #188
  • Shortcut for new stub returning args #187
  • Can't find variable: Proxy #186

Merged pull requests:

  • Improve the error message when using Proxy incorrectly. #190 (Schoonology)

v1.11.1 (2017-01-27)

Full Changelog

Closed issues:

  • Is it possible to thenReturn the receiver? #182
  • Multiple stubbings with argThat causes unexpected behavior #180

Merged pull requests:

v1.11.0 (2017-01-17)

Full Changelog

Closed issues:

  • Having something like "verifyNoFurtherInvocations(mock)" would be nice (feature request) #176

Merged pull requests:

  • feat: contains allows for regexps against strings #178 (JaKXz)

v1.10.2 (2016-12-31)

Full Changelog

Closed issues:

  • Possible pollution issue (2 tests work individually, but fails when run together) #171
  • td.verify and td.when redundency warning #170
  • Does not work with jest #128

Merged pull requests:

v1.10.1 (2016-12-20)

Full Changelog

Implemented enhancements:

  • Make the constructor property of td.replaced() instantiable types useful #121
  • Improve output for times verification failures #85
  • Allow argument matchers to enhance failure messages #59
  • td.constructor() feature for creating fake constructors #54

Closed issues:

  • typings for typescript #167
  • A little typo in Getting Started documentation #165
  • Unable to stub static method on ES6 classes #164
  • transcribe unusual spending kata from ES5 to ES6/babel #163
  • Classes with overridden methods not doubling properly since 1.10.0 #159
  • td.replace\(\) doesn't work with import? #147
  • Support multiple capture invocations #139
  • Constructor replacements will fail instanceof checks #107

Merged pull requests:

v1.10.0 (2016-12-11)

Full Changelog

Implemented enhancements:

  • td.replace doesn't properly detect ES6 classes #119

Closed issues:

  • Matcher for a specific position #156

Merged pull requests:

  • Sort out replacement of especially 6+ Classes #158 (searls)

v1.9.1 (2016-12-03)

Full Changelog

Implemented enhancements:

  • td.replace for functions that have additional function properties #99

Closed issues:

  • Is testdouble.js not compatible with PhantomJS? #154
  • Model instance creation assistance #149
  • Excessive warn "was both stubbed and verified" #148

Merged pull requests:

v1.9.0 (2016-10-25)

Full Changelog

Implemented enhancements:

  • Note when ignoreExtraArgs is used for a failed verification #60

Closed issues:

  • td.replace multiple property names at once #146
  • Consider ignoreExtraArgs method instead of parameter #143

Merged pull requests:

  • Gives better hint when verification fails while ignoring extra args #150 (samjonester)

v1.8.0 (2016-10-12)

Full Changelog

Closed issues:

  • Feature request: Partial object matchers #141
  • Drop CoffeeScript #140
  • Question with verifications #138
  • td.reset() it´s working has expected? #133

Merged pull requests:

v1.7.0 (2016-09-18)

Full Changelog

Merged pull requests:

v1.6.2 (2016-09-18)

Full Changelog

Closed issues:

  • Add support for concurrent test runners (ava)? #131
  • Async use of verify results in timeout #129

Merged pull requests:

  • Should methods on super types be stubbed in td.object? #130 (paultyng)

v1.6.1 (2016-08-31)

Full Changelog

Closed issues:

  • td.explain should indicate thenCallback / thenResolve / thenReject from thenReturn #126
  • td.when and td.verify warning #125
  • td.callback, when given a td.object, raises a TypeError #124
  • not matcher and calling function multiple times #122
  • Verify of a specific call when multiple calls happen #120

Merged pull requests:

v1.6.0 (2016-07-14)

Full Changelog

Closed issues:

  • Nested stubbing doesn't work #117

Merged pull requests:

  • Allow nested stubbing configuration #118 (searls)

v1.5.0 (2016-07-13)

Full Changelog

Closed issues:

  • support promises resolve/reject #46

Merged pull requests:

  • Use stringify-object now that my change is merged #116 (searls)
  • Promise stubbing sugar #115 (searls)

v1.4.3 (2016-06-22)

Full Changelog

Closed issues:

  • Build with Travis on Node 6.x #114
  • Wrong test double name for proxies #112
  • Improve error output message #111
  • Flexible parameters #110
  • How can I install and use this in an ember/ember-cli project? #105
  • td.replace breaks subsequent require calls #103

Merged pull requests:

  • Generate test double name for a Proxy test double #113 (mgryszko)

v1.4.2 (2016-04-29)

Full Changelog

Closed issues:

  • matchers.contains(number) support #102

Merged pull requests:

  • Fix contains() behavior for arrays #104 (searls)
  • Add testdouble-timers as plugin to docs #101 (kuy)

v1.4.1 (2016-04-05)

Full Changelog

Closed issues:

  • Changelog #97

Merged pull requests:

  • Generate a changelog whenever we pubish #98 (searls)

v1.4.0 (2016-04-03)

Full Changelog

Closed issues:

  • Reserved word #82
  • Warn when users verify an invocation they also stubbed #76
  • Feature request: captors without verify #65

Merged pull requests:

v1.3.1 (2016-04-03)

Full Changelog

Closed issues:

  • Throws in node 0.10 #94
  • td.replace() property replacement warning & failure states #92
  • give users a way to squelch individual warnings #90

v1.3.0 (2016-04-03)

Full Changelog

Closed issues:

  • What's the best way to use testdouble.js with tape? #93
  • help #91
  • td.replace() fails for method on prototype #86

Merged pull requests:

  • README: Replace GIFs with code blocks #88 (Turbo87)
  • replace: Use object[property] to check if property exists #87 (Turbo87)

v1.2.0 (2016-03-20)

Full Changelog

Merged pull requests:

v1.1.3 (2016-03-16)

Full Changelog

Closed issues:

  • Quibble in the browser #77

Merged pull requests:

  • Improve support for webpack users #80 (searls)

v1.1.1 (2016-03-15)

Full Changelog

Merged pull requests:

  • Add webpack specific metadata to package.json #79 (davemo)

v1.1.0 (2016-03-11)

Full Changelog

Closed issues:

  • Add a property-namespacing-like replace strategy for browsers. #55

Merged pull requests:

  • td.replace support for object properties (incl. browsers) #75 (searls)
  • td.explain tells you if you passed it a test double #74 (searls)

v1.0.0 (2016-03-10)

Full Changelog

Closed issues:

  • Document thenDo and thenThrow #64

Merged pull requests:

v0.10.0 (2016-03-09)

Full Changelog

Merged pull requests:

  • Change window.testdouble to window.td #71 (searls)

v0.9.0 (2016-03-09)

Full Changelog

Implemented enhancements:

  • Stubbing callbacks #66

Closed issues:

  • Getting testdouble.js to play nicely with Jasmine expectations? #41

Merged pull requests:

v0.8.0 (2016-02-06)

Full Changelog

Closed issues:

  • Add thenDo #8
  • Add thenThrow #7

v0.7.3 (2015-12-07)

Full Changelog

Implemented enhancements:

  • td.matchers.contains does not work on sparse object trees #58

Fixed bugs:

  • td.matchers.contains does not work on sparse object trees #58

Merged pull requests:

v0.7.2 (2015-11-25)

Full Changelog

Fixed bugs:

  • td.matchers.contains blows up on sparse matches #56

Merged pull requests:

v0.7.1 (2015-11-12)

Full Changelog

v0.7.0 (2015-11-12)

Full Changelog

Closed issues:

  • Is there a way to reset the state of a double? #43

Merged pull requests:

v0.6.0 (2015-10-27)

Full Changelog

Closed issues:

  • add ES2015 Proxy support #39

Merged pull requests:

  • Implement ES2015 proxy doubles #42 (searls)

v0.5.0 (2015-10-25)

Full Changelog

Closed issues:

  • Add verify times() #5

Merged pull requests:

v0.4.0 (2015-10-24)

Full Changelog

Closed issues:

  • Allow when & verify to disregard arity #36
  • implement argument captors #35

Merged pull requests:

v0.3.1 (2015-10-24)

Full Changelog

Fixed bugs:

  • contains() matcher doesn't seem to work on arrays #31

Closed issues:

  • verify does not throw exception when too many arguments are passed #33
  • Building CoffeeScript at runtime is slow. #29

Merged pull requests:

v0.3.0 (2015-10-21)

Full Changelog

Closed issues:

  • When stringifying args, use a testdouble's name if it has one #21

Merged pull requests:

v0.2.0 (2015-09-13)

Full Changelog

Closed issues:

  • Add a build task that distributes a web version / bower.json / etc #10

Merged pull requests:

v0.1.0 (2015-09-09)

Full Changelog

Closed issues:

  • name a test double with create\("name"\) #15
  • Implement default matchers #9
  • Add sequential stubbing #6
  • Implement Prototype for create() #2
  • Implement argument matchers #1

Merged pull requests:

v0.0.5 (2015-09-08)

Full Changelog

Closed issues:

  • Add verify\(\) #4

0.0.4 (2015-09-08)

Full Changelog

0.0.3 (2015-09-08)

Full Changelog

Closed issues:

  • Print version in browserify build #23
  • Add a require\('testdouble'\).explain function #12
  • Ensure last stubbing wins #11

0.0.2 (2015-09-07)