### Install testdouble.js with npm Source: https://testdouble.github.io/testdouble.js/1-installation.md Install testdouble.js as a development dependency using npm. This is the recommended method for both Node.js and browser projects managed with npm. ```bash $ npm install --save-dev testdouble ``` -------------------------------- ### td.verify() - Argument Matchers Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Details how to use argument matchers with td.verify() to relax verification constraints. Covers td.matchers.anything(), td.matchers.isA(), and td.matchers.contains() with examples for each. ```APIDOC ## td.verify() - Relaxing verifications with argument matchers ### Description Each of the [argument matchers supported when stubbing](5-stubbing-results.md#what-are-argument-matchers) also work when verifying an interaction. Below are simple examples of each built-in matcher #### td.matchers.anything() The `anything()` matcher will only ensure that an argument was passed, but will ignore whatever its value was. ```javascript var bark = td.function() bark('woof') td.verify(bark('woof')) // passes td.verify(bark(td.matchers.anything())) // passes td.verify(bark(td.matchers.anything(), td.matchers.anything())) // throws - was 1 arg td.verify(bark()) // throws - 1 arg needed ``` #### td.matchers.isA() The `isA()` matcher can be used to verify a matching type for a given argument. ```javascript var eatBiscuit = td.function() eatBiscuit(44) td.verify(eatBiscuit(44)) // passes td.verify(eatBiscuit(td.matchers.isA(Number))) // passes td.verify(eatBiscuit(td.matchers.isA(Date))) // throws - 44 is not a Date td.verify(eatBiscuit(td.matchers.isA(Object))) // throws - Number is not an Object ``` Unfortunately, the error message generated when a verification fails due to an argument matcher mis-match is not very informative. If you'd like to help out, see this issue to [improve the argument matcher](https://github.com/testdouble/testdouble.js/issues/59) API. #### td.matchers.contains() The contains matcher is satisified if the passed-in portion of a string, array, or object is found on an actual invocation of the test double. ##### Strings ```javascript var log = td.function() log('Why hello there!') td.verify(log('Why hello there!')) // passes td.verify(log(td.matchers.contains('hello'))) // passes td.verify(log(td.matchers.contains('goodbye'))) // throws - string not found ``` ``` -------------------------------- ### Define ESM module structure Source: https://testdouble.github.io/testdouble.js/7-replacing-dependencies.md Example structure for ESM modules to be replaced. ```javascript // brake.mjs export default function brake() {...} export function abs() {...} // car.mjs import brake, {abs} from './brake.mjs' ``` -------------------------------- ### td.verify() - Basic Usage Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Demonstrates the basic usage of td.verify() to check if a test double function was invoked with expected arguments. It highlights the similarity to td.when() and shows an example of a successful verification and the error message for a failed one. ```APIDOC ## POST /api/users ### Description Creates a new user in the system. ### Method POST ### Endpoint /api/users ### Parameters #### Query Parameters - **name** (string) - Required - The name of the user. - **email** (string) - Required - The email address of the user. ### Request Body - **user_id** (integer) - Required - The unique identifier for the user. ### Request Example ```json { "user_id": 12345 } ``` ### Response #### Success Response (200) - **message** (string) - A confirmation message. - **user_id** (integer) - The ID of the created user. #### Response Example ```json { "message": "User created successfully", "user_id": 12345 } ``` ## td.verify() - Basic Usage ### Description A basic verification looks like this: ```javascript var quack = td.function('quack') quack('QUACK') td.verify(quack('QUACK')) // Nothing happens, because verification was satisfied ``` As you can see, `td.verify` is very similar to `td.when`, in that it ignores the first argument passed to it so that in our test we can write a "demonstration" of how we expected the test double to have been invoked by our code under test. When a verification fails, an error is thrown with a message like the following: ```javascript td.verify(quack()) Error: Unsatisfied verification on test double `quack`. Wanted: - called with `() `. But was actually called: - called with `("QUACK")`. at Object.module.exports [as verify] (/Users/justin/code/testdouble/testdouble.js/lib/verify.js:22:15) ``` As you can see, the expected arguments of the failed verification are printed along with any actual invocations of the test double function. ``` -------------------------------- ### Test interaction with a double Source: https://testdouble.github.io/testdouble.js/B-frequently-asked-questions.html An example test case showing the redundant use of td.verify after stubbing with td.when. ```javascript var load = td.function() td.when(load(42)).thenReturn({name: "Jane"}) var result = getName(load, 42) assert(result, "Jane") td.verify(load(42)) ``` -------------------------------- ### Basic Jasmine/Mocha Test Structure Source: https://testdouble.github.io/testdouble.js/3-getting-started.html An empty test suite structure using a Jasmine/Mocha compatible DSL. This serves as the initial setup for testing. ```javascript describe('MathProblem', function(){ it('POSTs a random problem', function(){ }) }) ``` -------------------------------- ### Subject Module Using Third-Party Dependency Source: https://testdouble.github.io/testdouble.js/7-replacing-dependencies.md An example of a subject module that depends on the 'is-number' module, which can be replaced during testing. ```javascript var isNumber = require('is-number') module.exports = function (thing) { if (!isNumber(thing)) { throw new Error('numbers only!') } return true } ``` -------------------------------- ### Test with td.replace Source: https://testdouble.github.io/testdouble.js/7-replacing-dependencies.md Example of using td.replace to mock an object property in a browser-like environment. ```javascript var brake = td.replace(app, 'brake') subject = app.car subject.slowDown() td.verify(brake(10)) ``` -------------------------------- ### Use Custom 'isA' Matcher in Testdouble.js Source: https://testdouble.github.io/testdouble.js/8-custom-matchers.html Demonstrates how to use the custom 'isA' matcher when defining stubbed behavior with `td.when()`. The example shows a function `datePicker` that returns 'good' when called with an instance of `Date`. ```javascript var datePicker = td.function() td.when(datePicker(isA(Date))).thenReturn('good') datePicker(new Date()) // 'good' datePicker(5) // undefined ``` -------------------------------- ### td.verify() - Argument Precision Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Explains how argument precision works with td.verify(), using lodash's _.isEqual by default. It provides examples of exact matches and mismatches due to missing properties or unequal values. ```APIDOC ## td.verify() - Argument Precision ### Description All of testdouble.js's [rules about argument precision when stubbing](5-stubbing-results.md#simple-precise-argument-stubbing) apply here, too. By default, each expected argument is tested against the arguments actually passed to the test double with lodash's [_.isEqual](http://lodash.com/docs#isEqual) function. ### Examples ```javascript var enroll = td.function() enroll({name: 'Joe', age: 22, gender: null}) td.verify(enroll({name: 'Joe', age: 22, gender: null})) // passes — deeply equal td.verify(enroll({name: 'Joe', age: 22})) // throws - missing property td.verify(enroll({name: 'Joe', age: 23, gender: null})) // throws - not equal ``` ``` -------------------------------- ### Stubbing with argThat Matcher Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Use `td.matchers.argThat` to provide a custom truth test function for stubbing when built-in matchers are insufficient. Be mindful of side effects in the predicate function, as they will be invoked during stubbing setup. ```javascript var pet = td.function() td.when(pet(td.matchers.argThat(function(animals){ return animals.length > 2 }))).thenReturn('goood') pet(['cat', 'dog', 'horse']) // 'goood' pet(['cat', 'dog']) // undefined pet({length: 81}) // 'goood' ``` -------------------------------- ### TypeScript error examples for interface mocks Source: https://testdouble.github.io/testdouble.js/10-using-with-typescript.html Examples of TypeScript compiler errors triggered by incorrect usage of mocked interface methods. ```typescript td.when(mockedRepository.findByName(3)).thenReturn("Alice Alicy"); ``` ```typescript td.when(mockedRepository.findByNaame("Alice")).thenReturn("returnedString"); ``` ```typescript td.when(mockedRepository.findByName("Alice")).thenReturn({ lastName: "Alicy" }); const found = mockedRepository.findByName("Alice"); expect(found.lastName).toEqual("Alicy"); ``` -------------------------------- ### TypeScript error examples for function mocks Source: https://testdouble.github.io/testdouble.js/10-using-with-typescript.html Examples of TypeScript compiler errors triggered by incorrect usage of mocked function types. ```typescript mockedPickFirst("myString"); ``` ```typescript td.when(mockedPickFirst(["", ""])).thenReturn({ abc: () => {} }); const result = mockedPickFirst(["", ""]); result.abc(); ``` -------------------------------- ### Download testdouble.js browser build via unpkg Source: https://testdouble.github.io/testdouble.js/1-installation.md Fetch the testdouble.js browser distribution file from the unpkg CDN using curl. This file can then be included in your project or source control. ```bash $ curl -L https://unpkg.com/testdouble/dist/testdouble.js ``` -------------------------------- ### Verifying with argument precision Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Illustrates how arguments are compared using deep equality by default. ```javascript var enroll = td.function() enroll({name: 'Joe', age: 22, gender: null}) td.verify(enroll({name: 'Joe', age: 22, gender: null})) // passes — deeply equal td.verify(enroll({name: 'Joe', age: 22})) // throws - missing property td.verify(enroll({name: 'Joe', age: 23, gender: null})) // throws - not equal ``` -------------------------------- ### Define Constructor and Method Source: https://testdouble.github.io/testdouble.js/3-getting-started.html Makes the test pass by defining the `MathProblem` constructor and its `generate` method. This is the 'make it green' step. ```javascript MathProblem = function(){} MathProblem.prototype.generate = function() {} // Green ``` -------------------------------- ### Basic verification with td.verify() Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Demonstrates a successful verification of a function call. ```javascript var quack = td.function('quack') quack('QUACK') td.verify(quack('QUACK')) // Nothing happens, because verification was satisfied ``` -------------------------------- ### Explain a new test double Source: https://testdouble.github.io/testdouble.js/9-debugging.html Use td.explain() on a newly created test double to see its initial state. This is useful for verifying that a double has been set up correctly before any interactions. ```javascript var myTestDouble = td.function('.someFunction') td.explain(myTestDouble) /* { name: '.someFunction', callCount: 0, calls: [], description: 'This test double has 0 stubbings and 0 invocations.' } */ ``` -------------------------------- ### td.explain(someTestDouble) Source: https://testdouble.github.io/testdouble.js/9-debugging.html The td.explain() method takes a test double function as an argument and returns an object describing its current configuration and state, including its name, call count, calls made, stubbings, and a human-readable description. ```APIDOC ## td.explain(someTestDouble) ### Description This method returns an object that describes the current configuration and state of a test double. It can be used to inspect stubbings, invocations, and other details about the test double. ### Method `td.explain()` ### Parameters #### Path Parameters - **someTestDouble** (function) - Required - The test double function to explain. ### Request Example ```javascript var myTestDouble = td.function('.someFunction'); td.explain(myTestDouble); ``` ### Response #### Success Response (200) - **name** (string) - The name of the test double. - **callCount** (number) - The total number of times the test double has been called. - **calls** (array) - An array of objects, where each object represents a call made to the test double and contains `args` and `context`. - **description** (string) - A human-readable description of the test double's configuration and state, including stubbings and invocations. #### Response Example ```json { "name": ".someFunction", "callCount": 0, "calls": [], "description": "This test double has 0 stubbings and 0 invocations." } ``` ### Example with Stubbing ```javascript td.when(myTestDouble(5)).thenReturn(10); td.explain(myTestDouble); ``` #### Response Example ```json { "name": "someFunction", "callCount": 0, "calls": [], "description": "This test double `.someFunction` has 1 stubbings and 0 invocations.\n\n Stubbings:\n - when called with `(5)`, then return `10`." } ``` ### Example with Invocation ```javascript myTestDouble(7); // undefined td.explain(myTestDouble); ``` #### Response Example ```json { "name": ".someFunction", "callCount": 1, "calls": [ { "args": [7], "context": window } ], "description": "This test double has 1 stubbings and 1 invocations.\n Stubbings:\n - when called with `(5)`, then return `10`.\n\n Invocations:\n - called with `(7)`." } ``` **Note:** `td.explain()` can also be used with test doubles created by `td.func()`, `td.object()`, `td.constructor()`, and `td.imitate()`. It will recursively describe all functions found within these test doubles. ``` -------------------------------- ### Configuring Custom Promise Libraries Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Point testdouble.js to a specific promise library if the runtime lacks native support or requires a specific implementation. ```javascript td.config({ promiseConstructor: require('bluebird') }) ``` -------------------------------- ### td.function - Creating a Fake Function Source: https://testdouble.github.io/testdouble.js/4-creating-test-doubles.html Demonstrates how to create a basic fake function using td.function and how to assign a name for better debugging messages. ```APIDOC ## td.function ### Description Creates a fake function (test double) that can be configured with `td.when`, verified with `td.verify`, and inspected with `td.explain`. ### Method `td.function([name])` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript var bark = td.function() // '[test double (unnamed)]' var woof = td.function('.woof') // test double for ".woof" ``` ### Response #### Success Response (200) Returns a test double function. #### Response Example ```json "[test double (unnamed)]" ``` ``` -------------------------------- ### td.function - Creating from a Real Function Source: https://testdouble.github.io/testdouble.js/4-creating-test-doubles.html Shows how to create a test double from an existing function, copying its properties and replacing nested functions with test doubles. ```APIDOC ## td.function (from real function) ### Description Creates a test double from a real function, copying all of its properties. If any properties are functions, they will also be replaced with test double functions. ### Method `td.function(realFunction)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript function meow () { throw 'unimplemented' } meow.volume = 'loud' meow.stop = function () {} var fakeMeow = td.function(meow) // test double for "meow" fakeMeow.volume // 'loud' fakeMeow.stop // test double for "meow.stop" ``` ### Response #### Success Response (200) Returns a test double function that is a copy of the provided real function with its own function properties replaced by test doubles. #### Response Example ```json "test double for \"meow\"" ``` ``` -------------------------------- ### Configure testdouble.js Global Options Source: https://testdouble.github.io/testdouble.js/C-configuration.html Use `td.config` to set global options like `ignoreWarnings`, `promiseConstructor`, and `suppressErrors`. Configuration is persisted; manage changes for individual tests manually. ```javascript td.config({ ignoreWarnings: false, // set to true to squelch generated console warnings promiseConstructor: Promise // defaults to native Promise (if available) suppressErrors: false // set to true to no longer throw API errors }) ``` -------------------------------- ### Explain a test double with stubbings Source: https://testdouble.github.io/testdouble.js/9-debugging.html After setting up stubbings on a test double, td.explain() will list them. This helps in understanding which specific calls are expected to be handled by predefined responses. ```javascript td.when(myTestDouble(5)).thenReturn(10) td.explain(myTestDouble) /* { name: 'someFunction', callCount: 0, calls: [], description: 'This test double `.someFunction` has 1 stubbings and 0 invocations. Stubbings: - when called with `(5)`, then return `10`.' } */ ``` -------------------------------- ### td.object - Creating a Fake Object Source: https://testdouble.github.io/testdouble.js/4-creating-test-doubles.html Explains how to create test doubles for objects, focusing on two styles: mirroring plain objects with functions or prototyping interactions by providing function names or an object name. ```APIDOC ## td.object ### Description Creates an object whose function properties are replaced with fake functions (test doubles). This can be done by passing a plain JavaScript object with functions as properties, or by providing an array of function names or an object name (for ES2015 Proxy runtimes) to prototype interactions. ### Method `td.object(options)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **options** (Object | Array | string) - Either a plain JavaScript object with function properties to mirror, an array of function names to create, or a name for the object if using ES2015 Proxy. ### Request Example ```javascript // Mirroring a plain object var fakeLogger = td.object({ info: function () {}, warn: function () {} }) // Prototyping interactions with function names var fakeApi = td.object(['get', 'post']) // Prototyping interactions with an object name (ES2015 Proxy) var fakeService = td.object('MyService') ``` ### Response #### Success Response (200) Returns a test double object with its function properties replaced by test doubles. #### Response Example ```json { "info": "[test double (unnamed)]", "warn": "[test double (unnamed)]" } ``` ``` -------------------------------- ### Create multiple test doubles Source: https://testdouble.github.io/testdouble.js/3-getting-started.html Initialize multiple test doubles for different dependencies within a test suite. ```javascript describe('MathProblem', function(){ var subject, createRandomProblem, savesProblem, submitProblem; beforeEach(function(){ createRandomProblem = td.function('createRandomProblem') savesProblem = td.object(SavesProblem) submitProblem = td.function('submitProblem') subject = new MathProblem(createRandomProblem, savesProblem, submitProblem) }) it('POSTs a random problem', function(){ // ... }) }) ``` -------------------------------- ### Implement Subject Function Source: https://testdouble.github.io/testdouble.js/3-getting-started.html This JavaScript class implements the `generate` method, orchestrating calls to `createRandomProblem`, `savesProblem.save`, and `submitProblem`. ```javascript function MathProblem(createRandomProblem, savesProblem, submitProblem) { this.createRandomProblem = createRandomProblem this.savesProblem = savesProblem this.submitProblem = submitProblem } MathProblem.prototype.generate = function(){ var problem = this.createRandomProblem(), savedProblem = this.savesProblem.save(problem) this.submitProblem(savedProblem) } ``` -------------------------------- ### Create Test Double Function Source: https://testdouble.github.io/testdouble.js/3-getting-started.html Demonstrates creating a test double for a dependency using `td.function()`. This double is then passed to the subject's constructor. ```javascript describe('MathProblem', function(){ var subject, createRandomProblem; beforeEach(function(){ createRandomProblem = td.function('createRandomProblem') subject = new MathProblem(createRandomProblem) }) it('POSTs a random problem', function(){ subject.generate() }) }) ``` -------------------------------- ### Subject Initialization in Test Source: https://testdouble.github.io/testdouble.js/3-getting-started.html Adds subject instantiation and invocation within the test. This step will initially fail, indicating the need to define the `MathProblem` class. ```javascript describe('MathProblem', function(){ var subject; before(function(){ subject = new MathProblem() }) it('POSTs a random problem', function(){ subject.generate() }) // Red -- ReferenceError: MathProblem is not defined }) ``` -------------------------------- ### Implement app.car Source: https://testdouble.github.io/testdouble.js/7-replacing-dependencies.md Implementation of the subject under test. ```js app.car = { slowDown: function() { app.brake(10) } } ``` -------------------------------- ### Configuring and verifying interface mocks Source: https://testdouble.github.io/testdouble.js/10-using-with-typescript.html Define behavior for interface methods and verify results using standard testdouble.js patterns. ```typescript td.when(mockedRepository.findByName("Alice")).thenReturn("Alice Alicy"); const value = mockedRepository.findByName("Alice"); expect(value).toEqual("Alice Alicy"); ``` -------------------------------- ### Create a constructable test double from function names Source: https://testdouble.github.io/testdouble.js/4-creating-test-doubles.html Pass an array of strings to td.constructor to define instance methods for the resulting constructor. ```javascript var FakeCat = td.constructor(['meow', 'scratch']) FakeCat.prototype.meow // a test double function named '#meow' FakeCat.prototype.scratch // a test double function named '#scratch' ``` -------------------------------- ### Default argument behavior in testdouble.js Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Demonstrates the default behavior where stubbing is satisfied even if the passed object is mutated after configuration. ```js const func = td.func() const person = { age: 17 } td.when(func(person)).thenReturn('minor') // Later, in your code person.age = 30 func(person) // 'minor' ``` -------------------------------- ### Instantiate a test double constructor Source: https://testdouble.github.io/testdouble.js/4-creating-test-doubles.html Use td.instance as a convenience method to instantiate a test double constructor directly. ```javascript const dog = td.instance(Dog) ``` ```javascript const FakeDog = td.constructor(Dog) const dog = new FakeDog() ``` -------------------------------- ### Explain Test Double State Source: https://testdouble.github.io/testdouble.js/3-getting-started.html Shows how to use `td.explain()` to inspect the state of a test double, including call counts, calls, and stubbings. This is useful for debugging. ```javascript { callCount: 0, calls: [], description: "This test double `createRandomProblem` has 0 stubbings and 0 invocations." } ``` -------------------------------- ### Implement subject under test Source: https://testdouble.github.io/testdouble.js/7-replacing-dependencies.md Implementation of the subject module that consumes the dependency. ```javascript var brake = require('./brake') module.exports.slowDown = function(){ brake(10) } ``` -------------------------------- ### Replace Third-Party Module with testdouble.js Source: https://testdouble.github.io/testdouble.js/7-replacing-dependencies.md Demonstrates how to replace a third-party npm module like 'is-number' using `td.replace`. Ensure `td.replace` is called before requiring the subject module. ```javascript var isNumber = td.replace('is-number') var numbersOnly = require('./numbers-only') td.when(isNumber('a string')).thenReturn(true) // tee-hee, this is silly var result = numbersOnly('a string') assert.equal(result, true) ``` -------------------------------- ### Prototype dependency for replacement Source: https://testdouble.github.io/testdouble.js/7-replacing-dependencies.md Export a function from the dependency file so testdouble.js can correctly identify the replacement type. ```javascript module.exports = function(){} ``` -------------------------------- ### Enforcing strict argument matching with cloneArgs Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Demonstrates using { cloneArgs: true } to ensure stubbing is only satisfied if arguments remain identical to their state during configuration. ```js const func = td.func() const person = { age: 17 } td.when(func(person), { cloneArgs: true }).thenReturn('minor') // Later, in your code person.age = 30 func(person) // undefined ``` -------------------------------- ### Capture and verify callback argument Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Initializes a captor to intercept the anonymous callback passed to the fetcher function. ```javascript var logger = td.function('logger'), fetcher = td.function('fetcher'), captor = td.matchers.captor() logInvalidComments(fetcher, logger) td.verify(fetcher('/comments', captor.capture())) ``` -------------------------------- ### Define app.brake Source: https://testdouble.github.io/testdouble.js/7-replacing-dependencies.md Initial definition of the property to be replaced. ```js app.brake = function(){} ``` -------------------------------- ### td.matchers.create Source: https://testdouble.github.io/testdouble.js/8-custom-matchers.html Creates a custom argument matcher for use in td.when() or td.verify() calls. ```APIDOC ## td.matchers.create ### Description Creates a custom argument matcher. Any object with a `__matches` function returning a truthy value is considered a matcher, but this helper ensures better error messages and integration with testdouble.js features. ### Parameters #### Request Body - **matches** (function) - Required - A function that returns truthy when an `actual` argument satisfies the matcher's rules. Receives `(matcherArgs, actual)`. - **name** (string|function) - Optional - A string name or a function returning a string for better error messages. - **onCreate** (function) - Optional - A function invoked when the matcher instance is created. Receives `(matcherInstance, matcherArgs)`. - **afterSatisfaction** (function) - Optional - A function invoked when `td.when` or `td.verify` is satisfied. Receives `(matcherArgs, actual)`. ### Request Example { "name": "isA", "matches": "function(matcherArgs, actual) { return actual instanceof matcherArgs[0] }" } ### Response #### Success Response (200) - **matcher** (object) - A matcher instance that can be used in testdouble stubbing or verification. ``` -------------------------------- ### Define a constructor dependency Source: https://testdouble.github.io/testdouble.js/3-getting-started.html Define a constructor function and prototype method to be used as a dependency. ```javascript function SavesProblem() {} SavesProblem.prototype.save = function(){} ``` -------------------------------- ### Stubbing with 'defer' option Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Forces callback execution to be scheduled on a later execution stack, useful for testing asynchronous behavior. ```APIDOC ## td.when(...).thenCallback(..., {defer: true}) ### Description Ensures that callbacks are invoked asynchronously on a later execution stack rather than synchronously. This helps identify tests that incorrectly rely on synchronous callback execution. ### Request Example ```javascript td.when(fetchBalance(42), {defer: true}).thenCallback(null, 1337) ``` ``` -------------------------------- ### Define function with anonymous callback Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md A sample function that accepts a fetcher and a logger, using an anonymous callback to process response data. ```javascript function logInvalidComments(fetcher, logger) { fetcher('/comments', function(response){ response.comments.forEach(function(comment) { if(!comment.valid) { logger('Hey, '+comment.text+' is invalid') } }) }) } ``` -------------------------------- ### Basic Stubbing with td.when() Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Configure a test double function to return a specific value when called. Assumes `testdouble` is aliased to `td`. ```javascript var quack = td.function('quack') td.when(quack()).thenReturn('some return value') quack() // 'some return value' ``` -------------------------------- ### Replace dependency with a custom fake Source: https://testdouble.github.io/testdouble.js/7-replacing-dependencies.md Overrides the default imitation scheme by providing a specific value to be returned by the module loader. ```javascript td.replace('./foo', 42) ``` -------------------------------- ### Using td.matchers.anything() Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Verifies that an argument was passed regardless of its specific value. ```javascript var bark = td.function() bark('woof') td.verify(bark('woof')) // passes td.verify(bark(td.matchers.anything())) // passes td.verify(bark(td.matchers.anything(), td.matchers.anything())) // throws - was 1 arg td.verify(bark()) // throws - 1 arg needed ``` -------------------------------- ### Create a test double function Source: https://testdouble.github.io/testdouble.js/4-creating-test-doubles.html Create a basic fake function using td.function, optionally providing a name for better debugging. ```javascript var bark = td.function() // '[test double (unnamed)]' ``` ```javascript var woof = td.function('.woof') // test double for ".woof" ``` -------------------------------- ### One-Liner Stubbing Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Create a test double and configure its stubbing in a single, concise line. This is useful for simple, one-off stubbing needs. ```javascript var woof = td.function() td.when(woof()).thenReturn('bark') ``` ```javascript var woof = td.when(td.function()()).thenReturn('bark') ``` -------------------------------- ### Create a Custom 'isA' Argument Matcher Source: https://testdouble.github.io/testdouble.js/8-custom-matchers.html Defines a custom matcher named 'isA' that checks if an argument is an instance of a specified constructor. This is useful for type checking arguments in test doubles. ```javascript isA = td.matchers.create({ name: 'isA', matches: function(matcherArgs, actual) { var expected = matcherArgs[0] return actual instanceof expected } }) ``` -------------------------------- ### Create a test double for an object instance Source: https://testdouble.github.io/testdouble.js/3-getting-started.html Initialize a test double for an instantiable type using td.object to mirror prototype methods. ```javascript describe('MathProblem', function(){ var subject, createRandomProblem, savesProblem; beforeEach(function(){ createRandomProblem = td.function('createRandomProblem') savesProblem = td.object(new SavesProblem()) subject = new MathProblem(createRandomProblem, savesProblem) }) it('POSTs a random problem', function(){ // ... }) }) ``` -------------------------------- ### Explain a test double with stubbings and invocations Source: https://testdouble.github.io/testdouble.js/9-debugging.html When a test double has been invoked, td.explain() will show the call count, the arguments passed, and the context in which it was called. This is crucial for debugging unexpected behavior or verifying actual usage patterns. ```javascript myTestDouble(7) // undefined td.explain(myTestDouble) /* { name: '.someFunction', callCount: 1, calls: [ { args: [7], context: window } ], description: 'This test double has 1 stubbings and 1 invocations. Stubbings: - when called with `(5)`, then return `10`. Invocations: - called with `(7)`.' } */ ``` -------------------------------- ### Using td.matchers.isA() Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Verifies that an argument matches a specific type. ```javascript var eatBiscuit = td.function() eatBiscuit(44) td.verify(eatBiscuit(44)) // passes td.verify(eatBiscuit(td.matchers.isA(Number))) // passes td.verify(eatBiscuit(td.matchers.isA(Date))) // throws - 44 is not a Date td.verify(eatBiscuit(td.matchers.isA(Object))) // throws - Number is not an Object ``` -------------------------------- ### Handling verification failure Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Shows the error output when a verification fails due to mismatched arguments. ```javascript td.verify(quack()) Error: Unsatisfied verification on test double `quack`. Wanted: - called with `()`. But was actually called: - called with `("QUACK")`. at Object.module.exports [as verify] (/Users/justin/code/testdouble/testdouble.js/lib/verify.js:22:15) ``` -------------------------------- ### Configuring Stubbing with ignoreExtraArgs Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Use ignoreExtraArgs to match calls regardless of additional arguments provided to the stubbed function. ```javascript logger = td.function() td.when(logger("Outcomes are:"), {ignoreExtraArgs: true}).thenReturn('loggy') logger("Outcomes are:") // 'loggy' logger("Outcomes are:", "stuff") // 'loggy' logger("Outcomes are:", "stuff", "that", "keeps", "going") // 'loggy' logger("Outcomes are not:", "stuff") // undefined ``` ```javascript whatever = td.function() td.when(whatever(), {ignoreExtraArgs: true}).thenReturn('yesss') whatever() // 'yesss' whatever(1,2,3,4,5) // 'yesss' ``` -------------------------------- ### Create a test double from a real function Source: https://testdouble.github.io/testdouble.js/4-creating-test-doubles.html Pass an existing function to td.function to create a double that inherits properties and replaces nested functions with test doubles. ```javascript function meow () { throw 'unimplemented' } meow.volume = 'loud' meow.stop = function () {} var fakeMeow = td.function(meow) // test double for "meow" fakeMeow.volume // 'loud' fakeMeow.stop // test double for "meow.stop" ``` -------------------------------- ### Create a test double from an array of function names Source: https://testdouble.github.io/testdouble.js/4-creating-test-doubles.html Passing an array of strings to td.object returns an object with those properties as test double functions. ```javascript var cat = td.object(['meow', 'purr']) cat.meow // a test double function named 'meow' ``` -------------------------------- ### Replace ES module with a test double Source: https://testdouble.github.io/testdouble.js/7-replacing-dependencies.md Asynchronously replaces an ES module; requires the use of await and explicit file extensions. ```javascript await td.replaceEsm('./brake.mjs') ``` -------------------------------- ### Using td.matchers.anything() Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Use `td.matchers.anything()` to make a stubbing ignore a specific parameter. Any value passed for that parameter during invocation will satisfy the stub. The stub will not be satisfied if the function is called with fewer arguments than specified in the stubbing. ```javascript var bark = td.function('bark') td.when(bark(td.matchers.anything())).thenReturn('woof') bark(1) // 'woof' bark('lol') // 'woof' bark() // undefined bark(2, 'other stuff') // undefined ``` -------------------------------- ### Stubbing Callback APIs with Meaningful Return Values Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Treat `td.callback` as an argument matcher and chain with `thenReturn` to stub functions that have both a callback and a significant return value. This provides explicitness for both callback invocation and function return. ```javascript td.when(glob('some/pattern/**', td.callback(null, ['foo', 'bar']))).thenReturn(8) ``` -------------------------------- ### Create a test double from a constructor function Source: https://testdouble.github.io/testdouble.js/4-creating-test-doubles.html Pass a constructor or class to td.constructor to replace its prototype and static methods with test doubles. ```javascript function Dog(){} Dog.prototype.bark = function(){} Dog.woof = function(){} ``` ```javascript var FakeDog = td.constructor(Dog) FakeDog.prototype.bark // a test double function named 'Dog#bark' FakeDog.woof // a test double function named 'Dog.woof' ``` ```javascript td.when(FakeDog.prototype.bark()).thenReturn('YIP') var dog = new FakeDog() dog.bark() // 'YIP ``` -------------------------------- ### Verify Array Arguments Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Demonstrates using td.matchers.contains to verify array arguments passed to a test double function. ```javascript var join = td.function() join(['this','and','that']) td.verify(join(['this','and','that'])) // passes td.verify(join(td.matchers.contains('and'))) // passes td.verify(join(td.matchers.contains('this','that'))) // passes td.verify(join(td.matchers.contains('this','not that'))) // throws - 'not that' absent ``` -------------------------------- ### Mocking an interface with testdouble.js Source: https://testdouble.github.io/testdouble.js/10-using-with-typescript.html Create a typed mock object from an interface to ensure contract compliance during testing. ```typescript interface IUserRepository { findByName(name: string): string; } const mockedRepository = td.object(); ``` -------------------------------- ### Capture multiple invocations Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Uses the captor's values array to inspect arguments from multiple callback invocations. ```javascript var captor = td.matchers.captor(), responseCallback = td.function(); subscribe('/chat', responseCallback); // subscribe() will call responseCallback twice td.verify(responseCallback('/chat', captor.capture())) assert.equal(captor.values[0], 'first message'); assert.equal(captor.values[1], 'second message'); ``` -------------------------------- ### Stubbing Promises with thenResolve and thenReject Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Use thenResolve and thenReject to simulate immediate promise resolution or rejection. Note that tests using these may need to run asynchronously. ```javascript var fetch = td.function() td.when(fetch('/user')).thenResolve('Jane') fetch('/user').then(function (value) { console.log(value) // prints "Jane" }) ``` ```javascript var fetch = td.function() td.when(fetch('/user')).thenReject('Joe') fetch('/user').catch(function (value) { console.log(value) // prints "Joe" }) ``` -------------------------------- ### Stub sequential return values Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Configure a stubbed function to return different values on subsequent calls by passing multiple arguments to `thenReturn()`. Subsequent calls after the sequence will return the last stubbed value. ```javascript var randomSound = td.function('randomSound') td.when(randomSound()).thenReturn('quack', 'honk', 'moo') randomSound() // 'quack' randomSound() // 'honk' randomSound() // 'moo' randomSound() // 'moo' ``` -------------------------------- ### Configure stubbing invocation limits with times Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Use the times property to limit how many times a specific stubbing configuration remains active before falling back to generic stubbings. ```javascript var nextToken = td.function() td.when(nextToken(td.matchers.isA(Number))).thenReturn("foo") td.when(nextToken(3), {times: 2}).thenReturn("bar") nextToken(3) // 'bar' nextToken(5) // 'foo' nextToken(3) // 'bar' nextToken(3) // 'foo' ``` -------------------------------- ### Define a function for testing Source: https://testdouble.github.io/testdouble.js/B-frequently-asked-questions.html A simple function used to demonstrate interaction with a test double. ```javascript function getName(load, id) { return load(id).name } ``` -------------------------------- ### Create a proxy-based test double Source: https://testdouble.github.io/testdouble.js/4-creating-test-doubles.html Passing a string or no arguments to td.object returns a Proxy that intercepts property access to create test doubles on the fly. ```javascript var parrot = td.object('Parrot') parrot.squawk // a test double function named 'Parrot#squawk' ``` -------------------------------- ### Control callback execution timing with defer Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md The defer option forces callbacks to execute on a later stack, which is useful for testing asynchronous dependencies that might otherwise pass synchronously in tests. ```javascript // Subject under test function printBalance (id, fetchBalance, print) { var balance; fetchBalance(id, function (er, amount) { balance = amount }) print('Your balance is ' + balance) } // Test body var fetchBalance = td.function('.fetchBalance') var print = td.function('.print') td.when(fetchBalance(42)).thenCallback(null, 1337) printBalance(42, fetchBalance, print) td.verify(print('Your balance is 1337')) ``` ```javascript td.when(fetchBalance(42), {defer: true}).thenCallback(null, 1337) ``` -------------------------------- ### Handle Argument Mutation with `cloneArgs` Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md When arguments passed to a test double might be mutated after the call, use `cloneArgs: true` to verify against the state of the arguments at the time of the call, not their mutated state. ```javascript const func = td.func() const person = { age: 17 } // later, in your code func(person) person.age = 30 // back in your test td.verify(func({ age: 17 })) // 💥 Test failure! td.js recorded age as 30! ``` ```javascript const func = td.func() const person = { age: 17 } // later, in your code func(person) person.age = 30 // back in your test td.verify(func({ age: 17 }), { cloneArgs: true }) // 😌 all good ``` -------------------------------- ### Stubbing with 'delay' option Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Introduces a millisecond delay before a callback or promise resolution completes. ```APIDOC ## td.when(...).thenCallback(..., {delay: ms}) ### Description Waits a specified number of milliseconds before the operation completes. Useful for testing scenarios where behavior depends on the order of async operations. ### Request Example ```javascript td.when(fetch('/A'), {delay: 20}).thenCallback(null, 1) ``` ``` -------------------------------- ### Verify with argThat Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Uses a custom truth test function within td.matchers.argThat to validate complex argument conditions. ```javascript var pet = td.function() pet(['cat', 'dog']) td.verify(pet(td.matchers.argThat(function(n){ return n.length > 1 }))) // passes td.verify(pet(td.matchers.argThat(function(n){ return n.length > 2 }))) // throws ``` -------------------------------- ### Stub a function response with td.when Source: https://testdouble.github.io/testdouble.js/3-getting-started.html Configure a test double function to return a specific value when invoked without arguments. ```javascript describe('MathProblem', function(){ // ... it('POSTs a random problem', function(){ td.when(createRandomProblem()).thenReturn('some problem') subject.generate() }) }) ``` -------------------------------- ### Ignore Extra Arguments in Verification Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Use `ignoreExtraArgs: true` when the number or values of subsequent arguments do not matter for the verification. This is useful when only the initial arguments need to be checked. ```javascript var print = td.function() print('some', 'stuff', 'out', 'like', 8) td.verify(print()) // throws, missng all arguments td.verify(print(), {ignoreExtraArgs: true}) // passes td.verify(print('some'), {ignoreExtraArgs: true}) // passes td.verify(print('some', 'stuff'), {ignoreExtraArgs: true}) // passes td.verify(print('some', 'stuff', 'NOPE'), {ignoreExtraArgs: true}) // throws, wrong arg ``` -------------------------------- ### Mocking abstract and concrete classes Source: https://testdouble.github.io/testdouble.js/10-using-with-typescript.html Create test doubles from abstract or concrete class definitions. ```typescript abstract class MyAbstractRepository { findByName(name: string): string; } const mockedRepository = td.object(); td.when(mockedRepository.findByName("Alice")).thenReturn("Alice Alicy"); ``` ```typescript class MyRepository implements IUserRepository { findByName(name: string): string { return ""; } } const mockedRepository = td.object(); td.when(mockedRepository.findByName("Alice")).thenReturn("Alice Alicy"); ``` -------------------------------- ### Verify Object Arguments Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Demonstrates using td.matchers.contains to verify object properties passed to a test double function. ```javascript var brew = td.function() brew({ingredient: 'beans', temperature: 'cold'}) td.verify(brew({ingredient: 'beans', temperature: 'cold'})) // passes td.verify(brew(td.matchers.contains({ingredient: 'beans'}))) // passes td.verify(brew(td.matchers.contains({temperature: 'hot'}))) // throws - wa cold ``` -------------------------------- ### Stub a method with arguments Source: https://testdouble.github.io/testdouble.js/3-getting-started.html Configure a test double method to return a value only when called with specific arguments. ```javascript describe('MathProblem', function(){ // ... it('POSTs a random problem', function(){ td.when(createRandomProblem()).thenReturn('some problem') td.when(savesProblem.save('some problem')).thenReturn('saved problem') subject.generate() }) }) ``` -------------------------------- ### Replace CommonJS dependency in a test Source: https://testdouble.github.io/testdouble.js/7-replacing-dependencies.md Use td.replace within a beforeEach hook to mock a CommonJS module dependency. ```javascript module.exports = { beforeEach: function() { var brake = td.replace('../../lib/brake') var subject = require('../../lib/car') }, 'slowing applies the break': function () { subject.slowDown() td.verify(brake(10)) } } ``` -------------------------------- ### Create a test double from an existing object Source: https://testdouble.github.io/testdouble.js/4-creating-test-doubles.html Pass an object to td.object to create a deep copy where functions are replaced by test doubles. ```javascript var fish = { eat: function(){} swim: function(){} details: { age: 10, name: 'goldie' } } ``` ```javascript var fish = td.object(fish) fish.eat // a test double function named '.eat' fish.details.age // still `10` ``` -------------------------------- ### Stubbing with 'times' option Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Configures a stub to return a value only a specific number of times before disabling the stub. ```APIDOC ## td.when(...).thenReturn(value, {times: n}) ### Description Configures a stub to be satisfied only 'n' times. After the limit is reached, the stub is disabled, allowing fallbacks to more generic stubbings. ### Request Example ```javascript td.when(nextToken(3), {times: 2}).thenReturn("bar") ``` ``` -------------------------------- ### Stubbing Multiple Callback Arguments Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Use td.callback to trigger multiple callback functions in a single test. Alternatively, use td.matchers.isA(Function) to isolate specific callback interactions. ```javascript var doWork = td.function() td.when(doWork(td.callback(null, 42), td.callback(null, 58))).thenReturn() var percent = 0 doWork(function(er, progress) { percent += progress }, function(er, progress) { percent += progress }) assert.equal(percent, 100) ``` ```javascript td.when(doWork(td.callback(null, 42), td.matchers.isA(Function))).thenReturn() ``` -------------------------------- ### Stubbing Callback APIs with td.callback Marker Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md Use `td.callback` as a marker to specify the position of a callback argument when it's not the last argument. This allows for more explicit control over callback placement. ```javascript td.when(glob(td.callback, 'some/pattern/**')).thenCallback(null, ['foo', 'bar']) ``` -------------------------------- ### Simulate asynchronous delays with delay Source: https://testdouble.github.io/testdouble.js/5-stubbing-results.md The delay option introduces a specified millisecond wait before a callback or promise resolves, useful for testing race conditions or operation ordering. ```javascript var fetch td.function('.fetch') td.when(fetch('/A'), {delay: 20}).thenCallback(null, 1) td.when(fetch('/B'), {delay: 10}).thenCallback(null, 2) td.when(fetch('/C'), {delay: 5}).thenResolve(3) fetch('/A', function (er, result) {}) // will be invoked 3rd fetch('/B', function (er, result) {}) // will be invoked 2nd fetch('/C').then(function (result) {}) // will be invoked 1st ``` -------------------------------- ### Verification Failure with Incorrect Argument Source: https://testdouble.github.io/testdouble.js/3-getting-started.html This error occurs when `td.verify` is used, but the actual invocation of the test double used arguments different from those specified in the verification. ```text Error: Unsatisfied verification on test double `submitProblem`. Wanted: - called with `("saved problem")`. But was actually called: - called with `("saved problem woah")`. ``` -------------------------------- ### Verify Function Never Called Source: https://testdouble.github.io/testdouble.js/6-verifying-invocations.md Combine `times: 0` and `ignoreExtraArgs: true` to verify that a function is never called, regardless of any arguments that might be passed. ```javascript var doNotCall = td.function() td.verify(doNotCall(), {times: 0, ignoreExtraArgs: true}) // passes ```