├── .gitignore ├── .travis.yml ├── HISTORY.md ├── LICENSE.md ├── README.md ├── browser.js ├── examples ├── basic │ ├── README.md │ ├── index.html │ ├── setup.js │ └── test.js └── failures │ ├── README.md │ ├── one.js │ └── two.js ├── index.js ├── package.json ├── test ├── fixtures │ └── rerequirable.js ├── globalize.js ├── jquery.js ├── mocha.opts ├── rerequire_test.js ├── robust.js ├── setup.js ├── simple.js ├── skip_window_check.js ├── standard_test.js └── use_each.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage.html 3 | /coverage -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | script: npm run coverage 4 | node_js: 5 | - '6' 6 | - '7' 7 | cache: 8 | directories: 9 | - node_modules 10 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | ## [v2.0.0] 2 | > Jun 5, 2018 3 | 4 | See [Upgrading to v2.0.0](https://github.com/rstacruz/mocha-jsdom#upgrading-to-v200) for notes on how to update from an older version. 5 | 6 | * [#32] - `jsdom` is now a direct dependency of `mocha-jsdom` :tada: 7 | 8 | [#32]: https://github.com/rstacruz/mocha-jsdom/issues/32 9 | [v2.0.0]: https://github.com/rstacruz/mocha-jsdom/compare/v1.2.0...v2.0.0 10 | 11 | ## [v1.2.0] 12 | > Jun 5, 2018 13 | 14 | * [#29] - Update Jsdom compatibility ([@RobLoach]) 15 | * [#31] - Update all npm dependencies 16 | 17 | [#29]: https://github.com/rstacruz/mocha-jsdom/issues/29 18 | [#31]: https://github.com/rstacruz/mocha-jsdom/issues/31 19 | [@RobLoach]: https://github.com/robloach 20 | [v1.2.0]: https://github.com/rstacruz/mocha-jsdom/compare/v1.1.0...v1.2.0 21 | 22 | ## [v1.1.0] 23 | > Feb 22, 2016 24 | 25 | * [#18] - Initialize global.window when it is undefined; fixes compatibility with [airbnb/enzyme][]. ([@moonboots]) 26 | 27 | [v1.1.0]: https://github.com/rstacruz/mocha-jsdom/compare/v1.0.0...v1.1.0 28 | 29 | ## [v1.0.0] - Jul 4, 2015 30 | 31 | * Add testling/browserify support. 32 | * Add more examples. 33 | 34 | [v1.0.0]: https://github.com/rstacruz/mocha-jsdom/compare/v0.5.0...v1.0.0 35 | 36 | ## [v0.5.0] - Jun 26, 2015 37 | 38 | * Add `rerequire()` to help with using mocha-jsdom with `mocha --watch`. 39 | * Internal: change coding standard to feross/standard. 40 | 41 | ## [v0.4.0] - May 25, 2015 42 | 43 | * [#5] - Add `useEach` option. ([@jasco], [#6]) 44 | * [#7] - Add a `skipWindowCheck` option. 45 | 46 | ## [v0.3.0] - Apr 3, 2015 47 | 48 | * [#3] - Bump `jsdom` dependency version. This fixes the "needs a context" error ([@nacyot], [#3]) 49 | 50 | [#3]: https://github.com/rstacruz/mocha-jsdom/issues/3 51 | [#4]: https://github.com/rstacruz/mocha-jsdom/issues/4 52 | [@nacyot]: https://github.com/nacyot 53 | 54 | ## [v0.2.1] - Feb 19, 2014 55 | 56 | * Add `LICENSE` file 57 | * Update documentation 58 | * No functionality changes 59 | 60 | ## [v0.2.0] - November 5, 2014 61 | 62 | * Skip warnings. Add `JSDOM_VERBOSE=1` to your env to reenable them. 63 | 64 | ## [v0.1.2] - September 27, 2014 65 | 66 | * Throw a useful error when invoked twice. 67 | 68 | ## [v0.1.1] - September 27, 2014 69 | 70 | * Re-release with updated Readme. 71 | 72 | [airbnb/enzyme]: https://github.com/airbnb/enzyme 73 | 74 | ## v0.1.0 - September 25, 2014 75 | 76 | * Initial version. 77 | 78 | [#5]: https://github.com/rstacruz/mocha-jsdom/issues/5 79 | [#6]: https://github.com/rstacruz/mocha-jsdom/issues/6 80 | [#7]: https://github.com/rstacruz/mocha-jsdom/issues/7 81 | [@jasco]: https://github.com/jasco 82 | [v0.5.0]: https://github.com/rstacruz/mocha-jsdom/compare/v0.4.0...v0.5.0 83 | [v0.4.0]: https://github.com/rstacruz/mocha-jsdom/compare/v0.3.0...v0.4.0 84 | [v0.3.0]: https://github.com/rstacruz/mocha-jsdom/compare/v0.2.1...v0.3.0 85 | [v0.2.1]: https://github.com/rstacruz/mocha-jsdom/compare/v0.2.0...v0.2.1 86 | [v0.2.0]: https://github.com/rstacruz/mocha-jsdom/compare/v0.1.2...v0.2.0 87 | [v0.1.2]: https://github.com/rstacruz/mocha-jsdom/compare/v0.1.1...v0.1.2 88 | [v0.1.1]: https://github.com/rstacruz/mocha-jsdom/compare/v0.1.0...v0.1.1 89 | [#18]: https://github.com/rstacruz/mocha-jsdom/issues/18 90 | [@moonboots]: https://github.com/moonboots 91 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2015 Rico Sta. Cruz 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > _Deprecation notice:_ 2 | > Consider [jsdom-global](https://github.com/rstacruz/jsdom-global) instead, a simpler alternative that also works outside of Mocha. `mocha-jsdom` still works, but `jsdom-global` is better supported. 3 | 4 | --- 5 | 6 | # mocha-jsdom 7 | 8 | > Test frontend libraries in the console using Node.js, [mocha] and [jsdom]. 9 | 10 | [![Status](https://travis-ci.org/rstacruz/mocha-jsdom.svg?branch=master)](https://travis-ci.org/rstacruz/mocha-jsdom "See test builds") 11 | 12 |
13 | 14 | ## Usage 15 | 16 | ```sh 17 | $ npm i --save-dev mocha-jsdom 18 | ``` 19 | 20 | [![npm version](http://img.shields.io/npm/v/mocha-jsdom.svg?style=flat)](https://npmjs.org/package/mocha-jsdom "View this project on npm") 21 | 22 | Use `jsdom()` inside your `describe(...)` block (or the global context). It will 23 | turn your Node.js environment into a mock browser environment supporting the 24 | full DOM and browser API. The variables `window`, `document`, `history` (and so 25 | on) will then be available for use. 26 | 27 | ```js 28 | var jsdom = require('mocha-jsdom') 29 | var expect = require('chai').expect 30 | 31 | describe('mocha tests', function () { 32 | 33 | jsdom() 34 | 35 | it('has document', function () { 36 | var div = document.createElement('div') 37 | expect(div.nodeName).eql('DIV') 38 | }) 39 | 40 | }) 41 | ``` 42 | 43 | See [examples/basic](examples/basic) for an example of a basic setup. 44 | 45 |
46 | 47 | ## Upgrading to v2.0.0 48 | 49 | If you are coming from mocha-jsdom v1.x, remove `jsdom` if you're not using it before upgrading. `jsdom` is now a direct dependency of `mocha-jsdom`. 50 | 51 | ```bash 52 | # using Yarn 53 | yarn remove jsdom 54 | yarn upgrade mocha-jsdom 55 | ``` 56 | 57 | ```bash 58 | # using npm 59 | npm uninstall -S -D jsdom 60 | npm upgrade mocha-jsdom 61 | ``` 62 | 63 |
64 | 65 | ## Node and io.js information 66 | 67 | As of jsdom 4.0.0, [jsdom now requires io.js](https://github.com/tmpvar/jsdom/blob/master/Changelog.md#400) and will not work with Node.js 0.12 or below. 68 | 69 |
70 | 71 | ## How it works 72 | 73 | mocha-jsdom is a simple glue to integrate [jsdom] to mocha. 74 | 75 | Invoking `jsdom()` will inject `before` and `after` handlers to the current 76 | mocha suite which will setup and teardown jsdom. Here's what it does: 77 | 78 | * __Window__: `global.window` will be available as the jsdom. 79 | 80 | * __Globals__: global variables like `document` and `history` are propagated, 81 | and they're cleaned up after tests run. 82 | 83 | * __Error handling__: jsdom errors are sanitized so that their stack traces are 84 | shortened. 85 | 86 | __NB:__ Before you try this library, learn about jsdom first. In fact, you may be 87 | able to integrate jsdom into your tests *without* this library; this is mostly 88 | syntactic sugar and reasonable defaults. 89 | 90 |
91 | 92 | ## Using with a library 93 | 94 | Perfect for testing small DOM-consuming utilities in the console. See 95 | [test/jquery.js](test/jquery.js) for an example. 96 | 97 | ```js 98 | describe('mocha tests', function () { 99 | 100 | var $ 101 | jsdom() 102 | 103 | before(function () { 104 | $ = require('jquery') 105 | }) 106 | 107 | it('works', function () { 108 | document.body.innerHTML = '
hola
' 109 | expect($("div").html()).eql('hola') 110 | }) 111 | 112 | }) 113 | ``` 114 | 115 | See [examples/basic](examples/basic) for an example of a basic setup. 116 | 117 |
118 | 119 | ## Using with a library, alternate 120 | 121 | You can also pass the source code via `src`: 122 | 123 | ```js 124 | describe('mocha tests', function () { 125 | jsdom({ 126 | src: fs.readFileSync('jquery.js', 'utf-8') 127 | }) 128 | 129 | ... 130 | }) 131 | ``` 132 | 133 |
134 | 135 | ## Configuration 136 | 137 | You can pass jsdom options: 138 | 139 | ```js 140 | describe('mocha tests', function () { 141 | jsdom({ 142 | parsingMode: 'xml' 143 | }) 144 | 145 | ... 146 | }) 147 | ``` 148 | 149 |
150 | 151 | ## Working with mocha --watch 152 | 153 | When using with `--watch`, you my encounter strange errors from 3rd-party 154 | libraries like jQuery not working properly. 155 | 156 | In these cases, use `require('mocha-jsdom').rerequire` instead of `require()`. 157 | This will ensure that the `require()` call will always happen. 158 | 159 | ```js 160 | var $ 161 | var jsdom = require('mocha-jsdom') 162 | var rerequire = jsdom.rerequire 163 | 164 | jsdom() 165 | 166 | before(function () { 167 | $ = rerequire('jquery') 168 | }) 169 | ``` 170 | 171 |
172 | 173 | ## Special config 174 | 175 | Other mocha-jsdom specific options: 176 | 177 | * `globalize` - propagates to values in `window` to `global`. defaults to true. 178 | 179 | * `console` - allows you to use `console.log` inside a jsdom script. defaults 180 | to true. 181 | 182 | * `useEach` - bind to Mocha's `beforeEach`/`afterEach` rather than `before`/`after`. 183 | defaults to false. 184 | 185 | * `skipWindowCheck` - skips checking of `window` at startup. When false, 186 | mocha-jsdom will throw an error if `window` already exists. Defaults to false. 187 | 188 | [jsdom]: https://www.npmjs.org/package/jsdom 189 | [mocha]: https://www.npmjs.com/package/mocha 190 | 191 |
192 | 193 | ## Testling support 194 | 195 | Yes, fully compatible with testling. A test suite using jsdom should be able to use testling. 196 | 197 | See [examples/basic](examples/basic/) for a setup that allows for testing via iojs (jsdom), testling, and mocha via the browser. 198 | 199 |
200 | 201 | ## Thanks 202 | 203 | > **mocha-jsdom** © 2014-2018 Rico Sta. Cruz. Released under the [MIT] License.
204 | > Authored and maintained by Rico Sta. Cruz with help from contributors ([list][contributors]). 205 | 206 | [![](https://img.shields.io/github/followers/rstacruz.svg?style=social&label=@rstacruz)](https://github.com/rstacruz) 207 |    208 | [![](https://img.shields.io/twitter/follow/rstacruz.svg?style=social&label=@rstacruz)](https://twitter.com/rstacruz) 209 |    210 | **[ricostacruz.com](http://ricostacruz.com)** 211 | 212 | [mit]: http://mit-license.org/ 213 | [contributors]: http://github.com/rstacruz/mocha-jsdom/contributors 214 | -------------------------------------------------------------------------------- /browser.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A noop version in case your tests are browserified (eg, when using 3 | * testling). 4 | */ 5 | 6 | module.exports = function () {} 7 | -------------------------------------------------------------------------------- /examples/basic/README.md: -------------------------------------------------------------------------------- 1 | This is a basic example of what you can put in your project's `test/` folder. 2 | It will allow you to run tests in both jsdom (iojs/node) and the browser. 3 | -------------------------------------------------------------------------------- /examples/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mocha 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/basic/setup.js: -------------------------------------------------------------------------------- 1 | if (typeof process === 'object') { 2 | // Initialize node environment 3 | global.expect = require('chai').expect 4 | require('mocha-jsdom')() 5 | } else { 6 | window.expect = window.chai.expect 7 | window.require = function () { /* noop */ } 8 | } 9 | -------------------------------------------------------------------------------- /examples/basic/test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, before, expect */ 2 | require('./setup') 3 | 4 | describe('my library', function () { 5 | var mylib 6 | 7 | before(function () { 8 | mylib = require('mylib') || window.mylib 9 | }) 10 | 11 | it('works', function () { 12 | expect(mylib.greet()).to.eql('hola') 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /examples/failures/README.md: -------------------------------------------------------------------------------- 1 | These examples are here so you can see what failures look like. 2 | 3 | Run `mocha one.js` or `mocha two.js` to see. 4 | -------------------------------------------------------------------------------- /examples/failures/one.js: -------------------------------------------------------------------------------- 1 | /* global it, expect, describe */ 2 | /* jshint expr: true */ 3 | 4 | var jsdom = require('../../index') 5 | 6 | describe('error', function () { 7 | jsdom({ 8 | src: "(function () { throw new Error('ffff'); })()" 9 | }) 10 | 11 | it('fails', function () { 12 | expect(global.document).be.undefined // eslint-disable-line no-unused-expressions 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /examples/failures/two.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, expect */ 2 | 3 | describe('src', function () { 4 | require('../../index')({ 5 | src: '}}' 6 | }) 7 | 8 | it('works', function () { 9 | expect(window.lol()).eql('DIV') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var extend = Object.assign || require('util')._extend // eslint-disable-line node/no-deprecated-api 2 | var Path = require('path') 3 | 4 | /* 5 | * store original global keys 6 | */ 7 | 8 | var blacklist = Object.keys(global) 9 | blacklist.push('constructor') 10 | 11 | /* 12 | * default config 13 | */ 14 | 15 | var defaults = { 16 | url: 'http://localhost', 17 | globalize: true, 18 | console: true, 19 | useEach: false, 20 | skipWindowCheck: false, 21 | html: 22 | "" + 23 | '' 24 | } 25 | 26 | /* 27 | * simple jsdom integration. 28 | * You can pass jsdom options in, too: 29 | * 30 | * require('./support/jsdom')({ 31 | * src: [ jquery ] 32 | * }) 33 | */ 34 | 35 | module.exports = function (_options) { 36 | var options = extend(extend({}, defaults), _options) 37 | 38 | var keys = [] 39 | 40 | var before = options.useEach ? global.beforeEach : global.before 41 | var after = options.useEach ? global.afterEach : global.after 42 | 43 | /* 44 | * register jsdom before the entire test suite 45 | */ 46 | 47 | before(function (next) { 48 | if (global.window && !options.skipWindowCheck) { 49 | throw new Error( 50 | 'mocha-jsdom: already a browser environment, or mocha-jsdom invoked ' + 51 | "twice. use 'skipWindowCheck' to disable this check." 52 | ) 53 | } 54 | require('jsdom/lib/old-api').env( 55 | extend(extend({}, options), { done: done }) 56 | ) 57 | 58 | function done (errors, window) { 59 | if (options.globalize) { 60 | propagateToGlobal(window) 61 | } else { 62 | global.window = window 63 | } 64 | 65 | if (options.console) { 66 | window.console = global.console 67 | } 68 | 69 | if (errors) { 70 | return next(getError(errors)) 71 | } 72 | 73 | next(null) 74 | } 75 | }) 76 | 77 | /* 78 | * undo keys from being propagated to global after the test suite 79 | */ 80 | 81 | after(function () { 82 | if (options.globalize) { 83 | keys.forEach(function (key) { 84 | delete global[key] 85 | }) 86 | } else { 87 | delete global.window 88 | } 89 | }) 90 | 91 | /* 92 | * propagate keys from `window` to `global` 93 | */ 94 | 95 | function propagateToGlobal (window) { 96 | for (var key in window) { 97 | if (!window.hasOwnProperty(key)) continue 98 | if (~blacklist.indexOf(key)) continue 99 | if (global[key]) { 100 | if (process.env.JSDOM_VERBOSE) { 101 | console.warn( 102 | "[jsdom] Warning: skipping cleanup of global['" + key + "']" 103 | ) 104 | } 105 | continue 106 | } 107 | 108 | keys.push(key) 109 | global[key] = window[key] 110 | } 111 | } 112 | 113 | /* 114 | * re-throws jsdom errors 115 | */ 116 | 117 | function getError (errors) { 118 | var data = errors[0].data 119 | var err = data.error 120 | err.message = err.message + ' [jsdom]' 121 | 122 | // clean up stack trace 123 | if (err.stack) { 124 | err.stack = err.stack 125 | .split('\n') 126 | .reduce(function (list, line) { 127 | if (line.match(/node_modules.+(jsdom|mocha)/)) { 128 | return list 129 | } 130 | 131 | line = line 132 | .replace(/file:\/\/.*