File: README.md

package info (click to toggle)
node-json-stringify-safe 5.0.1%2Brepack-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,108 kB
  • sloc: javascript: 6,398; makefile: 117
file content (427 lines) | stat: -rw-r--r-- 20,475 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
Must.js
=======
[![NPM version][npm-badge]](https://www.npmjs.com/package/must)
[![Build status][travis-badge]](https://travis-ci.org/moll/js-must)

Must.js is a testing and assertion library for JavaScript and Node.js with
a friendly **BDD** syntax (`awesome.must.be.true()`). It ships with **many
expressive matchers** and is **test runner and framework agnostic**. Follows
[RFC 2119][rfc2119] with its use of **MUST**. Good and well testsed stuff.

For those new to testing JavaScript on Node.js, you'll also need a test
framework (also called a test-runner or a harness) to run your tests. One such
tool is [Mocha][mocha].

[npm-badge]: https://img.shields.io/npm/v/must.svg
[travis-badge]: https://travis-ci.org/moll/js-must.png?branch=master
[rfc2119]: https://www.ietf.org/rfc/rfc2119.txt
[mocha]: https://mochajs.org

### Tour
- Assert with a **beautiful and fluent chain** that saves you from wrapping
  objects manually and reads nicely, too:
  ```javascript
  require("must/register")
  obj.must.be.true()
  ```

- Supports the **expect flavor** of wrapping as well:
  ```javascript
  var demand = require("must")
  demand(obj).be.string()
  ```

- **Many expressive matchers** out of the box, including:
  ```javascript
  [].must.be.empty()
  obj.must.have.nonenumerable("foo")
  (42).must.be.above(13)
  ```

- **Simple**, because **matchers always behave the same way** and don't depend
  on any "special flags" in the chain. They are also **not interdependent** the
  way `foo.should.have.property(x).with.lengthOf(5)` would be.

- **Reasonable**, because it asserts only when you call the matcher
  `[].must.be.empty()` and not when you merely get the property `empty`. See
  below why [asserting on property access](#asserting-on-property-access) is
  **dangerous** in other assertion libraries.

- Has an **intelligent and type-safe** recursive [`eql`][Must.prototype.eql]
  matcher that compares arrays and objects by content and supports value
  objects.  It's fully type-safe, so instances of *different classes* aren't
  *eql*, even if their properties are. It also supports **circular and
  self-referential** objects.
  ```javascript
  primesBelowTen.must.eql([2, 3, 5, 7])
  model.attributes.must.eql({title: "New", createdAt: new Date(2000, 1, 1)})
  ```

- Built-in support for **asserting on promises** with stack traces leading back
  to _your_ assertion, not to the library's internals.

  ```javascript
  Promise.resolve(42).must.then.equal(42)
  Promise.resolve([1, 2, 3]).must.eventually.not.include(42)
  Promise.reject(new Error("Problemo")).must.reject.with.error(/problem/i)
  ```

- **Human readable error messages** let you know if an object wasn't what you
  expected. You can also customize or prepend to the autogenerated error
  message for further clarification.

- Honors [RFC 2119][rfc2119] by using the word **MUST** because your
  tests assert things, they don't list wishes or prayers, right? Exactly!
  `Foo.must.equal(42)`, not `foo.pretty.please.equal(42)`.

- Works with any test runner and framework.  
- Avoids type coercions and mismatches.
- Well tested — over 700 cases in over 2500 lines of tests. That makes a test to
  code ratio of 5:1.

### Using Should.js or Chai.js? Switch for safety!
Among other things, one reason why [Should.js][should.js] and [Chai.js][chai.js]
inspired me to write Must.js is that they have a **fundamental design mistake**
that makes them both **surprising in a bad way** and **dangerous to use**. [Read
more below](#asserting-on-property-access).

### Extensible

Must.js features a very simple implementation and one you can extend yourself. In Must.js, every matcher is a function on `Must.prototype` that calls `Must.prototype.assert`. For now, please see the source of Must for examples.

There are [plugins for Must.js](#plugins) by others available, too.


Installing
----------
**Note**: Must.js will follow the [semantic versioning](http://semver.org/)
starting from v1.0.0.

### Installing on Node.js
```
npm install must
```

### Installing for the browser
Must.js doesn't yet have a build ready for the browser, but you might be able
to use [Browserify][browserify] to have it run there till then.

[browserify]: https://github.com/substack/node-browserify


Using
-----
To use the **fluent chain**, just require Must.js's "register" file and it'll
make itself available everywhere:
```javascript
require("must/register")
```

Then just access the `must` property on any object and call matchers on it.
```javascript
answer.must.equal(42)
new Date().must.be.an.instanceof(Date)
```

If you wish to use the **expect flavor**, assign Must to any name of your
choice, e.g:
```javascript
var expect = require("must")
var demand = require("must")
```

And call it with the object you wish to assert:
```javascript
expect(answer).to.equal(42)
demand(null).be.null()
```

For a list of all matchers, please see the [Must.js API Documentation][api].

### Negative asserting or matching the opposite
To assert the opposite, just add `not` between the chain:
```javascript
true.must.not.be.false()
[].must.not.be.empty()
```

Use it multiple times to create lots of fun puzzles! :-)
```javascript
true.must.not.not.be.true()
```

### Asserting on null and undefined values
In almost all cases you can freely call methods on any object in JavaScript.
Except for `null` and `undefined`.

Most of the time this won't be a problem, because if you're asserting that
`something.must.be.true()` and `something` ends up `null`, the test will still
fail. If, however, you do need to assert its nullness, aliasing Must to `expect`
or `demand` and wrapping it manually works well:

```javascript
var demand = require("must")
demand(something).be.null()
demand(undefined).be.undefined()
```

If you've got an object on which a `null` or an `undefined` property must
_exist_ in addition to having a nully value, use the
[`property`][Must.prototype.property] matcher:

```javascript
var obj = {id: null, name: undefined}
obj.must.have.property("id", null)
obj.must.have.property("name", undefined)
```

### Autoloading
If your test runner supports an options file, you might want to require Must
there so you wouldn't have to remember to `require` in each test file.

For [Mocha][mocha], that file is `test/mocha.opts`:
```
--require must/register
```

### Full example
Inside a test runner or framework things would look something like this:
```javascript
require("must/register")
var MySong = require("../my_song")

describe("MySong", function() {
  it("must be creatable", function() {
    new MySong().must.be.an.instanceof(MySong)
  })

  it("must have cowbell", function() {
    new MySong().cowbell.must.be.true()
  })

  it("must not have pop", function() {
    new MySong().must.not.have.property("pop")
  })
})
```


API
---
For extended documentation on all functions, please see the
[Must.js API Documentation][api].

[api]: https://github.com/moll/js-must/blob/master/doc/API.md

### [Must](https://github.com/moll/js-must/blob/master/doc/API.md#Must)
- [.prototype.a](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.a)(class)
- [.prototype.above](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.above)(expected)
- [.prototype.after](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.after)(expected)
- [.prototype.an](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.an)(class)
- [.prototype.array](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.array)()
- [.prototype.at](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.at)
- [.prototype.be](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.be)(expected)
- [.prototype.before](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.before)(expected)
- [.prototype.below](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.below)(expected)
- [.prototype.between](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.between)(begin, end)
- [.prototype.boolean](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.boolean)()
- [.prototype.contain](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.contain)(expected)
- [.prototype.date](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.date)()
- [.prototype.empty](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.empty)()
- [.prototype.endWith](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.endWith)(expected)
- [.prototype.enumerable](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.enumerable)(property)
- [.prototype.enumerableProperty](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.enumerableProperty)(property)
- [.prototype.eql](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.eql)(expected)
- [.prototype.equal](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.equal)(expected)
- [.prototype.error](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.error)([constructor], [expected])
- [.prototype.eventually](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.eventually)
- [.prototype.exist](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.exist)()
- [.prototype.false](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.false)()
- [.prototype.falsy](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.falsy)()
- [.prototype.frozen](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.frozen)()
- [.prototype.function](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.function)()
- [.prototype.gt](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.gt)(expected)
- [.prototype.gte](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.gte)(expected)
- [.prototype.have](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.have)
- [.prototype.include](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.include)(expected)
- [.prototype.instanceOf](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.instanceOf)(class)
- [.prototype.instanceof](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.instanceof)(class)
- [.prototype.is](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.is)(expected)
- [.prototype.keys](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.keys)(keys)
- [.prototype.least](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.least)(expected)
- [.prototype.length](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.length)(expected)
- [.prototype.lt](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.lt)(expected)
- [.prototype.lte](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.lte)(expected)
- [.prototype.match](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.match)(regexp)
- [.prototype.most](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.most)(expected)
- [.prototype.must](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.must)
- [.prototype.nan](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.nan)()
- [.prototype.nonenumerable](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.nonenumerable)(property)
- [.prototype.nonenumerableProperty](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.nonenumerableProperty)(property)
- [.prototype.not](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.not)
- [.prototype.null](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.null)()
- [.prototype.number](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.number)()
- [.prototype.object](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.object)()
- [.prototype.own](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.own)(property, [value])
- [.prototype.ownKeys](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.ownKeys)(keys)
- [.prototype.ownProperties](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.ownProperties)(properties)
- [.prototype.ownProperty](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.ownProperty)(property, [value])
- [.prototype.permutationOf](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.permutationOf)(expected)
- [.prototype.properties](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.properties)(properties)
- [.prototype.property](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.property)(property, [value])
- [.prototype.regexp](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.regexp)()
- [.prototype.reject](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.reject)
- [.prototype.resolve](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.resolve)
- [.prototype.startWith](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.startWith)(expected)
- [.prototype.string](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.string)()
- [.prototype.symbol](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.symbol)()
- [.prototype.the](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.the)
- [.prototype.then](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.then)
- [.prototype.throw](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.throw)([constructor], [expected])
- [.prototype.to](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.to)
- [.prototype.true](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.true)()
- [.prototype.truthy](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.truthy)()
- [.prototype.undefined](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.undefined)()
- [.prototype.with](https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.with)


Migrating to Must.js
--------------------
You're likely to be already using some testing library and have a set of tests
in them. I'm **honored you picked** Must.js to go forward. Let's **get you up to
speed** on how Must.js differs from others and how to **migrate your old tests**
over.

### From Should.js
Must.js and [Should.js][should.js] are fairly similar when it comes to matchers.

- Just add parentheses after each assertion and you're almost set.
- Must.js does not have static matchers like `should.not.exist(obj.foo)`.  
  Convert to `demand(foo).not.to.exist()`.
- Must.js lacks `with.lengthOf` because its matchers are all independent.  
  Convert to `obj.must.have.length(5)`
- Must.js lacks the `ok` matcher because unambiguous names are better.  
  Convert to `truthy`.
- Must.js does not support custom error descriptions.

Here's a quick `sed` script to convert `obj.should.xxx` style to
`obj.must.xxx()`:
```
sed -i.should -E -f /dev/stdin test/**/*.js <<-end
  /\.should\.([[:alpha:].]+)([[:space:]}\);]|$)/s/\.should\.([[:alpha:].]+)/.must.\1()/g
  s/\.should\.([[:alpha:].]+)/.must.\1/g
end
```

### From Chai.js
Must.js and [Chai.js][chai.js] are fairly similar when it comes to matchers.

- Just add parentheses after each assertion and you're almost set.  
  That goes for both the BDD (`obj.should`) and *expect*
  (`expect(obj).to`) flavor.
- Must.js lacks the `include` flag because its matchers are all independent.  
  Convert to `Object.keys(obj).must.include("foo")`.
- Must.js lacks the `deep` flag for the `equal` matcher because
  [`eql`][Must.prototype.eql] already compares recursively and in a type-safe
  way.  
  Convert to `obj.must.eql({some: {deep: "object"}})`.
- Must.js lacks the `deep` flag for the `property` matcher because it prefers
  regular property access.  
  Convert to `obj.some.nested.property.must.equal(42)`.
- Must.js lacks the `ok` matcher because unambiguous names are better.  
  Convert to `truthy`.
- Must.js lacks the `respondTo` matcher because unambiguous names are better.  
  Convert to `MyClass.prototype.must.be.a.function()`.

Here's a quick `sed` script to convert `obj.should.xxx` style to
`obj.must.xxx()`:
```
sed -i.should -E -f /dev/stdin test/**/*.js <<-end
  /\.should\.([[:alpha:].]+)([[:space:]}\);]|$)/s/\.should\.([[:alpha:].]+)/.must.\1()/g
  s/\.should\.([[:alpha:].]+)/.must.\1/g
end
```

### Convert test case titles to MUST
If you've used the `should` style before, you most likely have test cases titled
`it("should do good")`.  
Migrate those to `it("must do good")` with this `sed` script:
```
sed -i.should -E -e 's/it\("should/it("must/g' test/**/*.js
```

<a name="asserting-on-property-access"></a>
### Beware of libraries that assert on property access
Among other things, one reason why [Should.js][should.js] and
[Chai.js][chai.js] inspired me to write Must.js is that they have
a **fundamental design mistake** that makes them both **surprising in a bad
way** and **dangerous to use**.

It has to do with them asserting on property access, like this:
```javascript
true.should.be.true
[].should.be.empty
```

What initially may seem familiar to Ruby programmers, first of all, is out of
place in JavaScript. Dot-something stands for getting a property's value and
getters, regardless of language, **should not** have **side-effects**.
Especially not **control-flow changing exceptions**!

Secondly, and this is where it's flat out **dangerous asserting on property
access**, is that accessing a non-existent property does **nothing** in
JavaScript.  Recall that JavaScript does not have Ruby's `method_missing` or
other hooks to catch such access. So, guess what happens when someone mistypes
or mis-remembers a matcher? Yep, nothin' again. And that's the way it's supposed
to be.  But what's good in JavaScript, **not so good** for your now **false
positive test**.

Imagine using a plugin that adds matchers for spies or mocks. Then using it with
`someFn.should.have.been.calledOnce`.  Someone accidentally removes the plugin
or thinks `calledQuadrice` sounds good?  Well, those assertions will surely
continue passing because they'll now just get `undefined` back.

Must.js **solves both problems** with the **simplest but effective solution**
— requires you to **always call matchers** because they're plain-old functions
— `expect(problem).to.not.exist()`.

[should.js]: https://github.com/visionmedia/should.js
[chai.js]: http://chaijs.com


Plugins
-------
- [must-sinon](https://www.npmjs.com/package/must-sinon) ([Repository](https://github.com/JohnnyEstilles/must-sinon)) — Sinon assertions.
- [must-targaryen](https://www.npmjs.com/package/must-targaryen) ([Repository](https://github.com/jtwebman/must-targaryen)) — Firebase Targaryen assertions.
- [must-jsx](https://www.npmjs.com/package/must-jsx) ([Repository](https://github.com/nwinch/must-jsx)] — React.js JSX assertions.

If you have a module extending Must.js one not listed above, please let me know or create a pull request.


License
-------
Must.js is released under a *Lesser GNU Affero General Public License*, which in
summary means:

- You **can** use this program for **no cost**.
- You **can** use this program for **both personal and commercial reasons**.
- You **do not have to share your own program's code** which uses this program.
- You **have to share modifications** (e.g bug-fixes) you've made to this
  program.

For more convoluted language, see the `LICENSE` file.


About
-----
**[Andri Möll](http://themoll.com)** typed this and the code.  
[Monday Calendar](https://mondayapp.com) supported the engineering work.

If you find Must.js needs improving, please don't hesitate to type to me now at
[andri@dot.ee][email] or [create an issue online][issues].

[email]: mailto:andri@dot.ee
[issues]: https://github.com/moll/js-must/issues

[Must.prototype.eql]: https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.eql
[Must.prototype.property]: https://github.com/moll/js-must/blob/master/doc/API.md#Must.prototype.property