diff --git a/client/karma.js b/client/karma.js index 0311a3dcc..684ce95be 100644 --- a/client/karma.js +++ b/client/karma.js @@ -222,14 +222,17 @@ var Karma = function(socket, iframe, opener, navigator, location) { // report browser name, id socket.on('connect', function() { - currentTransport = socket.socket.transport.name; - - // TODO(vojta): make resultsBufferLimit configurable - if (currentTransport === 'websocket' || currentTransport === 'flashsocket') { - resultsBufferLimit = 1; - } else { - resultsBufferLimit = 50; - } + // Change buffer limit when upgraded + socket.io.engine.on('upgrade', function() { + currentTransport = socket.io.engine.transport.name; + + // TODO(vojta): make resultsBufferLimit configurable + if (currentTransport === 'websocket' || currentTransport === 'flashsocket') { + resultsBufferLimit = 1; + } else { + resultsBufferLimit = 50; + } + }); socket.emit('register', { name: navigator.userAgent, diff --git a/lib/server.js b/lib/server.js index 5cf4a3f19..a16deb20e 100644 --- a/lib/server.js +++ b/lib/server.js @@ -264,7 +264,6 @@ var createSocketIoServer = function(webServer, executor, config) { 'client store expiration': 0, logger: logger.create('socket.io', constant.LOG_ERROR), resource: config.urlRoot + 'socket.io', - transports: config.transports }); // hack to overcome circular dependency diff --git a/package.json b/package.json index e407c36b2..844088bdc 100644 --- a/package.json +++ b/package.json @@ -163,7 +163,7 @@ ], "dependencies": { "di": "~0.0.1", - "socket.io": "~0.9.13", + "socket.io": "~1.1.0", "chokidar": ">=0.8.2", "glob": "~3.2.7", "minimatch": "~0.2", diff --git a/static/karma.js b/static/karma.js new file mode 100644 index 000000000..3a4ecd534 --- /dev/null +++ b/static/karma.js @@ -0,0 +1,413 @@ +(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);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o cancel + if (!hasError) { + this.start(this.config); + } + + // remove reference to child iframe + this.start = UNIMPLEMENTED_START; + }; + + this.store = function(key, value) { + if (util.isUndefined(value)) { + return store[key]; + } + + if (util.instanceOf(value, 'Array')) { + var s = store[key] = []; + for (var i = 0; i < value.length; i++) { + s.push(value[i]); + } + } else { + // TODO(vojta): clone objects + deep + store[key] = value; + } + }; + + // supposed to be overriden by the context + // TODO(vojta): support multiple callbacks (queue) + this.start = UNIMPLEMENTED_START; + + socket.on('execute', function(cfg) { + // reset hasError and reload the iframe + hasError = false; + startEmitted = false; + reloadingContext = false; + self.config = cfg; + navigateContextTo(constant.CONTEXT_URL); + + // clear the console before run + // works only on FF (Safari, Chrome do not allow to clear console from js source) + if (window.console && window.console.clear) { + window.console.clear(); + } + }); + + // report browser name, id + socket.on('connect', function() { + // Change buffer limit when upgraded + socket.io.engine.on('upgrade', function() { + currentTransport = socket.io.engine.transport.name; + + // TODO(vojta): make resultsBufferLimit configurable + if (currentTransport === 'websocket' || currentTransport === 'flashsocket') { + resultsBufferLimit = 1; + } else { + resultsBufferLimit = 50; + } + }); + + socket.emit('register', { + name: navigator.userAgent, + id: browserId + }); + }); +}; + +module.exports = Karma; + +},{"./constants":1,"./stringify":4,"./util":6}],3:[function(require,module,exports){ +var Karma = require('./karma'); +var StatusUpdater = require('./updater'); +var util = require('./util'); + +var KARMA_URL_ROOT = require('./constants').KARMA_URL_ROOT; + + +// connect socket.io +// https://github.com/LearnBoost/Socket.IO/wiki/Configuring-Socket.IO +var socket = io.connect('http://' + location.host, { + 'reconnection delay': 500, + 'reconnection limit': 2000, + 'resource': KARMA_URL_ROOT.substr(1) + 'socket.io', + 'sync disconnect on unload': true, + 'max reconnection attempts': Infinity +}); + +// instantiate the updater of the view +new StatusUpdater(socket, util.elm('title'), util.elm('banner'), util.elm('browsers')); +window.karma = new Karma(socket, util.elm('context'), window.open, + window.navigator, window.location); + +},{"./constants":1,"./karma":2,"./updater":5,"./util":6}],4:[function(require,module,exports){ +var instanceOf = require('./util').instanceOf; + +var stringify = function stringify(obj, depth) { + + if (depth === 0) { + return '...'; + } + + if (obj === null) { + return 'null'; + } + + switch (typeof obj) { + case 'string': + return '\'' + obj + '\''; + case 'undefined': + return 'undefined'; + case 'function': + return obj.toString().replace(/\{[\s\S]*\}/, '{ ... }'); + case 'boolean': + return obj ? 'true' : 'false'; + case 'object': + var strs = []; + if (instanceOf(obj, 'Array')) { + strs.push('['); + for (var i = 0, ii = obj.length; i < ii; i++) { + if (i) { + strs.push(', '); + } + strs.push(stringify(obj[i], depth - 1)); + } + strs.push(']'); + } else if (instanceOf(obj, 'Date')) { + return obj.toString(); + } else if (instanceOf(obj, 'Text')) { + return obj.nodeValue; + } else if (instanceOf(obj, 'Comment')) { + return ''; + } else if (obj.outerHTML) { + return obj.outerHTML; + } else { + strs.push(obj.constructor.name); + strs.push('{'); + var first = true; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + if (first) { + first = false; + } else { + strs.push(', '); + } + + strs.push(key + ': ' + stringify(obj[key], depth - 1)); + } + } + strs.push('}'); + } + return strs.join(''); + default: + return obj; + } +}; + + +module.exports = stringify; + +},{"./util":6}],5:[function(require,module,exports){ +var VERSION = require('./constants').VERSION; + + +var StatusUpdater = function(socket, titleElement, bannerElement, browsersElement) { + var updateBrowsersInfo = function(browsers) { + var items = [], status; + for (var i = 0; i < browsers.length; i++) { + status = browsers[i].isReady ? 'idle' : 'executing'; + items.push('
  • ' + browsers[i].name + ' is ' + status + '
  • '); + } + browsersElement.innerHTML = items.join('\n'); + }; + + var updateBanner = function(status) { + return function(param) { + var paramStatus = param ? status.replace('$', param) : status; + titleElement.innerHTML = 'Karma v' + VERSION + ' - ' + paramStatus; + bannerElement.className = status === 'connected' ? 'online' : 'offline'; + }; + }; + + socket.on('connect', updateBanner('connected')); + socket.on('disconnect', updateBanner('disconnected')); + socket.on('reconnecting', updateBanner('reconnecting in $ ms...')); + socket.on('reconnect', updateBanner('connected')); + socket.on('reconnect_failed', updateBanner('failed to reconnect')); + socket.on('info', updateBrowsersInfo); + socket.on('disconnect', function() { + updateBrowsersInfo([]); + }); +}; + +module.exports = StatusUpdater; + +},{"./constants":1}],6:[function(require,module,exports){ +exports.instanceOf = function(value, constructorName) { + return Object.prototype.toString.apply(value) === '[object ' + constructorName + ']'; +}; + +exports.elm = function(id) { + return document.getElementById(id); +}; + +exports.generateId = function(prefix) { + return prefix + Math.floor(Math.random() * 10000); +}; + +exports.isUndefined = function(value) { + return typeof value === 'undefined'; +}; + +exports.isDefined = function(value) { + return !exports.isUndefined(value); +}; + +exports.parseQueryParams = function(locationSearch) { + var params = {}; + var pairs = locationSearch.substr(1).split('&'); + var keyValue; + + for (var i = 0; i < pairs.length; i++) { + keyValue = pairs[i].split('='); + params[decodeURIComponent(keyValue[0])] = decodeURIComponent(keyValue[1]); + } + + return params; +}; + +},{}]},{},[3]); \ No newline at end of file