Last active
August 29, 2015 14:22
-
-
Save ide/77d6e4d907083f23143e to your computer and use it in GitHub Desktop.
Using <script> tags to evaluate code in jest
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright (c) 2014, Facebook, Inc. All rights reserved. | |
* | |
* This source code is licensed under the BSD-style license found in the | |
* LICENSE file in the root directory of this source tree. An additional grant | |
* of patent rights can be found in the PATENTS file in the same directory. | |
*/ | |
'use strict'; | |
var FakeTimers = require('./lib/FakeTimers'); | |
var util = require('util'); | |
var uuid = require('uuid'); | |
function _deepCopy(obj) { | |
var newObj = {}; | |
var value; | |
for (var key in obj) { | |
value = obj[key]; | |
if (typeof value === 'object' && value !== null) { | |
value = _deepCopy(value); | |
} | |
newObj[key] = value; | |
} | |
return newObj; | |
} | |
function JSDomEnvironment(config) { | |
// We lazily require jsdom because it takes a good ~.5s to load. | |
// | |
// Since this file may be require'd at the top of other files that may/may not | |
// use it (depending on the context -- such as TestRunner.js when operating as | |
// a workerpool parent), this is the best way to ensure we only spend time | |
// require()ing this when necessary. | |
var jsdom = require('./lib/jsdom-compat'); | |
this.document = jsdom.jsdom(/* markup */undefined, { | |
resourceLoader: this._fetchExternalResource.bind(this), | |
features: { | |
FetchExternalResources: ['script'], | |
ProcessExternalResources: ['script'], | |
}, | |
}); | |
this.global = this.document.defaultView; | |
// Node's error-message stack size is limited at 10, but it's pretty useful to | |
// see more than that when a test fails. | |
this.global.Error.stackTraceLimit = 100; | |
// Setup defaults for navigator.onLine | |
// TODO: It's questionable as to whether this should go here | |
// It's a pretty rarely depended on feature, so maybe tests that care | |
// about it should just shim it themselves?) | |
this.global.navigator.onLine = true; | |
// Pass through the node implementation of some needed APIs | |
this.global.ArrayBuffer = ArrayBuffer; | |
this.global.Float32Array = Float32Array; | |
this.global.Int16Array = Int16Array; | |
this.global.Int32Array = Int32Array; | |
this.global.Int8Array = Int8Array; | |
this.global.Uint8Array = Uint8Array; | |
this.global.Uint16Array = Uint16Array; | |
this.global.Uint32Array = Uint32Array; | |
this.global.DataView = DataView; | |
this.global.Buffer = Buffer; | |
this.global.setImmediate = setImmediate; | |
this.global.clearImmediate = clearImmediate; | |
this.fakeTimers = new FakeTimers(this.global); | |
// I kinda wish tests just did this manually rather than relying on a | |
// helper function to do it, but I'm keeping it for backward compat reasons | |
// while we get jest deployed internally. Then we can look into removing it. | |
// | |
// #3376754 | |
if (!this.global.hasOwnProperty('mockSetReadOnlyProperty')) { | |
this.global.mockSetReadOnlyProperty = function(obj, property, value) { | |
obj.__defineGetter__(property, function() { | |
return value; | |
}); | |
}; | |
} | |
// jsdom doesn't have support for window.Image, so we just replace it with a | |
// dummy constructor | |
try { | |
/* jshint nonew:false */ | |
new this.global.Image(); | |
} catch (e) { | |
this.global.Image = function Image() {}; | |
} | |
// Pass through the node `process` global. | |
// TODO: Consider locking this down somehow so tests can't do crazy stuff to | |
// worker processes... | |
this.global.process = process; | |
// Apply any user-specified global vars | |
var globalValues = _deepCopy(config.globals); | |
for (var customGlobalKey in globalValues) { | |
// Always deep-copy objects so isolated test environments can't share memory | |
this.global[customGlobalKey] = globalValues[customGlobalKey]; | |
} | |
} | |
JSDomEnvironment.prototype._fetchExternalResource = function(resource, callback) { | |
var content = this._scriptToServe; | |
delete this._scriptToServe; | |
if (content == null) { | |
var error = new Error('Unable to find source for ' + resource.url.href); | |
} | |
callback(error, content); | |
}; | |
JSDomEnvironment.prototype.dispose = function() { | |
// TODO: In node 0.8.8 (at least), closing each jsdom context appears to | |
// reproducibly cause a worker to segfault after a large number of tests | |
// have run (repro cases had > 1200). | |
// | |
// Disabling this to solve the problem for now -- but we should come | |
// back and investigate this soon. There's a reasonable chance that not | |
// closing out our contexts is eating an absurd amount of memory... | |
//this.global.close(); | |
}; | |
/** | |
* Evaluates the given source text as if it were in a file with the given name | |
* and returns the result. | |
*/ | |
JSDomEnvironment.prototype.runSourceText = function(sourceText, fileName) { | |
// We evaluate code by inserting <script src="${filename}"> into the document | |
// and using jsdom's resource loader to simulate serving the source code. We | |
// wrap the source in an eval call to capture the result. | |
var tempVariable = '_' + uuid().replace(/-/g, '_'); | |
this._scriptToServe = util.format( | |
'var %s = eval(%s);', | |
tempVariable, | |
JSON.stringify(sourceText) | |
); | |
var scriptElement = this.document.createElement('script'); | |
scriptElement.src = fileName; | |
this.document.head.appendChild(scriptElement); | |
var result = this.global[tempVariable]; | |
delete this.global[tempVariable]; | |
return result; | |
}; | |
JSDomEnvironment.prototype.runWithRealTimers = function(cb) { | |
this.fakeTimers.runWithRealTimers(cb); | |
}; | |
module.exports = JSDomEnvironment; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ node bin/jest.js | |
Using Jest CLI v0.4.5 | |
PASS HasteModuleLoader/__tests__/HasteModuleLoader-currentTestPath-test.js (0.035s) | |
PASS HasteModuleLoader/__tests__/HasteModuleLoader-genMockFromModule-test.js (0.792s) | |
PASS __tests__/TestRunner-test.js (1.258s) | |
PASS jasmineTestRunner/__tests__/JasmineReporter-test.js (0.15s) | |
PASS lib/__tests__/FakeTimers-test.js (0.223s) | |
PASS lib/__tests__/moduleMocker-test.js (0.025s) | |
PASS __tests__/TestRunner-fs-test.js (2.149s) | |
PASS HasteModuleLoader/__tests__/HasteModuleLoader-getTestEnvData-test.js (2.191s) | |
PASS lib/__tests__/utils-pathNormalize-test.js (0.074s) | |
PASS lib/__tests__/utils-normalizeConfig-test.js (0.652s) | |
PASS HasteModuleLoader/__tests__/HasteModuleLoader-NODE_PATH-test.js (3.638s) | |
PASS HasteModuleLoader/__tests__/HasteModuleLoader-hasDependency-test.js (5.392s) | |
PASS HasteModuleLoader/__tests__/HasteModuleLoader-requireModuleOrMock-test.js (8.758s) | |
Waiting on 2 tests..._writableState.buffer is deprecated. Use _writableState.getBuffer() instead. | |
PASS HasteModuleLoader/__tests__/HasteModuleLoader-requireMock-test.js (29.202s) | |
PASS HasteModuleLoader/__tests__/HasteModuleLoader-requireModule-test.js (43.083s) | |
15 tests passed (15 total) | |
Run time: 44.466s |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment