| // 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 overriden 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) | |
| } | |
| // DEV: We must defined a function since we don't want to pass the event object | |
| contextWindow.onbeforeunload = function (e, b) { | |
| callParentKarmaMethod('onbeforeunload', []) | |
| } | |
| 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 |