d2-ui
Version:
180 lines (148 loc) • 4.09 kB
JavaScript
var extend = require('util')._extend
var Path = require('path')
/*
* store original global keys
*/
var blacklist = Object.keys(global)
blacklist.push('constructor')
/*
* default config
*/
var defaults = {
globalize: true,
console: true,
useEach: false,
skipWindowCheck: false,
html: "<!doctype html><html><head><meta charset='utf-8'></head>" +
'<body></body></html>'
}
/*
* simple jsdom integration.
* You can pass jsdom options in, too:
*
* require('./support/jsdom')({
* src: [ jquery ]
* })
*/
module.exports = function (_options) {
var options = extend(extend({}, defaults), _options)
var keys = []
var before = options.useEach ? global.beforeEach : global.before
var after = options.useEach ? global.afterEach : global.after
/*
* register jsdom before the entire test suite
*/
before(function (next) {
if (global.window && !options.skipWindowCheck) {
throw new Error(
'mocha-jsdom: already a browser environment, or mocha-jsdom invoked ' +
"twice. use 'skipWindowCheck' to disable this check.")
}
require('jsdom').env(
extend(extend({}, options), { done: done }))
function done (errors, window) {
if (options.globalize) {
propagateToGlobal(window)
} else {
global.window = window
}
if (options.console) {
window.console = global.console
}
if (errors) {
return next(getError(errors))
}
next(null)
}
})
/*
* undo keys from being propagated to global after the test suite
*/
after(function () {
if (options.globalize) {
keys.forEach(function (key) {
delete global[key]
})
} else {
delete global.window
}
})
/*
* propagate keys from `window` to `global`
*/
function propagateToGlobal (window) {
for (var key in window) {
if (!window.hasOwnProperty(key)) continue
if (~blacklist.indexOf(key)) continue
if (global[key]) {
if (process.env.JSDOM_VERBOSE) {
console.warn("[jsdom] Warning: skipping cleanup of global['" + key + "']")
}
continue
}
keys.push(key)
global[key] = window[key]
}
}
/*
* re-throws jsdom errors
*/
function getError (errors) {
var data = errors[0].data
var err = data.error
err.message = err.message + ' [jsdom]'
// clean up stack trace
if (err.stack) {
err.stack = err.stack.split('\n')
.reduce(function (list, line) {
if (line.match(/node_modules.+(jsdom|mocha)/)) {
return list
}
line = line
.replace(/file:\/\/.*<script>/g, '<script>')
.replace(/:undefined:undefined/g, '')
list.push(line)
return list
}, []).join('\n')
}
return err
}
}
module.exports.rerequire = rerequire
/**
* Requires a module via `require()`, but invalidates the cache so it may be
* called again in the future. Useful for `mocha --watch`.
*
* var rerequire = require('mocha-jsdom').rerequire
* var $ = rerequire('jquery')
*/
function rerequire (module) {
if (module[0] === '.') {
module = Path.join(Path.dirname(getCaller()), module)
}
var oldkeys = Object.keys(require.cache)
var result = require(module)
var newkeys = Object.keys(require.cache)
newkeys.forEach(function (newkey) {
if (!~oldkeys.indexOf(newkey)) {
delete require.cache[newkey]
}
})
return result
}
/**
* Internal: gets the filename of the caller function. The `offset` defines how
* many hops away it's expected to be from in the stack trace.
*
* See: http://stackoverflow.com/questions/16697791/nodejs-get-filename-of-caller-function
*/
function getCaller (offset) {
/* eslint-disable handle-callback-err */
if (typeof offset !== 'number') offset = 1
var old = Error.prepareStackTrace
var err = new Error()
Error.prepareStackTrace = function (err, stack) { return stack }
var fname = err.stack[1 + offset].getFileName()
Error.prepareStackTrace = old
return fname
}