[Pkg-javascript-commits] [sockjs-client] 91/350: Basic tests passing

tonnerre at ancient-solutions.com tonnerre at ancient-solutions.com
Fri Aug 5 01:03:46 UTC 2016


This is an automated email from the git hooks/post-receive script.

tonnerre-guest pushed a commit to branch upstream
in repository sockjs-client.

commit 6bd16c0b58e3f53edd373b4219687500f3caba5d
Author: Bryce Kahle <bkahle at gmail.com>
Date:   Tue Oct 7 22:22:16 2014 -0400

    Basic tests passing
---
 .eslintrc                                          |  18 ++
 .travis.yml                                        |   2 +-
 gulpfile.js                                        |  27 ++-
 lib/abstract-xhr.js                                |  14 +-
 lib/closeevent.js                                  |   2 +-
 lib/entry.js                                       |  23 +++
 lib/{ => error}/invalidaccesserror.js              |   0
 lib/{ => error}/invalidstateerror.js               |   0
 lib/{ => error}/securityerror.js                   |   0
 lib/info-receiver-fake.js                          |  19 --
 lib/info-receiver-iframe.js                        |   2 +
 lib/info-receiver.js                               |  54 ++++--
 lib/main.js                                        | 193 ++++++++++++++++++---
 lib/{ => polyfills}/event.js                       |   0
 lib/{ => polyfills}/eventtarget.js                 |  12 +-
 lib/{ => polyfills}/location.js                    |   1 +
 lib/protocols.js                                   |  48 -----
 lib/shims.js                                       |  25 +++
 lib/simpleevent.js                                 |  23 +--
 lib/trans-iframe.js                                |  14 +-
 lib/trans-message-event.js                         |  15 ++
 lib/trans-receiver-eventsource.js                  |   6 +-
 lib/trans-receiver-htmlfile.js                     |   5 +-
 lib/trans-receiver-xhr.js                          |   5 +-
 .../iframe-eventsource.js}                         |   2 +-
 .../iframe-htmlfile.js}                            |   2 +-
 .../iframe-xhr-polling.js}                         |   2 +-
 .../jsonp-polling.js}                              |   5 +-
 lib/{trans-websocket.js => transport/websocket.js} |  29 +++-
 .../xdr-polling.js}                                |   8 +-
 .../xdr-streaming.js}                              |  14 +-
 .../xhr-polling.js}                                |  10 +-
 .../xhr-streaming.js}                              |  14 +-
 lib/transports.js                                  |  27 +++
 lib/utils.js                                       |  30 ++--
 lib/xdr.js                                         |   4 +-
 lib/xhr-cors.js                                    |   4 +-
 lib/xhr-fake.js                                    |  17 ++
 lib/xhr-local.js                                   |   2 +-
 package.json                                       |   8 +-
 tests/main.js                                      |  23 +--
 tests/transports.js                                |  39 +++++
 42 files changed, 529 insertions(+), 219 deletions(-)

diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..f7c6371
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,18 @@
+{
+  "env": {
+    "node": true,
+    "browser": true
+  },
+  "rules": {
+    "consistent-this": [2, "self"],
+    "quotes": [1, "single", "avoid-escape"],
+    "no-space-before-semi": [0],
+    "no-underscore-dangle": [0]
+  },
+  "globals": {
+    "XDomainRequest": true,
+    "XMLHttpRequest": true,
+    "EventSource": true,
+    "ActiveXObject": true
+  }
+}
diff --git a/.travis.yml b/.travis.yml
index 6ef9762..4b002ad 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,7 @@ language: node_js
 node_js:
   - '0.10'
 before_script:
-  - "gulp test"
+  - "gulp testbundle"
 script:
   - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && npm test || false'
 addons:
diff --git a/gulpfile.js b/gulpfile.js
index 0487098..3ccaa6c 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -6,12 +6,31 @@ var gulp = require('gulp')
   , mold = require('mold-source-map')
   , source = require('vinyl-source-stream')
   , path = require('path')
-  , jsRoot = path.join(__dirname, 'lib')
+  , mocha = require('gulp-mocha')
+  , eslint = require('gulp-eslint')
   , pkg = require('./package.json')
+  ;
+
+var jsRoot = path.join(__dirname, 'lib')
   , libName = 'sockjs-' + pkg.version
   ;
 
