// Load our dependencies var stringify = require('../common/stringify') // Define our context Karma constructor function ContextKarma (callParentKarmaMethod) { // Define local variables var hasError = false var self = this var isLoaded = false // Define our loggers // DEV: These are intentionally repeated in client and context this.log = function (type, args) { var values = [] for (var i = 0; i < args.length; i++) { values.push(this.stringify(args[i], 3)) } this.info({ log: values.join(', '), type: type }) } this.stringify = stringify // Define our proxy error handler // DEV: We require one in our context to track `hasError` this.error = function () { hasError = true callParentKarmaMethod('error', [].slice.call(arguments)) return false } // Define our start handler function UNIMPLEMENTED_START () { this.error('You need to include some adapter that implements __karma__.start method!') } // all files loaded, let's start the execution this.loaded = function () { // has error -> cancel if (!hasError && !isLoaded) { isLoaded = true try { this.start(this.config) } catch (error) { this.error(error.stack || error.toString()) } } // remove reference to child iframe this.start = UNIMPLEMENTED_START } // supposed to be overridden by the context // TODO(vojta): support multiple callbacks (queue) this.start = UNIMPLEMENTED_START // Define proxy methods // DEV: This is a closured `for` loop (same as a `forEach`) for IE support var proxyMethods = ['complete', 'info', 'result'] for (var i = 0; i < proxyMethods.length; i++) { (function bindProxyMethod (methodName) { self[methodName] = function boundProxyMethod () { callParentKarmaMethod(methodName, [].slice.call(arguments)) } }(proxyMethods[i])) } // Define bindings for context window this.setupContext = function (contextWindow) { // If we clear the context after every run and we already had an error // then stop now. Otherwise, carry on. if (self.config.clearContext && hasError) { return } // Perform window level bindings // DEV: We return `self.error` since we want to `return false` to ignore errors contextWindow.onerror = function () { return self.error.apply(self, arguments) } contextWindow.onbeforeunload = function () { return self.error('Some of your tests did a full page reload!') } contextWindow.dump = function () { self.log('dump', arguments) } var _confirm = contextWindow.confirm var _prompt = contextWindow.prompt contextWindow.alert = function (msg) { self.log('alert', [msg]) } contextWindow.confirm = function (msg) { self.log('confirm', [msg]) return _confirm(msg) } contextWindow.prompt = function (msg, defaultVal) { self.log('prompt', [msg, defaultVal]) return _prompt(msg, defaultVal) } // If we want to overload our console, then do it function getConsole (currentWindow) { return currentWindow.console || { log: function () {}, info: function () {}, warn: function () {}, error: function () {}, debug: function () {} } } if (self.config.captureConsole) { // patch the console var localConsole = contextWindow.console = getConsole(contextWindow) var logMethods = ['log', 'info', 'warn', 'error', 'debug'] var patchConsoleMethod = function (method) { var orig = localConsole[method] if (!orig) { return } localConsole[method] = function () { self.log(method, arguments) try { return Function.prototype.apply.call(orig, localConsole, arguments) } catch (error) { self.log('warn', ['Console method ' + method + ' threw: ' + error]) } } } for (var i = 0; i < logMethods.length; i++) { patchConsoleMethod(logMethods[i]) } } } } // Define call/proxy methods ContextKarma.getDirectCallParentKarmaMethod = function (parentWindow) { return function directCallParentKarmaMethod (method, args) { // If the method doesn't exist, then error out if (!parentWindow.karma[method]) { parentWindow.karma.error('Expected Karma method "' + method + '" to exist but it doesn\'t') return } // Otherwise, run our method parentWindow.karma[method].apply(parentWindow.karma, args) } } ContextKarma.getPostMessageCallParentKarmaMethod = function (parentWindow) { return function postMessageCallParentKarmaMethod (method, args) { parentWindow.postMessage({ __karmaMethod: method, __karmaArguments: args }, window.location.origin) } } // Export our module module.exports = ContextKarma