diff --git a/client/karma.js b/client/karma.js index 8bdd9fb07..30dfba7eb 100644 --- a/client/karma.js +++ b/client/karma.js @@ -49,12 +49,31 @@ var Karma = function (socket, iframe, opener, navigator, location) { var childWindow = null var navigateContextTo = function (url) { if (self.config.useIframe === false) { - // If there is a window already open, then close it - // DEV: In some environments (e.g. Electron), we don't have setter access for location - if (childWindow !== null && childWindow.closed !== true) { - childWindow.close() + // run in new window + if (self.config.runInParent === false) { + // If there is a window already open, then close it + // DEV: In some environments (e.g. Electron), we don't have setter access for location + if (childWindow !== null && childWindow.closed !== true) { + childWindow.close() + } + childWindow = opener(url) + // run context on parent element and dynamically loading scripts + } else if (url !== 'about:blank') { + var loadScript = function (idx) { + if (idx < window.__karma__.scriptUrls.length) { + var ele = document.createElement('script') + ele.src = window.__karma__.scriptUrls[idx] + ele.onload = function () { + loadScript(idx + 1) + } + document.body.appendChild(ele) + } else { + window.__karma__.loaded() + } + } + loadScript(0) } - childWindow = opener(url) + // run in iframe } else { iframe.src = url } diff --git a/client/updater.js b/client/updater.js index fa5e6383b..c5c0cf425 100644 --- a/client/updater.js +++ b/client/updater.js @@ -2,6 +2,9 @@ var VERSION = require('./constants').VERSION var StatusUpdater = function (socket, titleElement, bannerElement, browsersElement) { var updateBrowsersInfo = function (browsers) { + if (!browsersElement) { + return + } var items = [] var status for (var i = 0; i < browsers.length; i++) { @@ -13,6 +16,9 @@ var StatusUpdater = function (socket, titleElement, bannerElement, browsersEleme var updateBanner = function (status) { return function (param) { + if (!titleElement || !bannerElement) { + return + } var paramStatus = param ? status.replace('$', param) : status titleElement.innerHTML = 'Karma v' + VERSION + ' - ' + paramStatus bannerElement.className = status === 'connected' ? 'online' : 'offline' diff --git a/docs/config/01-configuration-file.md b/docs/config/01-configuration-file.md index da70a16b1..c5b15ea56 100644 --- a/docs/config/01-configuration-file.md +++ b/docs/config/01-configuration-file.md @@ -225,6 +225,14 @@ How this value is used is up to your test adapter - you should check your adapte If true, Karma runs the tests inside an iFrame. If false, Karma runs the tests in a new window. Some tests may not run in an iFrame and may need a new window to run. +## client.runInParent +**Type:** Boolean + +**Default:** `false` + +**Description:** Run the tests on the same window as the client, without using iframe or a new window + +If true, Karma runs the tests inside the original window without using iframe. It will load the test scripts dynamically. ## client.captureConsole **Type:** Boolean @@ -289,6 +297,14 @@ Disable this when you need to load external scripts that are served without the **Description:** If `null` (default), uses karma's own `debug.html` file. +## customClientContextFile +**Type:** string + +**Default:** `null` + +**Description:** If `null` (default), uses karma's own `client_with_context.html` file (which is used when client.runInParent set to true). + + ## customHeaders **Type:** Array diff --git a/lib/config.js b/lib/config.js index 00f631789..deeaf6d7d 100644 --- a/lib/config.js +++ b/lib/config.js @@ -138,6 +138,7 @@ var normalizeConfig = function (config, configFilePath) { config.exclude = config.exclude.map(basePathResolve) config.customContextFile = config.customContextFile && basePathResolve(config.customContextFile) config.customDebugFile = config.customDebugFile && basePathResolve(config.customDebugFile) + config.customClientContextFile = config.customClientContextFile && basePathResolve(config.customClientContextFile) // normalize paths on windows config.basePath = helper.normalizeWinPath(config.basePath) @@ -145,6 +146,7 @@ var normalizeConfig = function (config, configFilePath) { config.exclude = config.exclude.map(helper.normalizeWinPath) config.customContextFile = helper.normalizeWinPath(config.customContextFile) config.customDebugFile = helper.normalizeWinPath(config.customDebugFile) + config.customClientContextFile = helper.normalizeWinPath(config.customClientContextFile) // normalize urlRoot config.urlRoot = normalizeUrlRoot(config.urlRoot) @@ -183,6 +185,16 @@ var normalizeConfig = function (config, configFilePath) { config.autoWatch = false } + if (config.runInParent) { + log.debug('useIframe set to false, because using runInParent') + config.useIframe = false + } + + if (!config.singleRun && !config.useIframe && config.runInParent) { + log.debug('singleRun set to true, because using runInParent') + config.singleRun = true + } + if (helper.isString(config.reporters)) { config.reporters = config.reporters.split(',') } @@ -296,6 +308,7 @@ var Config = function () { } this.customContextFile = null this.customDebugFile = null + this.customClientContextFile = null this.exclude = [] this.logLevel = constant.LOG_INFO this.colors = true @@ -320,6 +333,7 @@ var Config = function () { this.defaultClient = this.client = { args: [], useIframe: true, + runInParent: false, captureConsole: true, clearContext: true } diff --git a/lib/middleware/karma.js b/lib/middleware/karma.js index 7f8b591ab..3392096bd 100644 --- a/lib/middleware/karma.js +++ b/lib/middleware/karma.js @@ -89,6 +89,7 @@ var createKarmaMiddleware = function ( var client = injector.get('config.client') var customContextFile = injector.get('config.customContextFile') var customDebugFile = injector.get('config.customDebugFile') + var customClientContextFile = injector.get('config.customClientContextFile') var jsVersion = injector.get('config.jsVersion') var includeCrossOriginAttribute = injector.get('config.crossOriginAttribute') @@ -112,11 +113,16 @@ var createKarmaMiddleware = function ( // serve client.html if (requestUrl === '/') { - return serveStaticFile('/client.html', requestedRangeHeader, response, function (data) { - return data - .replace('\n%X_UA_COMPATIBLE%', getXUACompatibleMetaElement(request.url)) - .replace('%X_UA_COMPATIBLE_URL%', getXUACompatibleUrl(request.url)) - }) + // redirect client_with_context.html + if (!client.useIframe && client.runInParent) { + requestUrl = '/client_with_context.html' + } else { // serve client.html + return serveStaticFile('/client.html', requestedRangeHeader, response, function (data) { + return data + .replace('\n%X_UA_COMPATIBLE%', getXUACompatibleMetaElement(request.url)) + .replace('%X_UA_COMPATIBLE_URL%', getXUACompatibleUrl(request.url)) + }) + } } // serve karma.js, context.js, and debug.js @@ -139,11 +145,12 @@ var createKarmaMiddleware = function ( // or debug.html - execution context without channel to the server var isRequestingContextFile = requestUrl === '/context.html' var isRequestingDebugFile = requestUrl === '/debug.html' - if (isRequestingContextFile || isRequestingDebugFile) { + var isRequestingClientContextFile = requestUrl === '/client_with_context.html' + if (isRequestingContextFile || isRequestingDebugFile || isRequestingClientContextFile) { return filesPromise.then(function (files) { var fileServer var requestedFileUrl - log.debug('custom files', customContextFile, customDebugFile) + log.debug('custom files', customContextFile, customDebugFile, customClientContextFile) if (isRequestingContextFile && customContextFile) { log.debug('Serving customContextFile %s', customContextFile) fileServer = serveFile @@ -152,6 +159,10 @@ var createKarmaMiddleware = function ( log.debug('Serving customDebugFile %s', customDebugFile) fileServer = serveFile requestedFileUrl = customDebugFile + } else if (isRequestingClientContextFile && customClientContextFile) { + log.debug('Serving customClientContextFile %s', customClientContextFile) + fileServer = serveFile + requestedFileUrl = customClientContextFile } else { log.debug('Serving static request %s', requestUrl) fileServer = serveStaticFile @@ -161,7 +172,10 @@ var createKarmaMiddleware = function ( fileServer(requestedFileUrl, requestedRangeHeader, response, function (data) { common.setNoCacheHeaders(response) - var scriptTags = files.included.map(function (file) { + var scriptTags = [] + var scriptUrls = [] + for (var i in files.included) { + var file = files.included[i] var filePath = file.path var fileExt = path.extname(filePath) @@ -173,12 +187,16 @@ var createKarmaMiddleware = function ( } } + scriptUrls.push(filePath) + if (fileExt === '.css') { - return util.format(LINK_TAG_CSS, filePath) + scriptTags.push(util.format(LINK_TAG_CSS, filePath)) + continue } if (fileExt === '.html') { - return util.format(LINK_TAG_HTML, filePath) + scriptTags.push(util.format(LINK_TAG_HTML, filePath)) + continue } // The script tag to be placed @@ -190,8 +208,8 @@ var createKarmaMiddleware = function ( } var crossOriginAttribute = includeCrossOriginAttribute ? CROSSORIGIN_ATTRIBUTE : '' - return util.format(SCRIPT_TAG, scriptType, filePath, crossOriginAttribute) - }) + scriptTags.push(util.format(SCRIPT_TAG, scriptType, filePath, crossOriginAttribute)) + } // TODO(vojta): don't compute if it's not in the template var mappings = files.served.map(function (file) { @@ -206,11 +224,14 @@ var createKarmaMiddleware = function ( var clientConfig = 'window.__karma__.config = ' + JSON.stringify(client) + ';\n' + var scriptUrlsJS = 'window.__karma__.scriptUrls = ' + JSON.stringify(scriptUrls) + ';\n' + mappings = 'window.__karma__.files = {\n' + mappings.join(',\n') + '\n};\n' return data .replace('%SCRIPTS%', scriptTags.join('\n')) .replace('%CLIENT_CONFIG%', clientConfig) + .replace('%SCRIPT_URL_ARRAY%', scriptUrlsJS) .replace('%MAPPINGS%', mappings) .replace('\n%X_UA_COMPATIBLE%', getXUACompatibleMetaElement(request.url)) }) diff --git a/static/client_with_context.html b/static/client_with_context.html new file mode 100644 index 000000000..e562bdee1 --- /dev/null +++ b/static/client_with_context.html @@ -0,0 +1,125 @@ + + + + +
+ +