From cd8ae513558b63a47732668c2f082c615f545310 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Tue, 16 Jan 2018 20:02:51 +0100 Subject: [PATCH] Add release documentation for v4.1.6 --- docs/_releases/v4.1.6.md | 49 ++ docs/_releases/v4.1.6/assertions.md | 190 +++++++ docs/_releases/v4.1.6/fake-timers.md | 140 +++++ docs/_releases/v4.1.6/fake-xhr-and-server.md | 395 +++++++++++++ docs/_releases/v4.1.6/json-p.md | 18 + docs/_releases/v4.1.6/matchers.md | 263 +++++++++ docs/_releases/v4.1.6/mocks.md | 166 ++++++ docs/_releases/v4.1.6/sandbox.md | 219 ++++++++ docs/_releases/v4.1.6/spies.md | 512 +++++++++++++++++ docs/_releases/v4.1.6/stubs.md | 559 +++++++++++++++++++ docs/_releases/v4.1.6/utils.md | 25 + 11 files changed, 2536 insertions(+) create mode 100644 docs/_releases/v4.1.6.md create mode 100644 docs/_releases/v4.1.6/assertions.md create mode 100644 docs/_releases/v4.1.6/fake-timers.md create mode 100644 docs/_releases/v4.1.6/fake-xhr-and-server.md create mode 100644 docs/_releases/v4.1.6/json-p.md create mode 100644 docs/_releases/v4.1.6/matchers.md create mode 100644 docs/_releases/v4.1.6/mocks.md create mode 100644 docs/_releases/v4.1.6/sandbox.md create mode 100644 docs/_releases/v4.1.6/spies.md create mode 100644 docs/_releases/v4.1.6/stubs.md create mode 100644 docs/_releases/v4.1.6/utils.md diff --git a/docs/_releases/v4.1.6.md b/docs/_releases/v4.1.6.md new file mode 100644 index 000000000..d5ac9aedc --- /dev/null +++ b/docs/_releases/v4.1.6.md @@ -0,0 +1,49 @@ +--- +layout: page +title: API documentation - Sinon.JS +release_id: v4.1.6 +--- + +# {{page.title}} - `{{page.release_id}}` + +This page contains the entire Sinon.JS API documentation along with brief introductions to the concepts Sinon implements. + +* [Spies](./spies) +* [Stubs](./stubs) +* [Mocks](./mocks) +* [Fake timers](./fake-timers) +* [Fake XHR and server](./fake-xhr-and-server) +* [JSON-P](./json-p) +* [Assertions](./assertions) +* [Matchers](./matchers) +* [Sandboxes](./sandbox) +* [Utils](./utils) + +{% include docs/migration-guides.md %} + +### Compatibility + +### ES5.1 + +Sinon `{{page.release_id}}` is written as [ES5.1][ES5] and requires no transpiler or polyfills to run in the runtimes listed below. + +### Supported runtimes + +`{{page.release_id}}` has been verified in these runtimes: + +* Firefox 45 +* Chrome 48 +* Internet Explorer 11 +* Edge 14 +* Safari 9 +* Node 4 + +There should not be any issues with using Sinon `{{page.release_id}}` in newer versions of the same runtimes. + +If you need to support very old runtimes that have incomplete support for [ES5.1][ES5] you might get away with using loading [`es5-shim`][es5-shim] in your test environment. If that fails, we recommend [getting a legacy releases of Sinon][legacy-site]. + +{% include docs/contribute.md %} + +[ES5]: http://www.ecma-international.org/ecma-262/5.1/ +[es5-shim]: https://github.com/es-shims/es5-shim +[legacy-site]: http://legacy.sinonjs.org diff --git a/docs/_releases/v4.1.6/assertions.md b/docs/_releases/v4.1.6/assertions.md new file mode 100644 index 000000000..67d4796c9 --- /dev/null +++ b/docs/_releases/v4.1.6/assertions.md @@ -0,0 +1,190 @@ +--- +layout: page +title: Assertions - Sinon.JS +breadcrumb: assertions +--- + +Sinon.JS ships with a set of assertions that mirror most behavior verification methods and properties on spies and stubs. The advantage of using the assertions is that failed expectations on stubs and spies can be expressed directly as assertion failures with detailed and helpful error messages. + +To make sure assertions integrate nicely with your test framework, you should customize either `sinon.assert.fail` or `sinon.assert.failException` and look into `sinon.assert.expose` and `sinon.assert.pass`. + +The assertions can be used with either spies or stubs. + +```javascript +"test should call subscribers with message as first argument" : function () { + var message = "an example message"; + var spy = sinon.spy(); + + PubSub.subscribe(message, spy); + PubSub.publishSync(message, "some payload"); + + sinon.assert.calledOnce(spy); + sinon.assert.calledWith(spy, message); +} +``` + +## Assertions API + +#### `sinon.assert.fail(message)` + +Every assertion fails by calling this method. + +By default it throws an error of type `sinon.assert.failException`. + +If the test framework looks for assertion errors by checking for a specific exception, you can simply override the kind of exception thrown. If that does not fit with your testing framework of choice, override the `fail` method to do the right thing. + + +#### `sinon.assert.failException;` + +Defaults to `AssertError`. + + +#### `sinon.assert.pass(assertion);` + +Called every time `assertion` passes. + +Default implementation does nothing. + + +#### `sinon.assert.notCalled(spy);` + +Passes if `spy` was never called + +#### `sinon.assert.called(spy);` + +Passes if `spy` was called at least once. + + +#### `sinon.assert.calledOnce(spy);` + +Passes if `spy` was called once and only once. + + +#### `sinon.assert.calledTwice(spy);` + +Passes if `spy` was called exactly twice. + + +#### `sinon.assert.calledThrice(spy)` + +Passes if `spy` was called exactly three times. + + +#### `sinon.assert.callCount(spy, num)` +Passes if `spy` was called exactly `num` times. + + +#### `sinon.assert.callOrder(spy1, spy2, ...)` +Passes if provided spies were called in the specified order. + + +#### `sinon.assert.calledOn(spy, obj)` + +Passes if `spy` was ever called with `obj` as its `this` value. + + +#### `sinon.assert.alwaysCalledOn(spy, obj)` + +Passes if `spy` was always called with `obj` as its `this` value. + + +#### `sinon.assert.calledWith(spy, arg1, arg2, ...);` + +Passes if `spy` was called with the provided arguments. + + +#### `sinon.assert.alwaysCalledWith(spy, arg1, arg2, ...);` + +Passes if `spy` was always called with the provided arguments. + + +#### `sinon.assert.neverCalledWith(spy, arg1, arg2, ...);` + +Passes if `spy` was never called with the provided arguments. + + +#### `sinon.assert.calledWithExactly(spy, arg1, arg2, ...);` + +Passes if `spy` was called with the provided arguments and no others. + + +#### `sinon.assert.alwaysCalledWithExactly(spy, arg1, arg2, ...);` + +Passes if `spy` was always called with the provided arguments and no others. + + +#### `sinon.assert.calledWithMatch(spy, arg1, arg2, ...)` + +Passes if `spy` was called with matching arguments. + +This behaves the same way as `sinon.assert.calledWith(spy, sinon.match(arg1), sinon.match(arg2), ...)`. + + +#### `sinon.assert.alwaysCalledWithMatch(spy, arg1, arg2, ...)` + +Passes if `spy` was always called with matching arguments. + +This behaves the same way as `sinon.assert.alwaysCalledWith(spy, sinon.match(arg1), sinon.match(arg2), ...)`. + + +#### `sinon.assert.calledWithNew(spy)` + +Passes if `spy` was called with the `new` operator. + + +#### `sinon.assert.neverCalledWithMatch(spy, arg1, arg2, ...)` + +Passes if `spy` was never called with matching arguments. + +This behaves the same way as `sinon.assert.neverCalledWith(spy, sinon.match(arg1), sinon.match(arg2), ...)`. + + +#### `sinon.assert.threw(spy, exception);` + +Passes if `spy` threw the given exception. + +The exception can be a `String` denoting its type, or an actual object. + +If only one argument is provided, the assertion passes if `spy` ever threw any exception. + + +#### `sinon.assert.alwaysThrew(spy, exception);` + +Like above, only required for all calls to the spy. + +#### `sinon.assert.match(actual, expectation);` + +Uses [`sinon.match`](../matchers) to test if the arguments can be considered a match. + +```javascript +var sinon = require('sinon'); + +describe('example', function(){ + it('should match on `x` property, and ignore `y` property', function() { + var expected = {x: 1}, + actual = {x: 1, y: 2}; + + sinon.assert.match(actual, expected); + }); +}); +``` + +#### `sinon.assert.expose(object, options);` + +Exposes assertions into another object, to better integrate with the test framework. For instance, JsTestDriver uses global assertions, and to make Sinon.JS assertions appear alongside them, you can do. + +```javascript +sinon.assert.expose(this); +``` + +This will give you `assertCalled(spy)`,`assertCallOrder(spy1, spy2, ...)` and so on. + +The method accepts an optional options object with two options. + +
+
prefix
+
is a prefix to give assertions. By default it is "assert", so sinon.assert.called becomes target.assertCalled. By passing a blank string, the exposed method will be target.called.
+ +
includeFail
+
true by default, copies over the fail and failException properties
+
diff --git a/docs/_releases/v4.1.6/fake-timers.md b/docs/_releases/v4.1.6/fake-timers.md new file mode 100644 index 000000000..8563b0606 --- /dev/null +++ b/docs/_releases/v4.1.6/fake-timers.md @@ -0,0 +1,140 @@ +--- +layout: page +title: Fake timers - Sinon.JS +breadcrumb: fake timers +--- + +Fake timers are synchronous implementations of `setTimeout` and friends that +Sinon.JS can overwrite the global functions with to allow you to more easily +test code using them. + +Fake timers provide a `clock` object to pass time, which can also be used to control `Date` objects created through either `new Date();` +or `Date.now();` (if supported by the browser). + +For standalone usage of fake timers it is recommended to use [lolex](https://github.com/sinonjs/lolex) package instead. It provides the same +set of features (Sinon uses it under the hood) and was previously extracted from Sinon.JS. + +```javascript +{ + setUp: function () { + this.clock = sinon.useFakeTimers(); + }, + + tearDown: function () { + this.clock.restore(); + }, + + "test should animate element over 500ms" : function(){ + var el = jQuery("
"); + el.appendTo(document.body); + + el.animate({ height: "200px", width: "200px" }); + this.clock.tick(510); + + assertEquals("200px", el.css("height")); + assertEquals("200px", el.css("width")); + } +} +``` + +## Fake timers API + + +#### `var clock = sinon.useFakeTimers();` + +Causes Sinon to replace the global `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval`, `setImmediate`, `clearImmediate`, `process.hrtime`, `performance.now`(when available) and `Date` with a custom implementation which is bound to the returned `clock` object. + +Starts the clock at the UNIX epoch (timestamp of `0`). + + +#### `var clock = sinon.useFakeTimers(now);` + +As above, but rather than starting the clock with a timestamp of 0, start at the provided timestamp `now`. + +*Since `sinon@2.0.0`* + +You can also pass in a Date object, and its `getTime()` will be used for the starting timestamp. + +#### `var clock = sinon.useFakeTimers(config);` + +As above, but allows further configuration options, some of which are: + +- `config.now` - *Number/Date* - installs lolex with the specified unix epoch (default: 0) +- `config.toFake` - *String[ ]* - an array with explicit function names to fake. By default lolex will automatically fake all methods *except* `process.nextTick`. You could, however, still fake `nextTick` by providing it explicitly +- `config.shouldAdvanceTime` - *Boolean* - tells lolex to increment mocked time automatically based on the real system time shift (default: false) + +Please visit the `lolex.install` [documentation](https://github.com/sinonjs/lolex#var-clock--lolexinstallconfig) for the full feature set. + +**Important note:** when faking `nextTick`, normal calls to `process.nextTick()` would not execute automatically as they would during normal event-loop phases. You would have to call either `clock.next()`, `clock.tick()`, `clock.runAll()` or `clock.runToLast()` (see example below). Please refer to the [lolex](https://github.com/sinonjs/lolex) documentation for more information. + +#### Examples + +Installs fake timers at January 1st 2017 and fakes `setTimeout` and `process.nextTick` only: + +```javascript +var clock = sinon.useFakeTimers({ + now: 1483228800000, + toFake: ["setTimeout", "nextTick"] + }); + +var called = false; + +process.nextTick(function () { + called = true; +}); + +clock.runAll(); //forces nextTick calls to flush synchronously +assert(called); //true +``` + +Install at the same date, advancing the fake time automatically (default is every `20ms`), causing timers to be fired automatically without the need to `tick()` the clock: + +```js +var clock = sinon.useFakeTimers({ + now: 1483228800000, + shouldAdvanceTime: true + }); + +setImmediate(function () { + console.log('tick'); //will print after 20ms +}); + +setTimeout(function () { + console.log('tock'); //will print after 20ms +}, 15); + +setTimeout(function () { + console.log('tack'); //will print after 40ms +}, 35); +``` + +Please refer to the `lolex.install` [documentation](https://github.com/sinonjs/lolex#var-clock--lolexinstallconfig) for the full set of features available and more elaborate explanations. + +*Since `sinon@3.0.0`* + +`var clock = sinon.useFakeTimers([now, ]prop1, prop2, ...)` is no longer supported. To define which methods to fake, please use `config.toFake`. + + +#### `clock.tick(time);` + +Tick the clock ahead `time` milliseconds. + +Causes all timers scheduled within the affected time range to be called. `time` may be the number of milliseconds to advance the clock by or a human-readable string. Valid string formats are "08" for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten seconds. + +time may be negative, which causes the clock to change but won't fire any callbacks. + +#### `clock.next();` + +Advances the clock to the the moment of the first scheduled timer, firing it. + +#### `clock.runAll();` + +This runs all pending timers until there are none remaining. If new timers are added while it is executing they will be run as well. + +This makes it easier to run asynchronous tests to completion without worrying about the number of timers they use, or the delays in those timers. + +#### `clock.restore();` + +Restore the faked methods. + +Call in e.g. `tearDown`. diff --git a/docs/_releases/v4.1.6/fake-xhr-and-server.md b/docs/_releases/v4.1.6/fake-xhr-and-server.md new file mode 100644 index 000000000..ec05f1876 --- /dev/null +++ b/docs/_releases/v4.1.6/fake-xhr-and-server.md @@ -0,0 +1,395 @@ +--- +layout: page +title: Fake XHR and server - Sinon.JS +breadcrumb: fake XHR and server +--- + +## Fake `XMLHttpRequest` + +Provides a fake implementation of `XMLHttpRequest` and provides +several interfaces for manipulating objects created by it. + +Also fakes native `XMLHttpRequest` and `ActiveXObject` (when available, and only for `XMLHTTP` progids). Helps with testing requests made with `XHR`. + +The fake server and XHR can be used completely stand-alone by downloading `sinon-server.js`. + +```javascript +{ + setUp: function () { + this.xhr = sinon.useFakeXMLHttpRequest(); + var requests = this.requests = []; + + this.xhr.onCreate = function (xhr) { + requests.push(xhr); + }; + }, + + tearDown: function () { + this.xhr.restore(); + }, + + "test should fetch comments from server" : function () { + var callback = sinon.spy(); + myLib.getCommentsFor("/some/article", callback); + assertEquals(1, this.requests.length); + + this.requests[0].respond(200, { "Content-Type": "application/json" }, + '[{ "id": 12, "comment": "Hey there" }]'); + assert(callback.calledWith([{ id: 12, comment: "Hey there" }])); + } +} +``` + + +### `sinon.useFakeXMLHttpRequest` + +#### `var xhr = sinon.useFakeXMLHttpRequest();` + +Causes Sinon to replace the native `XMLHttpRequest` object in browsers that support it with a custom implementation which does not send actual requests. + +In browsers that support `ActiveXObject`, this constructor is replaced, and fake objects are returned for `XMLHTTP` progIds. Other progIds, such as `XMLDOM` are left untouched. + +The native `XMLHttpRequest` object will be available at `sinon.xhr.XMLHttpRequest` + + +#### `xhr.onCreate = function (xhr) {};` + +By assigning a function to the `onCreate` property of the returned object from `useFakeXMLHttpRequest()` you can subscribe to newly created `FakeXMLHttpRequest` objects. See below for the fake xhr object API. + +Using this observer means you can still reach objects created by e.g. `jQuery.ajax` (or other abstractions/frameworks). + +#### `xhr.restore();` + +Restore original function(s). + + +### `FakeXMLHttpRequest` + +#### `String request.url` + +The URL set on the request object. + + +#### `String request.method` + +The request method as a string. + + +#### `Object request.requestHeaders` + +An object of all request headers, i.e.: + +```javascript +{ + "Accept": "text/html, */*", + "Connection": "keep-alive" +} +``` + + +#### `String request.requestBody` + +The request body + +#### `int request.status` + +The request's status code. + +`undefined` if the request has not been handled (see [`respond`](#respond) below) + + +#### `String request.statusText` + +Only populated if the [`respond`](#respond) method is called (see below). + + +#### `boolean request.async` + +Whether or not the request is asynchronous. + + +#### `String request.username` + +Username, if any. + + +#### `String request.password` + +Password, if any. + + +#### `Document request.responseXML` + +When using [`respond`](#respond), this property is populated with a parsed document if response headers indicate as much (see [the spec](http://www.w3.org/TR/XMLHttpRequest/)) + + +#### `String request.getResponseHeader(header);` + +The value of the given response header, if the request has been responded to (see [`respond`](#respond)). + + +#### `Object request.getAllResponseHeaders();` + +All response headers as an object. + + +### Filtered requests + +When using Sinon.JS for mockups or partial integration/functional testing, you might want to fake some requests, while allowing others to go through to the backend server. With filtered `FakeXMLHttpRequest`s (new in v1.3.0), you can. + + +#### `FakeXMLHttpRequest.useFilters` + +Default `false`. + +When set to `true`, Sinon will check added filters if certain requests should be "unfaked" + + +#### `FakeXMLHttpRequest.addFilter(fn)` + +Add a filter that will decide whether or not to fake a request. + +The filter will be called when `xhr.open` is called, with the exact same arguments (`method`, `url`, `async`, `username`, `password`). If the filter returns `true`, the request will not be faked. + + +### Simulating server responses + +#### `request.setStatus(status);` + +Sets response status (`status` and `statusText` properties). + +Status should be a number, the status text is looked up from `sinon.FakeXMLHttpRequest.statusCodes`. + +#### `request.setResponseHeaders(object);` + +Sets response headers (e.g. `{ "Content-Type": "text/html", /* ... */ }`, updates the `readyState` property and fires `onreadystatechange`. + + +#### `request.setResponseBody(body);` + +Sets the respond body, updates the `readyState` property and fires `onreadystatechange`. + +Additionally, populates `responseXML` with a parsed document if [response headers indicate as much](http://www.w3.org/TR/XMLHttpRequest/). + + +#### `request.respond(status, headers, body);` + +Calls the above three methods. + +#### `request.error();` + +Simulates a network error on the request. The `onerror` handler will be called and the `status` will be `0`. + +#### `Boolean request.autoRespond` + +When set to `true`, causes the server to automatically respond to incoming requests after a timeout. + +The default timeout is 10ms but you can control it through the `autoRespondAfter` property. + +Note that this feature is intended to help during mockup development, and is not suitable for use in tests. + +#### `Number request.autoRespondAfter` + +When `autoRespond` is `true`, respond to requests after this number of milliseconds. Default is 10. + + +## Fake server +High-level API to manipulate `FakeXMLHttpRequest` instances. + +For help with handling JSON-P please refer to our [notes below](#json-p) + +```javascript +{ + setUp: function () { + this.server = sinon.createFakeServer(); + }, + + tearDown: function () { + this.server.restore(); + }, + + "test should fetch comments from server" : function () { + this.server.respondWith("GET", "/some/article/comments.json", + [200, { "Content-Type": "application/json" }, + '[{ "id": 12, "comment": "Hey there" }]']); + + var callback = sinon.spy(); + myLib.getCommentsFor("/some/article", callback); + this.server.respond(); + + sinon.assert.calledWith(callback, [{ id: 12, comment: "Hey there" }]); + + assert(server.requests.length > 0) + } +} +``` + + +#### `var server = sinon.createFakeServer([config]);` + +Creates a new server. + +This function also calls `sinon.useFakeXMLHttpRequest()`. + +`createFakeServer` accepts optional properties to configure the fake server. See [options](#options) below for configuration parameters. + + +#### `var server = sinon.createFakeServerWithClock();` + +Creates a server that also manages fake timers. + +This is useful when testing `XHR` objects created with e.g. jQuery 1.3.x, which uses a timer to poll the object for completion, rather than the usual `onreadystatechange`. + + +#### `server.configure(config);` + +Configures the fake server. + +See [options](#options) below for configuration parameters. + +#### `server.respondWith(response);` + +Causes the server to respond to any request not matched by another response with the provided data. The default catch-all response is `[404, {}, ""]`. + +`response` can be one of three things: + +1. A `String` representing the response body +2. An `Array` with status, headers and response body, e.g. `[200, { "Content-Type": "text/html", "Content-Length": 2 }, "OK"]` +3. A `Function`. + +Default status is 200 and default headers are none. + +When the response is a `Function`, it will be passed the request object. You +must manually call [respond](#respond) on it to complete the +request. + + +#### `server.respondWith(url, response);` + +Responds to all requests to given URL, e.g. `/posts/1`. + + +#### `server.respondWith(method, url, response);` + +Responds to all `method` requests to the given URL with the given response. + +`method` is an HTTP verb. + + +#### `server.respondWith(urlRegExp, response);` + +URL may be a regular expression, e.g. `/\\/post\\//\\d+` + +If the response is a `Function`, it will be passed any capture groups from the regular expression along with the XMLHttpRequest object: + +```javascript +server.respondWith(/\/todo-items\/(\d+)/, function (xhr, id) { + xhr.respond(200, { "Content-Type": "application/json" }, '[{ "id": ' + id + " }]"); +}); +``` + + +#### `server.respondWith(method, urlRegExp, response);` + +Responds to all `method` requests to URLs matching the regular expression. + +#### `server.respond();` + +Causes all queued asynchronous requests to receive a response. + +If none of the responses added through `respondWith` match, the default response is `[404, {}, ""]`. + +Synchronous requests are responded to immediately, so make sure to call `respondWith` upfront. + +If called with arguments, `respondWith` will be called with those arguments before responding to requests. + + +#### `server.autoRespond = true;` + +If set, will automatically respond to every request after a timeout. + +The default timeout is 10ms but you can control it through the `autoRespondAfter` property. + +Note that this feature is intended to help during mockup development, and is not suitable for use in tests. For synchronous immediate responses, use `respondImmediately` instead. + + +#### `server.autoRespondAfter = ms;` + +Causes the server to automatically respond to incoming requests after a timeout. + +#### `server.respondImmediately = true;` + +If set, the server will respond to every request immediately and synchronously. + +This is ideal for faking the server from within a test without having to call `server.respond()` after each request made in that test. + +As this is synchronous and immediate, this is not suitable for simulating actual network latency in tests or mockups. To simulate network latency with automatic responses, see `server.autoRespond` and `server.autoRespondAfter`. + +#### array `server.requests` + +You can inspect the `server.requests` to verify request ordering, find unmatched requests or check that no requests has been done. +`server.requests` is an array of all the `FakeXMLHttpRequest` objects that have been created. + +#### `Boolean server.fakeHTTPMethods` + +If set to `true`, server will find `_method` parameter in POST body and recognize that as the actual method. + +Supports a pattern common to Ruby on Rails applications. For custom HTTP method faking, override `server.getHTTPMethod(request)`. + + +#### `server.getHTTPMethod(request)` + +Used internally to determine the HTTP method used with the provided request. + +By default this method simply returns `request.method`. When `server.fakeHTTPMethods` is true, the method will return the value of the `_method` parameter if the method is "POST". + +This method can be overridden to provide custom behavior. + + +#### `server.restore();` + +Restores the native XHR constructor. + + +### Fake server options + +These options are properties on the server object and can be set directly + + +```javascript +server.autoRespond = true +``` + +You can also pass options with an object literal to `createFakeServer` and `.configure`. + +#### `Boolean autoRespond` + +If set, will automatically respond to every request after a timeout. + +The default timeout is 10ms but you can control it through the `autoRespondAfter` property. + +Note that this feature is intended to help during mockup development, and is not suitable for use in tests. + +For synchronous immediate responses, use `respondImmediately` instead. + + +#### `Number autoRespondAfter (ms)` + +Causes the server to automatically respond to incoming requests after a timeout. + +#### `Boolean respondImmediately` + +If set, the server will respond to every request immediately and synchronously. + +This is ideal for faking the server from within a test without having to call `server.respond()` after each request made in that test. + +As this is synchronous and immediate, this is not suitable for simulating actual network latency in tests or mockups. To simulate network latency with automatic responses, see `server.autoRespond` and `server.autoRespondAfter`. + + +#### `boolean fakeHTTPMethods` + +If set to `true`, server will find `_method` parameter in `POST` body and recognize that as the actual method. + +Supports a pattern common to Ruby on Rails applications. + +For custom HTTP method faking, override `server.getHTTPMethod(request)` diff --git a/docs/_releases/v4.1.6/json-p.md b/docs/_releases/v4.1.6/json-p.md new file mode 100644 index 000000000..2d817337b --- /dev/null +++ b/docs/_releases/v4.1.6/json-p.md @@ -0,0 +1,18 @@ +--- +layout: page +title: JSON-P - Sinon.JS +breadcrumb: JSON-P +--- + +# JSON-P + +JSON-P doesn't use `XHR` requests, which is what the fake server is concerned with. A JSON-P request creates a script element and inserts it into the document. + +There is no sufficiently unobtrusive way to fake this automatically. The best option is to simply stub jQuery in this case: + +```javascript +sinon.stub(jQuery, "ajax"); +sinon.assert.calledOnce(jQuery.ajax); +``` + +We could potentially have had the fake server detect `jQuery` and fake any calls to `jQuery.ajax` when JSON-P is used, but that felt like a compromise in the focus of the Sinon project compared to simply documenting the above practice. diff --git a/docs/_releases/v4.1.6/matchers.md b/docs/_releases/v4.1.6/matchers.md new file mode 100644 index 000000000..ad5d44e8c --- /dev/null +++ b/docs/_releases/v4.1.6/matchers.md @@ -0,0 +1,263 @@ +--- +layout: page +title: Matchers - Sinon.JS +breadcrumb: matchers +--- + +Matchers can be passed as arguments to `spy.calledOn`, `spy.calledWith`, `spy.returned` and the +corresponding `sinon.assert` functions as well as `spy.withArgs`. Matchers allow to be either more fuzzy or more specific about the expected value. + +```javascript +"test should assert fuzzy": function () { + var book = { + pages: 42, + author: "cjno" + id: { + isbn10: "0596517742", + isbn13: "978-0596517748" + } + }; + var spy = sinon.spy(); + + spy(book); + + sinon.assert.calledWith(spy, sinon.match({ author: "cjno" })); + sinon.assert.calledWith(spy, sinon.match.has("pages", 42)); + sinon.assert.calledWith(spy, sinon.match.has("id", sinon.match.has("isbn13", "978-0596517748"))); +} +``` + +```javascript +"test should stub method differently based on argument types": function () { + var callback = sinon.stub(); + callback.withArgs(sinon.match.string).returns(true); + callback.withArgs(sinon.match.number).throws("TypeError"); + + callback("abc"); // Returns true + callback(123); // Throws TypeError +} +``` + +## Matchers API + +#### `sinon.match(number);` + +Requires the value to be == to the given number. + + +#### `sinon.match(string);` + +Requires the value to be a string and have the expectation as a substring. + + +#### `sinon.match(regexp);` + +Requires the value to be a string and match the given regular expression. + + +#### `sinon.match(object);` + +Requires the value to be not `null` or `undefined` and have at least the same properties as `expectation`. + +This supports nested matchers. + + +#### `sinon.match(function)` + +See `custom matchers`. + + +#### `sinon.match.any` + +Matches anything. + + +#### `sinon.match.defined` + +Requires the value to be defined. + + +#### `sinon.match.truthy` + +Requires the value to be truthy. + + +#### `sinon.match.falsy` + +Requires the value to be falsy. + + +#### `sinon.match.bool` + +Requires the value to be a `Boolean` + + +#### `sinon.match.number` + +Requires the value to be a `Number`. + + +#### `sinon.match.string` + +Requires the value to be a `String`. + + +#### `sinon.match.object` + +Requires the value to be an `Object`. + + +#### `sinon.match.func` + +Requires the value to be a `Function`. + + +#### `sinon.match.array` + +Requires the value to be an `Array`. + + +#### `sinon.match.array.deepEquals(arr)` + +Requires an `Array` to be deep equal another one. + + +#### `sinon.match.array.startsWith(arr)` + +Requires an `Array` to start with the same values as another one. + + +#### `sinon.match.array.endsWith(arr)` + +Requires an `Array` to end with the same values as another one. + + +#### `sinon.match.array.contains(arr)` + +Requires an `Array` to contain each one of the values the given array has. + + +#### `sinon.match.map` + +Requires the value to be a `Map`. + + +#### `sinon.match.map.deepEquals(map)` + +Requires a `Map` to be deep equal another one. + + +#### `sinon.match.map.contains(map)` + +Requires a `Map` to contain each one of the items the given map has. + + +#### `sinon.match.set` + +Requires the value to be a `Set`. + + +#### `sinon.match.set.deepEquals(set)` + +Requires a `Set` to be deep equal another one. + + +#### `sinon.match.set.contains(set)` + +Requires a `Set` to contain each one of the items the given set has. + + +#### `sinon.match.regexp` + +Requires the value to be a regular expression. + + +#### `sinon.match.date` + +Requires the value to be a `Date` object. + + +#### `sinon.match.symbol` + +Requires the value to be a `Symbol`. + +*Since `sinon@2.0.0`* + +#### `sinon.match.same(ref)` + +Requires the value to strictly equal `ref`. + + +#### `sinon.match.typeOf(type)` + +Requires the value to be of the given type, where `type` can be one of + `"undefined"`, + `"null"`, + `"boolean"`, + `"number"`, + `"string"`, + `"object"`, + `"function"`, + `"array"`, + `"regexp"`, + `"date"` or + `"symbol"`. + + +#### `sinon.match.instanceOf(type)` + +Requires the value to be an instance of the given `type`. + + +#### `sinon.match.has(property[, expectation])` + +Requires the value to define the given `property`. + +The property might be inherited via the prototype chain. If the optional expectation is given, the value of the property is deeply compared with the expectation. The expectation can be another matcher. + +#### `sinon.match.hasOwn(property[, expectation])` + +Same as `sinon.match.has` but the property must be defined by the value itself. Inherited properties are ignored. + + +#### `sinon.match.hasNested(propertyPath[, expectation])` + +Requires the value to define the given `propertyPath`. Dot (`prop.prop`) and bracket (`prop[0]`) notations are supported as in (Lodash.get)[https://lodash.com/docs/4.4.2#get]. + +The propertyPath might be inherited via the prototype chain. If the optional expectation is given, the value at the propertyPath is deeply compared with the expectation. The expectation can be another matcher. + + +```javascript +sinon.match.hasNested("a[0].b.c"); + +// Where actual is something like +var actual = { "a": [{ "b": { "c": 3 } }] }; + +sinon.match.hasNested("a.b.c"); + +// Where actual is something like +var actual = { "a": { "b": { "c": 3 } } }; +``` + + +## Combining matchers + +All matchers implement `and` and `or`. This allows to logically combine mutliple matchers. The result is a new matchers that requires both (and) or one of the matchers (or) to return `true`. + +```javascript +var stringOrNumber = sinon.match.string.or(sinon.match.number); +var bookWithPages = sinon.match.instanceOf(Book).and(sinon.match.has("pages")); +``` + + +## Custom matchers + +Custom matchers are created with the `sinon.match` factory which takes a test function and an optional message. + +The test function takes a value as the only argument, returns `true` if the value matches the expectation and `false` otherwise. The message string is used to generate the error message in case the value does not match the expectation. + +```javascript +var trueIsh = sinon.match(function (value) { + return !!value; +}, "trueIsh"); +``` diff --git a/docs/_releases/v4.1.6/mocks.md b/docs/_releases/v4.1.6/mocks.md new file mode 100644 index 000000000..be7419f95 --- /dev/null +++ b/docs/_releases/v4.1.6/mocks.md @@ -0,0 +1,166 @@ +--- +layout: page +title: Mocks - Sinon.JS +breadcrumb: mocks +--- + +### Introduction + +### What are mocks? + +Mocks (and mock expectations) are fake methods (like spies) with pre-programmed behavior (like stubs) as well as **pre-programmed expectations**. + +A mock will fail your test if it is not used as expected. + + +### When to use mocks? + +Mocks should only be used for the *method under test*. In every unit test, there should be one unit under test. + +If you want to control how your unit is being used and like stating expectations upfront (as opposed to asserting after the fact), use a mock. + + +### When to **not** use mocks? + +Mocks come with built-in expectations that may fail your test. + +Thus, they enforce implementation details. The rule of thumb is: if you wouldn't add an assertion for some specific call, don't mock it. Use a stub instead. + +In general you should have **no more than one** mock (possibly with several expectations) in a single test. + +[Expectations](#expectations) implement both the [spies](../spies) and [stubs](../stubs) APIs. + +To see what mocks look like in Sinon.JS, here is one of the [PubSubJS][pubsubjs] tests again, this time using a method as callback and using mocks to verify its behavior + +```javascript +"test should call all subscribers when exceptions": function () { + var myAPI = { method: function () {} }; + + var spy = sinon.spy(); + var mock = sinon.mock(myAPI); + mock.expects("method").once().throws(); + + PubSub.subscribe("message", myAPI.method); + PubSub.subscribe("message", spy); + PubSub.publishSync("message", undefined); + + mock.verify(); + assert(spy.calledOnce); +} +``` + +[pubsubjs]: https://github.com/mroderick/pubsubjs + + +## Mocks API + +### Properties + +#### `var mock = sinon.mock(obj);` + +Creates a mock for the provided object. + +Does not change the object, but returns a mock object to set expectations on the object's methods. + + +#### `var expectation = mock.expects("method");` + +Overrides `obj.method` with a mock function and returns it. + +See [expectations](#expectations) below. + + +#### `mock.restore();` + +Restores all mocked methods. + + +#### `mock.verify();` + +Verifies all expectations on the mock. + +If any expectation is not satisfied, an exception is thrown. + +Also restores the mocked methods. + + +### Expectations + +All the expectation methods return the expectation, meaning you can chain them. + +Typical usage: + +```javascript +sinon.mock(jQuery).expects("ajax").atLeast(2).atMost(5); +jQuery.ajax.verify(); +``` + + +#### `var expectation = sinon.expectation.create([methodName]);` + +Creates an expectation without a mock object, basically an anonymous mock function. + +Method name is optional and is used in exception messages to make them more readable. + + +#### `var expectation = sinon.mock([methodName]);` + +The same as the above. + + +#### `expectation.atLeast(number);` + +Specify the minimum amount of calls expected. + + +#### `expectation.atMost(number);` + +Specify the maximum amount of calls expected. + + +#### `expectation.never();` +Expect the method to never be called. + + +#### `expectation.once();` + +Expect the method to be called exactly once. + + +#### `expectation.twice();` + +Expect the method to be called exactly twice. + + +#### `expectation.thrice();` + +Expect the method to be called exactly thrice. + + +#### `expectation.exactly(number);` + +Expect the method to be called exactly `number` times. + + +#### `expectation.withArgs(arg1, arg2, ...);` + +Expect the method to be called with the provided arguments and possibly others. + +An `expectation` instance only holds onto a single set of arguments specified with `withArgs`. Subsequent calls will overwrite the previously-specified set of arguments (even if they are different), so it is generally not intended that this method be invoked more than once per test case. + + +#### `expectation.withExactArgs(arg1, arg2, ...);` + +Expect the method to be called with the provided arguments and no others. + +An `expectation` instance only holds onto a single set of arguments specified with `withExactArgs`. Subsequent calls will overwrite the previously-specified set of arguments (even if they are different), so it is generally not intended that this method be invoked more than once per test case. + + +#### `expectation.on(obj);` + +Expect the method to be called with `obj` as `this`."} + + +#### `expectation.verify();` + +Verifies the expectation and throws an exception if it's not met. diff --git a/docs/_releases/v4.1.6/sandbox.md b/docs/_releases/v4.1.6/sandbox.md new file mode 100644 index 000000000..f65ab15a8 --- /dev/null +++ b/docs/_releases/v4.1.6/sandbox.md @@ -0,0 +1,219 @@ +--- +layout: page +title: Sandboxes - Sinon.JS +breadcrumb: sandbox +--- + +Sandboxes removes the need to keep track of every fake created, which greatly simplifies cleanup. + +```javascript +var sinon = require('sinon'); + +var myAPI = { hello: function () {} }; +var sandbox = sinon.createSandbox(); + +describe('myAPI.hello method', function () { + + beforeEach(function () { + // stub out the `hello` method + sandbox.stub(myAPI, 'hello'); + }); + + afterEach(function () { + // completely restore all fakes created through the sandbox + sandbox.restore(); + }); + + it('should be called once', function () { + myAPI.hello(); + sinon.assert.calledOnce(myAPI.hello); + }); + + it('should be called twice', function () { + myAPI.hello(); + myAPI.hello(); + sinon.assert.calledTwice(myAPI.hello); + }); +}); +``` + +## Sandbox API + +#### `var sandbox = sinon.createSandbox();` + +Creates a sandbox object with spies, stubs, and mocks. + + +#### `var sandbox = sinon.createSandbox(config);` + +The `sinon.createSandbox(config)` method is often an integration feature, and can be used for scenarios including a global object to coordinate all fakes through. + +Sandboxes are partially configured by default such that calling: + +```javascript +var sandbox = sinon.createSandbox({}); +``` + +will merge in extra defaults analogous to: + +```javascript +var sandbox = sinon.createSandbox({ + // ... + injectInto: null, + properties: ["spy", "stub", "mock"], + useFakeTimers: false, + useFakeServer: false +}); +``` + +The `useFakeTimers` and `useFakeServers` are **false** as opposed to the defaults in `sinon.defaultConfig`: + +```javascript +sinon.defaultConfig = { + // ... + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "server", "requests"], + useFakeTimers: true, + useFakeServer: true +} +``` + +To get a full sandbox with stubs, spies, etc. **and** fake timers and servers, you can call: + +```javascript +// Inject the sinon defaults explicitly. +var sandbox = sinon.createSandbox(sinon.defaultConfig); + +// (OR) Add the extra properties that differ from the sinon defaults. +var sandbox = sinon.createSandbox({ + useFakeTimers: true + useFakeServer: true +}); +``` + +##### injectInto + +The sandbox's methods can be injected into another object for convenience. The +`injectInto` configuration option can name an object to add properties to. + +##### properties + +What properties to inject. Note that simply naming "server" here is not +sufficient to have a `server` property show up in the target object, you also +have to set `useFakeServer` to `true`. + +##### useFakeTimers + +If set to `true`, the sandbox will have a `clock` property. You can optionally pass +in a configuration object that follows the [specification for fake timers](../fake-timers), +such as `{ toFake: ["setTimeout", "setInterval"] }`. + +##### useFakeServer + +If `true`, `server` and `requests` properties are added to the sandbox. Can +also be an object to use for fake server. The default one is `sinon.fakeServer`, +but if you're using jQuery 1.3.x or some other library that does not set the XHR's +`onreadystatechange` handler, you might want to do: + +```javascript +sinon.config = { + useFakeServer: sinon.fakeServerWithClock +}; +``` + +#### `sandbox.assert();` + +A convenience reference for [`sinon.assert`](./assertions) + +*Since `sinon@2.0.0`* + +#### `sandbox.spy();` + +Works exactly like `sinon.spy`, only also adds the returned spy to the internal collection of fakes for easy restoring through `sandbox.restore()` + +#### `sandbox.createStubInstance();` + +Works almost exactly like `sinon.createStubInstance`, only also adds the returned stubs to the internal collection of fakes for easy restoring through `sandbox.restore()`. + +#### `sandbox.stub();` + +Works almost exactly like `sinon.stub`, only also adds the returned stub to the internal collection of fakes for easy restoring through `sandbox.restore()`. + +The sandbox `stub` method can also be used to stub any kind of property. This is useful if you need to override an object's property for the duration of a test, and have it restored when the test completes. + +##### Stubbing a non-function property +```javascript +const myObject = { + 'hello': 'world' +}; + +sandbox.stub(myObject, 'hello').value('Sinon'); + +console.log(myObject.hello); +// Sinon + +sandbox.restore(); +console.log(myObject.hello); +// world +``` + +#### `sandbox.mock();` + +Works exactly like `sinon.mock`, only also adds the returned mock to the internal collection of fakes for easy restoring through `sandbox.restore()` + + +#### `sandbox.useFakeTimers();` + +Fakes timers and binds the `clock` object to the sandbox such that it too is restored when calling `sandbox.restore()`. + +Access through `sandbox.clock`. + + +#### `sandbox.useFakeXMLHttpRequest();` + +Fakes XHR and binds the resulting object to the sandbox such that it too is restored when calling `sandbox.restore()`. + +Since 2.x, you can no longer access requests through `sandbox.requests` - use `sandbox.useFakeServer` to do this. This function maps to `sinon.useFakeXMLHttpRequest`, only with sandboxing. + + +#### `sandbox.useFakeServer();` + +Fakes XHR and binds a server object to the sandbox such that it too is restored when calling `sandbox.restore()`. + +Access requests through `sandbox.requests` and server through `sandbox.server` + +#### `sandbox.usingPromise(promiseLibrary);` + +Causes all stubs created from the sandbox to return promises using a specific +Promise library instead of the global one when using `stub.rejects` or +`stub.resolves`. Returns the stub to allow chaining. + +*Since `sinon@2.0.0`* + +#### `sandbox.restore();` + +Restores all fakes created through sandbox. + +#### `sandbox.reset();` + +Resets the internal state of all fakes created through sandbox. + +#### `sandbox.resetBehavior();` + +Resets the behaviour of all stubs created through the sandbox. + +*Since `sinon@2.0.0`* + +#### `sandbox.resetHistory();` + +Resets the history of all stubs created through the sandbox. + +*Since `sinon@2.0.0`* + +#### `sandbox.verify();` + +Verifies all mocks created through the sandbox. + +#### `sandbox.verifyAndRestore();` + +Verifies all mocks and restores all fakes created through the sandbox. diff --git a/docs/_releases/v4.1.6/spies.md b/docs/_releases/v4.1.6/spies.md new file mode 100644 index 000000000..62e985d87 --- /dev/null +++ b/docs/_releases/v4.1.6/spies.md @@ -0,0 +1,512 @@ +--- +layout: page +title: Spies - Sinon.JS +breadcrumb: spies +--- + +### Introduction + +### What is a test spy? + +A test spy is a function that records arguments, return value, the value of +`this` and exception thrown (if any) for all its calls. There are two types of spies: +Some are anonymous functions, while others wrap methods that already exist in +the system under test. + + +### Creating a spy as an anonymous function + +When the behavior of the spied-on function is not under test, you can use an +anonymous function spy. The spy won't do anything except record information +about its calls. A common use case for this type of spy is testing how a function +handles a callback, as in the following simplified example: + +```javascript +"test should call subscribers on publish": function () { + var callback = sinon.spy(); + PubSub.subscribe("message", callback); + + PubSub.publishSync("message"); + + assertTrue(callback.called); +} +``` + + +### Using a spy to wrap an existing method + +`sinon.spy(object, "method")` creates a spy that wraps the existing function +`object.method`. The spy will behave exactly like the original method +(including when used as a constructor), but you will have access to data about +all calls. The following is a slightly contrived example: + +```javascript +{ + setUp: function () { + sinon.spy(jQuery, "ajax"); + }, + + tearDown: function () { + jQuery.ajax.restore(); // Unwraps the spy + }, + + "test should inspect jQuery.getJSON's usage of jQuery.ajax": function () { + jQuery.getJSON("/some/resource"); + + assert(jQuery.ajax.calledOnce); + assertEquals("/some/resource", jQuery.ajax.getCall(0).args[0].url); + assertEquals("json", jQuery.ajax.getCall(0).args[0].dataType); + } +} +``` + + +### Creating spies: `sinon.spy()` Method Signatures + +
+
var spy = sinon.spy();
+
+ Creates an anonymous function that records arguments, this value, + exceptions and return values for all calls. +
+
var spy = sinon.spy(myFunc);
+
Spies on the provided function
+
var spy = sinon.spy(object, "method");
+
+ Creates a spy for object.method and + replaces the original method with the spy. An exception is thrown if the property + is not already a function. The spy acts exactly like the original method in + all cases. The original method can be restored by calling + object.method.restore(). The returned spy is the function + object which replaced the original method. spy === object.method. +
+
+ + +### Spy API + +Spies provide a rich interface to inspect their usage. The above examples showed +the `calledOnce` boolean property as well as the `getCall` method and the +returned object's `args` property. There are three ways of inspecting call data. + +The preferred approach is to use the spy's `calledWith` method (and friends) +because it keeps your test from being too specific about which call did what and +so on. It will return `true` if the spy was ever called with the provided +arguments. + +```javascript +"test should call subscribers with message as first argument" : function () { + var message = 'an example message'; + var spy = sinon.spy(); + + PubSub.subscribe(message, spy); + PubSub.publishSync(message, "some payload"); + + assert(spy.calledWith(message)); +} +``` + +If you want to be specific, you can directly check the first argument of the +first call. There are two ways of achieving this: + +```javascript +"test should call subscribers with message as first argument" : function () { + var message = 'an example message'; + var spy = sinon.spy(); + + PubSub.subscribe(message, spy); + PubSub.publishSync(message, "some payload"); + + assertEquals(message, spy.args[0][0]); +} +``` + +```javascript +"test should call subscribers with message as first argument" : function () { + var message = 'an example message'; + var spy = sinon.spy(); + + PubSub.subscribe(message, spy); + PubSub.publishSync(message, "some payload"); + + assertEquals(message, spy.getCall(0).args[0]); +} +``` + +The first example uses the two-dimensional `args` array directly on the spy, +while the second example fetches the first call object and then accesses its +`args` array. Which one to use is a matter of preference, but the recommended +approach is going with `spy.calledWith(arg1, arg2, ...)` unless there's a need +to make the tests highly specific. + + +## API + +Spy objects are objects returned from `sinon.spy()`. When spying on existing +methods with `sinon.spy(object, method)`, the following properties and methods +are also available on `object.method`. + +### Properties + + +#### `spy.withArgs(arg1[, arg2, ...]);` + +Creates a spy that only records calls when the received arguments match those passed to `withArgs`. This is useful to be more expressive in your assertions, where you can access the spy with the same call. + +```javascript +"should call method once with each argument": function () { + var object = { method: function () {} }; + var spy = sinon.spy(object, "method"); + + object.method(42); + object.method(1); + + assert(spy.withArgs(42).calledOnce); + assert(spy.withArgs(1).calledOnce); +} +``` + + +#### `spy.callCount` + +The number of recorded calls. + + +#### `spy.called` + +`true` if the spy was called at least once + + +#### `spy.notCalled` + +`true` if the spy was not called + + +#### `spy.calledOnce` + +`true` if spy was called exactly once + + +#### `spy.calledTwice` + +`true` if the spy was called exactly twice + + +#### `spy.calledThrice` + +`true` if the spy was called exactly thrice + + +#### `spy.firstCall` + +The first call + + +#### `spy.secondCall` + +The second call + + +#### `spy.thirdCall` + +The third call + + +#### `spy.lastCall` + +The last call + + +#### `spy.calledBefore(anotherSpy);` + +Returns `true` if the spy was called before `anotherSpy` + + +#### `spy.calledAfter(anotherSpy);` + +Returns `true` if the spy was called after `anotherSpy` + + +#### `spy.calledImmediatelyBefore(anotherSpy);` + +Returns `true` if `spy` was called before `anotherSpy`, and no spy calls +occurred between `spy` and `anotherSpy`. + + +#### `spy.calledImmediatelyAfter(anotherSpy);` + +Returns `true` if `spy` was called after `anotherSpy`, and no spy calls +occurred between `anotherSpy` and `spy`. + + +#### `spy.calledOn(obj);` + +Returns `true` if the spy was called at least once with `obj` as `this`. `calledOn` also accepts a matcher `spyCall.calledOn(sinon.match(fn))` (see [matchers](#matchers)). + + +#### `spy.alwaysCalledOn(obj);` + +Returns `true` if the spy was always called with `obj` as `this`. + + +#### `spy.calledWith(arg1, arg2, ...);` + +Returns `true` if spy was called at least once with the provided arguments. + +Can be used for partial matching, Sinon only checks the provided arguments against actual arguments, so a call that received the provided arguments (in the same spots) and possibly others as well will return `true`. + + +#### `spy.alwaysCalledWith(arg1, arg2, ...);` + +Returns `true` if spy was always called with the provided arguments (and possibly others). + + +#### `spy.calledWithExactly(arg1, arg2, ...);` + +Returns `true` if spy was called at least once with the provided arguments and no others. + + +#### `spy.alwaysCalledWithExactly(arg1, arg2, ...);` + +Returns `true` if spy was always called with the exact provided arguments. + + +#### `spy.calledWithMatch(arg1, arg2, ...);` + +Returns `true` if spy was called with matching arguments (and possibly others). + +This behaves the same as `spy.calledWith(sinon.match(arg1), sinon.match(arg2), ...)`. + + +#### `spy.alwaysCalledWithMatch(arg1, arg2, ...);` + +Returns `true` if spy was always called with matching arguments (and possibly others). + +This behaves the same as `spy.alwaysCalledWith(sinon.match(arg1), sinon.match(arg2), ...)`. + + +#### `spy.calledWithNew();` + +Returns `true` if spy/stub was called the `new` operator. + +Beware that this is inferred based on the value of the `this` object and the spy function's `prototype`, so it may give false positives if you actively return the right kind of object. + + +#### `spy.neverCalledWith(arg1, arg2, ...);` + +Returns `true` if the spy/stub was never called with the provided arguments. + + +#### `spy.neverCalledWithMatch(arg1, arg2, ...);` + +Returns `true` if the spy/stub was never called with matching arguments. + +This behaves the same as `spy.neverCalledWith(sinon.match(arg1), sinon.match(arg2), ...)`. + + +#### `spy.threw();` + +Returns `true` if spy threw an exception at least once. + + +#### `spy.threw("TypeError");` + +Returns `true` if spy threw an exception of the provided type at least once. + + +#### `spy.threw(obj);` + +Returns `true` if spy threw the provided exception object at least once. + + +#### `spy.alwaysThrew();` + +Returns `true` if spy always threw an exception. + + +#### `spy.alwaysThrew("TypeError");` + +Returns `true` if spy always threw an exception of the provided type. + + +#### `spy.alwaysThrew(obj);` + +Returns `true` if spy always threw the provided exception object. + + +#### `spy.returned(obj);` + +Returns `true` if spy returned the provided value at least once. + +Uses deep comparison for objects and arrays. Use `spy.returned(sinon.match.same(obj))` for strict comparison (see [matchers](#matchers)). + + +#### `spy.alwaysReturned(obj);` + +Returns `true` if spy always returned the provided value. + + +#### `var spyCall = spy.getCall(n);` + +Returns the *nth* [call](#spycall). + +Accessing individual calls helps with more detailed behavior verification when the spy is called more than once. + +```javascript +sinon.spy(jQuery, "ajax"); +jQuery.ajax("/stuffs"); +var spyCall = jQuery.ajax.getCall(0); + +assertEquals("/stuffs", spyCall.args[0]); +``` + + +#### `var spyCalls = spy.getCalls();` + +Returns an `Array` of all [calls](#spycall) recorded by the spy. + + +#### `spy.thisValues` + +Array of `this` objects, `spy.thisValues[0]` is the `this` object for the first call. + + +#### `spy.args` + +Array of arguments received, `spy.args[0]` is an array of arguments received in the first call. + + +#### `spy.exceptions` + +Array of exception objects thrown, `spy.exceptions[0]` is the exception thrown by the first call. + +If the call did not throw an error, the value at the call's location in `.exceptions` will be `undefined`. + + +#### `spy.returnValues` + +Array of return values, `spy.returnValues[0]` is the return value of the first call. + +If the call did not explicitly return a value, the value at the call's location in `.returnValues` will be `undefined`. + + +#### `spy.resetHistory()` + +Resets the state of a spy. + + +#### `spy.restore()` + +Replaces the spy with the original method. Only available if the spy replaced an existing method. + + +#### `spy.printf("format string", [arg1, arg2, ...])` + +Returns the passed format string with the following replacements performed: + +
+
%n
+
the name of the spy "spy" by default)
+ +
%c
+
the number of times the spy was called, in words ("once", "twice", etc.)
+
%C
+
a list of string representations of the calls to the spy, with each call prefixed by a newline and four spaces
+ +
%t
+
a comma-delimited list of this values the spy was called on
+ +
%n
+
the formatted value of the nth argument passed to printf
+ +
%*
+
a comma-delimited list of the (non-format string) arguments passed to printf
+
+ + +### Individual spy calls + + +##### `var spyCall = spy.getCall(n)` + +Returns the *nth* [call](#spycall). Accessing individual calls helps with more detailed behavior verification when the spy is called more than once. + +```javascript +sinon.spy(jQuery, "ajax"); +jQuery.ajax("/stuffs"); +var spyCall = jQuery.ajax.getCall(0); + +assertEquals("/stuffs", spyCall.args[0]); +``` + + +#### `spyCall.calledOn(obj);` + +Returns `true` if `obj` was `this` for this call. `calledOn` also accepts a matcher `spyCall.calledOn(sinon.match(fn))` (see [matchers](#matchers)). + + +#### `spyCall.calledWith(arg1, arg2, ...);` + +Returns `true` if call received provided arguments (and possibly others). + + +#### `spyCall.calledWithExactly(arg1, arg2, ...);` + +Returns `true` if call received provided arguments and no others. + + +#### `spyCall.calledWithMatch(arg1, arg2, ...);` + +Returns `true` if call received matching arguments (and possibly others). +This behaves the same as `spyCall.calledWith(sinon.match(arg1), sinon.match(arg2), ...)`. + + +#### `spyCall.notCalledWith(arg1, arg2, ...);` + +Returns `true` if call did not receive provided arguments. + + +#### `spyCall.notCalledWithMatch(arg1, arg2, ...);` + +Returns `true` if call did not receive matching arguments. +This behaves the same as `spyCall.notCalledWith(sinon.match(arg1), sinon.match(arg2), ...)`. + +#### `spyCall.returned(value);` + +Returns `true` if spied function returned the provided `value` on this call. + +Uses deep comparison for objects and arrays. Use `spyCall.returned(sinon.match.same(obj))` for strict comparison (see [matchers](#matchers)). + +#### `spyCall.threw();` + +Returns `true` if call threw an exception. + + +#### `spyCall.threw("TypeError");` + +Returns `true` if call threw exception of provided type. + + +#### `spyCall.threw(obj);` + +Returns `true` if call threw provided exception object. + + +#### `spyCall.thisValue` + +The call's `this` value. + + +#### `spyCall.args` + +Array of received arguments. + + +#### `spyCall.exception` + +Exception thrown, if any. + + +#### `spyCall.returnValue` + +Return value. diff --git a/docs/_releases/v4.1.6/stubs.md b/docs/_releases/v4.1.6/stubs.md new file mode 100644 index 000000000..f6d2f30b2 --- /dev/null +++ b/docs/_releases/v4.1.6/stubs.md @@ -0,0 +1,559 @@ +--- +layout: page +title: Stubs - Sinon.JS +breadcrumb: stubs +--- + +### What are stubs? + +Test stubs are functions (spies) with pre-programmed behavior. + +They support the full [test spy API](../spies) in addition to methods which can be used to alter the stub's behavior. + +As spies, stubs can be either anonymous, or wrap existing functions. When +wrapping an existing function with a stub, the original function is not called. + + +### When to use stubs? + +Use a stub when you want to: + +1. Control a method's behavior from a test to force the code down a specific path. Examples include forcing a method to throw an error in order to test error handling. + +2. When you want to prevent a specific method from being called directly (possibly because it triggers undesired behavior, such as a `XMLHttpRequest` or similar). + +The following example is yet another test from [PubSubJS][pubsubjs] which shows how to create an anonymous stub that throws an exception when called. + +```javascript +"test should call all subscribers, even if there are exceptions" : function(){ + var message = 'an example message'; + var stub = sinon.stub().throws(); + var spy1 = sinon.spy(); + var spy2 = sinon.spy(); + + PubSub.subscribe(message, stub); + PubSub.subscribe(message, spy1); + PubSub.subscribe(message, spy2); + + PubSub.publishSync(message, undefined); + + assert(spy1.called); + assert(spy2.called); + assert(stub.calledBefore(spy1)); +} +``` + +Note how the stub also implements the spy interface. The test verifies that all +callbacks were called, and also that the exception throwing stub was called +before one of the other callbacks. + +### Defining stub behavior on consecutive calls + +Calling behavior defining methods like `returns` or `throws` multiple times +overrides the behavior of the stub. As of Sinon version 1.8, you can use the +[`onCall`](#stuboncalln-added-in-v18) method to make a stub respond differently on +consecutive calls. + +Note that in Sinon version 1.5 to version 1.7, multiple calls to the `yields*` +and `callsArg*` family of methods define a sequence of behaviors for consecutive +calls. As of 1.8, this functionality has been removed in favor of the +[`onCall`](#stuboncalln-added-in-v18) API. + +[pubsubjs]: https://github.com/mroderick/pubsubjs + +### Stub API + +If you need to stub getters/setters or non-function properties, then you should be using [`sandbox.stub`](../sandbox/#sandboxstub) + +### Properties + +#### `var stub = sinon.stub();` + +Creates an anonymous stub function + + +#### `var stub = sinon.stub(object, "method");` + +Replaces `object.method` with a stub function. An exception is thrown if the property is not already a function. + +The original function can be restored by calling `object.method.restore();` (or `stub.restore();`). + +#### ~~`var stub = sinon.stub(object, "method", func);`~~ + +This has been removed from `v3.0.0`. Instead you should use + +`stub(obj, 'meth').callsFake(fn)` + +A [codemod is available](https://github.com/hurrymaplelad/sinon-codemod) to upgrade your code + +#### `var stub = sinon.stub(obj);` + +Stubs all the object's methods. + +Note that it's usually better practice to stub individual methods, particularly on objects that you don't understand or control all the methods for (e.g. library dependencies). + +Stubbing individual methods tests intent more precisely and is less susceptible to unexpected behavior as the object's code evolves. + +If you want to create a stub object of `MyConstructor`, but don't want the constructor to be invoked, use this utility function. + +```javascript +var stub = sinon.createStubInstance(MyConstructor) +``` + +#### `stub.withArgs(arg1[, arg2, ...]);` + +Stubs the method only for the provided arguments. + +This is useful to be more expressive in your assertions, where you can access the spy with the same call. It is also useful to create a stub that can act differently in response to different arguments. + +```javascript +"test should stub method differently based on arguments": function () { + var callback = sinon.stub(); + callback.withArgs(42).returns(1); + callback.withArgs(1).throws("TypeError"); + + callback(); // No return value, no exception + callback(42); // Returns 1 + callback(1); // Throws TypeError +} +``` + +#### `stub.onCall(n);` *Added in v1.8* + +Defines the behavior of the stub on the *nth* call. Useful for testing sequential interactions. + +```javascript +"test should stub method differently on consecutive calls": function () { + var callback = sinon.stub(); + callback.onCall(0).returns(1); + callback.onCall(1).returns(2); + callback.returns(3); + + callback(); // Returns 1 + callback(); // Returns 2 + callback(); // All following calls return 3 +} +``` + +There are methods `onFirstCall`, `onSecondCall`,`onThirdCall` to make stub definitions read more naturally. + +`onCall` can be combined with all of the behavior defining methods in this section. In particular, it can be used together with `withArgs`. + +```javascript +"test should stub method differently on consecutive calls with certain argument": function () { + var callback = sinon.stub(); + callback.withArgs(42) + .onFirstCall().returns(1) + .onSecondCall().returns(2); + callback.returns(0); + + callback(1); // Returns 0 + callback(42); // Returns 1 + callback(1); // Returns 0 + callback(42); // Returns 2 + callback(1); // Returns 0 + callback(42); // Returns 0 +} +``` + +Note how the behavior of the stub for argument `42` falls back to the default behavior once no more calls have been defined. + +#### `stub.onFirstCall();` + +Alias for `stub.onCall(0);` + +#### `stub.onSecondCall();` + +Alias for `stub.onCall(1);` + +#### `stub.onThirdCall();` +Alias for `stub.onCall(2);` + + +#### `stub.reset();` + +Resets both behaviour and history of the stub. + +This is equivalent to calling both `stub.resetBehavior()` and `stub.resetHistory()` + +*Updated in `sinon@2.0.0`* + +#### `stub.resetBehavior();` + +Resets the stub's behaviour to the default behaviour + +```javascript +var stub = sinon.stub(); + +stub.returns(54) + +stub(); // 54 + +stub.resetBehavior(); + +stub(); // undefined +``` + + +#### `stub.resetHistory();` + +Resets the stub's history + +```javascript +var stub = sinon.stub(); + +stub.called // false + +stub(); + +stub.called // true + +stub.resetHistory(); + +stub.called // false +``` + +*Since `sinon@2.0.0`* + +#### `stub.callsFake(fakeFunction);` +Makes the stub call the provided `fakeFunction` when invoked. + +```javascript +var myObj = {}; +myObj.prop = function propFn() { + return 'foo'; +}; + +sinon.stub(myObj, 'prop').callsFake(function fakeFn() { + return 'bar'; +}); + +myObj.prop(); // 'bar' +``` + +#### `stub.returns(obj);` +Makes the stub return the provided value. + +#### `stub.returnsArg(index);` + +Causes the stub to return the argument at the provided index. + +`stub.returnsArg(0);` causes the stub to return the first argument. + + +#### `stub.returnsThis();` +Causes the stub to return its this value. + +Useful for stubbing jQuery-style fluent APIs. + +#### `stub.resolves(value);` + +Causes the stub to return a Promise which resolves to the provided value. + +When constructing the Promise, sinon uses the `Promise.resolve` method. You are +responsible for providing a polyfill in environments which do not provide `Promise`. +The Promise library can be overwritten using the `usingPromise` method. + +*Since `sinon@2.0.0`* + +#### `stub.throws();` + +Causes the stub to throw an exception (`Error`). + + +#### `stub.throws("TypeError");` + +Causes the stub to throw an exception of the provided type. + + +#### `stub.throws(obj);` + +Causes the stub to throw the provided exception object. + + +#### `stub.throws(function() { return new Error(); });` + +Causes the stub to throw the exception returned by the function. + + +#### `stub.rejects();` + +Causes the stub to return a Promise which rejects with an exception (`Error`). + +When constructing the Promise, sinon uses the `Promise.reject` method. You are +responsible for providing a polyfill in environments which do not provide `Promise`. +The Promise library can be overwritten using the `usingPromise` method. + +*Since `sinon@2.0.0`* + + +#### `stub.rejects("TypeError");` + +Causes the stub to return a Promise which rejects with an exception of the provided type. + +*Since `sinon@2.0.0`* + + +#### `stub.rejects(value);` + +Causes the stub to return a Promise which rejects with the provided exception object. + +*Since `sinon@2.0.0`* + + +#### `stub.callsArg(index);` + +Causes the stub to call the argument at the provided index as a callback function. `stub.callsArg(0);` causes the stub to call the first argument as a callback. + + +#### `stub.callThrough();` + +Causes the original method wrapped into the stub to be called when none of the conditional stubs are matched. + +```javascript +var stub = sinon.stub(); + +var obj = {}; + +obj.sum = function sum(a, b) { + return a + b; +}; + +stub(obj, 'sum'); + +obj.sum.withArgs(2, 2).callsFake(function foo() { + return 'bar'; +}); + +obj.sum.callThrough(); + +obj.sum(2, 2); // 'bar' +obj.sum(1, 2); // 3 +``` + + +#### `stub.callsArgOn(index, context);` + +Like `stub.callsArg(index);` but with an additional parameter to pass the `this` context. + + +#### `stub.callsArgWith(index, arg1, arg2, ...);` + +Like `callsArg`, but with arguments to pass to the callback. + + +#### `stub.callsArgOnWith(index, context, arg1, arg2, ...);` + +Like above but with an additional parameter to pass the `this` context. + +#### `stub.usingPromise(promiseLibrary);` + +Causes the stub to return promises using a specific Promise library instead of +the global one when using `stub.rejects` or `stub.resolves`. Returns the stub +to allow chaining. + +```javascript +var myObj = { + saveSomething: sinon.stub().usingPromise(bluebird.Promise).resolves("baz"); +} + +myObj.saveSomething() + .tap(function(actual) { + console.log(actual); // baz + }); +``` + +*Since `sinon@2.0.0`* + +#### `stub.yields([arg1, arg2, ...])` + +Similar to `callsArg`. + +Causes the stub to call the first callback it receives with the provided arguments (if any). + +If a method accepts more than one callback, you need to use `callsArg` to have the stub invoke other callbacks than the first one. + + +#### `stub.yieldsOn(context, [arg1, arg2, ...])` + +Like above but with an additional parameter to pass the `this` context. + + +#### `stub.yieldsTo(property, [arg1, arg2, ...])` + +Causes the spy to invoke a callback passed as a property of an object to the spy. + +Like `yields`, `yieldsTo` grabs the first matching argument, finds the callback and calls it with the (optional) arguments. + + +#### `stub.yieldsToOn(property, context, [arg1, arg2, ...])` + +Like above but with an additional parameter to pass the `this` context. + +```javascript +"test should fake successful ajax request": function () { + sinon.stub(jQuery, "ajax").yieldsTo("success", [1, 2, 3]); + + jQuery.ajax({ + success: function (data) { + assertEquals([1, 2, 3], data); + } + }); +} +``` + + +#### `stub.yield([arg1, arg2, ...])` + +Invoke callbacks passed to the `stub` with the given arguments. + +If the stub was never called with a function argument, `yield` throws an error. + +Also aliased as `invokeCallback`. + + +#### `stub.yieldTo(callback, [arg1, arg2, ...])` + +Invokes callbacks passed as a property of an object to the stub. + +Like `yield`, `yieldTo` grabs the first matching argument, finds the callback and calls it with the (optional) arguments. + +```javascript +"calling callbacks": function () { + var callback = sinon.stub(); + callback({ + "success": function () { + console.log("Success!"); + }, + "failure": function () { + console.log("Oh noes!"); + } + }); + + callback.yieldTo("failure"); // Logs "Oh noes!" +} +``` + + +#### `stub.callArg(argNum)` + +Like `yield`, but with an explicit argument number specifying which callback to call. + +Useful if a function is called with more than one callback, and simply calling the first callback is not desired. + +```javascript +"calling the last callback": function () { + var callback = sinon.stub(); + callback(function () { + console.log("Success!"); + }, function () { + console.log("Oh noes!"); + }); + + callback.callArg(1); // Logs "Oh noes!" +} +``` + +#### `stub.callArgWith(argNum, [arg1, arg2, ...])` + +Like `callArg`, but with arguments. + + +#### `stub.callsArgAsync(index);` + +Same as their corresponding non-Async counterparts, but with callback being deferred (executed not immediately but after short timeout and in another "thread") + +#### `stub.callsArgAsync(index);` + +#### `stub.callsArgOnAsync(index, context);` + +#### `stub.callsArgWithAsync(index, arg1, arg2, ...);` + +#### `stub.callsArgOnWithAsync(index, context, arg1, arg2, ...);` + +#### `stub.yieldsAsync([arg1, arg2, ...]);` + +Same as their corresponding non-Async counterparts, but with callback being deferred (executed not immediately but after short timeout and in another "thread") + +#### `stub.yieldsOnAsync(context, [arg1, arg2, ...]);` + +#### `stub.yieldsToAsync(property, [arg1, arg2, ...]);` + +#### `stub.yieldsToOnAsync(property, context, [arg1, arg2, ...])` + +#### `sinon.addBehavior(name, fn);` + +Add a custom behavior. The name will be available as a function on stubs, and the chaining mechanism will be set up for you (e.g. no need to return anything from your function, its return value will be ignored). The `fn` will be passed the fake instance as its first argument, and then the user's arguments. + +```javascript +const sinon = require('sinon'); + +sinon.addBehavior('returnsNum', (fake, n) => fake.returns(n)); + +var stub = sinon.stub().returnsNum(42); + +assert.equals(stub(), 42); +``` + +#### `stub.get(getterFn)` + +Replaces a new getter for this stub. + +```javascript +var myObj = { + prop: 'foo' +}; + +sinon.stub(myObj, 'prop').get(function getterFn() { + return 'bar'; +}); + +myObj.prop; // 'bar' +``` + +#### `stub.set(setterFn)` + +Defines a new setter for this stub. + +```javascript +var myObj = { + example: 'oldValue', + prop: 'foo' +}; + +sinon.stub(myObj, 'prop').set(function setterFn(val) { + myObj.example = val; +}); + +myObj.prop = 'baz'; + +myObj.example; // 'baz' +``` + +#### `stub.value(newVal)` + +Defines a new value for this stub. + +```javascript +var myObj = { + example: 'oldValue', +}; + +sinon.stub(myObj, 'example').value('newValue'); + +myObj.example; // 'newValue' +``` + +You can restore values by calling the `restore` method: + +```javascript +var myObj = { + example: 'oldValue', +}; + +var stub = sinon.stub(myObj, 'example').value('newValue'); +stub.restore() + +myObj.example; // 'oldValue' +``` + diff --git a/docs/_releases/v4.1.6/utils.md b/docs/_releases/v4.1.6/utils.md new file mode 100644 index 000000000..79ca18dea --- /dev/null +++ b/docs/_releases/v4.1.6/utils.md @@ -0,0 +1,25 @@ +--- +layout: page +title: Utilities - Sinon.JS +breadcrumb: utilities +--- + +Sinon.JS has a few utilities used internally in `lib/sinon.js`. Unless the method in question is documented here, it should not be considered part of the public API, and thus is subject to change. + +## Utils API + +#### `sinon.createStubInstance(constructor);` + +Creates a new object with the given function as the protoype and stubs all implemented functions. + +```javascript + class Container { + contains(item) { /* ... */ } + } + + var stubContainer = sinon.createStubInstance(Container); + stubContainer.contains.returns(false); + stubContainer.contains.withArgs("item").returns(true); +``` + +The given constructor function is not invoked. See also the [stub API](../stubs).