├── .circleci
└── config.yml
├── .gitignore
├── .npmrc
├── .nvmrc
├── .prettierrc
├── BACKLOG.md
├── LICENSE
├── README.md
├── index.js
├── package-lock.json
├── package.json
├── src
├── index.js
├── operations.js
├── react-component
│ ├── Button.js
│ ├── __mocks__
│ │ └── httpService.js
│ └── httpService.js
└── utils.js
└── tests
├── __snapshots__
└── snapshots.test.js.snap
├── poke.into.prototype.test.js
├── poke.into.react.components.test.js
├── react-components-async.test.js
├── setupTests.js
├── snapshots.test.js
├── spies.basics.test.js
├── spies.checking-arguments.test.js
├── spies.custom-behavior.test.js
├── spies.spy-on-object-method.test.js
├── spies.times.test.js
└── timers.test.js
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 | orbs:
3 | node: circleci/node@5.0.2
4 |
5 | jobs:
6 | build_and_test:
7 | executor: node/default
8 | steps:
9 | - checkout
10 | - node/install-packages:
11 | pkg-manager: npm
12 | - run:
13 | command: npm test
14 | name: Run tests
15 |
16 | workflows:
17 | test_my_app:
18 | jobs:
19 | - build_and_test
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .idea/
3 |
4 | npm-debug.log
5 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmjs.org
2 |
3 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | lts/*
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "semi": true,
4 | "singleQuote": true
5 | }
6 |
--------------------------------------------------------------------------------
/BACKLOG.md:
--------------------------------------------------------------------------------
1 | # Backlog
2 |
3 | ## [Sinon 4.1.2](http://sinonjs.org/releases/v4.1.2/)
4 |
5 |
6 | ### Sinon Spies
7 | 1. Spy on function example?
8 | 2. Calls: firstCall / secondCall / thirdCall / lastCall
9 | 3. Called
10 | 1. calledBefore / calledAfter / calledImmediatelyBefore / calledImmediatelyAfter
11 | 2. calledOn / alwaysCalledOn / calledWith / alwaysCalledWith / calledWithExactly / alwaysCalledWithExactly
12 | 3. calledWithMatch / alwaysCalledWithMatch
13 | 4. calledWithNew / neverCalledWith / neverCalledWithMatch
14 | 4. threw / alwaysThrew
15 | 5. returned / alwaysReturned
16 | 6. getCall(num) / getCalls
17 | 7. thisValues / exceptions / returnValues
18 | 8. printf
19 |
20 | ### Sinon Stubs
21 | 1. createStubInstance
22 | 2. onFirstCall / onSecondCall / onThirdCall
23 | 3. reset / resetHistory / resetBehavior
24 | 4. returnsArg / returnsThis
25 | 5. resolves / throws / rejects
26 | 6. callsArg / callsArgOn / callsArgWith / callsArgOnWith
27 | 7. callThrough
28 | 8. usingPromise(promiseLibrary)
29 | 9. yields / yieldsOn / yieldsTo / yieldsToOn
30 | 10. callArg / callArgWith
31 | 11. callsArgAsync / callsArgOnAsync / callsArgWithAsync / callsArgOnWithAsync
32 | 12. yieldsAsync / yieldsOnAsync / yieldsToAsync / yieldsToOnAsync
33 | 13. addBehavior
34 | 14. get / set / value
35 |
36 | ### Misc
37 | 1. **Mocks** (and mock expectations) are fake methods (like spies) with pre-programmed behavior (like stubs)
38 | as well as pre-programmed expectations.
39 | 2. **Fake timers**.
40 | 3. **Fake XHR and server**.
41 |
42 |
43 | ## [Jest](http://facebook.github.io/jest/docs/en/api.html)
44 |
45 | ### Mock Functions
46 | 1. getMockName
47 | 2. mock.instances
48 | 3. mockClear / mockName / mockReturnThis
49 | 4. Timer mocks
50 |
51 | ### Misc
52 | 1. Globals, Expect and Matchers examples.
53 | 2. The Jest Object
54 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2017 Mauro Carrero
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Sinon # Jest (a cheatsheet).
2 |
3 | [](https://github.com/facebook/jest)
4 | [](https://github.com/prettier/prettier)
5 | [](https://dl.circleci.com/status-badge/redirect/circleci/KGvHWvXnzGS4FPUQXWKdAZ/SfzZ9zFtmW67xuFET6yjFZ/tree/master)
6 |
7 | Some examples on how to achieve the same goal with either of both libraries: [sinon](http://sinonjs.org/) and [jest](http://facebook.github.io/jest/).
8 | Also some of those goals achievable only by one of these tools.
9 |
10 | What's inside? just this **README** file and many **unit tests** using jest as runner.
11 |
12 | ###### Clone the repo:
13 |
14 | ```shell
15 | git clone https://github.com/maurocarrero/sinon-jest-cheatsheet.git
16 | ```
17 |
18 | ###### Install:
19 |
20 | ```shell
21 | npm install
22 | ```
23 |
24 | ###### Run tests:
25 |
26 | ```shell
27 | npm test
28 | ```
29 |
30 | or use watch
31 |
32 | ```shell
33 | npm run test:watch
34 | ```
35 |
36 | ## Table of Contents
37 |
38 | 1. [Create Spies](#create-spies)
39 | 2. [Are they called?](#are-they-called)
40 | 3. [How many times?](#how-many-times)
41 | 4. [Checking arguments](#checking-arguments)
42 | 5. [Spy on objects methods](#spy-on-objects-method)
43 | 6. [Reset and Restore original method](#restore-original-method)
44 | 7. [Return value](#return-value)
45 | 8. [Custom implementation](#custom-implementation)
46 | 9. [Poking into React component methods](#react-component-methods)
47 | 10. [Timers](#timers)
48 |
49 | ##### [Jest specific](#jest-specific)
50 |
51 | 1. [Snapshot testing](#snapshot-testing)
52 | 2. [Automock](#automock)
53 |
54 |
55 |
56 | ## Spies
57 |
58 | While **sinon** uses three different terms for its snooping functions: `spy`, `stub` and `mock`,
59 | **jest** uses mostly the term `mock function` for what'd be a spy/stub and `manual mock` or `mock` ...well, for mocks.
60 |
61 | ### 1. Create spies:
62 |
63 | ###### sinon
64 |
65 | ```js
66 | const spy = sinon.spy();
67 | ```
68 |
69 | ###### jest
70 |
71 | ```js
72 | const spy = jest.fn();
73 | ```
74 |
75 |
76 |
77 | ### 2. Know if they are called:
78 |
79 | ###### sinon
80 |
81 | ```js
82 | spy.called; // boolean
83 | spy.notCalled; // boolean
84 | ```
85 |
86 | ###### jest
87 |
88 | ```js
89 | spy.mock.calls.length; // number;
90 | ```
91 |
92 | ```js
93 | expect(spy).toHaveBeenCalled();
94 | ```
95 |
96 |
97 |
98 | ### 3. How many times are called:
99 |
100 | ###### sinon
101 |
102 | ```js
103 | spy.calledOnce; // boolean
104 | spy.calledTwice; // boolean
105 | spy.calledThrice; // boolean
106 | spy.callCount; // number
107 | ```
108 |
109 | ###### jest
110 |
111 | ```js
112 | spy.mock.calls.length; // number;
113 | ```
114 |
115 | ```js
116 | expect(spy).toHaveBeenCalledTimes(n);
117 | ```
118 |
119 |
120 |
121 | ### 4. Checking arguments:
122 |
123 | ###### sinon
124 |
125 | ```js
126 | // args[call][argIdx]
127 | spy.args[0][0];
128 | ```
129 |
130 | ```jsjs
131 | // spy.calledWith(...args)
132 | spy.calledWith(1, 'Hey')
133 | ```
134 |
135 | ###### jest
136 |
137 | ```js
138 | // mock.calls[call][argIdx]
139 | spy.mock.calls[0][0];
140 | ```
141 |
142 | ```js
143 | expect(spy).toHaveBeenCalledWith(1, 'Hey');
144 | expect(spy).toHaveBeenLastCalledWith(1, 'Hey');
145 | ```
146 |
147 | ```js
148 | .toHaveBeenCalledWith(expect.anything());
149 | .toHaveBeenCalledWith(expect.any(constructor));
150 | .toHaveBeenCalledWith(expect.arrayContaining([ values ]));
151 | .toHaveBeenCalledWith(expect.objectContaining({ props }));
152 | .toHaveBeenCalledWith(expect.stringContaining(string));
153 | .toHaveBeenCalledWith(expect.stringMatching(regexp));
154 | ```
155 |
156 |
157 |
158 | ### 5. Spy on objects' methods
159 |
160 | ###### sinon
161 |
162 | ```js
163 | sinon.spy(someObject, 'aMethod');
164 | ```
165 |
166 | ###### jest
167 |
168 | ```js
169 | jest.spyOn(someObject, 'aMethod');
170 | ```
171 |
172 |
173 |
174 | ### 6. Reset and Restore original method
175 |
176 | ###### sinon
177 |
178 | reset both, history and behavior:
179 |
180 | ```js
181 | stub.resetHistory();
182 | ```
183 |
184 | reset call history:
185 |
186 | ```js
187 | stub.resetHistory();
188 | ```
189 |
190 | reset behaviour:
191 |
192 | ```js
193 | stub.resetBehavior();
194 | ```
195 |
196 | restore (remove mock):
197 |
198 | ```js
199 | someObject.aMethod.restore();
200 | ```
201 |
202 | ###### jest
203 |
204 | ```js
205 | someObject.aMethod.mockRestore();
206 | ```
207 |
208 |
209 |
210 | ### 7. Spy on method and return value:
211 |
212 | ###### sinon
213 |
214 | ```js
215 | stub = sinon.stub(operations, 'add');
216 | stub.returns(89);
217 | ```
218 |
219 | ```js
220 | stub.withArgs(42).returns(89);
221 | stub.withArgs(4, 9, 32).returns('OK');
222 | ```
223 |
224 | On different calls:
225 |
226 | ```js
227 | stub.onCall(1).returns(7);
228 | expect(fn()).not.toEqual(7);
229 | expect(fn()).toEqual(7);
230 | ```
231 |
232 | ###### jest
233 |
234 | ```js
235 | jest.spyOn(operations, 'add').mockReturnValue(89);
236 | ```
237 |
238 | On different calls:
239 |
240 | ```js
241 | spy.mockReturnValueOnce(undefined);
242 | spy.mockReturnValueOnce(7);
243 |
244 | expect(fn()).not.toEqual(7);
245 | expect(fn()).toEqual(7);
246 | ```
247 |
248 |
249 |
250 | ### 8. Custom implementation:
251 |
252 | ###### sinon
253 |
254 | ```js
255 | sinonStub.callsFake(function() {
256 | return 'Peteco';
257 | });
258 | expect(operations.add(1, 2)).toEqual('Peteco');
259 | ```
260 |
261 | Different implementation on different call:
262 |
263 | ###### jest
264 |
265 | ```js
266 | jest.spyOn(operations, 'add').mockImplementation(function(a, b, c) {
267 | if (a === 42) {
268 | return 89;
269 | }
270 | if (a === 4 && b === 9 && c === 32) {
271 | return 'OK';
272 | }
273 | });
274 | ```
275 |
276 |
277 |
278 | ### 9. Poking into React components methods:
279 |
280 | Suppose `foo` is called when mounting Button.
281 |
282 | ###### sinon
283 |
284 | ```js
285 | sinon.spy(Button.prototype, 'foo');
286 |
287 | wrapper = shallow();
288 |
289 | expect(Button.prototype.foo.called).toEqual(true);
290 | ```
291 |
292 | ###### jest
293 |
294 | ```js
295 | jest.spyOn(Button.prototype, 'foo');
296 |
297 | wrapper = shallow();
298 |
299 | expect(Button.prototype.foo).toHaveBeenCalled();
300 | ```
301 |
302 | ###### can be used together
303 |
304 | ```js
305 | const jestSpy = jest.spyOn(Button.prototype, 'doSomething');
306 | const sinonSpy = sinon.spy(Button.prototype, 'doSomething');
307 | ```
308 |
309 | ```js
310 | wrapper = shallow(React.createElement(Button));
311 | ```
312 |
313 | ```js
314 | expect(jestSpy).toHaveBeenCalled();
315 | expect(sinonSpy.called).toEqual(true);
316 | ```
317 |
318 |
319 |
320 | ### 10. Timers:
321 |
322 | ###### sinon
323 |
324 | Fake the date:
325 |
326 | ```js
327 | const clock = sinon.useFakeTimers({
328 | now: new Date(TIMESTAMP)
329 | });
330 | ```
331 |
332 | Fake the ticks:
333 |
334 | ```js
335 | const clock = sinon.useFakeTimers({
336 | toFake: ['nextTick']
337 | });
338 | ```
339 |
340 | Restore it:
341 |
342 | ```js
343 | clock.restore();
344 | ```
345 |
346 | ###### jest
347 |
348 | Enable fake timers:
349 |
350 | ```js
351 | jest.useFakeTimers();
352 | ```
353 |
354 | ```js
355 | setTimeout(() => {
356 | setTimeout(() => {
357 | console.log('Don Inodoro!');
358 | }, 200);
359 | console.log('Negociemos');
360 | }, 100);
361 | ```
362 |
363 | Fast-forward until all timers have been executed:
364 |
365 | ```js
366 | jest.runAllTimers(); // Negociemos Don Inodoro!
367 | ```
368 |
369 | Run pending timers, avoid nested timers:
370 |
371 | ```js
372 | jest.runOnlyPendingTimers(); // Negociemos
373 | jest.runOnlyPendingTimers(); // Don Inodoro!
374 | ```
375 |
376 | Fast-forward until the value (in millis) and run all timers in the path:
377 |
378 | ```js
379 | jest.runTimersToTime(100); // Negociemos
380 | jest.runTimersToTime(200); // Don Inodoro!
381 | ```
382 |
383 | > jest 22.0.0: .advanceTimersByTime
384 |
385 | Clear all timers:
386 |
387 | ```js
388 | jest.clearAllTimers();
389 | ```
390 |
391 | ##### Date: Use Lolex
392 |
393 | `Jest` does not provide a way of faking the Date, we use here [lolex](https://github.com/sinonjs/lolex),
394 | a library extracted from `sinon`, with a implementation of the **timer APIs**: _setTimeout_, _clearTimeout_,
395 | _setImmediate_, _clearImmediate_, _setInterval_, _clearInterval_, _requetsAnimationFrame_ and _clearAnimationFrame_,
396 | a **clock instance** that controls the flow of time, and a **Date** implementation.
397 |
398 | ```js
399 | clock = lolex.install({
400 | now: TIMESTAMP
401 | });
402 | ```
403 |
404 | ##### Fake the ticks:
405 |
406 | ```js
407 | clock = lolex.install({
408 | toFake: ['nextTick']
409 | });
410 |
411 | let called = false;
412 |
413 | process.nextTick(function() {
414 | called = true;
415 | });
416 | ```
417 |
418 | Forces nextTick calls to flush synchronously:
419 |
420 | ```js
421 | clock.runAll();
422 |
423 | expect(called).toBeTruthy();
424 | ```
425 |
426 | Trigger a tick:
427 |
428 | ```js
429 | clock.tick();
430 | ```
431 |
432 | Restore it:
433 |
434 | ```
435 | clock.uninstall();
436 | ```
437 |
438 |
439 |
440 | ## Jest specific
441 |
442 |
443 |
444 | ### 1. Snapshot testing:
445 |
446 | > Clean obsolete snapshots: `npm t -- -u`
447 | >
448 | > Update snapshots: `npm t -- --updateSnapshot`
449 |
450 | ###### snapshot of a function output
451 |
452 | ```js
453 | expect(fn()).toMatchSnapshot();
454 | ```
455 |
456 | ###### snapshot of a React Component (using react-test-renderer)
457 |
458 | ```js
459 | expect(ReactTestRenderer.create(React.createElement(Button))).toMatchSnapshot();
460 | ```
461 |
462 | ```js
463 | const tree = renderer.create(Facebook).toJSON();
464 | ```
465 |
466 |
467 |
468 | ### 2. Automock
469 |
470 | Jest disabled the [automock](https://facebook.github.io/jest/blog/2016/09/01/jest-15.html#disabled-automocking) feature by default.
471 | Enabling it again from the setup file `./tests/setupTests`:
472 |
473 | ```js
474 | jest.enableAutomock();
475 | ```
476 |
477 | Now all dependencies are mocked, we must whitelist some of them, from `package.json`:
478 |
479 | ```json5
480 | "jest": {
481 | "unmockedModulePathPatterns": [
482 | "/src/react-component/Button.js",
483 | "/node_modules/axios",
484 | "/node_modules/enzyme",
485 | "/node_modules/enzyme-adapter-react-16",
486 | "/node_modules/react",
487 | "/node_modules/react-dom",
488 | "/node_modules/react-test-renderer",
489 | "/node_modules/sinon"
490 | ]
491 | ...
492 | ```
493 |
494 | or otherwise unmock them from the test:
495 |
496 | ```js
497 | jest.unmock('./path/to/dep');
498 | const Comp = require('../Comp'); // depends on dep, now will use the original
499 | ```
500 |
501 | ##### Using the mock with spies
502 |
503 | ```js
504 | // MOCK: path/to/original/__mocks__/myService
505 | module.exports = {
506 | get: jest.fn()
507 | };
508 | ```
509 |
510 | then from the test:
511 |
512 | ```js
513 | const mockService = require('path/to/original/myService');
514 | ```
515 |
516 | ```js
517 | // Trigger the use of the service from tested component
518 | wrapper.simulate('click');
519 | expect(mockService.get).toHaveBeenCalled();
520 | ```
521 |
522 | ## Pending work
523 |
524 | Refer to [backlog](./BACKLOG.md).
525 |
526 | ## Contributing
527 |
528 | Please, clone this repo and send your PR.
529 | Make sure to add your examples as unit tests and the explanation of
530 | the case into the README file.
531 | If you will add something specific of a library, make sure that
532 | is not somehow achievable with the other ;)
533 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | console.log('Please run `npm t`');
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sinon-jest-cheatsheet",
3 | "version": "0.0.0",
4 | "description": "Some examples on how to achieve the same goal with either of both libraries: sinon and jest. Also some of those goals achievable only by one of these tools.",
5 | "main": "index.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/maurocarrero/sinon-jest-cheatsheet"
9 | },
10 | "scripts": {
11 | "prettier": "prettier --config .prettierrc --write ./{src,tests}/**/*.js",
12 | "start": "npm test",
13 | "test": "jest --env=jsdom",
14 | "test:watch": "jest --env=jsdom --watch"
15 | },
16 | "keywords": [
17 | "jest",
18 | "sinon",
19 | "cheatsheet"
20 | ],
21 | "author": "Mauro Carrero",
22 | "license": "MIT",
23 | "dependencies": {
24 | "axios": "^1.7.2",
25 | "create-react-class": "^15.6.2",
26 | "enzyme": "^3.2.0",
27 | "enzyme-adapter-react-16": "^1.1.0",
28 | "jest": "^29.7.0",
29 | "jest-environment-jsdom": "^29.7.0",
30 | "lolex": "^2.3.1",
31 | "prettier": "^1.8.2",
32 | "react": "^16.2.0",
33 | "react-dom": "^16.2.0",
34 | "react-test-renderer": "^16.2.0",
35 | "sinon": "^4.1.2"
36 | },
37 | "jest": {
38 | "setupFilesAfterEnv": [
39 | "/tests/setupTests.js"
40 | ],
41 | "unmockedModulePathPatterns": [
42 | "/src/react-component/Button.js",
43 | "/node_modules/axios",
44 | "/node_modules/enzyme",
45 | "/node_modules/enzyme-adapter-react-16",
46 | "/node_modules/lolex",
47 | "/node_modules/react",
48 | "/node_modules/react-dom",
49 | "/node_modules/react-test-renderer",
50 | "/node_modules/sinon"
51 | ],
52 | "verbose": true
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | const operations = require('./operations');
2 |
3 | module.exports = operations;
4 |
5 |
--------------------------------------------------------------------------------
/src/operations.js:
--------------------------------------------------------------------------------
1 | const { PI } = require('./utils')
2 |
3 | function add(a, b) {
4 | return a + b;
5 | }
6 |
7 | function subtract(a, b) {
8 | return a - b;
9 | }
10 |
11 | function multiply(a, b) {
12 | return a * b;
13 | }
14 |
15 | function divide(a, b) {
16 | return a / b;
17 | }
18 |
19 | function circumference(r) {
20 | return Math.pow(r, 2) * PI;
21 | }
22 |
23 | module.exports = {
24 | add,
25 | circumference,
26 | subtract,
27 | multiply,
28 | divide
29 | };
30 |
--------------------------------------------------------------------------------
/src/react-component/Button.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { get, GITHUB_URL } = require('./httpService');
3 |
4 | module.exports = class Button extends React.Component {
5 | constructor() {
6 | super();
7 | this.state = {
8 | task: 'Nothing yet'
9 | };
10 | this.doSomething = this.doSomething.bind(this);
11 | this.clickHandler = this.clickHandler.bind(this);
12 | }
13 |
14 | clickHandler() {
15 | get(GITHUB_URL).then(this.doSomething);
16 | }
17 |
18 | doSomething(task) {
19 | this.setState({
20 | task
21 | });
22 | return task;
23 | }
24 |
25 | componentDidMount() {
26 | this.doSomething('initial doSomething');
27 | return 'componentDidMount';
28 | }
29 |
30 | render() {
31 | return React.createElement(
32 | 'button',
33 | {
34 | onClick: this.clickHandler
35 | },
36 | 'Click me'
37 | );
38 | }
39 | };
40 |
41 | // TODO: Using create-react-class I was unable to spy on methods. Dig into this.
42 |
43 | // const createReactClass = require('create-react-class');
44 |
45 | // module.exports = createReactClass({
46 | // clickHandler() {
47 | // console.log('clicked')
48 | // return 'clicked';
49 | // },
50 | // doSomething(task) {
51 | // return task;
52 | // },
53 | // componentDidMount() {
54 | // this.doSomething('something');
55 | // return 'componentDidMount';
56 | // },
57 | // render() {
58 | // return React.createElement(
59 | // 'button',
60 | // {
61 | // onClick: this.clickHandler
62 | // },
63 | // 'Click me'
64 | // );
65 | // }
66 | // });
67 | //
68 |
--------------------------------------------------------------------------------
/src/react-component/__mocks__/httpService.js:
--------------------------------------------------------------------------------
1 | const sinon = require('sinon');
2 | const httpService = jest.requireActual('../httpService');
3 |
4 | const get = (url) => {
5 | return Promise.resolve(`url was requested: ${url}`);
6 | }
7 |
8 | module.exports = {
9 | get: sinon.stub().callsFake(get),
10 | GITHUB_URL: httpService.GITHUB_URL
11 | };
12 |
--------------------------------------------------------------------------------
/src/react-component/httpService.js:
--------------------------------------------------------------------------------
1 | const GITHUB_URL = 'https://api.github.com/';
2 | const axios = require('axios');
3 |
4 | const get = url => {
5 | return axios
6 | .get(url)
7 | .then(function(response) {
8 | return response;
9 | })
10 | .catch(function(error) {
11 | return error;
12 | });
13 | };
14 |
15 | module.exports = {
16 | get,
17 | GITHUB_URL
18 | };
19 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | PI: Math.PI
3 | };
4 |
--------------------------------------------------------------------------------
/tests/__snapshots__/snapshots.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`should match a React Component 1`] = `
4 |
9 | `;
10 |
11 | exports[`should match a function 1`] = `undefined`;
12 |
--------------------------------------------------------------------------------
/tests/poke.into.prototype.test.js:
--------------------------------------------------------------------------------
1 | const sinon = require('sinon');
2 |
3 | function Peteco() {}
4 |
5 | Peteco.prototype.hola = function() {
6 | return 'hola';
7 | };
8 | Peteco.prototype.chau = function() {
9 | return 'chau';
10 | };
11 |
12 | it("sinon.spy(Peteco.prototype, 'hola')", function() {
13 | const holaSpy = sinon.spy(Peteco.prototype, 'hola');
14 | const chauSpy = sinon.spy(Peteco.prototype, 'chau');
15 |
16 | new Peteco().hola();
17 | new Peteco().chau();
18 |
19 | expect(holaSpy.called).toEqual(true);
20 | expect(chauSpy.called).toEqual(true);
21 | });
22 |
23 | it("jest.spyOn(Peteco.prototype, 'hola')", function() {
24 | const holaSpy = jest.spyOn(Peteco.prototype, 'hola');
25 | const chauSpy = jest.spyOn(Peteco.prototype, 'chau');
26 |
27 | new Peteco().hola();
28 | new Peteco().chau();
29 |
30 | expect(holaSpy).toHaveBeenCalled();
31 | expect(chauSpy).toHaveBeenCalled();
32 | });
33 |
--------------------------------------------------------------------------------
/tests/poke.into.react.components.test.js:
--------------------------------------------------------------------------------
1 | const sinon = require('sinon');
2 |
3 | const React = require('react');
4 | const { shallow } = require('enzyme');
5 |
6 | const Button = require('../src/react-component/Button');
7 |
8 | let wrapper;
9 | let instance;
10 |
11 | describe('sinon', function() {
12 | let sinonCDMSpy;
13 | let sinonRenderSpy;
14 | let sinonDoSomethingSpy;
15 | let sinonClickHandlerSpy;
16 |
17 | beforeEach(function() {
18 | sinonCDMSpy = sinon.spy(Button.prototype, 'componentDidMount');
19 | sinonRenderSpy = sinon.spy(Button.prototype, 'render');
20 | sinonDoSomethingSpy = sinon.spy(Button.prototype, 'doSomething');
21 | sinonClickHandlerSpy = sinon.spy(Button.prototype, 'clickHandler');
22 |
23 | wrapper = shallow(React.createElement(Button));
24 | });
25 |
26 | afterEach(function() {
27 | sinonCDMSpy.restore();
28 | sinonRenderSpy.restore();
29 | sinonDoSomethingSpy.restore();
30 | sinonClickHandlerSpy.restore();
31 | });
32 |
33 | it('spy on componentDidMount', function() {
34 | expect(sinonCDMSpy.called).toEqual(true);
35 | });
36 |
37 | it('spy on render', function() {
38 | expect(sinonRenderSpy.called).toEqual(true);
39 | });
40 |
41 | it('spy on doSomething', function() {
42 | expect(sinonDoSomethingSpy.called).toEqual(true);
43 | });
44 |
45 | it('spy on clickHandler', function() {
46 | expect(sinonClickHandlerSpy.called).toEqual(false);
47 | wrapper.simulate('click');
48 | expect(sinonClickHandlerSpy.called).toEqual(true);
49 | });
50 | });
51 |
52 | describe('jest', function() {
53 | let jestCDMSpy;
54 | let jestRenderSpy;
55 | let jestDoSomethingSpy;
56 | let jestClickHandlerSpy;
57 |
58 | beforeEach(function() {
59 | jestCDMSpy = jest.spyOn(Button.prototype, 'componentDidMount');
60 | jestRenderSpy = jest.spyOn(Button.prototype, 'render');
61 | jestDoSomethingSpy = jest.spyOn(Button.prototype, 'doSomething');
62 | jestClickHandlerSpy = jest.spyOn(Button.prototype, 'clickHandler');
63 |
64 | wrapper = shallow(React.createElement(Button));
65 | });
66 |
67 | afterEach(function() {
68 | jestCDMSpy.mockRestore();
69 | jestRenderSpy.mockRestore();
70 | jestDoSomethingSpy.mockRestore();
71 | jestClickHandlerSpy.mockRestore();
72 | });
73 |
74 | it('spy on componentDidMount', function() {
75 | expect(jestCDMSpy).toHaveBeenCalled();
76 | });
77 |
78 | it('spy on doSomething', function() {
79 | expect(jestDoSomethingSpy).toHaveBeenCalled();
80 | });
81 |
82 | it('spy on clickHandler', function() {
83 | wrapper.simulate('click');
84 |
85 | expect(jestClickHandlerSpy).toHaveBeenCalled();
86 | });
87 | });
88 |
89 | describe('sinon && jest', function() {
90 | it('spying both at a time', function() {
91 | const jestSpy = jest.spyOn(Button.prototype, 'doSomething');
92 | const sinonSpy = sinon.spy(Button.prototype, 'doSomething');
93 |
94 | expect(jestSpy).not.toHaveBeenCalled();
95 | expect(sinonSpy.called).toEqual(false);
96 |
97 | wrapper = shallow(React.createElement(Button));
98 |
99 | expect(jestSpy).toHaveBeenCalled();
100 | expect(sinonSpy.called).toEqual(true);
101 | });
102 | });
103 |
--------------------------------------------------------------------------------
/tests/react-components-async.test.js:
--------------------------------------------------------------------------------
1 | const sinon = require('sinon');
2 |
3 | const React = require('react');
4 | const { shallow } = require('enzyme');
5 |
6 | const Button = require('../src/react-component/Button');
7 |
8 | let httpServiceMock = require('../src/react-component/httpService');
9 |
10 | const EXPECTED = 'url was requested: https://api.github.com/';
11 | const INITIAL = 'initial doSomething';
12 |
13 | let wrapper;
14 |
15 | describe('sinon', function() {
16 | it('should call the mocked service', function(done) {
17 | const stub = sinon.stub(Button.prototype, 'doSomething').callThrough();
18 |
19 | wrapper = shallow(React.createElement(Button));
20 |
21 | expect(wrapper.state('task')).toEqual(INITIAL);
22 |
23 | wrapper.simulate('click');
24 | wrapper.simulate('click');
25 |
26 | process.nextTick(() => {
27 | try {
28 | // Button.prototype.doSomething spy
29 | expect(stub.callCount).toEqual(3);
30 | expect(stub.args[0][0]).toEqual(INITIAL);
31 | expect(stub.args[1][0]).toEqual(EXPECTED);
32 | expect(stub.args[2][0]).toEqual(EXPECTED);
33 |
34 | // The state of the component has been updated
35 | expect(wrapper.state('task')).toEqual(EXPECTED);
36 | done();
37 | } catch (e) {
38 | return done(e);
39 | }
40 | });
41 |
42 | expect(httpServiceMock.get.callCount).toEqual(2);
43 |
44 | stub.restore();
45 | });
46 | });
47 |
48 | describe('jest', function() {
49 | it('should call the mocked service', function(done) {
50 | const jestSpy = jest.spyOn(Button.prototype, 'doSomething');
51 |
52 | // httpServiceMock is still a sinon stub since it is implemented in
53 | // the manual mock.
54 | // We use .resetHistory instead of .reset, otherwise behavior is also reset.
55 | httpServiceMock.get.resetHistory();
56 |
57 | wrapper = shallow(React.createElement(Button));
58 |
59 | console.log('POST', jestSpy.mock.calls[0][0]);
60 |
61 | expect(wrapper.state('task')).toEqual(INITIAL);
62 |
63 | wrapper.simulate('click');
64 | wrapper.simulate('click');
65 |
66 | process.nextTick(() => {
67 | try {
68 | // Button.prototype.doSomething spy
69 | expect(jestSpy.mock.calls.length).toEqual(3);
70 | expect(jestSpy.mock.calls[0][0]).toEqual(INITIAL);
71 |
72 | // The state of the component has been updated
73 | expect(wrapper.state('task')).toEqual(EXPECTED);
74 | jestSpy.mockRestore();
75 | done();
76 | } catch (e) {
77 | jestSpy.mockRestore();
78 | return done(e);
79 | }
80 | });
81 |
82 | expect(httpServiceMock.get.callCount).toEqual(2);
83 | });
84 | });
85 |
--------------------------------------------------------------------------------
/tests/setupTests.js:
--------------------------------------------------------------------------------
1 | global.requestAnimationFrame = function(callback) {
2 | setTimeout(callback, 0);
3 | };
4 |
5 | const Enzyme = require('enzyme');
6 | const Adapter = require('enzyme-adapter-react-16');
7 |
8 | Enzyme.configure({ adapter: new Adapter() });
9 |
10 | // Enabling automock since now is disabled by default:
11 | // https://facebook.github.io/jest/blog/2016/09/01/jest-15.html#disabled-automocking
12 | jest.enableAutomock();
13 |
--------------------------------------------------------------------------------
/tests/snapshots.test.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const ReactTestRenderer = require('react-test-renderer');
3 |
4 | const operations = require('../src/index');
5 | const Button = require('../src/react-component/Button');
6 |
7 | it('should match a function', function() {
8 | expect(operations.add(45, 234)).toMatchSnapshot();
9 | });
10 |
11 | it('should match a React Component', function() {
12 | expect(ReactTestRenderer.create(React.createElement(Button))).toMatchSnapshot();
13 | });
14 |
--------------------------------------------------------------------------------
/tests/spies.basics.test.js:
--------------------------------------------------------------------------------
1 | const sinon = require('sinon');
2 |
3 | let sinonSpy;
4 | let jestSpy;
5 |
6 | beforeAll(function() {
7 | sinonSpy = sinon.spy();
8 | jestSpy = jest.fn();
9 | });
10 |
11 | beforeEach(function() {
12 | sinonSpy.resetHistory();
13 | jestSpy.mockReset();
14 | });
15 |
16 | afterAll(function() {
17 | sinonSpy = null;
18 | jestSpy = null;
19 | });
20 |
21 | describe('called | not called', function() {
22 | describe('sinon: sinon.spy', function() {
23 | it('spy.called', function() {
24 | expect(sinonSpy.called).toEqual(false);
25 |
26 | sinonSpy();
27 |
28 | expect(sinonSpy.called).toEqual(true);
29 | });
30 |
31 | it('spy.notCalled', function() {
32 | expect(sinonSpy.notCalled).toEqual(true);
33 |
34 | sinonSpy();
35 |
36 | expect(sinonSpy.notCalled).toEqual(false);
37 | });
38 | });
39 |
40 | describe('jest: jest.fn', function() {
41 | it('.mock.calls.length', function() {
42 | jestSpy();
43 |
44 | expect(jestSpy.mock.calls.length).toEqual(1);
45 | });
46 |
47 | it('expect(spy).toHaveBeenCalled', function() {
48 | jestSpy();
49 |
50 | expect(jestSpy).toHaveBeenCalled();
51 | });
52 |
53 | it('expect(spy).toBeCalled', function() {
54 | jestSpy();
55 |
56 | expect(jestSpy).toBeCalled();
57 | });
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/tests/spies.checking-arguments.test.js:
--------------------------------------------------------------------------------
1 | const sinon = require('sinon');
2 |
3 | let sinonSpy;
4 | let jestSpy;
5 |
6 | beforeAll(function() {
7 | sinonSpy = sinon.spy();
8 | jestSpy = jest.fn();
9 | });
10 |
11 | beforeEach(function() {
12 | sinonSpy.resetHistory();
13 | jestSpy.mockReset();
14 | });
15 |
16 | afterAll(function() {
17 | sinonSpy = null;
18 | jestSpy = null;
19 | });
20 |
21 | describe('checking arguments', function() {
22 | /**
23 | * sinon
24 | */
25 | describe('sinon', function() {
26 | it('spy.args', function() {
27 | sinonSpy(1, 2);
28 |
29 | expect(sinonSpy.args[0][0]).toEqual(1);
30 | expect(sinonSpy.args[0][1]).toEqual(2);
31 | });
32 |
33 | it('spy.calledWith', function() {
34 | sinonSpy(1, 2);
35 |
36 | expect(sinonSpy.calledWith(1, 2)).toEqual(true);
37 | });
38 | });
39 |
40 | describe('jest', function() {
41 | it('spy.mock.calls', function() {
42 | jestSpy(1, 2);
43 |
44 | expect(jestSpy.mock.calls[0][0]).toEqual(1);
45 | expect(jestSpy.mock.calls[0][1]).toEqual(2);
46 | });
47 |
48 | it('.toHaveBeenCalledWith', function() {
49 | jestSpy(1, 2);
50 |
51 | expect(jestSpy).toHaveBeenCalledWith(1, 2);
52 | });
53 | });
54 |
55 | it('expect .toHaveBeenLastCalledWith', function() {
56 | jestSpy();
57 | jestSpy();
58 | jestSpy();
59 | jestSpy(7);
60 |
61 | expect(jestSpy).toHaveBeenLastCalledWith(7);
62 | });
63 |
64 | describe('expect .toHaveBeenCalledWith', function() {
65 | it('expect.anything()', function() {
66 | jestSpy(7);
67 |
68 | expect(jestSpy).toHaveBeenLastCalledWith(expect.anything());
69 | });
70 |
71 | it('expect.any(constructor)', function() {
72 | jestSpy(7);
73 |
74 | expect(jestSpy).toHaveBeenLastCalledWith(expect.any(Number));
75 | });
76 |
77 | it('expect.arrayContaining([ values ])', function() {
78 | jestSpy([7, 27, 33, 48]);
79 |
80 | expect(jestSpy).toHaveBeenLastCalledWith(expect.arrayContaining([33, 48]));
81 | });
82 |
83 | it('expect.objectContaining({ props })', function() {
84 | const mock = {
85 | id: 1,
86 | name: 'Peteco'
87 | };
88 | jestSpy(mock);
89 |
90 | expect(jestSpy).toHaveBeenCalledWith(expect.objectContaining({ id: mock.id }));
91 | expect(jestSpy).toHaveBeenLastCalledWith(expect.objectContaining({ name: mock.name }));
92 | });
93 |
94 | it('expect.stringContaining(string)', function() {
95 | jestSpy('This was all about foo bar.');
96 |
97 | expect(jestSpy).toHaveBeenCalledWith(expect.stringContaining('foo'));
98 | });
99 |
100 | it('expect.stringMatching(regexp)', function() {
101 | jestSpy('This was all about foo bar.');
102 |
103 | expect(jestSpy).toHaveBeenCalledWith(expect.stringMatching(/^This/));
104 | });
105 | });
106 | });
107 |
--------------------------------------------------------------------------------
/tests/spies.custom-behavior.test.js:
--------------------------------------------------------------------------------
1 | const sinon = require('sinon');
2 |
3 | // Unmocking operations dependency
4 | jest.unmock('../src/operations');
5 | const operations = require('../src/operations');
6 |
7 | let sinonStub;
8 | let jestSpy;
9 |
10 | beforeAll(function() {
11 | sinonStub = sinon.spy();
12 | jestSpy = jest.fn();
13 | });
14 |
15 | afterAll(function() {
16 | sinonStub = null;
17 | jestSpy = null;
18 | });
19 |
20 | describe("sinon's stub and jest's spyOn", function() {
21 | describe('sinon.stub', function() {
22 | beforeEach(() => {
23 | sinonStub = sinon.stub(operations, 'add');
24 | });
25 |
26 | afterEach(() => {
27 | sinonStub.restore();
28 | });
29 |
30 | it("sinon.stub(obj, 'method')", function() {
31 | operations.add(1, 2);
32 |
33 | expect(sinonStub.calledOnce).toEqual(true);
34 | });
35 |
36 | it('.returns', function() {
37 | sinonStub.returns(89);
38 |
39 | const result = operations.add(1, 2);
40 |
41 | expect(sinonStub.calledOnce).toEqual(true);
42 | expect(result).toEqual(89);
43 | });
44 |
45 | it('.withArgs.returns', function() {
46 | sinonStub.withArgs(42).returns(89);
47 | sinonStub.withArgs(4, 9, 32).returns('OK');
48 |
49 | const noReturn = operations.add(1, 2);
50 | const result = operations.add(42);
51 | const result2 = operations.add(4, 9, 32);
52 |
53 | expect(noReturn).toEqual(undefined);
54 | expect(result).toEqual(89);
55 | expect(result2).toEqual('OK');
56 | });
57 | });
58 |
59 | describe('jest', () => {
60 | beforeEach(() => {
61 | jestSpy = jest.spyOn(operations, 'add');
62 | });
63 |
64 | afterEach(() => {
65 | jestSpy.mockRestore();
66 | });
67 |
68 | it("jest.spyOn(obj, 'method')", function() {
69 | operations.add(3, 4);
70 |
71 | expect(jestSpy).toHaveBeenCalledTimes(1);
72 | });
73 |
74 | it('.mockReturnValue', function() {
75 | jestSpy.mockReturnValue(89);
76 |
77 | const result = operations.add(3, 4);
78 |
79 | expect(jestSpy).toHaveBeenCalled();
80 | expect(result).toEqual(89);
81 | });
82 |
83 | it('.mockReturnValueOnce', function() {
84 | jestSpy.mockReturnValueOnce(89);
85 |
86 | let result = operations.add(3, 4);
87 |
88 | expect(jestSpy).toHaveBeenCalled();
89 | expect(result).toEqual(89);
90 |
91 | result = operations.add(3, 4);
92 |
93 | expect(result).toEqual(7);
94 | });
95 | });
96 |
97 | describe('mocking implementation', function() {
98 | describe('sinon', function() {
99 | beforeEach(() => {
100 | sinonStub = sinon.stub(operations, 'add');
101 | });
102 |
103 | afterEach(() => {
104 | sinonStub.restore();
105 | });
106 |
107 | it('.callsFake', function() {
108 | sinonStub.callsFake(function() {
109 | return 'Peteco';
110 | });
111 | expect(operations.add(1, 2)).toEqual('Peteco');
112 | });
113 | });
114 |
115 | describe('jest', () => {
116 | beforeEach(() => {
117 | jestSpy = jest.spyOn(operations, 'add');
118 | });
119 |
120 | afterEach(() => {
121 | jestSpy.mockRestore();
122 | });
123 |
124 | it('.mockImplementation(function () {})', function() {
125 | jestSpy.mockImplementation(function() {
126 | return 89;
127 | });
128 |
129 | const result = operations.add(3, 4);
130 |
131 | expect(jestSpy).toHaveBeenCalled();
132 | expect(result).toEqual(89);
133 | });
134 |
135 | it('.mockImplementation evaluating args', function() {
136 | jestSpy = jest.spyOn(operations, 'add').mockImplementation(function(a, b, c) {
137 | if (a === 42) {
138 | return 89;
139 | }
140 | if (a === 4 && b === 9 && c === 32) {
141 | return 'OK';
142 | }
143 | });
144 |
145 | const noReturn = operations.add(1, 2);
146 | const result = operations.add(42);
147 | const result2 = operations.add(4, 9, 32);
148 |
149 | expect(noReturn).toEqual(undefined);
150 | expect(result).toEqual(89);
151 | expect(result2).toEqual('OK');
152 |
153 | jestSpy.mockRestore();
154 | });
155 | });
156 | });
157 |
158 | describe('different implementations on different calls', function() {
159 | describe('sinon', function() {
160 | beforeEach(() => {
161 | sinonStub = sinon.stub(operations, 'add');
162 | sinonStub.onCall(0).returns('Peteco');
163 | sinonStub.onCall(1).returns('Rambla');
164 | sinonStub.onCall(2).returns('Palta');
165 | });
166 |
167 | afterEach(() => {
168 | sinonStub.restore();
169 | });
170 |
171 | it('.onCall', function() {
172 | expect(operations.add()).toEqual('Peteco');
173 | expect(operations.add()).toEqual('Rambla');
174 | expect(operations.add()).toEqual('Palta');
175 | });
176 | });
177 |
178 | describe('jest', () => {
179 | beforeEach(() => {
180 | jestSpy = jest.spyOn(operations, 'add');
181 | });
182 |
183 | afterEach(() => {
184 | jestSpy.mockRestore();
185 | });
186 |
187 | it('.mockImplementationOnce', function() {
188 | jestSpy.mockReturnValueOnce('Peteco');
189 | jestSpy.mockReturnValueOnce('Rambla');
190 | jestSpy.mockReturnValueOnce('Palta');
191 |
192 | expect(operations.add()).toEqual('Peteco');
193 | expect(operations.add()).toEqual('Rambla');
194 | expect(operations.add()).toEqual('Palta');
195 | });
196 | });
197 | });
198 | });
199 |
--------------------------------------------------------------------------------
/tests/spies.spy-on-object-method.test.js:
--------------------------------------------------------------------------------
1 | const sinon = require('sinon');
2 |
3 | const someObject = {
4 | id: 43,
5 | model: 'C4',
6 | getModel: function() {
7 | return this.model;
8 | }
9 | };
10 |
11 | let sinonSpy;
12 | let jestSpy;
13 |
14 | beforeAll(function() {
15 | sinonSpy = sinon.spy();
16 | jestSpy = jest.fn();
17 | });
18 |
19 | beforeEach(function() {
20 | sinonSpy.resetHistory();
21 | jestSpy.mockReset();
22 | });
23 |
24 | afterAll(function() {
25 | sinonSpy = null;
26 | jestSpy = null;
27 | });
28 |
29 | describe('spy on method', function() {
30 | it("sinon.spy(obj, 'method')", function() {
31 | sinonSpy = sinon.spy(someObject, 'getModel');
32 |
33 | someObject.getModel();
34 |
35 | expect(sinonSpy.called).toEqual(true);
36 |
37 | sinonSpy.restore();
38 | });
39 |
40 | it("jest.spyOn(obj, 'method')", function() {
41 | jestSpy = jest.spyOn(someObject, 'getModel');
42 |
43 | someObject.getModel();
44 |
45 | expect(jestSpy).toHaveBeenCalled();
46 |
47 | jestSpy.mockRestore();
48 | });
49 | });
50 |
--------------------------------------------------------------------------------
/tests/spies.times.test.js:
--------------------------------------------------------------------------------
1 | const sinon = require('sinon');
2 |
3 | let sinonSpy;
4 | let jestSpy;
5 |
6 | beforeAll(function() {
7 | sinonSpy = sinon.spy();
8 | jestSpy = jest.fn();
9 | });
10 |
11 | beforeEach(function() {
12 | sinonSpy.resetHistory();
13 | jestSpy.mockReset();
14 | });
15 |
16 | afterAll(function() {
17 | sinonSpy = null;
18 | jestSpy = null;
19 | });
20 |
21 | describe('counting times', function() {
22 | /**
23 | * sinon
24 | */
25 | describe('sinon', function() {
26 | it('spy.calledOnce', function() {
27 | sinonSpy();
28 |
29 | expect(sinonSpy.calledOnce).toEqual(true);
30 | });
31 |
32 | it('spy.calledTwice', function() {
33 | sinonSpy();
34 | sinonSpy();
35 |
36 | expect(sinonSpy.calledTwice).toEqual(true);
37 | });
38 |
39 | it('spy.calledThrice', function() {
40 | sinonSpy();
41 | sinonSpy();
42 | sinonSpy();
43 |
44 | expect(sinonSpy.calledThrice).toEqual(true);
45 | });
46 |
47 | it('spy.callCount', function() {
48 | sinonSpy();
49 |
50 | expect(sinonSpy.callCount).toEqual(1);
51 |
52 | sinonSpy();
53 |
54 | expect(sinonSpy.callCount).toEqual(2);
55 |
56 | sinonSpy();
57 |
58 | expect(sinonSpy.callCount).toEqual(3);
59 | });
60 | });
61 |
62 | /**
63 | * jest
64 | */
65 | describe('jest', function() {
66 | it('spy.mock.calls.length', function() {
67 | jestSpy();
68 |
69 | expect(jestSpy.mock.calls.length).toEqual(1);
70 |
71 | jestSpy();
72 |
73 | expect(jestSpy.mock.calls.length).toEqual(2);
74 | });
75 |
76 | it('expect .toHaveBeenCalled', function() {
77 | jestSpy();
78 |
79 | expect(jestSpy).toHaveBeenCalled();
80 | });
81 |
82 | it('expect .toHaveBeenCalledTimes', function() {
83 | jestSpy();
84 |
85 | expect(jestSpy).toHaveBeenCalledTimes(1);
86 |
87 | jestSpy();
88 |
89 | expect(jestSpy).toHaveBeenCalledTimes(2);
90 | });
91 | });
92 | });
93 |
--------------------------------------------------------------------------------
/tests/timers.test.js:
--------------------------------------------------------------------------------
1 | const sinon = require('sinon');
2 | const lolex = require('lolex');
3 |
4 | const TIMESTAMP = 233550000000;
5 |
6 | const formatDate = d => `${d.getDate()}/${d.getMonth() + 1}/${d.getFullYear()}`;
7 |
8 | const timerFn = cb => setTimeout(cb, 100);
9 |
10 | let clock;
11 |
12 | describe('sinon .useFakeTimers', () => {
13 | it('fake Date', () => {
14 | clock = sinon.useFakeTimers({
15 | now: new Date(TIMESTAMP)
16 | });
17 |
18 | expect(formatDate(new Date())).toEqual('27/5/1977');
19 |
20 | clock.restore();
21 | });
22 |
23 | it('fake nextTick', () => {
24 | clock = sinon.useFakeTimers({
25 | toFake: ['nextTick']
26 | });
27 |
28 | let called = false;
29 |
30 | process.nextTick(function() {
31 | called = true;
32 | });
33 |
34 | clock.runAll(); //forces nextTick calls to flush synchronously
35 |
36 | expect(called).toBeTruthy();
37 |
38 | clock.restore();
39 | });
40 |
41 | it('fake tick', () => {
42 | let result = '';
43 |
44 | clock = sinon.useFakeTimers();
45 |
46 | setImmediate(function() {
47 | result = 'tick';
48 | });
49 |
50 | setTimeout(function() {
51 | result = 'tock';
52 | }, 15);
53 |
54 | setTimeout(function() {
55 | result = 'tack';
56 | }, 35);
57 |
58 | expect(result).toEqual('');
59 | clock.tick();
60 | expect(result).toEqual('tick');
61 | clock.tick(15);
62 | expect(result).toEqual('tock');
63 | clock.tick(20);
64 | expect(result).toEqual('tack');
65 |
66 | clock.restore();
67 | });
68 | });
69 |
70 | describe('jest', function() {
71 | describe('.fakeTimers', function() {
72 | const innerSpy = jest.fn();
73 | const callback = jest.fn().mockImplementation(() => {
74 | return setTimeout(innerSpy, 200);
75 | });
76 | let timeout;
77 |
78 | beforeAll(() => {
79 | // Enable fake timers
80 | jest.useFakeTimers();
81 | });
82 |
83 | beforeEach(() => {
84 | timeout = timerFn(callback);
85 | });
86 |
87 | afterEach(() => {
88 | callback.mockClear();
89 | innerSpy.mockClear();
90 | clearTimeout(timeout);
91 | });
92 |
93 | afterAll(() => {
94 | jest.clearAllTimers();
95 | });
96 |
97 |
98 | it('setTimeout is NOT a mock function as before but it works as expected in Jest 29', function() {
99 | expect(setTimeout.mock).toBeUndefined();
100 | });
101 |
102 | it('.runAllTimers', () => {
103 | expect(callback).not.toBeCalled();
104 |
105 | // Fast-forward until all timers have been executed
106 | jest.runAllTimers();
107 |
108 | expect(callback.mock.calls.length).toEqual(1);
109 | expect(innerSpy.mock.calls.length).toEqual(1);
110 | });
111 |
112 | it('.runOnlyPendingTimers', () => {
113 | jest.runOnlyPendingTimers();
114 |
115 | expect(callback.mock.calls.length).toEqual(1);
116 | expect(innerSpy.mock.calls.length).toEqual(0);
117 |
118 | jest.runOnlyPendingTimers();
119 |
120 | expect(innerSpy.mock.calls.length).toEqual(1);
121 | });
122 |
123 | it('.advanceTimersByTime | jest 26.0.0: .advanceTimersByTime', () => {
124 | jest.advanceTimersByTime(100);
125 |
126 | expect(callback.mock.calls.length).toEqual(1);
127 | expect(innerSpy.mock.calls.length).toEqual(0);
128 |
129 | jest.advanceTimersByTime(200);
130 |
131 | expect(innerSpy.mock.calls.length).toEqual(1);
132 | });
133 | });
134 | describe('lolex (to provide timer API for Jest)', function() {
135 | it('mock the Date', function() {
136 | clock = lolex.install({
137 | now: TIMESTAMP
138 | });
139 |
140 | expect(formatDate(new Date())).toEqual('27/5/1977');
141 |
142 | clock.uninstall();
143 | });
144 |
145 | it('fake nextTick', () => {
146 | clock = lolex.install({
147 | toFake: ['nextTick']
148 | });
149 |
150 | let spy = jest.fn();
151 |
152 | process.nextTick(spy);
153 |
154 | clock.runAll(); //forces nextTick calls to flush synchronously
155 |
156 | expect(spy).toHaveBeenCalled();
157 |
158 | clock.uninstall();
159 | });
160 |
161 | it('fake tick', () => {
162 | let result = '';
163 |
164 | clock = lolex.install();
165 |
166 | setImmediate(function() {
167 | result = 'tick';
168 | });
169 |
170 | setTimeout(function() {
171 | result = 'tock';
172 | }, 15);
173 |
174 | setTimeout(function() {
175 | result = 'tack';
176 | }, 35);
177 |
178 | expect(result).toEqual('');
179 | clock.tick();
180 | expect(result).toEqual('tick');
181 | clock.tick(15);
182 | expect(result).toEqual('tock');
183 | clock.tick(20);
184 | expect(result).toEqual('tack');
185 |
186 | clock.uninstall();
187 | });
188 | });
189 | });
190 |
--------------------------------------------------------------------------------