-gulp.task('test', function() {
+gulp.task('test', function () {
+  gulp.src('tests/main.js', {read: false})
+    .pipe(mocha());
+});
+
+gulp.task('eslint', function () {
+  gulp.src(['lib/**/*.js', '!lib/sockjs.js'])
+    .pipe(eslint())
+    .pipe(eslint.format());
+});
+
+gulp.task('watch', function () {
+  gulp.watch('tests/*.js', ['test']);
+});
+
+gulp.task('testbundle', function() {
   browserify('./lib/sockjs.js')
     .bundle({
       standalone: 'SockJS'
@@ -48,7 +67,7 @@ gulp.task('browserify:min', function () {
     .plugin('minifyify', {
       map: libName + '.min.js.map'
     , compressPath: jsRoot
-    , output: './build/'+ libName + '.min.js.map'
+    , output: './build/' + libName + '.min.js.map'
     })
     .bundle({
       standalone: 'SockJS'
@@ -56,4 +75,4 @@ gulp.task('browserify:min', function () {
     .pipe(source(libName + '.min.js'))
     .pipe(gulp.dest('./build/'))
     ;
-});
\ No newline at end of file
+});
diff --git a/lib/abstract-xhr.js b/lib/abstract-xhr.js
index f5dc3a2..de79385 100644
--- a/lib/abstract-xhr.js
+++ b/lib/abstract-xhr.js
@@ -5,16 +5,12 @@ var EventEmitter = require('events').EventEmitter
   , utils = require('./utils')
   ;
 
-function AbstractXHRObject() {
-}
-
-util.inherits(AbstractXHRObject, EventEmitter);
-
-AbstractXHRObject.prototype._start = function(method, url, payload, opts) {
+function AbstractXHRObject(method, url, payload, opts) {
   var self = this;
+  EventEmitter.call(this);
 
   try {
-    this.xhr = new XMLHttpRequest();
+    this.xhr = new global.XMLHttpRequest();
   } catch(x) {}
 
   if (!this.xhr) {
@@ -88,7 +84,9 @@ AbstractXHRObject.prototype._start = function(method, url, payload, opts) {
     }
   };
   self.xhr.send(payload);
-};
+}
+
+util.inherits(AbstractXHRObject, EventEmitter);
 
 AbstractXHRObject.prototype._cleanup = function(abort) {
   if (!this.xhr) {
diff --git a/lib/closeevent.js b/lib/closeevent.js
index 31beb6b..de9a51b 100644
--- a/lib/closeevent.js
+++ b/lib/closeevent.js
@@ -1,7 +1,7 @@
 'use strict';
 
 var util = require('util')
-  , Event = require('./event')
+  , Event = require('./polyfills/event')
   ;
 
 function CloseEvent() {
diff --git a/lib/entry.js b/lib/entry.js
new file mode 100644
index 0000000..1591a96
--- /dev/null
+++ b/lib/entry.js
@@ -0,0 +1,23 @@
+'use strict';
+
+var browserTransports = [
+  // streaming transports
+  require('./transport/websocket')
+, require('./transport/xdr-streaming')
+, require('./transport/xhr-streaming')
+, require('./transport/iframe-eventsource')
+
+  // polling transports
+, require('./transport/iframe-htmlfile')
+, require('./transport/xdr-polling')
+, require('./transport/xhr-polling')
+, require('./transport/iframe-xhr-polling')
+, require('./transport/jsonp-polling')
+];
+
+var nodeTransports = [
+  require('./transport/websocket')
+];
+
+var transports = typeof window !== 'undefined' ? browserTransports : nodeTransports;
+module.exports = require('./main')(transports);
diff --git a/lib/invalidaccesserror.js b/lib/error/invalidaccesserror.js
similarity index 100%
rename from lib/invalidaccesserror.js
rename to lib/error/invalidaccesserror.js
diff --git a/lib/invalidstateerror.js b/lib/error/invalidstateerror.js
similarity index 100%
rename from lib/invalidstateerror.js
rename to lib/error/invalidstateerror.js
diff --git a/lib/securityerror.js b/lib/error/securityerror.js
similarity index 100%
rename from lib/securityerror.js
rename to lib/error/securityerror.js
diff --git a/lib/info-receiver-fake.js b/lib/info-receiver-fake.js
deleted file mode 100644
index d64a223..0000000
--- a/lib/info-receiver-fake.js
+++ /dev/null
@@ -1,19 +0,0 @@
-'use strict';
-
-var EventEmitter = require('events').EventEmitter
-  , util = require('util')
-  ;
-
-var InfoReceiverFake = function() {
-  // It may not be possible to do cross domain AJAX to get the info
-  // data, for example for IE7. But we want to run JSONP, so let's
-  // fake the response, with rtt=2s (rto=6s).
-  var self = this;
-  process.nextTick(function() {
-    self.emit('finish', {}, 2000);
-  });
-};
-
-util.inherits(InfoReceiverFake, EventEmitter);
-
-module.exports = InfoReceiverFake;
diff --git a/lib/info-receiver-iframe.js b/lib/info-receiver-iframe.js
index a0562ff..d957cb8 100644
--- a/lib/info-receiver-iframe.js
+++ b/lib/info-receiver-iframe.js
@@ -9,6 +9,8 @@ var EventEmitter = require('events').EventEmitter
 
 function InfoReceiverIframe(baseUrl) {
   var self = this;
+  EventEmitter.call(this);
+
   var go = function() {
     var ifr = new IframeTransport();
     ifr.protocol = 'w-iframe-info-receiver';
diff --git a/lib/info-receiver.js b/lib/info-receiver.js
index edee3e4..d61eed0 100644
--- a/lib/info-receiver.js
+++ b/lib/info-receiver.js
@@ -2,11 +2,33 @@
 
 var EventEmitter = require('events').EventEmitter
   , util = require('util')
+  , utils = require('./utils')
   , JSON3 = require('json3')
+  , loc = require('./polyfills/location')
+  , XHRCors = require('./xhr-cors')
+  , XHRLocal = require('./xhr-local')
+  , XDR = require('./xdr')
+  , XHRFake = require('./xhr-fake')
+  // it seems odd to include these just for the 'enabled' function
+  , XDRPolling = require('./transport/xdr-polling')
+  //, IframeTransport = require('./trans-iframe')
   ;
 
-function InfoReceiver(baseUrl, AjaxObject) {
+function InfoReceiver(baseUrl) {
   var self = this;
+  EventEmitter.call(this);
+
+  var AjaxObject = XHRFake;
+  if (utils.isSameOriginUrl(baseUrl, loc.href)) {
+    AjaxObject = XHRCors;
+  } else if (utils.isXHRCorsCapable() === 1) {
+    AjaxObject = XHRLocal;
+  } else if (XDRPolling.enabled(baseUrl)) {
+    AjaxObject = XDR;
+  } //else if (IframeTransport.enabled()) {
+    //AjaxObject = IframeXHR;
+  //}
+
   process.nextTick(function(){
     self.doXhr(baseUrl, AjaxObject);
   });
@@ -17,13 +39,15 @@ util.inherits(InfoReceiver, EventEmitter);
 InfoReceiver.prototype.doXhr = function(baseUrl, AjaxObject) {
   var self = this;
   var t0 = Date.now();
-  var xo = new AjaxObject('GET', baseUrl + '/info');
+  this.xo = new AjaxObject('GET', baseUrl + '/info');
 
-  var tref = setTimeout(function(){xo.ontimeout();}, 8000);
+  this.timeoutRef = setTimeout(function() {
+    self.xo.close();
+    self.emit('finish');
+  }, 8000);
 
-  xo.on('finish', function(status, text) {
-    clearTimeout(tref);
-    tref = null;
+  this.xo.on('finish', function(status, text) {
+    self._cleanup(true);
     if (status === 200) {
       var rtt = Date.now() - t0;
       var info;
@@ -41,10 +65,20 @@ InfoReceiver.prototype.doXhr = function(baseUrl, AjaxObject) {
       self.emit('finish');
     }
   });
-  xo.ontimeout = function() {
-    xo.close();
-    self.emit('finish');
-  };
+};
+
+InfoReceiver.prototype._cleanup = function(wasClean) {
+  clearTimeout(this.timeoutRef);
+  this.timeoutRef = null;
+  if (!wasClean && this.xo) {
+    this.xo.close();
+  }
+  this.xo = null;
+};
+
+InfoReceiver.prototype.close = function() {
+  this.removeAllListeners();
+  this._cleanup(false);
 };
 
 module.exports = InfoReceiver;
diff --git a/lib/main.js b/lib/main.js
index 2789c45..610fb74 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -4,24 +4,35 @@ require('./shims');
 
 var u = require('url')
   , util = require('util')
-  , SecurityError = require('./securityerror')
-  , InvalidAccessError = require('./invalidaccesserror')
-  , InvalidStateError = require('./invalidstateerror')
+  , utils = require('./utils')
+  , SecurityError = require('./error/securityerror')
+  , InvalidAccessError = require('./error/invalidaccesserror')
+  , InvalidStateError = require('./error/invalidstateerror')
+  , Event = require('./polyfills/event')
   , CloseEvent = require('./closeevent')
-  , EventTarget = require('./eventtarget')
-  , loc = require('./location')
+  , EventTarget = require('./polyfills/eventtarget')
+  , loc = require('./polyfills/location')
+  , InfoReceiver = require('./info-receiver')
+  , JSON3 = require('json3')
   ;
 
+var transports;
+
 // follow constructor steps defined at http://dev.w3.org/html5/websockets/#the-websocket-interface
-function SockJS(url, protocols) {
+function SockJS(url, protocols, transportsWhitelist) {
   if (!(this instanceof SockJS)) {
     return new SockJS(url, protocols);
   }
+  EventTarget.call(this);
 
   this.readyState = SockJS.CONNECTING;
   this.extensions = '';
   this.protocol = '';
 
+  // non-standard extension
+  // TODO attempt to remove and provide another way
+  this._transportsWhitelist = transportsWhitelist;
+
   // Step 1 of WS spec - parse and validate the url
   var parsedUrl = u.parse(url);
   if (!parsedUrl.host || !parsedUrl.pathname || !parsedUrl.protocol) {
@@ -63,8 +74,15 @@ function SockJS(url, protocols) {
 
   // Step 7 - start connection in background
   this.url = parsedUrl.href;
+  // if we don't have any path component, remove the trailing slash to make code easier
+  if (parsedUrl.path === '/') {
+    this.url = this.url.slice(0, -1);
+  }
 
-  // TODO initiate info request
+  // obtain server info
+  // http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-26
+  this._ir = new InfoReceiver(this.url);
+  this._ir.on('finish', this._receiveInfo.bind(this));
 }
 
 util.inherits(SockJS, EventTarget);
@@ -84,10 +102,148 @@ SockJS.prototype.close = function(code, reason) {
     return;
   }
 
+  // TODO look at docs to determine how to set this
   var wasClean = true;
-  // TODO if connection not established, stop it
+  this._close(code || 1000, reason || 'Normal closure', wasClean);
+};
+
+SockJS.prototype.send = function(data) {
+  if (this.readyState === SockJS.CONNECTING) {
+    throw new InvalidStateError('The connection has not been established yet');
+  }
+  if (this.readyState !== SockJS.OPEN) {
+    return;
+  }
+  this._transport.send(data);
+};
+
+SockJS.CONNECTING = 0;
+SockJS.OPEN = 1;
+SockJS.CLOSING = 2;
+SockJS.CLOSED = 3;
+
+SockJS.prototype._receiveInfo = function(info, rtt) {
+  this._ir = null;
+  if (!info) {
+    this._close(1002, 'Cannot connect to server');
+    return;
+  }
+
+  // establish a round-trip timeout (RTO) based on the
+  // round-trip time (RTT)
+  this._rto = utils.countRTO(rtt);
+  // allow server to override url used for the actual transport
+  this._transUrl = info.base_url ? info.base_url : this.url;
+  info.nullOrigin = !document.domain;
+  // determine list of desired and supported transports
+  this._transports = transports(this.url, this._transportsWhitelist, info);
+  this._connect();
+};
+
+SockJS.prototype._connect = function() {
+  for (var Transport = this._transports.shift(); Transport; Transport = this._transports.shift()) {
+    if (Transport.needBody) {
+      if (!document.body ||
+          (typeof document.readyState !== 'undefined' && document.readyState !== 'complete')) {
+        this._transports.unshift(Transport);
+        // TODO attach to load event to call _connect
+        return;
+      }
+    }
+
+    // calculate timeout based on RTO and round trips. Default to 5s
+    var timeoutMs = (this._rto * Transport.roundTrips) || 5000;
+    this._transportTimeoutId = setTimeout(this._transportTimeout.bind(this), timeoutMs);
+
+    var transportUrl = this._transUrl + '/' + this._server + '/' + utils.randomString(8);
+    var transport = new Transport(transportUrl, this._transUrl);
+    transport.onmessage = this._transportMessage.bind(this);
+    transport.onclose = this._transportClose.bind(this);
+    this._transport = transport;
+
+    return;
+  }
+  this._close(2000, 'All transports failed', false);
+};
+
+SockJS.prototype._transportTimeout = function() {
+  if (this.readyState === SockJS.CONNECTING) {
+    this._close(2007, 'Transport timed out');
+  }
+};
+
+SockJS.prototype._transportMessage = function(e) {
+  var type = e.data.slice(0, 1);
+  var payload;
+  switch (type) {
+    case 'o':
+      this._open();
+      break;
+    case 'a':
+      payload = JSON3.parse(e.data.slice(1) || '[]');
+      for (var i = 0; i < payload.length; i++){
+        this._dispatchMessage(payload[i]);
+      }
+      break;
+    case 'm':
+      payload = JSON3.parse(e.data.slice(1) || 'null');
+      this._dispatchMessage(payload);
+      break;
+    case 'c':
+      payload = JSON3.parse(e.data.slice(1) || '[]');
+      this._close(payload[0], payload[1]);
+      break;
+    case 'h':
+      this.dispatchEvent(new Event().initEvent('heartbeat'));
+      break;
+  }
+};
+
+SockJS.prototype._transportClose = function(e) {
+  this._close(e.code, e.reason);
+};
+
+SockJS.prototype._open = function() {
+  if (this.readyState === SockJS.CONNECTING) {
+    if (this._transportTimeoutId) {
+      clearTimeout(this._transportTimeoutId);
+      this._transportTimeoutId = null;
+    }
+    this.readyState = SockJS.OPEN;
+    this.transport = this._transport.transportName;
+    this.dispatchEvent(new Event().initEvent('open'));
+  } else {
+    // The server might have been restarted, and lost track of our
+    // connection.
+    this._close(1006, 'Server lost session');
+  }
+};
+
+SockJS.prototype._dispatchMessage = function(data) {
+  var e = new Event().initEvent('message');
+  e.data = data;
+  this.dispatchEvent(e);
+};
+
+SockJS.prototype._close = function(code, reason, wasClean) {
+  var forceFail = false;
+
+  if (this._ir) {
+    forceFail = true;
+    this._ir.close();
+    this._ir = null;
+  }
+  if (this._transport) {
+    this._transport.close();
+    this._transport.onmessage = null;
+    this._transport.onclose = null;
+    this._transport = null;
+  }
+
+  if (this.readyState === SockJS.CLOSED) {
+    throw new InvalidStateError('SockJS has already been closed');
+  }
 
-  // TODO start closing handshake
   this.readyState = SockJS.CLOSING;
   process.nextTick(function () {
     this.readyState = SockJS.CLOSED;
@@ -103,20 +259,7 @@ SockJS.prototype.close = function(code, reason) {
   }.bind(this));
 };
 
-SockJS.prototype.send = function(/* data */) {
-  if (this.readyState === SockJS.CONNECTING) {
-    throw new InvalidStateError('connection has not been established yet');
-  }
-  if (this.readyState !== SockJS.OPEN) {
-    return;
-  }
-
-  // TODO send data
+module.exports = function (availableTransports) {
+  transports = require('./transports')(availableTransports);
+  return SockJS;
 };
-
-SockJS.CONNECTING = 0;
-SockJS.OPEN = 1;
-SockJS.CLOSING = 2;
-SockJS.CLOSED = 3;
-
-module.exports = SockJS;
diff --git a/lib/event.js b/lib/polyfills/event.js
similarity index 100%
rename from lib/event.js
rename to lib/polyfills/event.js
diff --git a/lib/eventtarget.js b/lib/polyfills/eventtarget.js
similarity index 81%
rename from lib/eventtarget.js
rename to lib/polyfills/eventtarget.js
index f4d85ab..b6d5336 100644
--- a/lib/eventtarget.js
+++ b/lib/polyfills/eventtarget.js
@@ -13,11 +13,11 @@ function arrayIndexOf(arr, item) {
   return -1;
 }
 
-var REventTarget = function() {
+var EventTarget = function() {
   this._listeners = {};
 };
 
-REventTarget.prototype.addEventListener = function (eventType, listener) {
+EventTarget.prototype.addEventListener = function (eventType, listener) {
   if (!(eventType in this._listeners)) {
     this._listeners[eventType] = [];
   }
@@ -30,7 +30,7 @@ REventTarget.prototype.addEventListener = function (eventType, listener) {
   return;
 };
 
-REventTarget.prototype.removeEventListener = function (eventType, listener) {
+EventTarget.prototype.removeEventListener = function (eventType, listener) {
   if (!(eventType in this._listeners)) {
     return;
   }
@@ -38,7 +38,7 @@ REventTarget.prototype.removeEventListener = function (eventType, listener) {
   var idx = arrayIndexOf(arr, listener);
   if (idx !== -1) {
     if (arr.length > 1) {
-      // Make a copy so as not to interfer with a current dispatchEvent.
+      // Make a copy so as not to interfere with a current dispatchEvent.
       this._listeners[eventType] = arr.slice(0, idx).concat(arr.slice(idx + 1));
     } else {
       delete this._listeners[eventType];
@@ -48,7 +48,7 @@ REventTarget.prototype.removeEventListener = function (eventType, listener) {
   return;
 };
 
-REventTarget.prototype.dispatchEvent = function (event) {
+EventTarget.prototype.dispatchEvent = function (event) {
   var t = event.type;
   var args = Array.prototype.slice.call(arguments, 0);
   // TODO: This doesn't match the real behavior; per spec, onfoo get
@@ -67,4 +67,4 @@ REventTarget.prototype.dispatchEvent = function (event) {
   }
 };
 
-module.exports = global.EventTarget || REventTarget;
+module.exports = global.EventTarget || EventTarget;
diff --git a/lib/location.js b/lib/polyfills/location.js
similarity index 83%
rename from lib/location.js
rename to lib/polyfills/location.js
index 9920ade..935f4b1 100644
--- a/lib/location.js
+++ b/lib/polyfills/location.js
@@ -5,4 +5,5 @@ module.exports = global.location || {
 , protocol: 'http'
 , host: 'localhost'
 , port: 80
+, href: 'http://localhost/'
 };
diff --git a/lib/protocols.js b/lib/protocols.js
deleted file mode 100644
index c626fcd..0000000
--- a/lib/protocols.js
+++ /dev/null
@@ -1,48 +0,0 @@
-'use strict';
-
-var protocolOrdering = [
-  'websocket',
-  'xdr-streaming',
-  'xhr-streaming',
-  'iframe-eventsource',
-  'iframe-htmlfile',
-  'xdr-polling',
-  'xhr-polling',
-  'iframe-xhr-polling',
-  'jsonp-polling'
-];
-
-var allProtocols = {
-  'websocket': require('./trans-websocket')
-, 'iframe-eventsource': require('./trans-iframe-eventsource')
-, 'iframe-htmlfile': require('./trans-iframe-htmlfile')
-, 'iframe-xhr-polling': require('./trans-iframe-xhr-polling')
-, 'jsonp-polling': require('./trans-jsonp-polling')
-, 'xdr-polling': require('./trans-xdr-polling')
-, 'xdr-streaming': require('./trans-xdr-streaming')
-, 'xhr-polling': require('./trans-xhr-polling')
-, 'xhr-streaming': require('./trans-xhr-streaming')
-};
-
-module.exports = function (url, protocolsWhitelist, info) {
-  var protocols = [];
-  if (!protocolsWhitelist) {
-    protocolsWhitelist = [];
-  }
-  if (!protocolsWhitelist.length) {
-    protocolsWhitelist = protocolOrdering;
-  }
-
-  for (var i = 0; i < protocolOrdering.length; i++) {
-    var protoName = protocolOrdering[i];
-    if (protocolsWhitelist.indexOf(protoName) === -1) {
-      continue;
-    }
-
-    var proto = allProtocols[protoName];
-    if (proto && proto.enabled(url, info)) {
-      protocols.push(proto);
-    }
-  }
-  return protocols;
-};
diff --git a/lib/shims.js b/lib/shims.js
index 2f994c5..a7348da 100644
--- a/lib/shims.js
+++ b/lib/shims.js
@@ -5,3 +5,28 @@ if (!Date.now) {
     return new Date().getTime();
   };
 }
+
+if (!Function.prototype.bind) {
+  Function.prototype.bind = function (oThis) {
+    if (typeof this !== "function") {
+      // closest thing possible to the ECMAScript 5
+      // internal IsCallable function
+      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
+    }
+
+    var aArgs = Array.prototype.slice.call(arguments, 1), 
+        fToBind = this, 
+        fNOP = function () {},
+        fBound = function () {
+          return fToBind.apply(this instanceof fNOP && oThis
+                 ? this
+                 : oThis,
+                 aArgs.concat(Array.prototype.slice.call(arguments)));
+        };
+
+    fNOP.prototype = this.prototype;
+    fBound.prototype = new fNOP();
+
+    return fBound;
+  };
+}
\ No newline at end of file
diff --git a/lib/simpleevent.js b/lib/simpleevent.js
index 4bcd8b5..755d424 100644
--- a/lib/simpleevent.js
+++ b/lib/simpleevent.js
@@ -1,7 +1,13 @@
 'use strict';
 
+var util = require('util')
+  , Event = require('./polyfills/event')
+  ;
+
 var SimpleEvent = function(type, obj) {
-  this.type = type;
+  Event.call(this);
+  this.initEvent(type);
+
   if (typeof obj !== 'undefined') {
     for (var k in obj) {
       if (!obj.hasOwnProperty(k)) {
@@ -12,19 +18,6 @@ var SimpleEvent = function(type, obj) {
   }
 };
 
-SimpleEvent.prototype.toString = function() {
-  var r = [];
-  for (var k in this) {
-    if (!this.hasOwnProperty(k)) {
-      continue;
-    }
-    var v = this[k];
-    if (typeof v === 'function') {
-      v = '[function]';
-    }
-    r.push(k + '=' + v);
-  }
-  return 'SimpleEvent(' + r.join(', ') + ')';
-};
+util.inherits(SimpleEvent, Event);
 
 module.exports = SimpleEvent;
diff --git a/lib/trans-iframe.js b/lib/trans-iframe.js
index fe625f2..96ba69f 100644
--- a/lib/trans-iframe.js
+++ b/lib/trans-iframe.js
@@ -1,9 +1,9 @@
 'use strict';
 
 // Few cool transports do work only for same-origin. In order to make
-// them working cross-domain we shall use iframe, served form the
-// remote domain. New browsers, have capabilities to communicate with
-// cross domain iframe, using postMessage(). In IE it was implemented
+// them work cross-domain we shall use iframe, served from the
+// remote domain. New browsers have capabilities to communicate with
+// cross domain iframe using postMessage(). In IE it was implemented
 // from IE 8+, but of course, IE got some details wrong:
 //    http://msdn.microsoft.com/en-us/library/cc197015(v=VS.85).aspx
 //    http://stevesouders.com/misc/test-postmessage.php
@@ -85,9 +85,11 @@ IframeTransport.prototype.doSend = function (message) {
 IframeTransport.enabled = function() {
   // postMessage misbehaves in konqueror 4.6.5 - the messages are delivered with
   // huge delay, or not at all.
-  var konqueror = navigator && navigator.userAgent && navigator.userAgent.indexOf('Konqueror') !== -1;
-  return ((typeof window.postMessage === 'function' ||
-          typeof window.postMessage === 'object') && (!konqueror));
+  var konqueror = global.navigator &&
+    global.navigator.userAgent &&
+    global.navigator.userAgent.indexOf('Konqueror') !== -1;
+  return ((typeof global.postMessage === 'function' ||
+          typeof global.postMessage === 'object') && (!konqueror));
 };
 
 module.exports = IframeTransport;
diff --git a/lib/trans-message-event.js b/lib/trans-message-event.js
new file mode 100644
index 0000000..69935ef
--- /dev/null
+++ b/lib/trans-message-event.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var util = require('util')
+  , Event = require('./polyfills/event')
+  ;
+
+function TransportMessageEvent(data) {
+  Event.call(this);
+  this.initEvent('message', false, false);
+  this.data = data;
+}
+
+util.inherits(TransportMessageEvent, Event);
+
+module.exports = TransportMessageEvent;
diff --git a/lib/trans-receiver-eventsource.js b/lib/trans-receiver-eventsource.js
index 0943062..cec679b 100644
--- a/lib/trans-receiver-eventsource.js
+++ b/lib/trans-receiver-eventsource.js
@@ -2,10 +2,12 @@
 
 var util = require('util')
   , SimpleEvent = require('./simpleevent')
-  , REventTarget = require('./reventtarget')
+  , EventTarget = require('./polyfills/eventtarget')
   ;
 
 function EventSourceReceiver(url) {
+  EventTarget.call(this);
+
   var self = this;
   var es = new EventSource(url);
   es.onmessage = function(e) {
@@ -29,7 +31,7 @@ function EventSourceReceiver(url) {
   };
 }
 
-util.inherits(EventSourceReceiver, REventTarget);
+util.inherits(EventSourceReceiver, EventTarget);
 
 EventSourceReceiver.prototype.abort = function() {
   if (this.esClose) {
diff --git a/lib/trans-receiver-htmlfile.js b/lib/trans-receiver-htmlfile.js
index beb0fc4..967fead 100644
--- a/lib/trans-receiver-htmlfile.js
+++ b/lib/trans-receiver-htmlfile.js
@@ -3,7 +3,7 @@
 var util = require('util')
   , utils = require('./utils')
   , SimpleEvent = require('./simpleevent')
-  , REventTarget = require('./reventtarget')
+  , EventTarget = require('./polyfills/eventtarget')
   ;
 
 var _isIeHtmlfileCapable;
@@ -22,6 +22,7 @@ var isIeHtmlfileCapable = function() {
 
 
 function HtmlfileReceiver(url) {
+  EventTarget.call(this);
   var self = this;
   utils.polluteGlobalNamespace();
 
@@ -55,7 +56,7 @@ function HtmlfileReceiver(url) {
   });
 }
 
-util.inherits(HtmlfileReceiver, REventTarget);
+util.inherits(HtmlfileReceiver, EventTarget);
 
 HtmlfileReceiver.prototype.abort = function() {
   if (this.iframeClose) {
diff --git a/lib/trans-receiver-xhr.js b/lib/trans-receiver-xhr.js
index 8766cd5..6066abd 100644
--- a/lib/trans-receiver-xhr.js
+++ b/lib/trans-receiver-xhr.js
@@ -2,10 +2,11 @@
 
 var util = require('util')
   , SimpleEvent = require('./simpleevent')
-  , REventTarget = require('./reventtarget')
+  , EventTarget = require('./polyfills/eventtarget')
   ;
 
 function XhrReceiver(url, AjaxObject) {
+  EventTarget.call(this);
   var self = this;
   var bufPos = 0;
 
@@ -34,7 +35,7 @@ function XhrReceiver(url, AjaxObject) {
   });
 }
 
-util.inherits(XhrReceiver, REventTarget);
+util.inherits(XhrReceiver, EventTarget);
 
 XhrReceiver.prototype.abort = function() {
   if (this.xo) {
diff --git a/lib/trans-iframe-eventsource.js b/lib/transport/iframe-eventsource.js
similarity index 92%
rename from lib/trans-iframe-eventsource.js
rename to lib/transport/iframe-eventsource.js
index 941539c..002b3e7 100644
--- a/lib/trans-iframe-eventsource.js
+++ b/lib/transport/iframe-eventsource.js
@@ -1,7 +1,7 @@
 'use strict';
 
 var util = require('util')
-  , IframeTransport = require('./trans-iframe')
+  , IframeTransport = require('../trans-iframe')
   ;
 
 function EventSourceIframeTransport() {
diff --git a/lib/trans-iframe-htmlfile.js b/lib/transport/iframe-htmlfile.js
similarity index 93%
rename from lib/trans-iframe-htmlfile.js
rename to lib/transport/iframe-htmlfile.js
index 11ebff1..aaf2a46 100644
--- a/lib/trans-iframe-htmlfile.js
+++ b/lib/transport/iframe-htmlfile.js
@@ -6,7 +6,7 @@
 // production it should be only run in IE.
 
 var util = require('util')
-  , IframeTransport = require('./trans-iframe')
+  , IframeTransport = require('../trans-iframe')
   ;
 
 function HtmlFileIframeTransport() {
diff --git a/lib/trans-iframe-xhr-polling.js b/lib/transport/iframe-xhr-polling.js
similarity index 91%
rename from lib/trans-iframe-xhr-polling.js
rename to lib/transport/iframe-xhr-polling.js
index 04faf6d..3339766 100644
--- a/lib/trans-iframe-xhr-polling.js
+++ b/lib/transport/iframe-xhr-polling.js
@@ -1,7 +1,7 @@
 'use strict';
 
 var util = require('util')
-  , IframeTransport = require('./trans-iframe')
+  , IframeTransport = require('../trans-iframe')
   ;
 
 function XhrPollingIframeTransport() {
diff --git a/lib/trans-jsonp-polling.js b/lib/transport/jsonp-polling.js
similarity index 98%
rename from lib/trans-jsonp-polling.js
rename to lib/transport/jsonp-polling.js
index 560af91..faefb91 100644
--- a/lib/trans-jsonp-polling.js
+++ b/lib/transport/jsonp-polling.js
@@ -9,8 +9,8 @@
 //   o for Konqueror a dumb timer is needed to detect errors
 
 var util = require('util')
-  , utils = require('./utils')
-  , BufferedSender = require('./buffered-sender')
+  , utils = require('../utils')
+  , BufferedSender = require('../buffered-sender')
   ;
 
 // Abstract away code that handles global namespace pollution.
@@ -260,6 +260,7 @@ JsonPTransport.enabled = function() {
 };
 
 JsonPTransport.transportName = 'jsonp-polling';
+JsonPTransport.roundTrips = 1;
 JsonPTransport.needBody = true;
 
 JsonPTransport.prototype.doCleanup = function() {
diff --git a/lib/trans-websocket.js b/lib/transport/websocket.js
similarity index 63%
rename from lib/trans-websocket.js
rename to lib/transport/websocket.js
index b20fe00..a922e87 100644
--- a/lib/trans-websocket.js
+++ b/lib/transport/websocket.js
@@ -1,8 +1,15 @@
 'use strict';
 
-var utils = require('./utils');
+var utils = require('../utils')
+  , util = require('util')
+  , EventTarget = require('../polyfills/eventtarget')
+  , TransportMessageEvent = require('../trans-message-event')
+  , CloseEvent = require('../closeevent')
+  ;
+
+function WebSocketTransport(transUrl) {
+  EventTarget.call(this);
 
-function WebSocketTransport(ri, transUrl) {
   var self = this;
   var url = transUrl + '/websocket';
   if (url.slice(0, 5) === 'https') {
@@ -10,13 +17,12 @@ function WebSocketTransport(ri, transUrl) {
   } else {
     url = 'ws' + url.slice(4);
   }
-  this.ri = ri;
   this.url = url;
-  var Constructor = window.WebSocket || window.MozWebSocket;
+  var Constructor = global.WebSocket || global.MozWebSocket || require('faye-websocket').Client;
 
   this.ws = new Constructor(this.url);
   this.ws.onmessage = function(e) {
-    self.ri._didMessage(e.data);
+    self.dispatchEvent(new TransportMessageEvent(e.data));
   };
   // Firefox has an interesting bug. If a websocket connection is
   // created after onunload, it stays alive even when user
@@ -28,21 +34,26 @@ function WebSocketTransport(ri, transUrl) {
     self.ws.close();
   });
   this.ws.onclose = this.ws.onerror = function() {
-    self.ri._didMessage(utils.closeFrame(1006, 'WebSocket connection broken'));
+    var closeEvent = new CloseEvent();
+    closeEvent.code = 1006;
+    closeEvent.reason = 'WebSocket connection broken';
+    self.dispatchEvent(closeEvent);
   };
 }
 
-WebSocketTransport.prototype.doSend = function(data) {
+util.inherits(WebSocketTransport, EventTarget);
+
+WebSocketTransport.prototype.send = function(data) {
   this.ws.send('[' + data + ']');
 };
 
-WebSocketTransport.prototype.doCleanup = function() {
+WebSocketTransport.prototype.close = function() {
   var ws = this.ws;
   if (ws) {
     ws.onmessage = ws.onclose = ws.onerror = null;
     ws.close();
     utils.unloadDel(this.unloadRef);
-    this.unloadRef = this.ri = this.ws = null;
+    this.unloadRef = this.ws = null;
   }
 };
 
diff --git a/lib/trans-xdr-polling.js b/lib/transport/xdr-polling.js
similarity index 68%
rename from lib/trans-xdr-polling.js
rename to lib/transport/xdr-polling.js
index f544191..da088fd 100644
--- a/lib/trans-xdr-polling.js
+++ b/lib/transport/xdr-polling.js
@@ -1,10 +1,10 @@
 'use strict';
 
 var util = require('util')
-  , AjaxBasedTransport = require('./ajax-based')
-  , XdrStreamingTransport = require('./trans-xdr-streaming')
-  , XhrReceiver = require('./trans-receiver-xhr')
-  , XDRObject = require('./xdr')
+  , AjaxBasedTransport = require('../ajax-based')
+  , XdrStreamingTransport = require('./xdr-streaming')
+  , XhrReceiver = require('../trans-receiver-xhr')
+  , XDRObject = require('../xdr')
   ;
 
 function XdrPollingTransport(ri, transUrl) {
diff --git a/lib/trans-xdr-streaming.js b/lib/transport/xdr-streaming.js
similarity index 67%
rename from lib/trans-xdr-streaming.js
rename to lib/transport/xdr-streaming.js
index 9da1f79..7a2e577 100644
--- a/lib/trans-xdr-streaming.js
+++ b/lib/transport/xdr-streaming.js
@@ -1,10 +1,10 @@
 'use strict';
 
 var util = require('util')
-  , AjaxBasedTransport = require('./ajax-based')
-  , XhrReceiver = require('./trans-receiver-xhr')
-  , XDRObject = require('./xdr')
-  , utils = require('./utils')
+  , AjaxBasedTransport = require('../ajax-based')
+  , XhrReceiver = require('../trans-receiver-xhr')
+  , XDRObject = require('../xdr')
+  , utils = require('../utils')
   ;
 
 // According to:
@@ -18,15 +18,15 @@ function XdrStreamingTransport(ri, transUrl) {
 util.inherits(XdrStreamingTransport, AjaxBasedTransport);
 
 XdrStreamingTransport.enabled = function(url, info) {
-  if (info.cookie_needed || info.null_origin) {
+  if (info && (info.cookie_needed || info.nullOrigin)) {
     return false;
   }
   // IE 8/9 if the request target uses the same scheme - #79
-  return !!(window.XDomainRequest && document.domain && utils.isSameOriginScheme(url));
+  return !!(global.XDomainRequest && global.document &&
+    global.document.domain && utils.isSameOriginScheme(url));
 };
 
 XdrStreamingTransport.transportName = 'xdr-streaming';
-
 XdrStreamingTransport.roundTrips = 2; // preflight, ajax
 
 module.exports = XdrStreamingTransport;
diff --git a/lib/trans-xhr-polling.js b/lib/transport/xhr-polling.js
similarity index 73%
rename from lib/trans-xhr-polling.js
rename to lib/transport/xhr-polling.js
index a55eeba..88ced22 100644
--- a/lib/trans-xhr-polling.js
+++ b/lib/transport/xhr-polling.js
@@ -1,10 +1,10 @@
 'use strict';
 
 var util = require('util')
-  , AjaxBasedTransport = require('./ajax-based')
-  , XhrReceiver = require('./trans-receiver-xhr')
-  , XHRCorsObject = require('./xhr-cors')
-  , utils = require('./utils')
+  , AjaxBasedTransport = require('../ajax-based')
+  , XhrReceiver = require('../trans-receiver-xhr')
+  , XHRCorsObject = require('../xhr-cors')
+  , utils = require('../utils')
   ;
 
 function XhrPollingTransport(ri, transUrl) {
@@ -14,7 +14,7 @@ function XhrPollingTransport(ri, transUrl) {
 util.inherits(XhrPollingTransport, AjaxBasedTransport);
 
 XhrPollingTransport.enabled = function(url, info) {
-  if (info.null_origin) {
+  if (info.nullOrigin) {
     return false;
   }
   if (window.XMLHttpRequest && utils.isSameOriginUrl(url)) {
diff --git a/lib/trans-xhr-streaming.js b/lib/transport/xhr-streaming.js
similarity index 70%
rename from lib/trans-xhr-streaming.js
rename to lib/transport/xhr-streaming.js
index 12014c8..acb8bbb 100644
--- a/lib/trans-xhr-streaming.js
+++ b/lib/transport/xhr-streaming.js
@@ -1,10 +1,10 @@
 'use strict';
 
 var util = require('util')
-  , AjaxBasedTransport = require('./ajax-based')
-  , XhrReceiver = require('./trans-receiver-xhr')
-  , XHRCorsObject = require('./xhr-cors')
-  , utils = require('./utils')
+  , AjaxBasedTransport = require('../ajax-based')
+  , XhrReceiver = require('../trans-receiver-xhr')
+  , XHRCorsObject = require('../xhr-cors')
+  , utils = require('../utils')
   ;
 
 function XhrStreamingTransport(ri, transUrl) {
@@ -14,14 +14,14 @@ function XhrStreamingTransport(ri, transUrl) {
 util.inherits(XhrStreamingTransport, AjaxBasedTransport);
 
 XhrStreamingTransport.enabled = function(url, info) {
-  if (info.null_origin) {
+  if (info.nullOrigin) {
     return false;
   }
   // Opera doesn't support xhr-streaming
-  if (/opera/i.test(navigator.userAgent)) {
+  if (/opera/i.test(global.navigator.userAgent)) {
     return false;
   }
-  if (window.XMLHttpRequest && utils.isSameOriginUrl(url)) {
+  if (global.XMLHttpRequest && utils.isSameOriginUrl(url)) {
     return true;
   }
 
diff --git a/lib/transports.js b/lib/transports.js
new file mode 100644
index 0000000..499aa76
--- /dev/null
+++ b/lib/transports.js
@@ -0,0 +1,27 @@
+'use strict';
+
+module.exports = function (availableTransports) {
+  return function (url, transportsWhitelist, info) {
+    var transports = [];
+    if (!transportsWhitelist) {
+      transportsWhitelist = [];
+    }
+
+    for (var i = 0; i < availableTransports.length; i++) {
+      var trans = availableTransports[i];
+      if (!trans) {
+        continue;
+      }
+
+      if (transportsWhitelist.length &&
+          transportsWhitelist.indexOf(trans.transportName) === -1) {
+        continue;
+      }
+
+      if (trans.enabled(url, info)) {
+        transports.push(trans);
+      }
+    }
+    return transports;
+  };
+};
diff --git a/lib/utils.js b/lib/utils.js
index 3913cf8..12717e2 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -5,10 +5,10 @@ var IframeTransport = require('./trans-iframe');
 var utils = {};
 
 var getRandomBytes;
-if (window && window.crypto && window.crypto.getRandomValues) {
+if (global && global.crypto && global.crypto.getRandomValues) {
   getRandomBytes = function (length) {
     var bytes = new Uint8Array(length);
-    window.crypto.getRandomValues(bytes);
+    global.crypto.getRandomValues(bytes);
     return bytes;
   };
 } else {
@@ -73,14 +73,14 @@ utils.getOrigin = function(url) {
 utils.isSameOriginUrl = function(urlA, urlB) {
   // location.origin would do, but it's not always available.
   if (!urlB) {
-    urlB = window.location.href;
+    urlB = global.location.href;
   }
   return utils.getOrigin(urlA) === utils.getOrigin(urlB);
 };
 
 utils.isSameOriginScheme = function(urlA, urlB) {
   if (!urlB) {
-    urlB = window.location.href;
+    urlB = global.location.href;
   }
 
   return (urlA.split(':')[0] === urlB.split(':')[0]);
@@ -316,12 +316,12 @@ utils.quote = function(string) {
 // 4. Nope, sorry.
 utils.isXHRCorsCapable = function() {
   try {
-    if (window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()) {
+    if (global.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()) {
       return 1;
     }
   } catch (ignored) {}
   // XDomainRequest doesn't work if page is served from file://
-  if (window.XDomainRequest && document.domain) {
+  if (global.XDomainRequest && global.document && global.document.domain) {
     return 2;
   }
   if (IframeTransport.enabled()) {
@@ -353,15 +353,15 @@ utils.attachMessage = function(listener) {
   utils.attachEvent('message', listener);
 };
 utils.attachEvent = function(event, listener) {
-  if (typeof window.addEventListener !== 'undefined') {
-    window.addEventListener(event, listener, false);
+  if (typeof global.addEventListener !== 'undefined') {
+    global.addEventListener(event, listener, false);
   } else {
     // IE quirks.
     // According to: http://stevesouders.com/misc/test-postmessage.php
     // the message gets delivered only to 'document', not 'window'.
     document.attachEvent('on' + event, listener);
     // I get 'window' for ie8.
-    window.attachEvent('on' + event, listener);
+    global.attachEvent('on' + event, listener);
   }
 };
 
@@ -369,11 +369,11 @@ utils.detachMessage = function(listener) {
   utils.detachEvent('message', listener);
 };
 utils.detachEvent = function(event, listener) {
-  if (typeof window.addEventListener !== 'undefined') {
-    window.removeEventListener(event, listener, false);
+  if (typeof global.addEventListener !== 'undefined') {
+    global.removeEventListener(event, listener, false);
   } else {
     document.detachEvent('on' + event, listener);
-    window.detachEvent('on' + event, listener);
+    global.detachEvent('on' + event, listener);
   }
 };
 
@@ -399,13 +399,15 @@ var unloadTriggered = function() {
 
 // 'unload' alone is not reliable in opera within an iframe, but we
 // can't use `beforeunload` as IE fires it on javascript: links.
-utils.attachEvent('unload', unloadTriggered);
+
+// TODO see if we need to uncomment this
+//utils.attachEvent('unload', unloadTriggered);
 
 utils.unloadAdd = function(listener) {
   var ref = utils.randomString(8);
   onUnload[ref] = listener;
   if (afterUnload) {
-    setTimeout(triggerUnloadCallbacks, 0);
+    process.nextTick(triggerUnloadCallbacks);
   }
   return ref;
 };
diff --git a/lib/xdr.js b/lib/xdr.js
index 6ba39a7..8291d75 100644
--- a/lib/xdr.js
+++ b/lib/xdr.js
@@ -11,6 +11,8 @@ var EventEmitter = require('events').EventEmitter
 
 function XDRObject(method, url, payload) {
   var self = this;
+  EventEmitter.call(this);
+  
   process.nextTick(function(){
     self._start(method, url, payload);
   });
@@ -20,7 +22,7 @@ util.inherits(XDRObject, EventEmitter);
 
 XDRObject.prototype._start = function(method, url, payload) {
   var self = this;
-  var xdr = new XDomainRequest();
+  var xdr = new global.XDomainRequest();
   // IE caches even POSTs
   url += ((url.indexOf('?') === -1) ? '?' : '&') + 't=' + Date.now();
 
diff --git a/lib/xhr-cors.js b/lib/xhr-cors.js
index ef79e5f..04d0052 100644
--- a/lib/xhr-cors.js
+++ b/lib/xhr-cors.js
@@ -4,12 +4,12 @@ var util = require('util')
   , AbstractXHRObject = require('./abstract-xhr')
   ;
 
-function XHRCorsObject() {
+function XHRCorsObject(method, url, payload, opts) {
   var self = this
     , args = arguments
     ;
   process.nextTick(function(){
-    self._start.apply(self, args);
+    AbstractXHRObject.apply(self, args);
   });
 }
 
diff --git a/lib/xhr-fake.js b/lib/xhr-fake.js
new file mode 100644
index 0000000..360f08d
--- /dev/null
+++ b/lib/xhr-fake.js
@@ -0,0 +1,17 @@
+'use strict';
+
+var EventEmitter = require('events').EventEmitter
+  , util = require('util')
+  ;
+
+function XHRFake(method, url, payload, opts) {
+  EventEmitter.call(this);
+
+  setTimeout(function() {
+    self.emit('finish', 200, '{}');
+  }, 2000);
+}
+
+util.inherits(XHRFake, EventEmitter);
+
+module.exports = XHRFake;
diff --git a/lib/xhr-local.js b/lib/xhr-local.js
index 5ab3b6d..654da17 100644
--- a/lib/xhr-local.js
+++ b/lib/xhr-local.js
@@ -7,7 +7,7 @@ var util = require('util')
 function XHRLocalObject(method, url, payload) {
   var self = this;
   process.nextTick(function(){
-    self._start(method, url, payload, {
+    AbstractXHRObject.call(self, method, url, payload, {
       noCredentials: true
     });
   });
diff --git a/package.json b/package.json
index b62ae2d..bfaf9d2 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,8 @@
     }
   ],
   "dependencies": {
-    "json3": "^3.3.2"
+    "json3": "^3.3.2",
+    "faye-websocket": "~0.7.3"
   },
   "devDependencies": {
     "browserify": "^4.2.3",
@@ -29,7 +30,6 @@
     "expect.js": "~0.3.1",
     "proxyquire": "~1.0.1",
     "gulp-mocha": "~1.1.0",
-    "gulp-jsbeautifier": "0.0.2",
     "gulp-eslint": "~0.1.8"
   },
   "homepage": "http://sockjs.org",
@@ -38,14 +38,14 @@
     "websocket"
   ],
   "license": "MIT",
-  "main": "./lib/sockjs.js",
+  "main": "./lib/entry.js",
   "private": true,
   "repository": {
     "type": "git",
     "url": "https://github.com/sockjs/sockjs-client.git"
   },
   "scripts": {
-    "t": "node ./node_modules/mocha/bin/mocha tests/main.js",
+    "t": "node ./node_modules/mocha/bin/mocha tests/main.js tests/transports.js",
     "test": "./node_modules/zuul/bin/zuul --sauce-connect -- tests/html/lib/unittests.js tests/html/lib/domtests.js tests/html/lib/endtoendtests.js tests/html/lib/tests.js",
     "test_ws": "./node_modules/zuul/bin/zuul --sauce-connect -- tests/html/lib/ws_test.js",
     "test_local": "./node_modules/zuul/bin/zuul --local 9090 -- tests/html/lib/unittests.js tests/html/lib/domtests.js tests/html/lib/endtoendtests.js tests/html/lib/tests.js"
diff --git a/tests/main.js b/tests/main.js
index 4ef1ce6..aa7fec2 100644
--- a/tests/main.js
+++ b/tests/main.js
@@ -2,8 +2,8 @@
 
 var expect = require('expect.js')
   , proxyquire = require('proxyquire')
-  , SecurityError = require('../lib/securityerror')
-  , SockJS = require('../lib/main')
+  , SecurityError = require('../lib/error/securityerror')
+  , SockJS = require('../lib/entry')
   ;
 
 describe('SockJS', function() {
@@ -15,7 +15,7 @@ describe('SockJS', function() {
 
     it('create a valid WebSocket object', function () {
       var s = new SockJS('http://sockjs.org');
-      expect(s).to.have.property('url', 'http://sockjs.org/');
+      expect(s).to.have.property('url', 'http://sockjs.org');
       expect(s).to.have.property('readyState', SockJS.CONNECTING);
       expect(s).to.have.property('extensions', '');
       expect(s).to.have.property('protocol', '');
@@ -24,13 +24,13 @@ describe('SockJS', function() {
     describe('WebSocket specification step #1', function () {
       it('should throw SyntaxError for an invalid url', function () {
         expect(function () {
-          SockJS('//sockjs.org')
+          SockJS('//sockjs.org');
         }).to.throwException(function (e) {
           expect(e).to.be.a(SyntaxError);
         });
 
         expect(function () {
-          SockJS('http://')
+          SockJS('http://');
         }).to.throwException(function (e) {
           expect(e).to.be.a(SyntaxError);
         });
@@ -38,13 +38,13 @@ describe('SockJS', function() {
 
       it('should throw SyntaxError when the url contains a querystring or fragment', function () {
         expect(function () {
-          SockJS('http://sockjs.org/?test')
+          SockJS('http://sockjs.org/?test');
         }).to.throwException(function (e) {
           expect(e).to.be.a(SyntaxError);
         });
 
          expect(function () {
-          SockJS('http://sockjs.org/#test')
+          SockJS('http://sockjs.org/#test');
         }).to.throwException(function (e) {
           expect(e).to.be.a(SyntaxError);
         });
@@ -52,7 +52,7 @@ describe('SockJS', function() {
 
       it('should throw SyntaxError for an invalid protocol', function () {
         expect(function () {
-          SockJS('ftp://sockjs.org')
+          SockJS('ftp://sockjs.org');
         }).to.throwException(function (e) {
           expect(e).to.be.a(SyntaxError);
         });
@@ -61,11 +61,12 @@ describe('SockJS', function() {
 
     describe('WebSocket specification step #2', function () {
       it('should throw SecurityError for an insecure url from a secure page', function () {
-        var sjs = proxyquire('../lib/main', { './location': {
+        var main = proxyquire('../lib/main', { './polyfills/location': {
           protocol: 'https'
         }});
+        var sjs = proxyquire('../lib/entry', { './main': main });
         expect(function () {
-          sjs('http://sockjs.org')
+          sjs('http://sockjs.org');
         }).to.throwException(function (e) {
           expect(e).to.be.a(SecurityError);
         });
@@ -75,7 +76,7 @@ describe('SockJS', function() {
     describe('WebSocket specification step #5', function () {
       it('should throw SyntaxError for duplicated protocols', function () {
         expect(function () {
-          SockJS('http://sockjs.org', ['test', 'test'])
+          SockJS('http://sockjs.org', ['test', 'test']);
         }).to.throwException(function (e) {
           expect(e).to.be.a(SyntaxError);
         });
diff --git a/tests/transports.js b/tests/transports.js
new file mode 100644
index 0000000..2808137
--- /dev/null
+++ b/tests/transports.js
@@ -0,0 +1,39 @@
+'use strict';
+
+var expect = require('expect.js')
+  , fs = require('fs')
+  , path = require('path')
+  , EventTarget = require('../lib/polyfills/eventtarget')
+  ;
+
+var transportFiles = [];
+var dir = path.resolve(__dirname, '../lib/transport');
+var files = fs.readdirSync(dir);
+files.forEach(function (file) {
+  if (file[0] === '.') {
+    return;
+  }
+  transportFiles.push(path.resolve(dir, file));
+});
+
+describe('Transports', function () {
+  transportFiles.forEach(function (tf) {
+    describe(path.basename(tf, '.js'), function () {
+      it('has a valid interface', function () {
+        var Trans = require(tf);
+        expect(Trans).to.be.ok();
+        expect(Trans).to.have.property('transportName');
+        expect(Trans.transportName.length).to.be.greaterThan(0);
+
+        expect(Trans).to.have.property('roundTrips');
+        expect(Trans.roundTrips).to.be.a('number');
+
+        expect(Trans).to.have.property('enabled');
+        expect(Trans.enabled).to.be.a('function');
+
+        //expect(new Trans('http://localhost')).to.be.an(EventTarget);
+        // TODO tests for event emitting
+      });
+    });
+  });
+});

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/sockjs-client.git



More information about the Pkg-javascript-commits mailing list