Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation for assertion options for the sandbox #2564

Merged
merged 3 commits into from
Oct 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs/release-source/release/examples/sandbox-configuration.test.js
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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