Skip to content

Commit

Permalink
Documentation for assertion options for the sandbox (#2564)
Browse files Browse the repository at this point in the history
* doc: improve JSDocs

* docs: improve public docs for sandbox

- move some important info up where it is more visible
- remove some bits no longer relevant (sinon.config)
  and replace with its modern (post Sinon 1) equivalent

* Add example on adding assertOptions to the sandbox
  • Loading branch information
fatso83 committed Oct 28, 2023
1 parent f7d180c commit b5fc367
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 70 deletions.
24 changes: 24 additions & 0 deletions docs/release-source/release/examples/sandbox-configuration.test.js
@@ -0,0 +1,24 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const { assert } = require("@sinonjs/referee");

it("should allow limiting the length of the assert.fake output", function () {
const sb = sinon.createSandbox({
assertOptions: {
shouldLimitAssertionLogs: true,
assertionLogLimit: 10,
},
});
const reallyLongErrorMessage = "a long string repeated 100 times".repeat(
100,
);

assert.exception(
() => {
sb.assert.fail(reallyLongErrorMessage);
},
{
message: "a long str",
},
);
});
105 changes: 43 additions & 62 deletions docs/release-source/release/sandbox.md
Expand Up @@ -7,8 +7,8 @@ breadcrumb: sandbox
Sandboxes remove the need to keep track of every fake created, which greatly simplifies cleanup.

```javascript
var sandbox = require("sinon").createSandbox();
var myAPI = { hello: function () {} };
const sandbox = require("sinon").createSandbox();
const myAPI = { hello: function () {} };

describe("myAPI.hello method", function () {
beforeEach(function () {
Expand All @@ -34,11 +34,11 @@ describe("myAPI.hello method", function () {
});
```

## Sandbox API
## Default sandbox

#### Default sandbox
Since Sinon 5, the `sinon` object is a default sandbox in itself! Unless you have a very advanced setup or need a special configuration, you probably only need to use that one in your tests for easy cleanup.

Since `sinon@5.0.0`, the `sinon` object is a default sandbox. Unless you have a very advanced setup or need a special configuration, you probably want to only use that one.
This also means all of the sandbox API is exposed on the default `sinon` instance.

```javascript
const myObject = {
Expand All @@ -55,52 +55,22 @@ console.log(myObject.hello);
// world
```

#### `var sandbox = sinon.createSandbox();`
## Sandbox API

#### `const sandbox = sinon.createSandbox();`

Creates a new sandbox object with spies, stubs, and mocks.

#### `var sandbox = sinon.createSandbox(config);`
#### `const 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`](https://github.com/sinonjs/sinon/blob/master/lib/sinon/util/core/default-config.js):

```javascript
sinon.defaultConfig = {
// ...
injectInto: null,
properties: ["spy", "stub", "mock", "clock", "server", "requests"],
useFakeTimers: true,
useFakeServer: true,
};
```
The default sandbox config has faking of XHR and timers turned off.

To get a full sandbox with stubs, spies, etc. **and** fake timers and servers, you can call:
To get a full sandbox with stubs, spies, etc. **and** fake timers and servers, you explicitly enable the additional features:

```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({
const sandbox = sinon.createSandbox({
useFakeTimers: true,
useFakeServer: true,
});
Expand All @@ -109,21 +79,17 @@ var sandbox = sinon.createSandbox({
##### `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.
`injectInto` configuration option can name an object to add properties to. See the example further down the page.

##### `properties`

What properties to inject. Note that only 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`.
Which properties to inject into the facade object. Note that only 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`.

The list of properties that can be injected are the ones exposed by the object
returned by the function `inject`, namely:
returned by the function `inject`:

```javascript
{
//...
properties: [
console.log(Object.keys(sinon.inject(obj)))
"spy",
"stub",
"mock",
Expand All @@ -132,12 +98,27 @@ returned by the function `inject`, namely:
"replace",
"replaceSetter",
"replaceGetter",
"match",
// If enabled:
// sinon.useFakeTimers();
"clock",
// sinon.useFakeServer();
"server",
"requests",
"match",
];
}
```

##### `assertOptions`

You can override the default behavior and limit the amount of
characters if the error strings should somehow be overwhelming
and overflow your display.

```javascript
@property {boolean} shouldLimitAssertionLogs
@property {number} assertionLogLimit
```

<div data-example-id="sandbox-configuration"></div>
```
##### `useFakeTimers`
Expand All @@ -154,22 +135,22 @@ but if you're using jQuery 1.3.x or some other library that does not set the XHR
`onreadystatechange` handler, you might want to do:
```javascript
sinon.config = {
sinon.createSandbox({
useFakeServer: sinon.fakeServerWithClock,
};
});
```

##### exposing sandbox example
##### Exposing sandbox example

To create an object `sandboxFacade` which gets the method `spy` injected, you
can code:

```javascript
// object that will have the spy method injected into it
var sandboxFacade = {};
const sandboxFacade = {};

// create sandbox and inject properties (in this case spy) into sandboxFacade
var sandbox = sinon.createSandbox({
const sandbox = sinon.createSandbox({
injectInto: sandboxFacade,
properties: ["spy"],
});
Expand All @@ -188,7 +169,7 @@ Defines the `property` on `object` with the value `value`. Attempts to define an
`value` can be any value except `undefined`, including `spies`, `stubs` and `fakes`.

```js
var myObject = {};
const myObject = {};

sandbox.define(myObject, "myValue", "blackberry");

Expand Down Expand Up @@ -222,7 +203,7 @@ Replaces `property` on `object` with `replacement` argument. Attempts to replace
This method only works on non-accessor properties, for replacing accessors, use `sandbox.replaceGetter()` and `sandbox.replaceSetter()`.

```js
var myObject = {
const myObject = {
myMethod: function () {
return "apple pie";
},
Expand Down Expand Up @@ -251,7 +232,7 @@ Replaces an existing getter for `property` on `object` with the `replacementFunc
`replacement` must be a `Function`, and can be instances of `spies`, `stubs` and `fakes`.

```js
var myObject = {
const myObject = {
get myProperty: function() {
return 'apple pie';
}
Expand All @@ -272,7 +253,7 @@ Replaces an existing setter for `property` on `object` with the `replacementFunc
`replacement` must be a `Function`, and can be instances of `spies`, `stubs` and `fakes`.

```js
var object = {
const object = {
set myProperty(value) {
this.prop = value;
},
Expand Down
25 changes: 17 additions & 8 deletions lib/sinon/create-sandbox.js
Expand Up @@ -42,30 +42,39 @@ function exposeValue(sandbox, config, key, value) {
}

/**
* Customize the sandbox.
* This is mostly an integration feature most users will not need
* Options to customize a sandbox
*
* The sandbox's methods can be injected into another object for
* convenience. The `injectInto` configuration option can name an
* object to add properties to.
*
* @typedef {object} SandboxConfig
* @property {string[]} properties The properties of the API to expose on the sandbox. Examples: ['spy', 'fake', 'restore']
* @property {(object|null)} injectInto TBD
* @property {object} injectInto an object in which to inject properties from the sandbox (a facade). This is mostly an integration feature (sinon-test being one).
* @property {boolean} useFakeTimers whether timers are faked by default
* @property {boolean} useFakeServer whether XHR's are faked and the server feature enabled by default
* @property {boolean|object} useFakeServer whether XHR's are faked and the server feature enabled by default. It could also be a different default fake server implementation to use
* @property {object} [assertOptions] see CreateAssertOptions in ./assert
*
* This type def is really suffering from JSDoc not having standardized
* how to reference types defined in other modules :(
*/
// This type def is really suffering from JSDoc not being
// able to reference types in other modules

/**
* A configured sinon sandbox.
* A configured sinon sandbox (private type)
*
* @typedef {object} ConfiguredSinonSandboxType
* @private
* @augments Sandbox
* @property {string[]} injectedKeys the keys that have been injected (from config.injectInto)
* @property {*} injectInto TBD
* @property {*[]} args the arguments for the sandbox
*/

/**
* Create a sandbox
*
* As of Sinon 5 the `sinon` instance itself is a Sandbox, so you
* hardly ever need to create additional instances for the sake of testing
*
* @param config {SandboxConfig}
* @returns {Sandbox}
*/
Expand Down

0 comments on commit b5fc367

Please sign in to comment.