UNPKG

8.88 kBMarkdownView Raw
1[![TODO board](https://imdone.io/api/1.0/projects/5b1adecc1883d42a1fbf805d/badge)](https://imdone.io/app#/board/bahmutov/snap-shot-it)
2
3# snap-shot-it
4
5> Smarter snapshot utility for Mocha and BDD test runners + data-driven testing!
6
7[![NPM][npm-icon] ][npm-url]
8
9[![Build status][ci-image] ][ci-url]
10[![semantic-release][semantic-image] ][semantic-url]
11[![js-standard-style][standard-image]][standard-url]
12
13## Why
14
15This tool makes [snapshot testing][snapshot testing] for Mocha (and other BDD)
16frameworks quick and painless. This module spies on global `it` function,
17which allows it to accurately get test information (beating static code parsing
18done in [snap-shot][snap-shot]); it should work in transpiled code.
19
20[snapshot testing]: https://glebbahmutov.com/blog/snapshot-testing/
21
22This package uses [snap-shot-compare](https://github.com/bahmutov/snap-shot-compare)
23to display object and text difference intelligently.
24
25This function also includes [data-driven][data-driven] testing mode,
26similar to [sazerac][sazerac], see [Data-driven testing](#data-driven-testing)
27section below.
28
29[data-driven]: https://hackernoon.com/sazerac-data-driven-testing-for-javascript-e3408ac29d8c#.9s4ikt67d
30[sazerac]: https://github.com/mikec/sazerac
31
32## Install
33
34Requires [Node](https://nodejs.org/en/) version 4 or above.
35
36```sh
37npm install --save-dev snap-shot-it
38```
39
40## Use
41
42Example from [spec.js](src/spec.js)
43
44```js
45const snapshot = require('snap-shot-it')
46describe('example', () => {
47 it('works', () => {
48 snapshot(add(10, 20))
49 snapshot('a text message')
50 return Promise.resolve(42).then(snapshot)
51 })
52})
53```
54
55Run Mocha tests, then open the created
56[__snapshots__/spec.js](__snapshots__/spec.js) file
57
58```js
59exports['example works 1'] = 30
60
61exports['example works 2'] = "a text message"
62
63exports['example works 3'] = 42
64```
65
66Suppose you change the resolved value from `42` to `80`
67
68```js
69const snapshot = require('snap-shot-it')
70describe('example', () => {
71 it('works', () => {
72 snapshot(add(10, 20))
73 snapshot('a text message')
74 return Promise.resolve(80).then(snapshot)
75 })
76})
77```
78
79The test will fail
80
81```
821) example works:
83 Error: 42 !== 80
84```
85
86The error message should intelligently handle numbers, objects, arrays,
87multi-line text, etc.
88
89## Advanced use
90
91You can see the saves snapshot values by running with environment variable
92
93```bash
94SNAPSHOT_SHOW=1 npm test
95```
96
97You can see snapshot values without writing them into the snapshot file
98
99```bash
100SNAPSHOT_DRY=1 npm test
101```
102
103You can update snapshot values
104
105```bash
106SNAPSHOT_UPDATE=1 npm test
107```
108
109By default, the snapshots are saved sorted alphabetically. You can skip sorting using an environment variable
110
111```bash
112SNAPSHOT_SKIP_SORTING=1 npm test
113```
114
115## Named snapshots
116
117Renaming tests might lead to confusion and pruning snapshots. You can name the snapshots
118yourself
119
120```js
121const value = 42
122snapshot('my name', value)
123```
124
125The snapshots will be saved as
126
127```js
128exports['my name'] = 42
129```
130
131**Note** you should make sure that the name is unique per spec file.
132
133## Pruning
134
135If the test run is successful and executed _all_ tests (there was no `.only`) then snapshots without a test are pruned.
136
137## Data-driven testing
138
139Writing multiple input / output pairs for a function under test quickly
140becomes tedious. Luckily, you can test a function by providing multiple
141inputs and a single snapshot of function's *behavior* will be saved.
142
143```js
144// checks if n is prime
145const isPrime = n => ...
146it('tests prime', () => {
147 snapshot(isPrime, 1, 2, 3, 4, 5, 6, 7, 8, 9)
148})
149```
150
151The saved snapshot file will have clear mapping between given input and
152produced result
153
154```js
155// snapshot file
156exports['tests prime 1'] = {
157 "name": "isPrime",
158 "behavior": [
159 {
160 "given": 1,
161 "expect": false
162 },
163 {
164 "given": 2,
165 "expect": true
166 },
167 {
168 "given": 3,
169 "expect": true
170 },
171 {
172 "given": 4,
173 "expect": false
174 },
175 {
176 "given": 5,
177 "expect": true
178 },
179 ...
180 ]
181}
182```
183
184You can also test functions that expect multiple arguments by providing
185arrays of inputs.
186
187```js
188const add = (a, b) => a + b
189it('checks behavior of binary function add', () => {
190 snapshot(add, [1, 2], [2, 2], [-5, 5], [10, 11])
191})
192```
193
194Again, the snapshot file gives clear picture of the `add` behavior
195
196```js
197// snapshot file
198exports['checks behavior of binary function add 1'] = {
199 "name": "add",
200 "behavior": [
201 {
202 "given": [
203 1,
204 2
205 ],
206 "expect": 3
207 },
208 {
209 "given": [
210 2,
211 2
212 ],
213 "expect": 4
214 },
215 {
216 "given": [
217 -5,
218 5
219 ],
220 "expect": 0
221 },
222 {
223 "given": [
224 10,
225 11
226 ],
227 "expect": 21
228 }
229 ]
230}
231```
232
233See [src/data-driven-spec.js](src/data-driven-spec.js) for more examples.
234
235## Debugging
236
237Run with environment variable `DEBUG=snap-shot-it ...` to see log messages.
238Because under the hood it uses [snap-shot-core][snap-shot-core] you might
239want to show messages from both libraries with `DEBUG=snap-shot* ...`
240
241## Examples
242
243### TypeScript
244
245An example using [ts-mocha](https://github.com/piotrwitek/ts-mocha) is
246shown in folder [ts-demo](ts-demo)
247
248### CoffeeScript
249
250CoffeeScript example is in [coffee-demo](coffee-demo) folder. Watch mode is
251working properly.
252
253## Inspiration
254
255Came during WorkBar Cambridge Happy Hour on the terrace as I was thinking about
256difficulty of adding CoffeeScript / TypeScript support to
257[snap-shot][snap-shot] project. Got the idea of overriding `global.it` when
258loading `snap-shot` because a day before I wrote [repeat-it][repeat-it]
259which overrides it and it is very simple [repeat/src/index.js][repeat source].
260
261[snap-shot]: https://github.com/bahmutov/snap-shot
262[repeat-it]: https://github.com/bahmutov/repeat-it
263[repeat source]: https://github.com/bahmutov/repeat-it/blob/master/src/index.js
264
265## Related projects
266
267This NPM module is part of my experiments with snapshot testing. There are
268lots of other ones, blog posts and slides on this topic.
269
270* [snap-shot-core][snap-shot-core] implements loading and saving snapshots
271* [snap-shot](https://github.com/bahmutov/snap-shot) is an alternative to this
272 package that tries to determine spec name using stack trace and static
273 source code parsing. Hard to do for transpiled code!
274* [schema-shot](https://github.com/bahmutov/schema-shot) is
275 "schema by example" snapshot testing
276* [subset-shot](https://github.com/bahmutov/subset-shot)
277 where new value can be a superset of the saved snapshot
278* Blog post [Picking snapshot library](https://glebbahmutov.com/blog/picking-snapshot-library/)
279* Slides [Snapshot testing the hard way](https://slides.com/bahmutov/snapshot-testing-the-hard-way)
280
281[snap-shot-core]: https://github.com/bahmutov/snap-shot-core
282
283### Small print
284
285Author: Gleb Bahmutov <gleb.bahmutov@gmail.com> © 2017
286
287* [@bahmutov](https://twitter.com/bahmutov)
288* [glebbahmutov.com](https://glebbahmutov.com)
289* [blog](https://glebbahmutov.com/blog)
290
291License: MIT - do anything with the code, but don't blame me if it does not work.
292
293Support: if you find any problems with this module, email / tweet /
294[open issue](https://github.com/bahmutov/snap-shot-it/issues) on Github
295
296## MIT License
297
298Copyright (c) 2017 Gleb Bahmutov <gleb.bahmutov@gmail.com>
299
300Permission is hereby granted, free of charge, to any person
301obtaining a copy of this software and associated documentation
302files (the "Software"), to deal in the Software without
303restriction, including without limitation the rights to use,
304copy, modify, merge, publish, distribute, sublicense, and/or sell
305copies of the Software, and to permit persons to whom the
306Software is furnished to do so, subject to the following
307conditions:
308
309The above copyright notice and this permission notice shall be
310included in all copies or substantial portions of the Software.
311
312THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
313EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
314OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
315NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
316HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
317WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
318FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
319OTHER DEALINGS IN THE SOFTWARE.
320
321[npm-icon]: https://nodei.co/npm/snap-shot-it.svg?downloads=true
322[npm-url]: https://npmjs.org/package/snap-shot-it
323[ci-image]: https://travis-ci.org/bahmutov/snap-shot-it.svg?branch=master
324[ci-url]: https://travis-ci.org/bahmutov/snap-shot-it
325[semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
326[semantic-url]: https://github.com/semantic-release/semantic-release
327[standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg
328[standard-url]: http://standardjs.com/