UNPKG

10.6 kBMarkdownView Raw
1# Chai Spies
2
3This is an addon plugin for the [chai](https://github.com/chaijs/chai) assertion library. It provides the
4most basic function spy ability and tests.
5
6This library is primarily meant to serve as a starting point for anyone interested in developing chai plugins. If
7developing a module, you are welcome to use this as a starting point. I also encourage the use of the compile
8tools to allow modules to work both in node.js and the browser.
9
10## Installation
11
12#### Node.js
13
14Chai spies are available on npm.
15
16 $ npm install chai-spies
17
18#### Browser
19
20Include `chai-spies.js` after including `chai.js`.
21
22```xml
23<script src="chai-spies.js"></script>
24```
25
26## Plug In
27
28If you are using `chai-spies` in the browser, there is nothing you need to do. It will detect `chai` in the global
29namespace and automatically get used.
30
31If you are using node, here is a useful bit.
32
33```js
34const chai = require('chai')
35 , spies = require('chai-spies');
36
37chai.use(spies);
38
39const should = chai.should()
40 , expect = chai.expect;
41```
42
43## TypeScript Setup
44
45If using TypeScript, this is how you can import `chai-spies`.
46
47```
48import { expect } from 'chai';
49import spies from 'chai-spies';
50chai.use(spies);
51```
52
53
54## Building for the Browser
55
56Currently this package uses [rollup](https://rollupjs.org/) to bundle source code. Just use `npm run build` to build browser version.
57
58## Chai Spies Api Reference
59
60### Creating Spies
61
62In this module, a spy is either an empty function, or a wrapped named function.
63Once chai has been extended, you can create a spy through chai's own interface.
64
65```js
66function original () {
67 // do something cool
68}
69
70const spy = chai.spy(original);
71
72// then use in place of original
73ee.on('some event', spy);
74
75// or use without original
76const spyAgain = chai.spy();
77ee.on('some other event', spyAgain);
78```
79
80#### spy.on
81
82`spy.on` allows to add spy on existing method of an object
83
84```js
85const array = [1, 2, 3];
86
87chai.spy.on(array, 'push');
88
89// or multiple spies
90chai.spy.on(array, ['push', 'pop']);
91```
92
93It's also possible to provide custom implementation of spied method:
94
95```js
96chai.spy.on(array, 'push', function (...items) {
97 // custom implementation of `push` method
98});
99```
100
101Using arrow functions, it's also easy to replace method implementation with constant:
102
103```js
104chai.spy.on(array, 'push', () => 5);
105
106// or more readable :)
107chai.spy.on(array, 'push', returns => 5);
108```
109
110#### spy.interface
111
112This method creates a mock (or spy object): an interface with spies on each of the object's methods. The object's methods have either fake implementations or no implementation.
113
114```js
115// with no implementation
116const arrayLike = chai.spy.interface('arrayLike', ['push', 'pop', 'filter']);
117
118// with fake implementation
119const arrayLike = chai.spy.interface({
120 push(item) {
121 this.__items = this.__items || [];
122 return this.__items.push(item)
123 },
124 // other method implementations
125});
126
127arrayLike.push(5);
128```
129
130#### spy.returns (Deprecated)
131
132`chai.spy.returns` is just a simple helper which creates a function that returns constant:
133
134```js
135const returnTrue = chai.spy.returns(true);
136
137returnTrue(); // true
138```
139
140Better to use arrow function:
141
142```js
143const returnTrue = chai.spy(returns => true);
144```
145
146### Sandboxes
147
148Sandbox is a set of spies. Sandbox allows to track methods on objects and restore original methods with on `restore` call.
149To create sandbox:
150
151```js
152const sandbox = chai.spy.sandbox();
153
154describe('Array', () => {
155 let array;
156
157 beforeEach(() => {
158 array = [];
159 sandbox.on(array, ['push', 'pop']);
160 });
161
162 afterEach(() => {
163 sandbox.restore(); // restores original methods on `array`
164 })
165
166 it('allows to add items', () => {
167 array.push(1);
168
169 expect(array.push).to.have.been.called.with(1);
170 });
171});
172```
173
174`chai.spy.on` and `chai.spy.restore` are bound to default sandbox.
175So to restore all methods spied by `chai.spy.on`, just call `chai.spy.restore()` (without arguments).
176
177`restore` method accepts 2 optional arguments: object to restore and method or methods to restore. So, this calls are also valid:
178
179```js
180const array = [1, 2, 3];
181
182chai.spy.on(array, ['push', 'pop']);
183
184chai.spy.restore(array) // restores all methods on object
185chai.spy.restore(array, 'push') // restores only `push` method
186```
187
188### Assertions
189
190#### .spy
191
192Asserts that object is a spy.
193
194```js
195expect(spy).to.be.spy;
196spy.should.be.spy;
197```
198
199#### .called
200
201Assert that a spy has been called. Negation passes through.
202
203```js
204expect(spy).to.have.been.called();
205spy.should.have.been.called();
206```
207
208Note that `called` can be used as a chainable method.
209
210#### .with
211
212Assert that a spy has been called with a given argument at least once,
213even if more arguments were provided.
214
215```js
216spy('foo');
217expect(spy).to.have.been.called.with('foo');
218spy.should.have.been.called.with('foo');
219```
220
221Will also pass for `spy('foo', 'bar')` and `spy(); spy('foo')`.
222
223If used with multiple arguments, assert that a spy has been called
224with all the given arguments at least once.
225
226```js
227spy('foo', 'bar', 1);
228expect(spy).to.have.been.called.with('bar', 'foo');
229spy.should.have.been.called.with('bar', 'foo');
230```
231
232#### .with.exactly
233
234Similar to .with, but will pass only if the list of arguments is
235exactly the same as the one provided.
236
237```js
238spy();
239spy('foo', 'bar');
240expect(spy).to.have.been.called.with.exactly('foo', 'bar');
241spy.should.have.been.called.with.exactly('foo', 'bar');
242```
243
244Will not pass for `spy('foo')`, `spy('bar')`, `spy('bar');
245spy('foo')`, `spy('foo'); spy('bar')`, `spy('bar', 'foo')` or
246`spy('foo', 'bar', 1)`.
247
248Can be used for calls with a single argument too.
249
250#### .always.with
251
252Assert that every time the spy has been called the argument list
253contained the given arguments.
254
255```js
256spy('foo');
257spy('foo', 'bar');
258spy(1, 2, 'foo');
259expect(spy).to.have.been.called.always.with('foo');
260spy.should.have.been.called.always.with('foo');
261```
262
263#### .always.with.exactly
264
265Assert that the spy has never been called with a different list of
266arguments than the one provided.
267
268```js
269spy('foo');
270spy('foo');
271expect(spy).to.have.been.called.always.with.exactly('foo');
272spy.should.have.been.called.always.with.exactly('foo');
273```
274
275#### .nth(n).called.with
276
277Asserts that the nth call of the spy has been made with the list of arguments provided. This assertion comes with other three flavors:
278
279* .first.called.with
280* .second.called.with
281* .third.called.with
282
283```js
284spy('foo');
285spy('bar');
286spy('baz');
287spy('foobar');
288expect(spy).to.have.been.first.called.with('foo');
289spy.should.have.been.first.called.with('foo');
290expect(spy).on.nth(5).be.called.with('foobar');
291spy.should.on.nth(5).be.called.with('foobar');
292```
293
294These assertions requires the spy to be called at least the
295number of times required, for example
296
297```js
298spy('foo');
299spy('bar');
300expect(spy).to.have.been.third.called.with('baz');
301spy.should.have.been.third.called.with('baz');
302```
303
304Won't pass because the spy has not been called a third time.
305
306#### .once
307
308Assert that a spy has been called exactly once.
309
310```js
311expect(spy).to.have.been.called.once;
312expect(spy).to.not.have.been.called.once;
313spy.should.have.been.called.once;
314spy.should.not.have.been.called.once;
315```
316
317#### .twice
318
319Assert that a spy has been called exactly twice.
320
321```js
322expect(spy).to.have.been.called.twice;
323expect(spy).to.not.have.been.called.twice;
324spy.should.have.been.called.twice;
325spy.should.not.have.been.called.twice;
326```
327
328#### .exactly(n)
329
330Assert that a spy has been called exactly `n` times.
331
332```js
333expect(spy).to.have.been.called.exactly(3);
334expect(spy).to.not.have.been.called.exactly(3);
335spy.should.have.been.called.exactly(3);
336spy.should.not.have.been.called.exactly(3);
337```
338
339#### .min(n) / .at.least(n)
340
341Assert that a spy has been called minimum of `n` times.
342
343```js
344expect(spy).to.have.been.called.min(3);
345expect(spy).to.not.have.been.called.at.least(3);
346spy.should.have.been.called.at.least(3);
347spy.should.not.have.been.called.min(3);
348```
349
350#### .max(n) / .at.most(n)
351
352Assert that a spy has been called maximum of `n` times.
353
354```js
355expect(spy).to.have.been.called.max(3);
356expect(spy).to.not.have.been.called.at.most(3);
357spy.should.have.been.called.at.most(3);
358spy.should.not.have.been.called.max(3);
359```
360#### .above(n) / .gt(n)
361
362Assert that a spy has been called more than `n` times.
363
364```js
365expect(spy).to.have.been.called.above(3);
366expect(spy).to.not.have.been.called.gt(3);
367spy.should.have.been.called.gt(3);
368spy.should.not.have.been.called.above(3);
369```
370
371#### .below(n) / .lt(n)
372
373Assert that a spy has been called fewer than `n` times.
374
375```js
376expect(spy).to.have.been.called.below(3);
377expect(spy).to.not.have.been.called.lt(3);
378spy.should.have.been.called.lt(3);
379spy.should.not.have.been.called.below(3);
380```
381
382## Tests
383
384Tests are written using [mocha](http://github.com/visionmedia/mocha) in the BDD interface.
385Node tests can be executed using `npm test`. Browser tests can be seen by opening `test/browser/index.html`.
386
387## Contributors
388
389 project : chai-spies
390 repo age : 3 years, 2 months
391 active : 26 days
392 commits : 77
393 files : 12
394 authors :
395 48 Jake Luer 62.3%
396 7 Glenn Jorde 9.1%
397 4 Keith Cirkel 5.2%
398 3 = 3.9%
399 3 Sergiy Stotskiy 3.9%
400 2 JamesMaroney 2.6%
401 2 PG Herveou 2.6%
402 2 Ryckes 2.6%
403 1 Veselin Todorov 1.3%
404 1 Steffen 1.3%
405 1 Daniel Walker 1.3%
406 1 Domenic Denicola 1.3%
407 1 Andre Jaenisch 1.3%
408 1 PG 1.3%
409
410## License
411
412(The MIT License)
413
414Copyright (c) 2012 Jake Luer <jake@alogicalparadox.com>
415
416Permission is hereby granted, free of charge, to any person obtaining a copy
417of this software and associated documentation files (the "Software"), to deal
418in the Software without restriction, including without limitation the rights
419to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
420copies of the Software, and to permit persons to whom the Software is
421furnished to do so, subject to the following conditions:
422
423The above copyright notice and this permission notice shall be included in
424all copies or substantial portions of the Software.
425
426THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
427IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
428FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
429AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
430LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
431OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
432THE SOFTWARE.