1 | assertive
|
2 | =========
|
3 |
|
4 | A terse, yet expressive assertion library
|
5 |
|
6 | Is Assertive different from other assertion libraries?
|
7 | ----------------------------------------------------------------------
|
8 |
|
9 | Assertive aims to make the exact cause of breakage and intent of tests
|
10 | as fast and easy to spot as possible, with much attention paid to both
|
11 | the colour and alignment of expected and actual data, so you should be
|
12 | able to glean what you need immediately.
|
13 |
|
14 | It also tries to pre-empt false negative tests from ever happening, by
|
15 | rigorously testing for correct assertion invocation and by avoiding to
|
16 | pick names for assertions with a track record of being misinterpreted,
|
17 | not just by people reading the code, but also by programmers _writing_
|
18 | them, which can make even 100%-test-coverage code fail on behalf of it
|
19 | testing for the wrong thing.
|
20 |
|
21 | Semantic Versioning
|
22 | ----------------------------------------------------------------------
|
23 |
|
24 | Assertive uses [semver](http://semver.org/) version numbers, though we
|
25 | should point out that we may tighten assertion checks in minor version
|
26 | number updates, making code that previously silently passed, now fail.
|
27 |
|
28 | Case in point: before v1.3.0, code using an assertion to verify that a
|
29 | string included the empty string, would do just that. In other words -
|
30 | nothing, since that assertion does not test anything. Now, such a test
|
31 | is flagged as a bug in your test suite that you should fix, as that is
|
32 | not asserting something about your code, but about strings in general.
|
33 |
|
34 | In Assertive, breaking changes implying a major version bump, would be
|
35 | things like argument order changes. If you really do not want improved
|
36 | coverage against this type of error with a random minor version update
|
37 | you should pin a version you like in your `package.json` rather than a
|
38 | version range.
|
39 |
|
40 | Usage
|
41 | ----------------------------------------------------------------------
|
42 |
|
43 | Each assertion lets you state a condition and an optional help message
|
44 | about what semantics your test asserts, which gets presented first, if
|
45 | the assertion fails. (This is generally much more useful than messages
|
46 | along the lines of "expected true to be false", especially when it may
|
47 | be hard to tell later what the intended purpose of a test really was.)
|
48 |
|
49 | Besides failing when what each assertion guards against, they also all
|
50 | fail if you pass too few, too many or otherwise illegal parameters, as
|
51 | when a tired programmer expects "expect" to compare the two parameters
|
52 | he passed in some way and trip when they mismatch, though all it would
|
53 | ever test is that the first was truthy. To not get test suites full of
|
54 | almost-no-op tests like that, Assertive fails straight away like this:
|
55 |
|
56 | ```
|
57 | Expected: true
|
58 | Actually: 10
|
59 | ```
|
60 |
|
61 | There have been test suites full of no-op tests similar to this, which
|
62 | have gone undetected for months or years, giving a false sense of what
|
63 | regressions you are guarded against.
|
64 |
|
65 | You may pass any of the functions an item to be tested as a promise,
|
66 | and it will be tested after the promise is resolved. In this case, the
|
67 | test will return a promise which will be resolved or rejected as appropriate.
|
68 | A promise-aware test runner (e.g. [Mocha](https://mochajs.org/)
|
69 | version >= 1.18.0) is highly recommended.
|
70 |
|
71 | These docs show a typical invocation, and what you see when it failed:
|
72 |
|
73 |
|
74 | ### `expect`
|
75 | ```javascript
|
76 | // fail if bool != true
|
77 | assert.expect(bool);
|
78 | ```
|
79 |
|
80 | ```javascript
|
81 | expect('2 > 1', 2 > 1);
|
82 | // Assertion failed: 2 > 1
|
83 | ```
|
84 |
|
85 |
|
86 | ### `truthy`
|
87 |
|
88 | **Note**: Using `truthy` in your tests is a code smell.
|
89 | More often than not there is another, more precise test.
|
90 | Only use `truthy` when there is no way of knowing what the actual value will be.
|
91 | If `bool` is the result of a boolean operation, use `expect`.
|
92 | If `bool` is an unknown value, use `match` or `include` to narrow it down.
|
93 |
|
94 | ```javascript
|
95 | // fail if !bool
|
96 | assert.truthy(bool);
|
97 | assert.truthy(explanation, bool);
|
98 | ```
|
99 |
|
100 | ```javascript
|
101 | truthy('something was populated in the email field', form.email.value);
|
102 |
|
103 | // Assertion failed: something was populated in the email field
|
104 | // expected undefined to be truthy
|
105 | ```
|
106 |
|
107 |
|
108 | ### `equal`
|
109 | ```javascript
|
110 | // fail unless actual === expected
|
111 | assert.equal(expected, actual);
|
112 | assert.equal(explanation, expected, actual);
|
113 |
|
114 | // Assertion failed: decode the Epoch to 0s after Jan 1st, 1970
|
115 | // Expected 86400000 to be
|
116 | // equal to 0
|
117 | ```
|
118 |
|
119 | ### `deepEqual`
|
120 | ```javascript
|
121 | // fail unless _.isEqual(expected, actual)
|
122 | assert.deepEqual(expected, actual);
|
123 | assert.deepEqual(explanation, expected, actual);
|
124 |
|
125 | /*
|
126 | Assertion failed: ensure that all methods we tested were handled, and in the right order
|
127 | Actual: - Expected: +
|
128 | {
|
129 | "methods": [
|
130 | "GET",
|
131 | - "GET",
|
132 | + "POST",
|
133 | + "PUT",
|
134 | + "DELETE"
|
135 | ]
|
136 | }
|
137 | */
|
138 | ```
|
139 |
|
140 | ### `include`
|
141 | ```javascript
|
142 | // fail unless haystack has a substring needle, or _.include haystack, needle
|
143 | assert.include(needle, haystack);
|
144 | assert.include(explanation, needle, haystack);
|
145 |
|
146 | // Assertion failed: only accept supported, case-normalized method names
|
147 | // expected ["GET","POST","PUT","DELETE"]
|
148 | // to include "get"
|
149 | ```
|
150 |
|
151 | ### `match`
|
152 | ```javascript
|
153 | // fail unless regexp matches the given string, or regexp.test string
|
154 | assert.match(regexp, string);
|
155 | assert.match(explanation, regexp, needle);
|
156 |
|
157 | // Assertion failed: only affirmative pirate answers accepted
|
158 | // Expected: /aye|yar+/
|
159 | // to match: "nay"
|
160 | ```
|
161 |
|
162 | ### `throws`
|
163 | ```javascript
|
164 | // fail unless the provided functionThatThrows() calls throw
|
165 | // (on non-failures the return value is whatever was thrown)
|
166 | const err = assert.throws(functionThatThrows);
|
167 | const err = assert.throws(explanation, functionThatThrows);
|
168 |
|
169 | // Assertion failed: ensure that bad inputs throw an error
|
170 | // didn't throw an exception as expected to
|
171 | ```
|
172 |
|
173 | ### `hasType`
|
174 | ```javascript
|
175 | // fail unless _.isType(value) is true for given Type, or the
|
176 | // same test for a more specific type (listed above) was true
|
177 | assert.hasType(<type>, value);
|
178 | assert.hasType(explanation, <type>, value);
|
179 | assert.hasType(null, value)
|
180 | assert.hasType(Date, value)
|
181 | assert.hasType(Array, value)
|
182 | assert.hasType(String, value)
|
183 | assert.hasType(RegExp, value)
|
184 | assert.hasType(Boolean, value)
|
185 | assert.hasType(Function, value)
|
186 | assert.hasType(Object, value)
|
187 | assert.hasType(NaN, value)
|
188 | assert.hasType(Number, value)
|
189 | assert.hasType(undefined, value)
|
190 | ```
|
191 |
|
192 | ### `resolves`
|
193 | ```javascript
|
194 | // Wait for promise to resolve, then resolve if successful, reject otherwise
|
195 | // Always returns a promise, unless called with non-promise (not allowed)
|
196 | const samePromise = assert.resolves(promise)
|
197 | const samePromise = assert.resolves(explanation, promise)
|
198 |
|
199 | // Assertion failed: should resolve to good stuff
|
200 | // Promise was rejected despite resolves assertion:
|
201 | // Timeout in 10000ms
|
202 | ```
|
203 |
|
204 | ### `rejects`
|
205 | ```javascript
|
206 | // Wait for promise to reject, resolve with error if it does, reject otherwise
|
207 | // Basically inverse of resolves(), but resolves with the error for more testing
|
208 | // Always returns a promise, unless called with non-promise (not allowed)
|
209 | const promiseForErr = assert.rejects(promise)
|
210 | const promiseForErr = assert.rejects(explanation, promise)
|
211 |
|
212 | // Assertion failed: should reject after Timeout
|
213 | // Promise wasn't rejected as expected to
|
214 | ```
|
215 |
|
216 | ### `falsey`, `notEqual`, `notDeepEqual`, `notInclude`, `notMatch`, `notThrows`, `notHasType`
|
217 | Versions of the above functions taking the same arguments, but asserting
|
218 | the opposite outcome. The assertion failure messages are just as helpful.
|
219 |
|
220 | License
|
221 | ----------------------------------------------------------------------
|
222 |
|
223 | [BSD 3-Clause open source license](LICENSE)
|