├── .babelrc
├── .eslintrc
├── .gitignore
├── .npmignore
├── .npmrc
├── .travis.yml
├── CHANGES.md
├── LICENSE.md
├── README.md
├── karma.conf.js
├── modules
├── Expectation.js
├── SpyUtils.js
├── TestUtils.js
├── __tests__
│ ├── .eslintrc
│ ├── chainable-test.js
│ ├── createSpy-test.js
│ ├── defaultExport-test.js
│ ├── extend-test.js
│ ├── restoreSpies-test.js
│ ├── spyOn-test.js
│ ├── toBeA-test.js
│ ├── toBeGreaterThan-test.js
│ ├── toBeGreaterThanOrEqualTo-test.js
│ ├── toBeLessThan-test.js
│ ├── toBeLessThanOrEqualTo-test.js
│ ├── toBeTruthy-test.js
│ ├── toEqual-test.js
│ ├── toExclude-test.js
│ ├── toExcludeKey-test.js
│ ├── toExcludeKeys-test.js
│ ├── toExist-test.js
│ ├── toInclude-test.js
│ ├── toIncludeKey-test.js
│ ├── toIncludeKeys-test.js
│ ├── toMatch-test.js
│ ├── toNotEqual-test.js
│ ├── toNotMatch-test.js
│ ├── withArgs-test.js
│ └── withContext-test.js
├── assert.js
├── extend.js
└── index.js
├── package.json
├── scripts
├── build.js
└── release.js
├── tests.webpack.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "es2015"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "plugins": [
4 | "import"
5 | ],
6 | "env": {
7 | "es6": true,
8 | "node": true
9 | },
10 | "extends": [
11 | "eslint:recommended",
12 | "plugin:import/errors"
13 | ],
14 | "settings": {
15 | "import/ignore": [
16 | "node_modules",
17 | "modules/index.js"
18 | ]
19 | },
20 | "rules": {
21 | "array-bracket-spacing": [ 2, "always" ],
22 | "semi": [ 2, "never" ]
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # gitignore
2 | lib
3 | umd
4 | node_modules
5 |
6 | # Only apps should have lockfiles
7 | npm-shrinkwrap.json
8 | package-lock.json
9 | yarn.lock
10 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .babelrc
2 | .eslintrc
3 | .travis.yml
4 | __tests__
5 | karma.conf.js
6 | scripts
7 | tests.webpack.js
8 | webpack.config.js
9 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | os:
3 | - linux
4 | node_js:
5 | - "9"
6 | - "8"
7 | - "7"
8 | - "6"
9 | - "5"
10 | - "4"
11 | before_install:
12 | - 'nvm install-latest-npm'
13 | install:
14 | - 'if [ "${TRAVIS_NODE_VERSION}" = "0.6" ] || [ "${TRAVIS_NODE_VERSION}" = "0.9" ]; then nvm install --latest-npm 0.8 && npm install && nvm use "${TRAVIS_NODE_VERSION}"; else npm install; fi;'
15 | script:
16 | - 'if [ -n "${PRETEST-}" ]; then npm run pretest ; fi'
17 | - 'if [ -n "${POSTTEST-}" ]; then npm run posttest ; fi'
18 | - 'if [ -n "${KARMA-}" ]; then npm run karma ; fi'
19 | - 'if [ -n "${COVERAGE-}" ]; then npm run coverage ; fi'
20 | - 'if [ -n "${TEST-}" ]; then npm run tests-only ; fi'
21 | sudo: false
22 | env:
23 | - TEST=true
24 | matrix:
25 | fast_finish: true
26 | include:
27 | - node_js: "lts/*"
28 | env: PRETEST=true
29 | - node_js: "lts/*"
30 | env: KARMA=true
31 | allow_failures:
32 | - os: osx
33 | - env: TEST=true ALLOW_FAILURE=true
34 | - env: COVERAGE=true
35 | - node_js: "9"
36 | - node_js: "7"
37 | - node_js: "5"
38 |
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 | ## [HEAD]
2 |
3 | - `toMatch` and `toNotMatch` use `tmatch` directly, so a wider array
4 | of objects and patterns are supported
5 |
6 | [HEAD]: https://github.com/mjackson/expect/compare/v1.20.1...HEAD
7 |
8 | ## [v1.20.1]
9 | > May 7, 2016
10 |
11 | - Objects that have different prototypes are not considered "equal". It
12 | was a bug to ever treat them as such.
13 |
14 | [v1.20.1]: https://github.com/mjackson/expect/compare/v1.20.0...v1.20.1
15 |
16 | ## [v1.20.0]
17 | > May 6, 2016
18 |
19 | - Objects that differ only by prototype are considered "equal". This means
20 | e.g. that `expect(Object.create(null)).toEqual({})` passes
21 | - Restored `isEqual` to behaving more like `==` instead of `===`. This is a
22 | regression that was introduced in 1.13.1 ([#62])
23 | - Handle non-array keys in `toIncludeKeys` ([#94], thanks @wuct)
24 |
25 | [v1.20.0]: https://github.com/mjackson/expect/compare/v1.19.0...v1.20.0
26 | [#62]: https://github.com/mjackson/expect/issues/62
27 | [#94]: https://github.com/mjackson/expect/pull/94
28 |
29 | ## [v1.19.0]
30 | > May 2, 2016
31 |
32 | - Spies preserve `length` property of original function ([#90], thanks @nfcampos)
33 | - Added ability to pass a `createMessage` function to `assert` that is
34 | only called when the assertion fails
35 | - Added `toNotIncludeKey(s)` alias
36 |
37 | [v1.19.0]: https://github.com/mjackson/expect/compare/v1.18.0...v1.19.0
38 |
39 | ## [v1.18.0]
40 | > Apr 18, 2016
41 |
42 | - Added support for using [tmatch] in `expect(object).toMatch`
43 |
44 | [v1.18.0]: https://github.com/mjackson/expect/compare/v1.17.0...v1.18.0
45 | [tmatch]: https://github.com/tapjs/tmatch
46 |
47 | ## [v1.17.0]
48 | > Apr 18, 2016
49 |
50 | - Added support for objects in `toExclude` ([#86], thanks @calebmer)
51 | - Added `toIncludeKeys` and `toExcludeKeys` ([#87], thanks @calebmer)
52 | - Added `toNotInclude` alias for `toExclude`
53 | - Deprecated `withContext` and `withArgs`. Use a closure instead.
54 | - Updated `is-equal` and `object-inspect` dependencies
55 |
56 | [v1.17.0]: https://github.com/mjackson/expect/compare/v1.16.0...v1.17.0
57 | [#86]: https://github.com/mjackson/expect/pull/86
58 | [#87]: https://github.com/mjackson/expect/pull/87
59 |
60 | ## [v1.16.0]
61 | > Mar 23, 1016
62 |
63 | - Added support for objects in `toInclude` (thanks @elado)
64 | - Minor fixes to docs
65 |
66 | [v1.16.0]: https://github.com/mjackson/expect/compare/v1.15.2...v1.16.0
67 |
68 | ## [v1.15.2]
69 | > Mar 11, 2016
70 |
71 | - Removed named exports, fixed a bad 1.15.0 release ([#72])
72 |
73 | [#72]: https://github.com/mjackson/expect/issues/72
74 | [v1.15.2]: https://github.com/mjackson/expect/compare/v1.15.0...v1.15.2
75 |
76 | ## [v1.15.0]
77 | > Mar 10, 2016
78 |
79 | - Various build system improvements
80 |
81 | [v1.15.0]: https://github.com/mjackson/expect/compare/v1.14.0...v1.15.0
82 |
83 | ## [v1.14.0]
84 | > Feb 1, 2016
85 |
86 | - Added `toBeGreaterThanOrEqualTo` and `toBeLessThanOrEqualTo` ([#11] and [#59])
87 | - Added `spy.reset()` ([#57])
88 |
89 | [v1.14.0]: https://github.com/mjackson/expect/compare/v1.13.4...v1.14.0
90 | [#11]: https://github.com/mjackson/expect/issues/11
91 | [#59]: https://github.com/mjackson/expect/issues/59
92 | [#57]: https://github.com/mjackson/expect/pull/57
93 |
94 | ## [v1.13.4]
95 | > Dec 16, 2015
96 |
97 | - Fixed comparing two arrays of nested objects when the first items are not equal ([#53])
98 |
99 | [v1.13.4]: https://github.com/mjackson/expect/compare/v1.13.3...v1.13.4
100 | [#53]: https://github.com/mjackson/expect/issues/53
101 |
102 | ## [v1.13.3]
103 | > Dec 14, 2015
104 |
105 | - Fix failing Map/Set tests
106 |
107 | [v1.13.3]: https://github.com/mjackson/expect/compare/v1.13.2...v1.13.3
108 |
109 | ## [v1.13.2]
110 | > Dec 11, 2015
111 |
112 | - Bump is-equal dependency to 1.4
113 |
114 | [v1.13.2]: https://github.com/mjackson/expect/compare/v1.13.1...v1.13.2
115 |
116 | ## [v1.13.1]
117 | > Dec 10, 2015
118 |
119 | - Fix comparisons of ES6 iterables Map and Set ([#47])
120 | - Fix comparisons of objects with circular references ([#50])
121 | - Better error messages in `toThrow`/`toNotThrow`
122 |
123 | [v1.13.1]: https://github.com/mjackson/expect/compare/v1.13.0...v1.13.1
124 | [#47]: https://github.com/mjackson/expect/issues/47
125 | [#50]: https://github.com/mjackson/expect/issues/50
126 |
127 | ## [v1.13.0]
128 | > Nov 13, 2015
129 |
130 | - Fix `toInclude` to use `deepEqual` for comparisons ([#44])
131 | - Run test suite in browsers
132 |
133 | [v1.13.0]: https://github.com/mjackson/expect/compare/v1.12.2...v1.13.0
134 | [#44]: https://github.com/mjackson/expect/issues/44
135 |
136 | ## [v1.12.2]
137 | > Oct 13, 2015
138 |
139 | - Fix postinstall script on Windows (see [#39])
140 |
141 | [v1.12.2]: https://github.com/mjackson/expect/compare/v1.12.1...v1.12.2
142 | [#39]: https://github.com/mjackson/expect/issues/39
143 |
144 | ## [v1.12.1]
145 | > Oct 10, 2015
146 |
147 | - Add support for building on Windows
148 | - Add postinstall npm script for installing from git repo
149 |
150 | [v1.12.1]: https://github.com/mjackson/expect/compare/v1.12.0...v1.12.1
151 |
152 | ## [v1.12.0]
153 | > Oct 5, 2015
154 |
155 | - Add `expect.extend(assertions)` (see [#34])
156 | - Add `expect.restoreSpies()` (see [#12])
157 | - Show object diffs using `toEqual()` in Mocha (see [#29])
158 |
159 | [v1.12.0]: https://github.com/mjackson/expect/compare/v1.11.1...v1.12.0
160 | [#29]: https://github.com/mjackson/expect/issues/29
161 | [#34]: https://github.com/mjackson/expect/pull/34
162 |
163 | ## [v1.11.1]
164 | > Sep 26, 2015
165 |
166 | - Add `spy.destroy()` (see [#12])
167 |
168 | [v1.11.1]: https://github.com/mjackson/expect/compare/v1.11.0...v1.11.1
169 | [#12]: https://github.com/mjackson/expect/issues/12
170 |
171 | ## [v1.11.0]
172 | > Sep 12, 2015
173 |
174 | - Add `expect.isSpy()`
175 | - Significant internal refactoring to use ES6 classes and the Babel transpiler
176 |
177 | [v1.11.0]: https://github.com/mjackson/expect/compare/v1.10.0...v1.11.0
178 |
179 | ## [v1.10.0]
180 | > Sep 3, 2015
181 |
182 | - Add `expect(spy).toNotHaveBeenCalled()`
183 | - Add `expect(obj).toBeAn('array')`
184 | - Add `expect(str).toNotMatch(regexp)`
185 | - Use [invariant](https://www.npmjs.com/package/invariant) instead of `assert` where applicable
186 | - Improve expectation error messages
187 | - Internal: use [eslint](https://www.npmjs.com/package/eslint) for linting
188 |
189 | [v1.10.0]: https://github.com/mjackson/expect/compare/v1.9.0...v1.10.0
190 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Michael Jackson
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # expect [![Travis][build-badge]][build] [![npm package][npm-badge]][npm]
2 |
3 | [build-badge]: https://img.shields.io/travis/mjackson/expect/master.svg?style=flat-square
4 | [build]: https://travis-ci.org/mjackson/expect
5 |
6 | [npm-badge]: https://img.shields.io/npm/v/expect.svg?style=flat-square
7 | [npm]: https://www.npmjs.org/package/expect
8 |
9 |
10 | ## Notice
11 |
12 | This package [has been donated](https://github.com/facebook/jest/issues/1679) to [Jest](https://github.com/facebook/jest/tree/master/packages/expect). This means that all future development of `expect` v21+ will take place at [facebook/jest](https://github.com/facebook/jest).
13 |
14 | You can use [`jest-codemods`](https://github.com/skovhus/jest-codemods) to automatically migrate your old tests using `expect@1.x` to the new jest version of `expect` (>= 21)
15 |
16 | Versions prior to v21 will receive limited support and bugfixes, and any future < v21 releases will be published on an npm tag that is not "latest", to avoid causing problems for v21+ users.
17 |
18 |
19 | ## expect@1.x documentation
20 |
21 | [expect](https://github.com/mjackson/expect) lets you write better assertions.
22 |
23 | When you use `expect`, you write assertions similarly to how you would say them, e.g. "I expect this value to be equal to 3" or "I expect this array to contain 3". When you write assertions in this way, you don't need to remember the order of actual and expected arguments to functions like `assert.equal`, which helps you write better tests.
24 |
25 | You can think of `expect` as a more compact alternative to [Chai](http://chaijs.com/) or [Sinon.JS](http://sinonjs.org/), just without the pretty website. ;)
26 |
27 | ## Installation
28 |
29 | Using [npm](https://www.npmjs.org/):
30 |
31 | $ npm install --save expect
32 |
33 | Then, use as you would anything else:
34 |
35 | ```js
36 | // using ES6 modules
37 | import expect, { createSpy, spyOn, isSpy } from 'expect'
38 |
39 | // using CommonJS modules
40 | var expect = require('expect')
41 | var createSpy = expect.createSpy
42 | var spyOn = expect.spyOn
43 | var isSpy = expect.isSpy
44 | ```
45 |
46 | The UMD build is also available on [unpkg](https://unpkg.com):
47 |
48 | ```html
49 |
50 | ```
51 |
52 | You can find the library on `window.expect`.
53 |
54 | ## Assertions
55 |
56 | ### toExist
57 |
58 | > `expect(object).toExist([message])`
59 |
60 | Asserts the given `object` is truthy.
61 |
62 | ```js
63 | expect('something truthy').toExist()
64 | ```
65 |
66 | Aliases:
67 | - `toBeTruthy`
68 |
69 | ### toNotExist
70 |
71 | > `expect(object).toNotExist([message])`
72 |
73 | Asserts the given `object` is falsy.
74 |
75 | ```js
76 | expect(null).toNotExist()
77 | ```
78 |
79 | Aliases:
80 | - `toBeFalsy`
81 |
82 | ### toBe
83 |
84 | > `expect(object).toBe(value, [message])`
85 |
86 | Asserts that `object` is strictly equal to `value` using `===`.
87 |
88 | ### toNotBe
89 |
90 | > `expect(object).toNotBe(value, [message])`
91 |
92 | Asserts that `object` is not strictly equal to `value` using `===`.
93 |
94 | ### toEqual
95 |
96 | > `expect(object).toEqual(value, [message])`
97 |
98 | Asserts that the given `object` equals `value` using [is-equal](https://www.npmjs.com/package/is-equal).
99 |
100 | ### toNotEqual
101 |
102 | > `expect(object).toNotEqual(value, [message])`
103 |
104 | Asserts that the given `object` is not equal to `value` using [is-equal](https://www.npmjs.com/package/is-equal).
105 |
106 | ### toThrow
107 |
108 | > `expect(block).toThrow([error], [message])`
109 |
110 | Asserts that the given `block` `throw`s an error. The `error` argument may be a constructor (to test using `instanceof`), or a string/`RegExp` to test against `error.message`.
111 |
112 | ```js
113 | expect(function () {
114 | throw new Error('boom!')
115 | }).toThrow(/boom/)
116 | ```
117 |
118 | ### toNotThrow
119 |
120 | > `expect(block).toNotThrow([message])`
121 |
122 | Asserts that the given `block` does not `throw`.
123 |
124 | ### toBeA(constructor)
125 |
126 | > `expect(object).toBeA(constructor, [message])`
127 | > `expect(object).toBeAn(constructor, [message])`
128 |
129 | Asserts the given `object` is an `instanceof constructor`.
130 |
131 | ```js
132 | expect(new User).toBeA(User)
133 | expect(new Asset).toBeAn(Asset)
134 | ```
135 |
136 | Aliases:
137 | - `toBeAn`
138 |
139 | ### toBeA(string)
140 |
141 | > `expect(object).toBeA(string, [message])`
142 | > `expect(object).toBeAn(string, [message])`
143 |
144 | Asserts the `typeof` the given `object` is `string`.
145 |
146 | ```js
147 | expect(2).toBeA('number')
148 | ```
149 |
150 | Aliases:
151 | - `toBeAn`
152 |
153 | ### toNotBeA(constructor)
154 |
155 | > `expect(object).toNotBeA(constructor, [message])`
156 | > `expect(object).toNotBeAn(constructor, [message])`
157 |
158 | Asserts the given `object` is *not* an `instanceof constructor`.
159 |
160 | ```js
161 | expect(new Asset).toNotBeA(User)
162 | expect(new User).toNotBeAn(Asset)
163 | ```
164 |
165 | Aliases:
166 | - `toNotBeAn`
167 |
168 | ### toNotBeA(string)
169 |
170 | > `expect(object).toNotBeA(string, [message])`
171 | > `expect(object).toNotBeAn(string, [message])`
172 |
173 | Asserts the `typeof` the given `object` is *not* `string`.
174 |
175 | ```js
176 | expect('a string').toNotBeA('number')
177 | expect(2).toNotBeAn('object')
178 | ```
179 |
180 | Aliases:
181 | - `toNotBeAn`
182 |
183 | ### toMatch
184 |
185 | > `expect(string).toMatch(pattern, [message])`
186 | > `expect(object).toMatch(pattern, [message])`
187 |
188 | Asserts the given `string` or `object` matches a `pattern`. When using a string, `pattern` must be a `RegExp`. When using an object, `pattern` may be anything acceptable to [`tmatch`](https://github.com/tapjs/tmatch).
189 |
190 | ```js
191 | expect('a string').toMatch(/string/)
192 | expect({
193 | statusCode: 200,
194 | headers: {
195 | server: 'nginx/1.6.5'
196 | }
197 | }).toMatch({
198 | headers: {
199 | server: /nginx/
200 | }
201 | })
202 | ```
203 |
204 | ### toNotMatch
205 |
206 | > `expect(string).toNotMatch(pattern, [message])`
207 | > `expect(object).toNotMatch(pattern, [message])`
208 |
209 | Asserts the given `string` or `object` does not match a `pattern`. When using a string, `pattern` must be a `RegExp`. When using an object, `pattern` may be anything acceptable to [`tmatch`](https://github.com/tapjs/tmatch).
210 |
211 | ```js
212 | expect('a string').toMatch(/string/)
213 | expect({
214 | statusCode: 200,
215 | headers: {
216 | server: 'nginx/1.6.5'
217 | }
218 | }).toNotMatch({
219 | headers: {
220 | server: /apache/
221 | }
222 | })
223 | ```
224 |
225 | ### toBeLessThan
226 |
227 | > `expect(number).toBeLessThan(value, [message])`
228 | > `expect(number).toBeFewerThan(value, [message])`
229 |
230 | Asserts the given `number` is less than `value`.
231 |
232 | ```js
233 | expect(2).toBeLessThan(3)
234 | ```
235 |
236 | Aliases:
237 | - `toBeFewerThan`
238 |
239 | ### toBeLessThanOrEqualTo
240 |
241 | > `expect(number).toBeLessThanOrEqualTo(value, [message])`
242 |
243 | Asserts the given `number` is less than or equal to `value`.
244 |
245 | ```js
246 | expect(2).toBeLessThanOrEqualTo(3)
247 | ```
248 |
249 | ### toBeGreaterThan
250 |
251 | > `expect(number).toBeGreaterThan(value, [message])`
252 | > `expect(number).toBeMoreThan(value, [message])`
253 |
254 | Asserts the given `number` is greater than `value`.
255 |
256 | ```js
257 | expect(3).toBeGreaterThan(2)
258 | ```
259 |
260 | Aliases:
261 | - `toBeMoreThan`
262 |
263 | ### toBeGreaterThanOrEqualTo
264 |
265 | > `expect(number).toBeGreaterThanOrEqualTo(value, [message])`
266 |
267 | Asserts the given `number` is greater than or equal to `value`.
268 |
269 | ```js
270 | expect(3).toBeGreaterThanOrEqualTo(2)
271 | ```
272 |
273 | ### toInclude
274 |
275 | > `expect(array).toInclude(value, [comparator], [message])`
276 | > `expect(object).toInclude(value, [comparator], [message])`
277 | > `expect(string).toInclude(value, [message])`
278 |
279 | Asserts that a given `value` is included (or "contained") within another. The `actual` value may be an array, object, or a string. The `comparator` function, if given, should compare two objects and `return false` if they are not equal. The default is to use [`isEqual`](https://github.com/ljharb/is-equal).
280 |
281 | ```js
282 | expect([ 1, 2, 3 ]).toInclude(3)
283 | expect({ a: 1, b: 2 }).toInclude({ b: 2 })
284 | expect({ a: 1, b: 2, c: { d: 3 } }).toInclude({ b: 2, c: { d: 3 } })
285 | expect('hello world').toInclude('world')
286 | ```
287 |
288 | Aliases:
289 | - `toContain`
290 |
291 | ### toExclude
292 |
293 | > `expect(array).toExclude(value, [comparator], [message])`
294 | > `expect(object).toExclude(value, [comparator], [message])`
295 | > `expect(string).toExclude(value, [message])`
296 |
297 | Asserts that a given `value` is not included (or "contained") within another. The `actual` value may be an array, object, or a string. The `comparator` function, if given, should compare two objects and `return false` if they are not equal. The default is to use [`isEqual`](https://github.com/ljharb/is-equal).
298 |
299 | ```js
300 | expect([ 1, 2, 3 ]).toExclude(4)
301 | expect({ a: 1, b: 2 }).toExclude({ c: 2 })
302 | expect({ a: 1, b: 2 }).toExclude({ b: 3 })
303 | expect({ a: 1, b: 2, c: { d: 3 } }).toExclude({ c: { d: 4 } })
304 | expect('hello world').toExclude('goodbye')
305 | ```
306 |
307 | Aliases:
308 | - `toNotContain`
309 | - `toNotInclude`
310 |
311 | ### toIncludeKey(s)
312 |
313 | > `expect(object).toIncludeKeys(keys, [comparator], [message])`
314 | > `expect(object).toIncludeKey(key, [comparator], [message])`
315 |
316 | Asserts that the given `object` (may be an array, or a function, or anything with keys) contains *all* of the provided keys. The optional parameter `comparator` is a function which if given an object and a string key, it should return a boolean detailing whether or not the key exists in the object. By default, a shallow check with `Object.prototype.hasOwnProperty` is performed.
317 |
318 | ```js
319 | expect({ a: 1 }).toIncludeKey('a')
320 | expect({ a: 1, b: 2 }).toIncludeKeys([ 'a', 'b' ])
321 | ```
322 |
323 | Aliases:
324 | - `toContainKey(s)`
325 |
326 | ### toExcludeKey(s)
327 |
328 | > `expect(object).toExcludeKeys(keys, [comparator], [message])`
329 | > `expect(object).toExcludeKey(key, [comparator], [message])`
330 |
331 | Asserts that the given `object` (may be an array, or a function, or anything with keys) does not contain *any* of the provided keys. The optional parameter `comparator` is a function which if given an object and a string key, it should return a boolean detailing whether or not the key exists in the object. By default, a shallow check with `Object.prototype.hasOwnProperty` is performed.
332 |
333 | ```js
334 | expect({ a: 1 }).toExcludeKey('b')
335 | expect({ a: 1, b: 2 }).toExcludeKeys([ 'c', 'd' ])
336 | ```
337 |
338 | Aliases:
339 | - `toNotContainKey(s)`
340 | - `toNotIncludeKey(s)`
341 |
342 | ### (spy) toHaveBeenCalled
343 |
344 | > `expect(spy).toHaveBeenCalled([message])`
345 |
346 | Asserts the given `spy` function has been called at least once.
347 |
348 | ```js
349 | expect(spy).toHaveBeenCalled()
350 | ```
351 |
352 | ### (spy) toNotHaveBeenCalled
353 |
354 | > `expect(spy).toNotHaveBeenCalled([message])`
355 |
356 | Asserts the given `spy` function has *not* been called.
357 |
358 | ```js
359 | expect(spy).toNotHaveBeenCalled()
360 | ```
361 |
362 | ### (spy) toHaveBeenCalledWith
363 |
364 | > `expect(spy).toHaveBeenCalledWith(...args)`
365 |
366 | Asserts the given `spy` function has been called with the expected arguments.
367 |
368 | ```js
369 | expect(spy).toHaveBeenCalledWith('foo', 'bar')
370 | ```
371 |
372 | ## Chaining Assertions
373 |
374 | Every assertion returns an `Expectation` object, so you can chain assertions together.
375 |
376 | ```js
377 | expect(3.14)
378 | .toExist()
379 | .toBeLessThan(4)
380 | .toBeGreaterThan(3)
381 | ```
382 |
383 | ## Spies
384 |
385 | expect also includes the ability to create spy functions that can track the calls that are made to other functions and make various assertions based on the arguments and context that were used.
386 |
387 | ```js
388 | var video = {
389 | play: function () {},
390 | pause: function () {},
391 | rewind: function () {}
392 | }
393 |
394 | var spy = expect.spyOn(video, 'play')
395 |
396 | video.play('some', 'args')
397 |
398 | expect(spy.calls.length).toEqual(1)
399 | expect(spy.calls[0].context).toBe(video)
400 | expect(spy.calls[0].arguments).toEqual([ 'some', 'args' ])
401 | expect(spy).toHaveBeenCalled()
402 | expect(spy).toHaveBeenCalledWith('some', 'args')
403 |
404 | spy.restore()
405 | expect.restoreSpies()
406 | ```
407 |
408 | ### createSpy
409 |
410 | > `expect.createSpy([fn], [restore])`
411 |
412 | Creates a spy function with an (optional) implementation and (optional) restore logic. (In order for your provided implementation to be used, you must call [`andCallThrough`](https://github.com/mjackson/expect#andcallthrough).) For this reason, it's better to use [`andCall`](https://github.com/mjackson/expect#andcall) if you don't need custom restore logic.
413 |
414 | ```js
415 | var spy = expect.createSpy()
416 | ```
417 |
418 | ### spyOn
419 |
420 | > `expect.spyOn(target, method)`
421 |
422 | Replaces the `method` in `target` with a spy.
423 |
424 | ```js
425 | var video = {
426 | play: function () {}
427 | }
428 |
429 | var spy = expect.spyOn(video, 'play')
430 | video.play()
431 |
432 | spy.restore()
433 | ```
434 |
435 | ### restoreSpies
436 |
437 | > `expect.restoreSpies()`
438 |
439 | Restores all spies created with `expect.spyOn()`. This is the same as calling `spy.restore()` on all spies created.
440 |
441 | ```js
442 | // mocha.js example
443 | beforeEach(function () {
444 | expect.spyOn(profile, 'load')
445 | })
446 |
447 | afterEach(function () {
448 | expect.restoreSpies()
449 | })
450 |
451 | it('works', function () {
452 | profile.load()
453 | expect(profile.load).toHaveBeenCalled()
454 | })
455 | ```
456 |
457 | ## Spy methods and properties
458 |
459 | ### andCall
460 |
461 | > `spy.andCall(fn)`
462 |
463 | Makes the spy invoke a function `fn` when called.
464 |
465 | ```js
466 | var dice = createSpy().andCall(function () {
467 | return (Math.random() * 6) | 0
468 | })
469 | ```
470 |
471 | ### andCallThrough
472 |
473 | > `spy.andCallThrough()`
474 |
475 | Makes the spy call the original function it's spying on.
476 |
477 | ```js
478 | spyOn(profile, 'load').andCallThrough()
479 |
480 | var getEmail = createSpy(function () {
481 | return "hi@gmail.com"
482 | }).andCallThrough()
483 | ```
484 |
485 | ### andReturn
486 |
487 | > `spy.andReturn(object)`
488 |
489 | Makes the spy return a value.
490 |
491 | ```js
492 | var dice = expect.createSpy().andReturn(3)
493 | ```
494 |
495 | ### andThrow
496 |
497 | > `spy.andThrow(error)`
498 |
499 | Makes the spy throw an `error` when called.
500 |
501 | ```js
502 | var failing = expect.createSpy()
503 | .andThrow(new Error('Not working'))
504 | ```
505 |
506 | ### restore
507 |
508 | > `spy.restore()`
509 |
510 | Restores a spy originally created with `expect.spyOn()`.
511 |
512 | ### reset
513 |
514 | > `spy.reset()`
515 |
516 | Clears out all saved calls to the spy.
517 |
518 | ### calls
519 |
520 | > `spy.calls`
521 |
522 | An array of objects representing all saved calls to the spy.
523 |
524 | You can use the length of the `calls` array to make assertions about how many times you expect the spy to have been called.
525 |
526 | ```js
527 | expect(spy.calls.length).toEqual(3)
528 | ```
529 |
530 | You can also use the array to make assertions about each individual call. Each call object contains the following properties:
531 |
532 | #### context
533 |
534 | > `spy.calls[index].context`
535 |
536 | The `this` value of the call's execution context.
537 |
538 | #### arguments
539 |
540 | > `spy.calls[index].arguments`
541 |
542 | An array of the arguments passed to the spy for the particular call.
543 |
544 | ## Extending expect
545 |
546 | You can add your own assertions using `expect.extend` and `expect.assert`:
547 |
548 | ```js
549 | expect.extend({
550 | toBeAColor() {
551 | expect.assert(
552 | this.actual.match(/^#[a-fA-F0-9]{3,6}$/),
553 | 'expected %s to be an HTML color',
554 | this.actual
555 | )
556 | return this
557 | }
558 | })
559 |
560 | expect('#ff00ff').toBeAColor()
561 | ```
562 |
563 | ## Extensions
564 |
565 | - [expect-element](https://github.com/mjackson/expect-element) Adds assertions that are useful for DOM elements
566 | - [expect-jsx](https://github.com/algolia/expect-jsx) Adds things like `expect(ReactComponent).toEqualJSX()`
567 | - [expect-predicate](https://github.com/erikras/expect-predicate) Adds assertions based on arbitrary predicates
568 | - [expect-enzyme](https://github.com/PsychoLlama/expect-enzyme) Augments and extends expect to supercharge your enzyme assertions
569 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack')
2 | const projectName = require('./package').name
3 |
4 | module.exports = (config) => {
5 | const customLaunchers = {
6 | BS_Chrome: {
7 | base: 'BrowserStack',
8 | os: 'Windows',
9 | os_version: '10',
10 | browser: 'chrome',
11 | browser_version: '47.0'
12 | },
13 | BS_Firefox: {
14 | base: 'BrowserStack',
15 | os: 'Windows',
16 | os_version: '10',
17 | browser: 'firefox',
18 | browser_version: '43.0'
19 | },
20 | BS_Safari: {
21 | base: 'BrowserStack',
22 | os: 'OS X',
23 | os_version: 'El Capitan',
24 | browser: 'safari',
25 | browser_version: '9.0'
26 | },
27 | BS_MobileSafari9: {
28 | base: 'BrowserStack',
29 | os: 'ios',
30 | os_version: '9.1',
31 | browser: 'iphone',
32 | real_mobile: false
33 | },
34 | BS_InternetExplorer10: {
35 | base: 'BrowserStack',
36 | os: 'Windows',
37 | os_version: '8',
38 | browser: 'ie',
39 | browser_version: '10.0'
40 | },
41 | BS_InternetExplorer11: {
42 | base: 'BrowserStack',
43 | os: 'Windows',
44 | os_version: '10',
45 | browser: 'ie',
46 | browser_version: '11.0'
47 | }
48 | }
49 |
50 | config.set({
51 | customLaunchers: customLaunchers,
52 |
53 | browsers: [ 'Chrome' ],
54 | frameworks: [ 'mocha' ],
55 | reporters: [ 'mocha' ],
56 |
57 | files: [
58 | 'tests.webpack.js'
59 | ],
60 |
61 | preprocessors: {
62 | 'tests.webpack.js': [ 'webpack', 'sourcemap' ]
63 | },
64 |
65 | webpack: {
66 | devtool: 'inline-source-map',
67 | module: {
68 | loaders: [
69 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel' }
70 | ]
71 | },
72 | plugins: [
73 | new webpack.DefinePlugin({
74 | 'process.env.NODE_ENV': JSON.stringify('test')
75 | })
76 | ]
77 | },
78 |
79 | webpackServer: {
80 | noInfo: true
81 | }
82 | })
83 |
84 | if (process.env.USE_CLOUD) {
85 | config.browsers = Object.keys(customLaunchers)
86 | config.reporters = [ 'dots' ]
87 | config.concurrency = 2
88 |
89 | config.browserDisconnectTimeout = 10000
90 | config.browserDisconnectTolerance = 3
91 |
92 | if (process.env.TRAVIS) {
93 | config.browserStack = {
94 | project: projectName,
95 | build: process.env.TRAVIS_BUILD_NUMBER,
96 | name: process.env.TRAVIS_JOB_NUMBER
97 | }
98 |
99 | config.singleRun = true
100 | } else {
101 | config.browserStack = {
102 | project: projectName
103 | }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/modules/Expectation.js:
--------------------------------------------------------------------------------
1 | import has from 'has'
2 | import tmatch from 'tmatch'
3 | import assert from './assert'
4 | import { isSpy } from './SpyUtils'
5 | import {
6 | isA,
7 | isFunction,
8 | isArray,
9 | isEqual,
10 | isObject,
11 | functionThrows,
12 | arrayContains,
13 | objectContains,
14 | stringContains
15 | } from './TestUtils'
16 |
17 | /**
18 | * An Expectation is a wrapper around an assertion that allows it to be written
19 | * in a more natural style, without the need to remember the order of arguments.
20 | * This helps prevent you from making mistakes when writing tests.
21 | */
22 | class Expectation {
23 | constructor(actual) {
24 | this.actual = actual
25 |
26 | if (isFunction(actual)) {
27 | this.context = null
28 | this.args = []
29 | }
30 | }
31 |
32 | toExist(message) {
33 | assert(
34 | this.actual,
35 | (message || 'Expected %s to exist'),
36 | this.actual
37 | )
38 |
39 | return this
40 | }
41 |
42 | toNotExist(message) {
43 | assert(
44 | !this.actual,
45 | (message || 'Expected %s to not exist'),
46 | this.actual
47 | )
48 |
49 | return this
50 | }
51 |
52 | toBe(value, message) {
53 | assert(
54 | this.actual === value,
55 | (message || 'Expected %s to be %s'),
56 | this.actual,
57 | value
58 | )
59 |
60 | return this
61 | }
62 |
63 | toNotBe(value, message) {
64 | assert(
65 | this.actual !== value,
66 | (message || 'Expected %s to not be %s'),
67 | this.actual,
68 | value
69 | )
70 |
71 | return this
72 | }
73 |
74 | toEqual(value, message) {
75 | try {
76 | assert(
77 | isEqual(this.actual, value),
78 | (message || 'Expected %s to equal %s'),
79 | this.actual,
80 | value
81 | )
82 | } catch (error) {
83 | // These attributes are consumed by Mocha to produce a diff output.
84 | error.actual = this.actual
85 | error.expected = value
86 | error.showDiff = true
87 | throw error
88 | }
89 |
90 | return this
91 | }
92 |
93 | toNotEqual(value, message) {
94 | assert(
95 | !isEqual(this.actual, value),
96 | (message || 'Expected %s to not equal %s'),
97 | this.actual,
98 | value
99 | )
100 |
101 | return this
102 | }
103 |
104 | toThrow(value, message) {
105 | assert(
106 | isFunction(this.actual),
107 | 'The "actual" argument in expect(actual).toThrow() must be a function, %s was given',
108 | this.actual
109 | )
110 |
111 | assert(
112 | functionThrows(this.actual, this.context, this.args, value),
113 | (message || 'Expected %s to throw %s'),
114 | this.actual,
115 | value || 'an error'
116 | )
117 |
118 | return this
119 | }
120 |
121 | toNotThrow(value, message) {
122 | assert(
123 | isFunction(this.actual),
124 | 'The "actual" argument in expect(actual).toNotThrow() must be a function, %s was given',
125 | this.actual
126 | )
127 |
128 | assert(
129 | !functionThrows(this.actual, this.context, this.args, value),
130 | (message || 'Expected %s to not throw %s'),
131 | this.actual,
132 | value || 'an error'
133 | )
134 |
135 | return this
136 | }
137 |
138 | toBeA(value, message) {
139 | assert(
140 | isFunction(value) || typeof value === 'string',
141 | 'The "value" argument in toBeA(value) must be a function or a string'
142 | )
143 |
144 | assert(
145 | isA(this.actual, value),
146 | (message || 'Expected %s to be a %s'),
147 | this.actual,
148 | value
149 | )
150 |
151 | return this
152 | }
153 |
154 | toNotBeA(value, message) {
155 | assert(
156 | isFunction(value) || typeof value === 'string',
157 | 'The "value" argument in toNotBeA(value) must be a function or a string'
158 | )
159 |
160 | assert(
161 | !isA(this.actual, value),
162 | (message || 'Expected %s to not be a %s'),
163 | this.actual,
164 | value
165 | )
166 |
167 | return this
168 | }
169 |
170 | toMatch(pattern, message) {
171 | assert(
172 | tmatch(this.actual, pattern),
173 | (message || 'Expected %s to match %s'),
174 | this.actual,
175 | pattern
176 | )
177 |
178 | return this
179 | }
180 |
181 | toNotMatch(pattern, message) {
182 | assert(
183 | !tmatch(this.actual, pattern),
184 | (message || 'Expected %s to not match %s'),
185 | this.actual,
186 | pattern
187 | )
188 |
189 | return this
190 | }
191 |
192 | toBeLessThan(value, message) {
193 | assert(
194 | typeof this.actual === 'number',
195 | 'The "actual" argument in expect(actual).toBeLessThan() must be a number'
196 | )
197 |
198 | assert(
199 | typeof value === 'number',
200 | 'The "value" argument in toBeLessThan(value) must be a number'
201 | )
202 |
203 | assert(
204 | this.actual < value,
205 | (message || 'Expected %s to be less than %s'),
206 | this.actual,
207 | value
208 | )
209 |
210 | return this
211 | }
212 |
213 | toBeLessThanOrEqualTo(value, message) {
214 | assert(
215 | typeof this.actual === 'number',
216 | 'The "actual" argument in expect(actual).toBeLessThanOrEqualTo() must be a number'
217 | )
218 |
219 | assert(
220 | typeof value === 'number',
221 | 'The "value" argument in toBeLessThanOrEqualTo(value) must be a number'
222 | )
223 |
224 | assert(
225 | this.actual <= value,
226 | (message || 'Expected %s to be less than or equal to %s'),
227 | this.actual,
228 | value
229 | )
230 |
231 | return this
232 | }
233 |
234 | toBeGreaterThan(value, message) {
235 | assert(
236 | typeof this.actual === 'number',
237 | 'The "actual" argument in expect(actual).toBeGreaterThan() must be a number'
238 | )
239 |
240 | assert(
241 | typeof value === 'number',
242 | 'The "value" argument in toBeGreaterThan(value) must be a number'
243 | )
244 |
245 | assert(
246 | this.actual > value,
247 | (message || 'Expected %s to be greater than %s'),
248 | this.actual,
249 | value
250 | )
251 |
252 | return this
253 | }
254 |
255 | toBeGreaterThanOrEqualTo(value, message) {
256 | assert(
257 | typeof this.actual === 'number',
258 | 'The "actual" argument in expect(actual).toBeGreaterThanOrEqualTo() must be a number'
259 | )
260 |
261 | assert(
262 | typeof value === 'number',
263 | 'The "value" argument in toBeGreaterThanOrEqualTo(value) must be a number'
264 | )
265 |
266 | assert(
267 | this.actual >= value,
268 | (message || 'Expected %s to be greater than or equal to %s'),
269 | this.actual,
270 | value
271 | )
272 |
273 | return this
274 | }
275 |
276 | toInclude(value, compareValues, message) {
277 | if (typeof compareValues === 'string') {
278 | message = compareValues
279 | compareValues = null
280 | }
281 |
282 | if (compareValues == null)
283 | compareValues = isEqual
284 |
285 | let contains = false
286 |
287 | if (isArray(this.actual)) {
288 | contains = arrayContains(this.actual, value, compareValues)
289 | } else if (isObject(this.actual)) {
290 | contains = objectContains(this.actual, value, compareValues)
291 | } else if (typeof this.actual === 'string') {
292 | contains = stringContains(this.actual, value)
293 | } else {
294 | assert(
295 | false,
296 | 'The "actual" argument in expect(actual).toInclude() must be an array, object, or a string'
297 | )
298 | }
299 |
300 | assert(
301 | contains,
302 | message || 'Expected %s to include %s',
303 | this.actual,
304 | value
305 | )
306 |
307 | return this
308 | }
309 |
310 | toExclude(value, compareValues, message) {
311 | if (typeof compareValues === 'string') {
312 | message = compareValues
313 | compareValues = null
314 | }
315 |
316 | if (compareValues == null)
317 | compareValues = isEqual
318 |
319 | let contains = false
320 |
321 | if (isArray(this.actual)) {
322 | contains = arrayContains(this.actual, value, compareValues)
323 | } else if (isObject(this.actual)) {
324 | contains = objectContains(this.actual, value, compareValues)
325 | } else if (typeof this.actual === 'string') {
326 | contains = stringContains(this.actual, value)
327 | } else {
328 | assert(
329 | false,
330 | 'The "actual" argument in expect(actual).toExclude() must be an array, object, or a string'
331 | )
332 | }
333 |
334 | assert(
335 | !contains,
336 | message || 'Expected %s to exclude %s',
337 | this.actual,
338 | value
339 | )
340 |
341 | return this
342 | }
343 |
344 | toIncludeKeys(keys, comparator, message) {
345 | if (typeof comparator === 'string') {
346 | message = comparator
347 | comparator = null
348 | }
349 |
350 | if (comparator == null)
351 | comparator = has
352 |
353 | assert(
354 | typeof this.actual === 'object',
355 | 'The "actual" argument in expect(actual).toIncludeKeys() must be an object, not %s',
356 | this.actual
357 | )
358 |
359 | assert(
360 | isArray(keys),
361 | 'The "keys" argument in expect(actual).toIncludeKeys(keys) must be an array, not %s',
362 | keys
363 | )
364 |
365 | const contains = keys.every(key => comparator(this.actual, key))
366 |
367 | assert(
368 | contains,
369 | message || 'Expected %s to include key(s) %s',
370 | this.actual,
371 | keys.join(', ')
372 | )
373 |
374 | return this
375 | }
376 |
377 | toIncludeKey(key, ...args) {
378 | return this.toIncludeKeys([ key ], ...args)
379 | }
380 |
381 | toExcludeKeys(keys, comparator, message) {
382 | if (typeof comparator === 'string') {
383 | message = comparator
384 | comparator = null
385 | }
386 |
387 | if (comparator == null)
388 | comparator = has
389 |
390 | assert(
391 | typeof this.actual === 'object',
392 | 'The "actual" argument in expect(actual).toExcludeKeys() must be an object, not %s',
393 | this.actual
394 | )
395 |
396 | assert(
397 | isArray(keys),
398 | 'The "keys" argument in expect(actual).toIncludeKeys(keys) must be an array, not %s',
399 | keys
400 | )
401 |
402 | const contains = keys.every(key => comparator(this.actual, key))
403 |
404 | assert(
405 | !contains,
406 | message || 'Expected %s to exclude key(s) %s',
407 | this.actual,
408 | keys.join(', ')
409 | )
410 |
411 | return this
412 | }
413 |
414 | toExcludeKey(key, ...args) {
415 | return this.toExcludeKeys([ key ], ...args)
416 | }
417 |
418 | toHaveBeenCalled(message) {
419 | const spy = this.actual
420 |
421 | assert(
422 | isSpy(spy),
423 | 'The "actual" argument in expect(actual).toHaveBeenCalled() must be a spy'
424 | )
425 |
426 | assert(
427 | spy.calls.length > 0,
428 | (message || 'spy was not called')
429 | )
430 |
431 | return this
432 | }
433 |
434 | toHaveBeenCalledWith(...expectedArgs) {
435 | const spy = this.actual
436 |
437 | assert(
438 | isSpy(spy),
439 | 'The "actual" argument in expect(actual).toHaveBeenCalledWith() must be a spy'
440 | )
441 |
442 | assert(
443 | spy.calls.some(call => isEqual(call.arguments, expectedArgs)),
444 | 'spy was never called with %s',
445 | expectedArgs
446 | )
447 |
448 | return this
449 | }
450 |
451 | toNotHaveBeenCalled(message) {
452 | const spy = this.actual
453 |
454 | assert(
455 | isSpy(spy),
456 | 'The "actual" argument in expect(actual).toNotHaveBeenCalled() must be a spy'
457 | )
458 |
459 | assert(
460 | spy.calls.length === 0,
461 | (message || 'spy was not supposed to be called')
462 | )
463 |
464 | return this
465 | }
466 | }
467 |
468 | const deprecate = (fn, message) => {
469 | let alreadyWarned = false
470 |
471 | return function (...args) {
472 | if (!alreadyWarned) {
473 | alreadyWarned = true
474 | console.warn(message) // eslint-disable-line no-console
475 | }
476 |
477 | return fn.apply(this, args)
478 | }
479 | }
480 |
481 | Expectation.prototype.withContext = deprecate(function (context) {
482 | assert(
483 | isFunction(this.actual),
484 | 'The "actual" argument in expect(actual).withContext() must be a function'
485 | )
486 |
487 | this.context = context
488 |
489 | return this
490 | }, `
491 | withContext is deprecated; use a closure instead.
492 |
493 | expect(fn).withContext(context).toThrow()
494 |
495 | becomes
496 |
497 | expect(() => fn.call(context)).toThrow()
498 | `)
499 |
500 | Expectation.prototype.withArgs = deprecate(function (...args) {
501 | assert(
502 | isFunction(this.actual),
503 | 'The "actual" argument in expect(actual).withArgs() must be a function'
504 | )
505 |
506 | if (args.length)
507 | this.args = this.args.concat(...args)
508 |
509 | return this
510 | }, `
511 | withArgs is deprecated; use a closure instead.
512 |
513 | expect(fn).withArgs(a, b, c).toThrow()
514 |
515 | becomes
516 |
517 | expect(() => fn(a, b, c)).toThrow()
518 | `)
519 |
520 | const aliases = {
521 | toBeAn: 'toBeA',
522 | toNotBeAn: 'toNotBeA',
523 | toBeTruthy: 'toExist',
524 | toBeFalsy: 'toNotExist',
525 | toBeFewerThan: 'toBeLessThan',
526 | toBeMoreThan: 'toBeGreaterThan',
527 | toContain: 'toInclude',
528 | toNotContain: 'toExclude',
529 | toNotInclude: 'toExclude',
530 | toContainKeys: 'toIncludeKeys',
531 | toNotContainKeys: 'toExcludeKeys',
532 | toNotIncludeKeys: 'toExcludeKeys',
533 | toContainKey: 'toIncludeKey',
534 | toNotContainKey: 'toExcludeKey',
535 | toNotIncludeKey: 'toExcludeKey'
536 | }
537 |
538 | for (const alias in aliases)
539 | if (aliases.hasOwnProperty(alias))
540 | Expectation.prototype[alias] = Expectation.prototype[aliases[alias]]
541 |
542 | export default Expectation
543 |
--------------------------------------------------------------------------------
/modules/SpyUtils.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable prefer-rest-params, no-underscore-dangle*/
2 | import { supportsDescriptors } from 'define-properties'
3 | import assert from './assert'
4 | import { isFunction } from './TestUtils'
5 |
6 | const noop = () => {}
7 |
8 | const supportsConfigurableFnLength = supportsDescriptors &&
9 | Object.getOwnPropertyDescriptor(() => {}, 'length').configurable
10 |
11 | export const isSpy = (object) =>
12 | object && object.__isSpy === true
13 |
14 | let spies = []
15 |
16 | export const restoreSpies = () => {
17 | for (let i = spies.length - 1; i >= 0; i--)
18 | spies[i].restore()
19 |
20 | spies = []
21 | }
22 |
23 | export const createSpy = (fn, restore = noop) => {
24 | if (fn == null)
25 | fn = noop
26 |
27 | assert(
28 | isFunction(fn),
29 | 'createSpy needs a function'
30 | )
31 |
32 | let targetFn, thrownValue, returnValue, spy
33 |
34 | function spyLogic() {
35 | spy.calls.push({
36 | context: this,
37 | arguments: Array.prototype.slice.call(arguments, 0)
38 | })
39 |
40 | if (targetFn)
41 | return targetFn.apply(this, arguments)
42 |
43 | if (thrownValue)
44 | throw thrownValue
45 |
46 | return returnValue
47 | }
48 |
49 | if (supportsConfigurableFnLength) {
50 | spy = Object.defineProperty(spyLogic, 'length',
51 | { value: fn.length, writable: false, enumerable: false, configurable: true })
52 | } else {
53 | spy = new Function('spy', `return function(${ // eslint-disable-line no-new-func
54 | [ ...Array(fn.length) ].map((_, i) => `_${i}`).join(',')
55 | }) {
56 | return spy.apply(this, arguments)
57 | }`)(spyLogic)
58 | }
59 |
60 | spy.calls = []
61 |
62 | spy.andCall = (otherFn) => {
63 | targetFn = otherFn
64 | return spy
65 | }
66 |
67 | spy.andCallThrough = () =>
68 | spy.andCall(fn)
69 |
70 | spy.andThrow = (value) => {
71 | thrownValue = value
72 | return spy
73 | }
74 |
75 | spy.andReturn = (value) => {
76 | returnValue = value
77 | return spy
78 | }
79 |
80 | spy.getLastCall = () =>
81 | spy.calls[spy.calls.length - 1]
82 |
83 | spy.reset = () => {
84 | spy.calls = []
85 | }
86 |
87 | spy.restore = spy.destroy = restore
88 |
89 | spy.__isSpy = true
90 |
91 | spies.push(spy)
92 |
93 | return spy
94 | }
95 |
96 | export const spyOn = (object, methodName) => {
97 | const original = object[methodName]
98 |
99 | if (!isSpy(original)) {
100 | assert(
101 | isFunction(original),
102 | 'Cannot spyOn the %s property; it is not a function',
103 | methodName
104 | )
105 |
106 | object[methodName] = createSpy(original, () => {
107 | object[methodName] = original
108 | })
109 | }
110 |
111 | return object[methodName]
112 | }
113 |
--------------------------------------------------------------------------------
/modules/TestUtils.js:
--------------------------------------------------------------------------------
1 | import isRegExp from 'is-regex'
2 | import whyNotStrictlyEqual from 'is-equal/why'
3 | import objectKeys from 'object-keys'
4 |
5 | /**
6 | * Returns the reason why the given arguments are not *conceptually*
7 | * equal, if any; the empty string otherwise.
8 | */
9 | export const whyNotEqual = (a, b) =>
10 | (a == b ? '' : whyNotStrictlyEqual(a, b)) // eslint-disable-line eqeqeq
11 |
12 | /**
13 | * Returns true if the given arguments are *conceptually* equal.
14 | */
15 | export const isEqual = (a, b) =>
16 | whyNotEqual(a, b) === ''
17 |
18 | /**
19 | * Returns true if the given object is a function.
20 | */
21 | export const isFunction = (object) =>
22 | typeof object === 'function'
23 |
24 | /**
25 | * Returns true if the given object is an array.
26 | */
27 | export const isArray = (object) =>
28 | Array.isArray(object)
29 |
30 | /**
31 | * Returns true if the given object is an object.
32 | */
33 | export const isObject = (object) =>
34 | object && !isArray(object) && typeof object === 'object'
35 |
36 | /**
37 | * Returns true if the given object is an instanceof value
38 | * or its typeof is the given value.
39 | */
40 | export const isA = (object, value) => {
41 | if (isFunction(value))
42 | return object instanceof value
43 |
44 | if (value === 'array')
45 | return Array.isArray(object)
46 |
47 | return typeof object === value
48 | }
49 |
50 | /**
51 | * Returns true if the given function throws the given value
52 | * when invoked. The value may be:
53 | *
54 | * - undefined, to merely assert there was a throw
55 | * - a constructor function, for comparing using instanceof
56 | * - a regular expression, to compare with the error message
57 | * - a string, to find in the error message
58 | */
59 | export const functionThrows = (fn, context, args, value) => {
60 | try {
61 | fn.apply(context, args)
62 | } catch (error) {
63 | if (value == null)
64 | return true
65 |
66 | if (isFunction(value) && error instanceof value)
67 | return true
68 |
69 | const message = error.message || error
70 |
71 | if (typeof message === 'string') {
72 | if (isRegExp(value) && value.test(error.message))
73 | return true
74 |
75 | if (typeof value === 'string' && message.indexOf(value) !== -1)
76 | return true
77 | }
78 | }
79 |
80 | return false
81 | }
82 |
83 | /**
84 | * Returns true if the given array contains the value, false
85 | * otherwise. The compareValues function must return false to
86 | * indicate a non-match.
87 | */
88 | export const arrayContains = (array, value, compareValues) =>
89 | array.some(item => compareValues(item, value) !== false)
90 |
91 | const ownEnumerableKeys = (object) => {
92 | if (typeof Reflect === 'object' && typeof Reflect.ownKeys === 'function') {
93 | return Reflect.ownKeys(object)
94 | .filter(key => Object.getOwnPropertyDescriptor(object, key).enumerable)
95 | }
96 |
97 | if (typeof Object.getOwnPropertySymbols === 'function') {
98 | return Object.getOwnPropertySymbols(object)
99 | .filter(key => Object.getOwnPropertyDescriptor(object, key).enumerable)
100 | .concat(objectKeys(object))
101 | }
102 |
103 | return objectKeys(object)
104 | }
105 |
106 | /**
107 | * Returns true if the given object contains the value, false
108 | * otherwise. The compareValues function must return false to
109 | * indicate a non-match.
110 | */
111 | export const objectContains = (object, value, compareValues) =>
112 | ownEnumerableKeys(value).every(k => {
113 | if (isObject(object[k]) && isObject(value[k]))
114 | return objectContains(object[k], value[k], compareValues)
115 |
116 | return compareValues(object[k], value[k])
117 | })
118 |
119 | /**
120 | * Returns true if the given string contains the value, false otherwise.
121 | */
122 | export const stringContains = (string, value) =>
123 | string.indexOf(value) !== -1
124 |
--------------------------------------------------------------------------------
/modules/__tests__/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "mocha": true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/modules/__tests__/chainable-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('chaining assertions', () => {
4 | it('should allow chaining for array-like applications', () => {
5 | expect([ 1, 2, 'foo', 3 ])
6 | .toExist()
7 | .toBeAn(Array)
8 | .toInclude('foo')
9 | .toExclude('bar')
10 | })
11 |
12 | it('should allow chaining for number checking', () => {
13 | expect(3.14)
14 | .toExist()
15 | .toBeLessThan(4.2)
16 | .toBeLessThanOrEqualTo(3.14)
17 | .toBeGreaterThan(3.0)
18 | .toBeGreaterThanOrEqualTo(3.14)
19 | })
20 | })
21 |
--------------------------------------------------------------------------------
/modules/__tests__/createSpy-test.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable prefer-rest-params*/
2 | import expect, { createSpy, isSpy } from '../index'
3 |
4 | describe('createSpy', () => {
5 | describe('when given a function', () => {
6 | it('returns a spy function', () => {
7 | const spy = createSpy(() => {})
8 | expect(spy).toBeA(Function)
9 | })
10 | })
11 |
12 | describe('when not given a function', () => {
13 | it('throws an error', () => {
14 | expect(() => {
15 | createSpy(0)
16 | }).toThrow()
17 | })
18 | })
19 | })
20 |
21 | describe('A spy', () => {
22 | let targetContext, targetArguments
23 | const target = {
24 | method() {
25 | targetContext = this
26 | targetArguments = Array.prototype.slice.call(arguments, 0)
27 | }
28 | }
29 |
30 | let spy
31 | beforeEach(() => {
32 | spy = createSpy(target.method)
33 | targetContext = targetArguments = null
34 | })
35 |
36 | it('is a spy', () => {
37 | expect(isSpy(spy)).toBe(true)
38 | })
39 |
40 | it('has the same length as the function passed in', () => {
41 | expect(spy.length).toBe(0)
42 | expect(createSpy(a => a).length).toBe(1)
43 | expect(createSpy((a, b, c) => a * b * c).length).toBe(3)
44 | })
45 |
46 | it('has a destroy method', () => {
47 | expect(spy.destroy).toBeA(Function)
48 | })
49 |
50 | it('has a restore method', () => {
51 | expect(spy.restore).toBeA(Function)
52 | })
53 |
54 | it('has a reset method', () => {
55 | expect(spy.reset).toBeA(Function)
56 | })
57 |
58 | it('reset clears out all previous calls', () => {
59 | spy()
60 | expect(spy.calls.length).toEqual(1)
61 | spy.reset()
62 | expect(spy.calls.length).toEqual(0)
63 | })
64 |
65 | it('knows how many times it has been called', () => {
66 | spy()
67 | spy()
68 | expect(spy.calls.length).toEqual(2)
69 | })
70 |
71 | it('knows the arguments it was called with', () => {
72 | spy(1, 2, 3)
73 | expect(spy).toHaveBeenCalledWith(1, 2, 3)
74 | })
75 |
76 | describe('that calls some other function', () => {
77 | let otherContext, otherArguments
78 | function otherFn() {
79 | otherContext = this
80 | otherArguments = Array.prototype.slice.call(arguments, 0)
81 | }
82 |
83 | beforeEach(() => {
84 | spy.andCall(otherFn)
85 | otherContext = otherArguments = null
86 | })
87 |
88 | it('calls that function', () => {
89 | spy()
90 | expect(otherContext).toNotBe(null)
91 | })
92 |
93 | it('uses the correct context', () => {
94 | const context = {}
95 | spy.call(context)
96 | expect(otherContext).toBe(context)
97 | })
98 |
99 | it('passes the arguments through', () => {
100 | spy(1, 2, 3)
101 | expect(otherArguments).toEqual([ 1, 2, 3 ])
102 | })
103 | })
104 |
105 | describe('that calls through', () => {
106 | beforeEach(() => {
107 | spy.andCallThrough()
108 | })
109 |
110 | it('calls the original function', () => {
111 | spy()
112 | expect(targetContext).toNotBe(null)
113 | })
114 |
115 | it('uses the correct context', () => {
116 | const context = {}
117 | spy.call(context)
118 | expect(targetContext).toBe(context)
119 | })
120 |
121 | it('passes the arguments through', () => {
122 | spy(1, 2, 3)
123 | expect(targetArguments).toEqual([ 1, 2, 3 ])
124 | })
125 | })
126 |
127 | describe('with a thrown value', () => {
128 | beforeEach(() => {
129 | spy.andThrow('hello')
130 | })
131 |
132 | it('throws the correct value', () => {
133 | expect(spy).toThrow('hello')
134 | })
135 | })
136 |
137 | describe('with a return value', () => {
138 | beforeEach(() => {
139 | spy.andReturn('hello')
140 | })
141 |
142 | it('returns the correct value', () => {
143 | expect(spy()).toEqual('hello')
144 | })
145 | })
146 | })
147 |
--------------------------------------------------------------------------------
/modules/__tests__/defaultExport-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 | const cjsExpect = require('../index')
3 |
4 | describe('default export', () => {
5 | it('is a function', () => {
6 | expect(typeof cjsExpect).toEqual('function')
7 | })
8 |
9 | it('is the same whether import-ed or require-d', () => {
10 | expect(cjsExpect).toEqual(expect)
11 | })
12 | })
13 |
--------------------------------------------------------------------------------
/modules/__tests__/extend-test.js:
--------------------------------------------------------------------------------
1 | import expect, { assert, extend } from '../index'
2 |
3 | describe('expect.extend', () => {
4 | const ColorAssertions = {
5 | toBeAColor() {
6 | assert(
7 | this.actual.match(/^#[a-fA-F0-9]{6}$/),
8 | 'expected %s to be an HTML color',
9 | this.actual
10 | )
11 | }
12 | }
13 |
14 | it('works', () => {
15 | expect(expect().toBeAColor).toNotExist()
16 | extend(ColorAssertions)
17 | expect(expect().toBeAColor).toBeA(Function)
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/modules/__tests__/restoreSpies-test.js:
--------------------------------------------------------------------------------
1 | import expect, { createSpy, spyOn, restoreSpies } from '../index'
2 |
3 | describe('restoreSpies', () => {
4 | describe('with one spy', () => {
5 | const original = () => {}
6 | const target = { method: original }
7 |
8 | beforeEach(() => {
9 | spyOn(target, 'method')
10 | })
11 |
12 | it('works with spyOn()', () => {
13 | expect(target.method).toNotEqual(original)
14 | restoreSpies()
15 | expect(target.method).toEqual(original)
16 | })
17 |
18 | it('is idempotent', () => {
19 | expect(target.method).toNotEqual(original)
20 | restoreSpies()
21 | restoreSpies()
22 | expect(target.method).toEqual(original)
23 | })
24 |
25 | it('can work even on createSpy()', () => {
26 | createSpy(original)
27 | restoreSpies()
28 | })
29 | })
30 |
31 | describe('with multiple spies', () => {
32 | const originals = [ () => {}, () => {} ]
33 | const targets = [
34 | { method: originals[0] },
35 | { method: originals[1] }
36 | ]
37 |
38 | it('still works', () => {
39 | spyOn(targets[0], 'method')
40 | spyOn(targets[1], 'method')
41 |
42 | expect(targets[0].method).toNotEqual(originals[0])
43 | expect(targets[1].method).toNotEqual(originals[1])
44 |
45 | restoreSpies()
46 |
47 | expect(targets[0].method).toEqual(originals[0])
48 | expect(targets[1].method).toEqual(originals[1])
49 | })
50 | })
51 | })
52 |
--------------------------------------------------------------------------------
/modules/__tests__/spyOn-test.js:
--------------------------------------------------------------------------------
1 | import expect, { spyOn } from '../index'
2 |
3 | describe('A function that was spied on', () => {
4 | const video = {
5 | play: () => {}
6 | }
7 |
8 | let spy
9 | beforeEach(() => {
10 | spy = spyOn(video, 'play')
11 | video.play('some', 'args')
12 | })
13 |
14 | it('tracks the number of calls', () => {
15 | expect(spy.calls.length).toEqual(1)
16 | })
17 |
18 | it('tracks the context that was used', () => {
19 | expect(spy.calls[0].context).toBe(video)
20 | })
21 |
22 | it('tracks the arguments that were used', () => {
23 | expect(spy.calls[0].arguments).toEqual([ 'some', 'args' ])
24 | })
25 |
26 | it('was called', () => {
27 | expect(spy).toHaveBeenCalled()
28 | })
29 |
30 | it('was called with the correct args', () => {
31 | expect(spy).toHaveBeenCalledWith('some', 'args')
32 | })
33 |
34 | it('can be restored', () => {
35 | expect(video.play).toEqual(spy)
36 | spy.restore()
37 | expect(video.play).toNotEqual(spy)
38 | })
39 | })
40 |
41 | describe('A function that was spied on but not called', () => {
42 | const video = {
43 | play: () => {}
44 | }
45 |
46 | let spy
47 | beforeEach(() => {
48 | spy = spyOn(video, 'play')
49 | })
50 |
51 | it('number of calls to be zero', () => {
52 | expect(spy.calls.length).toEqual(0)
53 | })
54 |
55 | it('was not called', () => {
56 | expect(spy).toNotHaveBeenCalled()
57 | })
58 | })
59 |
--------------------------------------------------------------------------------
/modules/__tests__/toBeA-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 | import Expectation from '../Expectation'
3 |
4 | describe('toBeA', () => {
5 | it('requires the value to be a function or string', () => {
6 | expect(() => {
7 | expect('actual').toBeA(4)
8 | }).toThrow(/must be a function or a string/)
9 | })
10 |
11 | it('does not throw when the actual value is an instanceof the constructor', () => {
12 | expect(() => {
13 | expect(new Expectation).toBeA(Expectation)
14 | }).toNotThrow()
15 | })
16 |
17 | it('throws when the actual value is not an instanceof the constructor', () => {
18 | expect(() => {
19 | expect('actual').toBeA(Expectation)
20 | }).toThrow(/to be/)
21 | })
22 |
23 | it('does not throw when the expected value is the typeof the actual value', () => {
24 | expect(() => {
25 | expect(4).toBeA('number')
26 | expect(NaN).toBeA('number') // hahaha
27 | }).toNotThrow()
28 | })
29 |
30 | it('throws when the expected value is not the typeof the actual value', () => {
31 | expect(() => {
32 | expect('actual').toBeA('number')
33 | }).toThrow(/to be/)
34 | })
35 |
36 | it('does not throw when the actual value is an array', () => {
37 | expect(() => {
38 | expect([]).toBeAn('array')
39 | }).toNotThrow()
40 | })
41 |
42 | it('throws when the actual value is not an array', () => {
43 | expect(() => {
44 | expect('actual').toBeAn('array')
45 | }).toThrow(/to be/)
46 | })
47 | })
48 |
--------------------------------------------------------------------------------
/modules/__tests__/toBeGreaterThan-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toBeGreaterThan', () => {
4 | it('does not throw when the actual value is greater than the expected value', () => {
5 | expect(() => {
6 | expect(3).toBeGreaterThan(2)
7 | }).toNotThrow()
8 | })
9 |
10 | it('throws when the actual value is not greater than the expected value', () => {
11 | expect(() => {
12 | expect(2).toBeGreaterThan(3)
13 | }).toThrow(/to be greater than/)
14 | })
15 | })
16 |
--------------------------------------------------------------------------------
/modules/__tests__/toBeGreaterThanOrEqualTo-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toBeGreaterThanOrEqualTo', () => {
4 | it('does not throw when the actual value is greater than the expected value', () => {
5 | expect(() => {
6 | expect(3).toBeGreaterThanOrEqualTo(2)
7 | }).toNotThrow()
8 | })
9 |
10 | it('does not throw when the actual value is equal to the expected value', () => {
11 | expect(() => {
12 | expect(3).toBeGreaterThanOrEqualTo(3)
13 | }).toNotThrow()
14 | })
15 |
16 | it('throws when the actual value is not greater than or equal to the expected value', () => {
17 | expect(() => {
18 | expect(2).toBeGreaterThanOrEqualTo(3)
19 | }).toThrow(/to be greater than or equal to/)
20 | })
21 | })
22 |
--------------------------------------------------------------------------------
/modules/__tests__/toBeLessThan-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toBeLessThan', () => {
4 | it('does not throw when the actual value is less than the expected value', () => {
5 | expect(() => {
6 | expect(2).toBeLessThan(3)
7 | }).toNotThrow()
8 | })
9 |
10 | it('throws when the actual value is not less than the expected value', () => {
11 | expect(() => {
12 | expect(3).toBeLessThan(2)
13 | }).toThrow(/to be less than/)
14 | })
15 | })
16 |
--------------------------------------------------------------------------------
/modules/__tests__/toBeLessThanOrEqualTo-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toBeLessThanOrEqualTo', () => {
4 | it('does not throw when the actual value is less than the expected value', () => {
5 | expect(() => {
6 | expect(2).toBeLessThanOrEqualTo(3)
7 | }).toNotThrow()
8 | })
9 |
10 | it('does not throw when the actual value is equal to the expected value', () => {
11 | expect(() => {
12 | expect(2).toBeLessThanOrEqualTo(2)
13 | }).toNotThrow()
14 | })
15 |
16 | it('throws when the actual value is not less than the expected value', () => {
17 | expect(() => {
18 | expect(3).toBeLessThanOrEqualTo(2)
19 | }).toThrow(/to be less than or equal to/)
20 | })
21 | })
22 |
--------------------------------------------------------------------------------
/modules/__tests__/toBeTruthy-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toBeTruthy', () => {
4 | it('does not throw on truthy actual values', () => {
5 | expect(() => {
6 | expect(1).toBeTruthy()
7 | expect({ hello: 'world' }).toBeTruthy()
8 | expect([ 1, 2, 3 ]).toBeTruthy()
9 | }).toNotThrow()
10 | })
11 |
12 | it('throws on falsy actual values', () => {
13 | expect(() => {
14 | expect(0).toBeTruthy()
15 | }).toThrow()
16 |
17 | expect(() => {
18 | expect(null).toBeTruthy()
19 | }).toThrow()
20 |
21 | expect(() => {
22 | expect(undefined).toBeTruthy()
23 | }).toThrow()
24 | })
25 | })
26 |
27 | describe('toBeFalsy', () => {
28 | it('throws on truthy values', () => {
29 | expect(() => {
30 | expect(42).toBeFalsy()
31 | }).toThrow()
32 |
33 | expect(() => {
34 | expect({ foo: 'bar' }).toBeFalsy()
35 | }).toThrow()
36 |
37 | expect(() => {
38 | expect([]).toBeFalsy()
39 | }).toThrow()
40 | })
41 |
42 | it('does not throw with falsy actual values', () => {
43 | expect(() => {
44 | expect(0).toBeFalsy()
45 | expect(null).toBeFalsy()
46 | expect(undefined).toBeFalsy()
47 | }).toNotThrow()
48 | })
49 | })
50 |
--------------------------------------------------------------------------------
/modules/__tests__/toEqual-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toEqual', () => {
4 | it('works', () => {
5 | expect('actual').toEqual('actual')
6 | })
7 |
8 | it('works with numbers and strings that have the same conceptual value', () => {
9 | expect(2).toEqual('2')
10 | })
11 |
12 | it('works with null and undefined', () => {
13 | expect(null).toEqual(undefined)
14 | })
15 |
16 | it('works with objects that have the same keys in different order', () => {
17 | const a = { a: 'a', b: 'b', c: 'c' }
18 | const b = { b: 'b', c: 'c', a: 'a' }
19 | expect(a).toEqual(b)
20 | })
21 |
22 | it('works when object has circular reference', () => {
23 | function Circular() {
24 | this.circularRef = this
25 | }
26 |
27 | const a = new Circular()
28 | const b = new Circular()
29 |
30 | expect(a).toEqual(b)
31 | })
32 |
33 | if (typeof Map !== 'undefined') {
34 | it('works with Map', () => {
35 | const a = new Map()
36 | a.set('key', 'value')
37 |
38 | const b = new Map()
39 | b.set('key', 'value')
40 |
41 | expect(a).toEqual(b)
42 | })
43 | }
44 |
45 | if (typeof Set !== 'undefined') {
46 | it('works with Set', () => {
47 | const a = new Set()
48 | a.add('a')
49 |
50 | const b = new Set()
51 | b.add('a')
52 |
53 | expect(a).toEqual(b)
54 | })
55 | }
56 |
57 | it('shows diff', () => {
58 | try {
59 | expect('actual').toEqual('expected')
60 | } catch (err) {
61 | expect(err.actual).toEqual('actual')
62 | expect(err.expected).toEqual('expected')
63 | expect(err.showDiff).toEqual(true)
64 | }
65 | })
66 | })
67 |
--------------------------------------------------------------------------------
/modules/__tests__/toExclude-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toExclude', () => {
4 | it('requires the actual value to be an array or string', () => {
5 | expect(() => {
6 | expect(1).toExclude(2)
7 | }).toThrow(/must be an array, object, or a string/)
8 | })
9 |
10 | it('does not throw when an array does not contain the expected value', () => {
11 | expect(() => {
12 | expect([ 1, 2, 3 ]).toExclude(4)
13 | }).toNotThrow()
14 | })
15 |
16 | it('throws when an array contains the expected value', () => {
17 | expect(() => {
18 | expect([ 1, 2, 3 ]).toExclude(2)
19 | }).toThrow(/to exclude/)
20 | })
21 |
22 | it('throws when an object contains an expected object', () => {
23 | expect(() => {
24 | expect({ a: 1 }).toExclude({ a: 1 })
25 | }).toThrow(/to exclude/)
26 | })
27 |
28 | it('does not throw when an array contains an unexpected object', () => {
29 | expect(() => {
30 | expect({ a: 1 }).toExclude({ b: 2 })
31 | }).toNotThrow()
32 | })
33 |
34 | it('does not throw when an object contains an expected object with an unexpected value', () => {
35 | expect(() => {
36 | expect({ a: 1 }).toExclude({ a: 2 })
37 | }).toNotThrow()
38 | })
39 |
40 | it('does not throw when an array does not contain the expected value', () => {
41 | expect(() => {
42 | expect('hello world').toExclude('goodbye')
43 | }).toNotThrow()
44 | })
45 |
46 | it('throws when a string contains the expected value', () => {
47 | expect(() => {
48 | expect('hello world').toExclude('hello')
49 | }).toThrow(/to exclude/)
50 | })
51 | })
52 |
--------------------------------------------------------------------------------
/modules/__tests__/toExcludeKey-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toExcludeKey', () => {
4 | it('requires the actual value to have keys', () => {
5 | expect(() => {
6 | expect(1).toExcludeKey('hello')
7 | }).toThrow(/must be an object/)
8 | })
9 |
10 | it('throws when there is a key that exists', () => {
11 | expect(() => {
12 | expect({ a: 1 }).toExcludeKey('a')
13 | }).toThrow(/exclude key/)
14 | })
15 |
16 | it('does not throw when there is a key that does not exist', () => {
17 | expect(() => {
18 | expect({ a: 1 }).toExcludeKey('b')
19 | }).toNotThrow()
20 | })
21 | })
22 |
--------------------------------------------------------------------------------
/modules/__tests__/toExcludeKeys-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toExcludeKeys', () => {
4 | it('requires the actual value to have keys', () => {
5 | expect(() => {
6 | expect(1).toExcludeKeys('hello')
7 | }).toThrow(/must be an object/)
8 | })
9 |
10 | it('requires the keys to be an array', () => {
11 | expect(() => {
12 | expect({ a: 1 }).toIncludeKeys({ b: 2 })
13 | }).toThrow(/must be an array/)
14 | })
15 |
16 | it('throws when there is a key that exists', () => {
17 | expect(() => {
18 | expect({ a: 1 }).toExcludeKeys([ 'a' ])
19 | }).toThrow(/exclude key/)
20 | })
21 |
22 | it('does not throw when there is a key that does not exist', () => {
23 | expect(() => {
24 | expect({ a: 1 }).toExcludeKeys([ 'b' ])
25 | }).toNotThrow()
26 | })
27 |
28 | it('throws when all keys exist', () => {
29 | expect(() => {
30 | expect({ a: 1, b: 2, c: 3 }).toExcludeKeys([ 'a', 'b', 'c' ])
31 | }).toThrow(/exclude key/)
32 | })
33 |
34 | it('does not throw when even one key does not exist', () => {
35 | expect(() => {
36 | expect({ a: 1, c: 3 }).toExcludeKeys([ 'a', 'b', 'c' ])
37 | }).toNotThrow()
38 | })
39 |
40 | it('works with arrays', () => {
41 | expect(() => {
42 | expect([ 0, 1, 2 ]).toExcludeKeys([ '0', 1, 2 ])
43 | }).toThrow(/exclude key/)
44 |
45 | expect(() => {
46 | expect([ 0, 1, 2 ]).toExcludeKeys([ 3 ])
47 | }).toNotThrow()
48 | })
49 | })
50 |
--------------------------------------------------------------------------------
/modules/__tests__/toExist-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toExist', () => {
4 | it('does not throw on truthy actual values', () => {
5 | expect(() => {
6 | expect(1).toExist()
7 | expect({ hello: 'world' }).toExist()
8 | expect([ 1, 2, 3 ]).toExist()
9 | }).toNotThrow()
10 | })
11 |
12 | it('throws on falsy actual values', () => {
13 | expect(() => {
14 | expect(0).toExist()
15 | }).toThrow()
16 |
17 | expect(() => {
18 | expect(null).toExist()
19 | }).toThrow()
20 |
21 | expect(() => {
22 | expect(undefined).toExist()
23 | }).toThrow()
24 | })
25 | })
26 |
27 | describe('toNotExist', () => {
28 | it('throws on truthy values', () => {
29 | expect(() => {
30 | expect(42).toNotExist()
31 | }).toThrow()
32 |
33 | expect(() => {
34 | expect({ foo: 'bar' }).toNotExist()
35 | }).toThrow()
36 |
37 | expect(() => {
38 | expect([]).toNotExist()
39 | }).toThrow()
40 | })
41 |
42 | it('does not throw with falsy actual values', () => {
43 | expect(() => {
44 | expect(0).toNotExist()
45 | expect(null).toNotExist()
46 | expect(undefined).toNotExist()
47 | }).toNotThrow()
48 | })
49 | })
50 |
--------------------------------------------------------------------------------
/modules/__tests__/toInclude-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toInclude', () => {
4 | it('requires the actual value to be an array, object, or a string', () => {
5 | expect(() => {
6 | expect(1).toInclude(2)
7 | }).toThrow(/must be an array, object, or a string/)
8 | })
9 |
10 | it('does not throw when an array contains an expected integer', () => {
11 | expect(() => {
12 | expect([ 1, 2, 3 ]).toInclude(2)
13 | expect([ { a: 1 }, { c: 2 } ]).toInclude({ c: 2 })
14 | }).toNotThrow()
15 | })
16 |
17 | it('does not throw when an array contains an expected object', () => {
18 | expect(() => {
19 | expect([ { a: 1 }, { c: 2 } ]).toInclude({ c: 2 })
20 | }).toNotThrow()
21 | })
22 |
23 | it('does not throw when an object contains an expected object', () => {
24 | expect(() => {
25 | expect({ a: 1, b: 2, c: 3 }).toInclude({ b: 2 })
26 | }).toNotThrow()
27 |
28 | expect(() => {
29 | expect({ a: 1, b: 2 }).toInclude({})
30 | }).toNotThrow()
31 | })
32 |
33 | it('throws when an object does not contain an expected object', () => {
34 | expect(() => {
35 | expect({ a: 1, b: 2, c: 3 }).toInclude({ d: 4 })
36 | }).toThrow(/to include/)
37 |
38 | expect(() => {
39 | expect({ a: 1, b: 2, c: 3 }).toInclude({ b: 4 })
40 | }).toThrow(/to include/)
41 | })
42 |
43 | it('does not throw when an object contains an expected object in a deep key', () => {
44 | expect(() => {
45 | expect(
46 | { a: 1, b: 2, c: { d: 4, e: { f: 5, g: 6, h: 7 } } }
47 | ).toInclude(
48 | { b: 2, c: { e: { f: 5, g: 6, h: 7 } } }
49 | )
50 | }).toNotThrow()
51 | })
52 |
53 | it('throws when an object does not contain an expected object in a deep key', () => {
54 | expect(() => {
55 | expect(
56 | { a: 1, b: 2, c: { d: 4, e: { f: 5, g: 6, h: 7 } } }
57 | ).toInclude(
58 | { b: 2, c: { e: { f: 5, g: 999, h: 7 } } }
59 | )
60 | }).toThrow(/to include/)
61 | })
62 |
63 | it('compares partial object only when both expected and actual properties are object', () => {
64 | expect(() => {
65 | expect({ a: { b: 2 } }).toInclude({ a: {} })
66 | }).toNotThrow()
67 |
68 | expect(() => {
69 | expect({ a: 1 }).toInclude({ a: {} })
70 | }).toThrow(/to include/)
71 |
72 | expect(() => {
73 | expect({ a: [] }).toInclude({ a: {} })
74 | }).toThrow(/to include/)
75 |
76 | expect(() => {
77 | expect({ a: '1' }).toInclude({ a: {} })
78 | }).toThrow(/to include/)
79 |
80 | expect(() => {
81 | expect({ a: () => {} }).toInclude({ a: {} })
82 | }).toThrow(/to include/)
83 | })
84 |
85 | if (typeof Object.create === 'function') {
86 | it('ignores nonenumerable properties of an expected object', () => {
87 | expect(() => {
88 | expect({}).toInclude(Object.create({}, { a: { value: 1 } }))
89 | }).toNotThrow()
90 | })
91 | }
92 |
93 | if (typeof Symbol === 'function') {
94 | const symbol = Symbol()
95 |
96 | it('does not throw when an object contains an expected object with a symbol key', () => {
97 | expect(() => {
98 | expect({ [symbol]: 1, b: 2 }).toInclude({ [symbol]: 1 })
99 | }).toNotThrow()
100 | })
101 |
102 | it('throws when an object contain an expected object without a symbol key', () => {
103 | expect(() => {
104 | expect({ a: 1, b: 2 }).toInclude({ [symbol]: 1 })
105 | }).toThrow(/to include/)
106 | })
107 | }
108 |
109 | it('throws when an array does not contain an expected integer', () => {
110 | expect(() => {
111 | expect([ 1, 2, 3 ]).toInclude(4)
112 | }).toThrow(/to include/)
113 | })
114 |
115 | it('throws when an array does not contain an expected object', () => {
116 | expect(() => {
117 | expect([ { a: 1 }, { c: 2 } ]).toInclude({ a: 2 })
118 | }).toThrow(/to include/)
119 | })
120 |
121 | it('does not throw when a string contains the expected value', () => {
122 | expect(() => {
123 | expect('hello world').toInclude('world')
124 | }).toNotThrow()
125 | })
126 |
127 | it('throws when a string does not contain the expected value', () => {
128 | expect(() => {
129 | expect('hello world').toInclude('goodbye')
130 | }).toThrow(/to include/)
131 | })
132 | })
133 |
--------------------------------------------------------------------------------
/modules/__tests__/toIncludeKey-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toIncludeKey', () => {
4 | it('requires the actual value to have keys', () => {
5 | expect(() => {
6 | expect(1).toIncludeKey('hello')
7 | }).toThrow(/must be an object/)
8 | })
9 |
10 | it('does not throw when there is a key that exists', () => {
11 | expect(() => {
12 | expect({ a: 1 }).toIncludeKey('a')
13 | }).toNotThrow()
14 | })
15 |
16 | it('throws when there is a key that does not exist', () => {
17 | expect(() => {
18 | expect({ a: 1 }).toIncludeKey('b')
19 | }).toThrow(/include key/)
20 | })
21 | })
22 |
--------------------------------------------------------------------------------
/modules/__tests__/toIncludeKeys-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toIncludeKeys', () => {
4 | it('requires the actual value to have keys', () => {
5 | expect(() => {
6 | expect(1).toIncludeKeys([ 'hello' ])
7 | }).toThrow(/must be an object/)
8 | })
9 |
10 | it('requires the keys to be an array', () => {
11 | expect(() => {
12 | expect({ a: 1 }).toIncludeKeys({ b: 2 })
13 | }).toThrow(/must be an array/)
14 | })
15 |
16 | it('does not throw when there is a key that exists', () => {
17 | expect(() => {
18 | expect({ a: 1 }).toIncludeKeys([ 'a' ])
19 | }).toNotThrow()
20 | })
21 |
22 | it('throws when there is a key that does not exist', () => {
23 | expect(() => {
24 | expect({ a: 1 }).toIncludeKeys([ 'b' ])
25 | }).toThrow(/include key/)
26 | })
27 |
28 | it('does not throw when all keys exist', () => {
29 | expect(() => {
30 | expect({ a: 1, b: 2, c: 3 }).toIncludeKeys([ 'a', 'b', 'c' ])
31 | }).toNotThrow()
32 | })
33 |
34 | it('throws when even one key does not exist', () => {
35 | expect(() => {
36 | expect({ a: 1, c: 3 }).toIncludeKeys([ 'a', 'b', 'c' ])
37 | }).toThrow(/include key/)
38 | })
39 |
40 | it('works with arrays', () => {
41 | expect(() => {
42 | expect([ 0, 1, 2 ]).toIncludeKeys([ '0', 1, 2 ])
43 | }).toNotThrow()
44 |
45 | expect(() => {
46 | expect([ 0, 1, 2 ]).toIncludeKeys([ 3 ])
47 | }).toThrow(/include key/)
48 | })
49 | })
50 |
--------------------------------------------------------------------------------
/modules/__tests__/toMatch-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('expect(string).toMatch', () => {
4 | it('does not throw when the actual value matches the pattern', () => {
5 | expect(() => {
6 | expect('actual').toMatch(/^actual$/)
7 | }).toNotThrow()
8 | })
9 |
10 | it('throws when the actual value does not match the pattern', () => {
11 | expect(() => {
12 | expect('actual').toMatch(/nope/)
13 | }).toThrow(/to match/)
14 | })
15 | })
16 |
17 | describe('expect(object).toMatch', () => {
18 | it('does not throw when the actual value matches the pattern', () => {
19 | expect(() => {
20 | expect({
21 | statusCode: 200,
22 | headers: {
23 | server: 'express web server'
24 | }
25 | }).toMatch({
26 | statusCode: 200,
27 | headers: {
28 | server: /express/
29 | }
30 | })
31 | }).toNotThrow()
32 | })
33 |
34 | it('throws when the actual value does not match the pattern', () => {
35 | expect(() => {
36 | expect({
37 | statusCode: 200,
38 | headers: {
39 | server: 'nginx web server'
40 | }
41 | }).toMatch({
42 | statusCode: 200,
43 | headers: {
44 | server: /express/
45 | }
46 | })
47 | }).toThrow(/to match/)
48 | })
49 | })
50 |
51 | describe('expect(array).toMatch', () => {
52 | it('does not throw when the array contains an object that matches the pattern', () => {
53 | const array = [
54 | { one: 'one' },
55 | { two: 'two' },
56 | { three: 'three' }
57 | ]
58 |
59 | expect(array).toMatch([ { one: /one/ } ])
60 | })
61 | })
62 |
--------------------------------------------------------------------------------
/modules/__tests__/toNotEqual-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('toNotEqual', () => {
4 | it('works', () => {
5 | expect('actual').toNotEqual('expected')
6 | })
7 |
8 | it('works with objects that do not have the same keys', () => {
9 | const a = { a: 'a', b: 'b', c: 'c' }
10 | const b = { a: 'a', b: 'b', d: 'c' }
11 | expect(a).toNotEqual(b)
12 | })
13 |
14 | it('works with objects that have different prototypes and different keys', () => {
15 | class A {
16 | constructor(prop) {
17 | this.a = prop
18 | }
19 | }
20 |
21 | class B {
22 | constructor(prop) {
23 | this.b = prop
24 | }
25 | }
26 |
27 | const a = new A('hi')
28 | const b = new B('hi')
29 |
30 | expect(a).toNotEqual(b)
31 | })
32 |
33 | it('works with arrays of objects', () => {
34 | const a = [
35 | {
36 | id: 0,
37 | text: 'Array Object 0',
38 | boo: false
39 | },
40 | {
41 | id: 1,
42 | text: 'Array Object 1',
43 | boo: false
44 | }
45 | ]
46 |
47 | const b = [
48 | {
49 | id: 0,
50 | text: 'Array Object 0',
51 | boo: true // value of boo is changed to true here
52 | },
53 | {
54 | id: 1,
55 | text: 'Array Object 1',
56 | boo: false
57 | }
58 | ]
59 |
60 | expect(a).toNotEqual(b)
61 | })
62 |
63 | if (typeof Map !== 'undefined') {
64 | it('works with Map', () => {
65 | const a = new Map()
66 | a.set('key', 'value')
67 |
68 | const b = new Map()
69 | b.set('key', 'another value')
70 |
71 | expect(a).toNotEqual(b)
72 | })
73 | }
74 |
75 | if (typeof Set !== 'undefined') {
76 | it('works with Set', () => {
77 | const a = new Set()
78 | a.add('a')
79 |
80 | const b = new Set()
81 | b.add('b')
82 |
83 | expect(a).toNotEqual(b)
84 | })
85 | }
86 | })
87 |
--------------------------------------------------------------------------------
/modules/__tests__/toNotMatch-test.js:
--------------------------------------------------------------------------------
1 | import expect from '../index'
2 |
3 | describe('expect(string).toNotMatch', () => {
4 | it('does not throw when the actual value does not match the pattern', () => {
5 | expect(() => {
6 | expect('actual').toNotMatch(/nope/)
7 | }).toNotThrow()
8 | })
9 |
10 | it('throws when the actual value matches the pattern', () => {
11 | expect(() => {
12 | expect('actual').toNotMatch(/^actual$/)
13 | }).toThrow(/to not match/)
14 | })
15 | })
16 |
17 | describe('expect(object).toNotMatch', () => {
18 | it('does not throw when the actual value does not match the pattern', () => {
19 | expect(() => {
20 | expect({
21 | statusCode: 200,
22 | headers: {
23 | server: 'nginx web server'
24 | }
25 | }).toNotMatch({
26 | statusCode: 200,
27 | headers: {
28 | server: /express/
29 | }
30 | })
31 | }).toNotThrow()
32 | })
33 |
34 | it('throws when the actual value matches the pattern', () => {
35 | expect(() => {
36 | expect({
37 | statusCode: 200,
38 | headers: {
39 | server: 'express web server'
40 | }
41 | }).toNotMatch({
42 | statusCode: 200,
43 | headers: {
44 | server: /express/
45 | }
46 | })
47 | }).toThrow(/to not match/)
48 | })
49 | })
50 |
51 | describe('expect(array).toNotMatch', () => {
52 | it('does not throw when the array does not contain an object that matches the pattern', () => {
53 | const array = [
54 | { one: 'one' },
55 | { two: 'two' },
56 | { three: 'three' }
57 | ]
58 |
59 | expect(array).toNotMatch([ { one: /two/ } ])
60 | })
61 | })
62 |
--------------------------------------------------------------------------------
/modules/__tests__/withArgs-test.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable newline-per-chained-call*/
2 | import expect from '../index'
3 |
4 | describe('withArgs', () => {
5 | const fn = (arg1, arg2) => {
6 | if (arg1 === 'first' && typeof arg2 === 'undefined') {
7 | throw new Error('first arg found')
8 | }
9 | if (arg1 === 'first' && arg2 === 'second') {
10 | throw new Error('both args found')
11 | }
12 | }
13 |
14 | it('invokes actual function with args', () => {
15 | expect(() => {
16 | expect(fn).withArgs('first').toThrow(/first arg found/)
17 | }).toNotThrow()
18 | })
19 |
20 | it('can be chained', () => {
21 | expect(() => {
22 | expect(fn).withArgs('first').withArgs('second').toThrow(/both args found/)
23 | }).toNotThrow()
24 | })
25 |
26 | it('throws when actual is not a function', () => {
27 | expect(() => {
28 | expect('not a function').withArgs('first')
29 | }).toThrow(/must be a function/)
30 | })
31 | })
32 |
--------------------------------------------------------------------------------
/modules/__tests__/withContext-test.js:
--------------------------------------------------------------------------------
1 | /*eslint-disable newline-per-chained-call*/
2 | import expect from '../index'
3 |
4 | describe('withContext', () => {
5 | const context = {
6 | check: true
7 | }
8 |
9 | const fn = function fn(arg) {
10 | if (this.check && typeof arg === 'undefined')
11 | throw new Error('context found')
12 |
13 | if (this.check && arg === 'good')
14 | throw new Error('context and args found')
15 | }
16 |
17 | it('calls function with context', () => {
18 | expect(() => {
19 | expect(fn).withContext(context).toThrow(/context found/)
20 | }).toNotThrow()
21 | })
22 |
23 | it('calls function with context and args', () => {
24 | expect(() => {
25 | expect(fn).withContext(context).withArgs('good').toThrow(/context and args found/)
26 | }).toNotThrow()
27 | })
28 |
29 | it('throws when actual is not a function', () => {
30 | expect(() => {
31 | expect('not a function').withContext(context).toThrow()
32 | }).toThrow(/must be a function/)
33 | })
34 | })
35 |
--------------------------------------------------------------------------------
/modules/assert.js:
--------------------------------------------------------------------------------
1 | import inspect from 'object-inspect'
2 |
3 | const formatString = (string, args) => {
4 | let index = 0
5 | return string.replace(/%s/g, () => inspect(args[index++]))
6 | }
7 |
8 | const assert = (condition, createMessage, ...extraArgs) => {
9 | if (condition)
10 | return
11 |
12 | const message = (typeof createMessage === 'string')
13 | ? formatString(createMessage, extraArgs)
14 | : createMessage(extraArgs)
15 |
16 | throw new Error(message)
17 | }
18 |
19 | export default assert
20 |
--------------------------------------------------------------------------------
/modules/extend.js:
--------------------------------------------------------------------------------
1 | import Expectation from './Expectation'
2 |
3 | const Extensions = []
4 |
5 | function extend(extension) {
6 | if (Extensions.indexOf(extension) === -1) {
7 | Extensions.push(extension)
8 |
9 | for (const p in extension)
10 | if (extension.hasOwnProperty(p))
11 | Expectation.prototype[p] = extension[p]
12 | }
13 | }
14 |
15 | export default extend
16 |
--------------------------------------------------------------------------------
/modules/index.js:
--------------------------------------------------------------------------------
1 | import Expectation from './Expectation'
2 | import { createSpy, spyOn, isSpy, restoreSpies } from './SpyUtils'
3 | import assert from './assert'
4 | import extend from './extend'
5 |
6 | function expect(actual) {
7 | return new Expectation(actual)
8 | }
9 |
10 | expect.createSpy = createSpy
11 | expect.spyOn = spyOn
12 | expect.isSpy = isSpy
13 | expect.restoreSpies = restoreSpies
14 | expect.assert = assert
15 | expect.extend = extend
16 |
17 | module.exports = expect
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "expect",
3 | "version": "1.20.2",
4 | "description": "Write better assertions",
5 | "repository": "mjackson/expect",
6 | "author": "Michael Jackson",
7 | "license": "MIT",
8 | "main": "lib",
9 | "files": [
10 | "lib",
11 | "umd"
12 | ],
13 | "scripts": {
14 | "build": "node ./scripts/build.js",
15 | "prebuild-lib": "rimraf lib",
16 | "build-lib": "babel ./modules -d lib --ignore '__tests__'",
17 | "build-umd": "webpack modules/index.js umd/expect.js",
18 | "build-min": "webpack -p modules/index.js umd/expect.min.js",
19 | "lint": "eslint modules",
20 | "pretest": "npm run lint",
21 | "test": "npm run tests-only",
22 | "tests-only": "npm run jest",
23 | "jest": "jest",
24 | "posttest": "npm run karma",
25 | "karma": "karma start",
26 | "release": "node ./scripts/release.js",
27 | "prepublish": "safe-publish-latest && npm run build"
28 | },
29 | "dependencies": {
30 | "define-properties": "~1.1.2",
31 | "has": "^1.0.1",
32 | "is-equal": "^1.5.5",
33 | "is-regex": "^1.0.3",
34 | "object-inspect": "^1.1.0",
35 | "object-keys": "^1.0.9",
36 | "tmatch": "^2.0.1"
37 | },
38 | "devDependencies": {
39 | "babel-cli": "^6.26.0",
40 | "babel-eslint": "^7.2.3",
41 | "babel-jest": "^21.2.0",
42 | "babel-loader": "^6.4.1",
43 | "babel-preset-es2015": "^6.24.1",
44 | "eslint": "^4.11.0",
45 | "eslint-plugin-import": "^2.8.0",
46 | "gzip-size": "^3.0.0",
47 | "in-publish": "^2.0.0",
48 | "jest": "^21.2.1",
49 | "karma": "^1.7.1",
50 | "karma-browserstack-launcher": "^1.3.0",
51 | "karma-chrome-launcher": "^2.2.0",
52 | "karma-mocha": "^1.3.0",
53 | "karma-mocha-reporter": "^2.2.5",
54 | "karma-sourcemap-loader": "^0.3.7",
55 | "karma-webpack": "^1.8.1",
56 | "mocha": "^3.5.3",
57 | "pretty-bytes": "^4.0.2",
58 | "readline-sync": "^1.4.7",
59 | "rimraf": "^2.6.2",
60 | "safe-publish-latest": "^1.1.1",
61 | "webpack": "^1.15.0"
62 | },
63 | "keywords": [
64 | "expect",
65 | "assert",
66 | "test",
67 | "spec"
68 | ]
69 | }
70 |
--------------------------------------------------------------------------------
/scripts/build.js:
--------------------------------------------------------------------------------
1 | const readFileSync = require('fs').readFileSync
2 | const execSync = require('child_process').execSync
3 | const inInstall = require('in-publish').inInstall
4 | const prettyBytes = require('pretty-bytes')
5 | const gzipSize = require('gzip-size')
6 |
7 | if (inInstall())
8 | process.exit(0)
9 |
10 | const exec = (command, env) =>
11 | execSync(command, { stdio: 'inherit', env })
12 |
13 | const webpackEnv = Object.assign({}, process.env, {
14 | NODE_ENV: 'production'
15 | })
16 |
17 | exec('npm run build-lib')
18 | exec('npm run build-umd', webpackEnv)
19 | exec('npm run build-min', webpackEnv)
20 |
21 | console.log(
22 | '\ngzipped, the UMD build is ' + prettyBytes(
23 | gzipSize.sync(readFileSync('umd/expect.min.js'))
24 | )
25 | )
26 |
--------------------------------------------------------------------------------
/scripts/release.js:
--------------------------------------------------------------------------------
1 | const resolvePath = require('path').resolve
2 | const readFileSync = require('fs').readFileSync
3 | const execSync = require('child_process').execSync
4 | const prompt = require('readline-sync').question
5 |
6 | const exec = (command) =>
7 | execSync(command, { stdio: 'inherit' })
8 |
9 | const getPackageVersion = () =>
10 | JSON.parse(readFileSync(resolvePath(__dirname, '../package.json'))).version
11 |
12 | if (process.cwd() !== resolvePath(__dirname, '..')) {
13 | console.error('The release script must be run from the repo root')
14 | process.exit(1)
15 | }
16 |
17 | // Get the next version, which may be specified as a semver
18 | // version number or anything `npm version` recognizes. This
19 | // is a "pre-release" if nextVersion is premajor, preminor,
20 | // prepatch, or prerelease
21 | const nextVersion = prompt(`Next version (current version is ${getPackageVersion()})? `)
22 | const isPrerelease = nextVersion.substring(0, 3) === 'pre'
23 |
24 | // 1) Make sure the tests pass
25 | exec('npm test -- --single-run')
26 |
27 | // 2) Increment the package version in package.json
28 | // 3) Create a new commit
29 | // 4) Create a v* tag that points to that commit
30 | exec(`npm version ${nextVersion} -m "Version %s"`)
31 |
32 | // 5) Push to the same branch on the git remote (GitHub).
33 | // Do this before we publish in case anyone has pushed
34 | // since we last pulled
35 | exec('git push origin')
36 |
37 | // 6) Publish to npm. Use the "next" tag for pre-releases,
38 | // "latest" for all others
39 | exec(`npm publish --tag ${isPrerelease ? 'next' : 'latest'}`)
40 |
41 | // 7) Push the v* tag to GitHub
42 | exec(`git push -f origin v${getPackageVersion()}`)
43 |
44 | // 8) Push the "latest" tag to GitHub
45 | if (!isPrerelease) {
46 | exec('git tag -f latest')
47 | exec('git push -f origin latest')
48 | }
49 |
--------------------------------------------------------------------------------
/tests.webpack.js:
--------------------------------------------------------------------------------
1 | var context = require.context('./modules', true, /-test\.js$/)
2 | context.keys().forEach(context)
3 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack')
2 |
3 | module.exports = {
4 | output: {
5 | library: 'expect',
6 | libraryTarget: 'umd'
7 | },
8 |
9 | module: {
10 | loaders: [
11 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel' }
12 | ]
13 | },
14 |
15 | plugins: [
16 | new webpack.DefinePlugin({
17 | 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
18 | })
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------