1 (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
3 VERSION: '%KARMA_VERSION%',
4 KARMA_URL_ROOT: '%KARMA_URL_ROOT%',
5 CONTEXT_URL: 'context.html'
8 },{}],2:[function(require,module,exports){
9 var stringify = require('./stringify')
10 var constant = require('./constants')
11 var util = require('./util')
13 /* jshint unused: false */
14 var Karma = function (socket, iframe, opener, navigator, location) {
16 var startEmitted = false
17 var reloadingContext = false
20 var queryParams = util.parseQueryParams(location.search)
21 var browserId = queryParams.id || util.generateId('manual-')
22 var returnUrl = queryParams['return_url' + ''] || null
25 var resultsBufferLimit = 1
26 var resultsBuffer = []
28 this.VERSION = constant.VERSION
31 var childWindow = null
32 var navigateContextTo = function (url) {
33 if (self.config.useIframe === false) {
34 if (childWindow === null || childWindow.closed === true) {
35 // If this is the first time we are opening the window, or the window is closed
36 childWindow = opener('about:blank')
38 childWindow.location = url
44 this.setupContext = function (contextWindow) {
49 var getConsole = function (currentWindow) {
50 return currentWindow.console || {
54 error: function () {},
59 contextWindow.__karma__ = this
61 // This causes memory leak in Chrome (17.0.963.66)
62 contextWindow.onerror = function () {
63 return contextWindow.__karma__.error.apply(contextWindow.__karma__, arguments)
66 contextWindow.onbeforeunload = function (e, b) {
67 if (!reloadingContext) {
68 // TODO(vojta): show what test (with explanation about jasmine.UPDATE_INTERVAL)
69 contextWindow.__karma__.error('Some of your tests did a full page reload!')
73 if (self.config.captureConsole) {
75 var localConsole = contextWindow.console = getConsole(contextWindow)
76 var logMethods = ['log', 'info', 'warn', 'error', 'debug']
77 var patchConsoleMethod = function (method) {
78 var orig = localConsole[method]
82 localConsole[method] = function () {
83 self.log(method, arguments)
84 return Function.prototype.apply.call(orig, localConsole, arguments)
87 for (var i = 0; i < logMethods.length; i++) {
88 patchConsoleMethod(logMethods[i])
92 contextWindow.dump = function () {
93 self.log('dump', arguments)
96 contextWindow.alert = function (msg) {
97 self.log('alert', [msg])
101 this.log = function (type, args) {
104 for (var i = 0; i < args.length; i++) {
105 values.push(this.stringify(args[i], 3))
108 this.info({log: values.join(', '), type: type})
111 this.stringify = stringify
113 var clearContext = function () {
114 reloadingContext = true
115 navigateContextTo('about:blank')
118 // error during js file loading (most likely syntax error)
119 // we are not going to execute at all
120 this.error = function (msg, url, line) {
122 socket.emit('error', url ? msg + '\nat ' + url + (line ? ':' + line : '') : msg)
127 this.result = function (result) {
129 socket.emit('start', {total: null})
133 if (resultsBufferLimit === 1) {
134 return socket.emit('result', result)
137 resultsBuffer.push(result)
139 if (resultsBuffer.length === resultsBufferLimit) {
140 socket.emit('result', resultsBuffer)
145 this.complete = function (result) {
146 if (resultsBuffer.length) {
147 socket.emit('result', resultsBuffer)
151 // give the browser some time to breath, there could be a page reload, but because a bunch of
152 // tests could run in the same event loop, we wouldn't notice.
153 setTimeout(function () {
157 socket.emit('complete', result || {}, function () {
159 location.href = returnUrl
164 this.info = function (info) {
165 // TODO(vojta): introduce special API for this
166 if (!startEmitted && util.isDefined(info.total)) {
167 socket.emit('start', info)
170 socket.emit('info', info)
174 var UNIMPLEMENTED_START = function () {
175 this.error('You need to include some adapter that implements __karma__.start method!')
178 // all files loaded, let's start the execution
179 this.loaded = function () {
180 // has error -> cancel
182 this.start(this.config)
185 // remove reference to child iframe
186 this.start = UNIMPLEMENTED_START
189 this.store = function (key, value) {
190 if (util.isUndefined(value)) {
194 if (util.instanceOf(value, 'Array')) {
195 var s = store[key] = []
196 for (var i = 0; i < value.length; i++) {
200 // TODO(vojta): clone objects + deep
205 // supposed to be overriden by the context
206 // TODO(vojta): support multiple callbacks (queue)
207 this.start = UNIMPLEMENTED_START
209 socket.on('execute', function (cfg) {
210 // reset hasError and reload the iframe
213 reloadingContext = false
215 navigateContextTo(constant.CONTEXT_URL)
217 // clear the console before run
218 // works only on FF (Safari, Chrome do not allow to clear console from js source)
219 if (window.console && window.console.clear) {
220 window.console.clear()
224 // report browser name, id
225 socket.on('connect', function () {
226 currentTransport = socket.socket.transport.name
228 // TODO(vojta): make resultsBufferLimit configurable
229 if (currentTransport === 'websocket' || currentTransport === 'flashsocket') {
230 resultsBufferLimit = 1
232 resultsBufferLimit = 50
235 socket.emit('register', {
236 name: navigator.userAgent,
242 module.exports = Karma
244 },{"./constants":1,"./stringify":4,"./util":6}],3:[function(require,module,exports){
246 /* eslint-disable no-new */
248 var Karma = require('./karma')
249 var StatusUpdater = require('./updater')
250 var util = require('./util')
252 var KARMA_URL_ROOT = require('./constants').KARMA_URL_ROOT
255 // https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO
256 var socket = io.connect(location.protocol + '//' + location.host, {
257 'reconnection delay': 500,
258 'reconnection limit': 2000,
259 'resource': KARMA_URL_ROOT.substr(1) + 'socket.io',
260 'sync disconnect on unload': true,
261 'max reconnection attempts': Infinity
264 // instantiate the updater of the view
265 new StatusUpdater(socket, util.elm('title'), util.elm('banner'), util.elm('browsers'))
266 window.karma = new Karma(socket, util.elm('context'), window.open,
267 window.navigator, window.location)
269 },{"./constants":1,"./karma":2,"./updater":5,"./util":6}],4:[function(require,module,exports){
270 var instanceOf = require('./util').instanceOf
272 var stringify = function stringify (obj, depth) {
281 switch (typeof obj) {
283 return "'" + obj + "'"
287 return obj.toString().replace(/\{[\s\S]*\}/, '{ ... }')
289 return obj ? 'true' : 'false'
292 if (instanceOf(obj, 'Array')) {
294 for (var i = 0, ii = obj.length; i < ii; i++) {
298 strs.push(stringify(obj[i], depth - 1))
301 } else if (instanceOf(obj, 'Date')) {
302 return obj.toString()
303 } else if (instanceOf(obj, 'Text')) {
305 } else if (instanceOf(obj, 'Comment')) {
306 return '<!--' + obj.nodeValue + '-->'
307 } else if (obj.outerHTML) {
310 var constructor = 'Object'
311 if (obj.constructor && typeof obj.constructor === 'function') {
312 constructor = obj.constructor.name
315 strs.push(constructor)
318 for (var key in obj) {
319 if (Object.prototype.hasOwnProperty.call(obj, key)) {
326 strs.push(key + ': ' + stringify(obj[key], depth - 1))
337 module.exports = stringify
339 },{"./util":6}],5:[function(require,module,exports){
340 var VERSION = require('./constants').VERSION
342 var StatusUpdater = function (socket, titleElement, bannerElement, browsersElement) {
343 var updateBrowsersInfo = function (browsers) {
344 var items = [], status
345 for (var i = 0; i < browsers.length; i++) {
346 status = browsers[i].isReady ? 'idle' : 'executing'
347 items.push('<li class="' + status + '">' + browsers[i].name + ' is ' + status + '</li>')
349 browsersElement.innerHTML = items.join('\n')
352 var updateBanner = function (status) {
353 return function (param) {
354 var paramStatus = param ? status.replace('$', param) : status
355 titleElement.innerHTML = 'Karma v' + VERSION + ' - ' + paramStatus
356 bannerElement.className = status === 'connected' ? 'online' : 'offline'
360 socket.on('connect', updateBanner('connected'))
361 socket.on('disconnect', updateBanner('disconnected'))
362 socket.on('reconnecting', updateBanner('reconnecting in $ ms...'))
363 socket.on('reconnect', updateBanner('connected'))
364 socket.on('reconnect_failed', updateBanner('failed to reconnect'))
365 socket.on('info', updateBrowsersInfo)
366 socket.on('disconnect', function () {
367 updateBrowsersInfo([])
371 module.exports = StatusUpdater
373 },{"./constants":1}],6:[function(require,module,exports){
374 exports.instanceOf = function (value, constructorName) {
375 return Object.prototype.toString.apply(value) === '[object ' + constructorName + ']'
378 exports.elm = function (id) {
379 return document.getElementById(id)
382 exports.generateId = function (prefix) {
383 return prefix + Math.floor(Math.random() * 10000)
386 exports.isUndefined = function (value) {
387 return typeof value === 'undefined'
390 exports.isDefined = function (value) {
391 return !exports.isUndefined(value)
394 exports.parseQueryParams = function (locationSearch) {
396 var pairs = locationSearch.substr(1).split('&')
399 for (var i = 0; i < pairs.length; i++) {
400 keyValue = pairs[i].split('=')
401 params[decodeURIComponent(keyValue[0])] = decodeURIComponent(keyValue[1])