siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
191 lines (129 loc) • 5.37 kB
JavaScript
/*
Siesta 5.6.1
Copyright(c) 2009-2022 Bryntum AB
https://bryntum.com/contact
https://bryntum.com/products/siesta/license
*/
Class('Scope.Provider.NodeJS', {
isa : Scope.Provider,
has : {
sourceURL : null,
requireFunc : null,
errorHandlerBorrowed : null,
onErrorHandler : null
},
methods : {
runInContext : function (code, scope, options) {
var vm = require('vm')
return vm.runInContext(code, scope, options)
},
addOnErrorHandler : function (handler, preventDefault) {
var me = this
if (me.eventHandlerBorrowed) throw new Error("Exclusive resource borrowing failed")
me.onErrorHandler = handler
var exceptionHander
var rejectionHandler
process.on('uncaughtException', exceptionHandler = function (e) {
handler(e.message, null, null, null, e)
})
process.on('unhandledRejection', rejectHandler = function (reason) {
handler(null, null, null, null, null, { reason : reason })
})
return me.eventHandlerBorrowed = function () {
process.removeListener('uncaughtException', exceptionHandler)
process.removeListener('unhandledRejection', rejectHandler)
me.eventHandlerBorrowed = null
me.onErrorHandler = null
}
},
create : function (callback) {
var vm = require('vm')
var sandbox = {}
Joose.O.extend(sandbox, {
process : process,
console : console,
global : sandbox,
// TODO wrap this in functions in target context
// currently in the test context `setTimeout instanceOf Function === false`
setImmediate : setImmediate,
clearImmediate : clearImmediate,
setTimeout : setTimeout,
clearTimeout : clearTimeout,
setInterval : setInterval,
clearInterval : clearInterval
})
var scope = this.scope = vm.createContext(sandbox)
callback && callback()
},
setup : function (callback) {
this.create()
var me = this
if (this.seedingCode) this.runCode(this.seedingCode)
Joose.A.each(this.getPreload(), function (preloadDesc) {
if (preloadDesc.type == 'js')
if (preloadDesc.url)
me.runScript(preloadDesc.url)
else
me.runCode(preloadDesc.content)
})
if (this.seedingScript) {
this.runScript(this.seedingScript)
}
callback && callback(me)
},
stripBom : function (content) {
// Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
// because the buffer-to-string conversion in `fs.readFileSync()`
// translates it to FEFF, the UTF-16 BOM.
if (content.charCodeAt(0) === 0xFEFF) content = content.slice(1)
return content
},
fileNameToModuleId : function (url) {
var path = require('path')
var filename
if (path.isAbsolute(url)) {
filename = url
} else {
filename = path.resolve('./', url)
}
return filename
},
runCode : function (text, callback) {
var vm = require('vm')
var res = vm.runInContext(this.stripBom(text), this.scope)
callback && callback(res)
return res
},
runScript : function (url, callback) {
if (/mjs(\?.*)?$/.test(url)) {
return this.importEcmaModule(url, callback)
} else
return this.requireCjsModule(url, callback)
},
requireCjsModule : function (url, callback) {
var vm = require('vm')
var old = vm.runInThisContext
var scope = this.scope
vm.runInThisContext = function (code, options) {
return vm.runInContext(code, scope, options)
}
try {
var res = this.requireFunc(this.fileNameToModuleId(url))
} catch (e) {
this.onErrorHandler && this.onErrorHandler(e.message, null, null, null, e)
}
vm.runInThisContext = old
callback && callback(res)
return res
},
importEcmaModule : function (url, callback) {
// seems node only support dynamic `import` for the current context
// see how it is implemented in NodeJsEmbed
throw new Error("Ecma module for different context - implement me?")
},
cleanup : function () {
if (this.beforeCleanupCallback) this.beforeCleanupCallback()
if (this.cleanupCallback) this.cleanupCallback()
}
}
})