[Pkg-javascript-commits] [sockjs-client] 51/350: All tests passing now

tonnerre at ancient-solutions.com tonnerre at ancient-solutions.com
Fri Aug 5 01:03:40 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 f373b0370bbb735ec28875e11a5e1922d82741cd
Author: Bryce Kahle <bkahle at gmail.com>
Date:   Mon May 26 23:43:00 2014 -0400

    All tests passing now
---
 .gitignore                      |   1 -
 lib/info-receiver.js            |  13 +-
 lib/sockjs.js                   |  10 +-
 lib/trans-eventsource.js        |   6 +-
 lib/trans-htmlfile.js           |  13 ++
 lib/trans-iframe-htmlfile.js    |  13 +-
 lib/trans-iframe-xhr-polling.js |  13 +-
 lib/trans-receiver-iframe.js    |  17 ++
 lib/xhr-polling-iframe.js       |  14 ++
 tests/html/lib/domtests.js      | 161 +++++++++++++++++
 tests/html/lib/endtoendtests.js | 153 ++++++++++++++++
 tests/html/lib/tests.js         | 333 +++++++++++++++++++++++++++++++++++
 tests/html/lib/testutils.js     |  27 +++
 tests/html/lib/unittests.js     | 375 ++++++++++++++++++++++++++++++++++++++++
 14 files changed, 1107 insertions(+), 42 deletions(-)

diff --git a/.gitignore b/.gitignore
index 1ead977..cd08623 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,6 @@ node_modules
 npm-debug.log
 sockjs.js
 sockjs.min.js
-tests/html/lib/*.js
 .testling_env.sh
 testling.js
 build/
diff --git a/lib/info-receiver.js b/lib/info-receiver.js
index 787abea..e83fc39 100644
--- a/lib/info-receiver.js
+++ b/lib/info-receiver.js
@@ -9,9 +9,7 @@
 
 var utils = require('./utils');
 var EventEmitter = require('./eventemitter');
-var FacadeJS = require('./facade');
 var JSON3 = require('json3');
-var XHRLocalObject = require('./xhr-local');
 
 function InfoReceiver(base_url, AjaxObject) {
     var that = this;
@@ -52,13 +50,4 @@ InfoReceiver.prototype.doXhr = function(base_url, AjaxObject) {
     };
 };
 
-module.exports = InfoReceiver;
-
-var WInfoReceiverIframe = FacadeJS['w-iframe-info-receiver'] = function(ri, _trans_url, base_url) {
-    var ir = new InfoReceiver(base_url, XHRLocalObject);
-    ir.onfinish = function(info, rtt) {
-        ri._didMessage('m'+JSON3.stringify([info, rtt]));
-        ri._didClose();
-    };
-};
-WInfoReceiverIframe.prototype.doCleanup = function() {};
\ No newline at end of file
+module.exports = InfoReceiver;
\ No newline at end of file
diff --git a/lib/sockjs.js b/lib/sockjs.js
index 4386fdf..4736287 100644
--- a/lib/sockjs.js
+++ b/lib/sockjs.js
@@ -15,7 +15,6 @@ var InfoReceiverIframe = require('./info-receiver-iframe');
 var InfoReceiverFake = require('./info-receiver-fake');
 var FacadeJS = require('./facade');
 var JSON3 = require('json3');
-var IframeTransport = require('./trans-iframe');
 var XHRLocalObject = require('./xhr-local');
 var XDRObject = require('./xdr');
 
@@ -359,8 +358,17 @@ SockJS['xhr-streaming'] = require('./xhr-streaming');
 
 module.exports = SockJS;
 
+FacadeJS['w-iframe-info-receiver'] = require('./info-receiver-iframe');
+FacadeJS['w-iframe-eventsource'] = require('./trans-eventsource');
+FacadeJS['w-iframe-htmlfile'] = require('./trans-htmlfile');
+FacadeJS['w-iframe-xhr-polling'] = require('./xhr-polling-iframe');
+
+// TODO get rid of both of these!!!!
 SockJS.getUtils = function () { return utils; };
 
+// This is seriously wack.
+if ('_sockjs_onload' in window) setTimeout(window._sockjs_onload, 1);
+
 function createInfoReceiver(base_url) {
     if (utils.isSameOriginUrl(base_url)) {
         // If, for some reason, we have SockJS locally - there's no
diff --git a/lib/trans-eventsource.js b/lib/trans-eventsource.js
index 56faebb..7ca18ae 100644
--- a/lib/trans-eventsource.js
+++ b/lib/trans-eventsource.js
@@ -2,13 +2,11 @@
 
 var AjaxBasedTransport = require('./ajax-based');
 var EventSourceReceiver = require('./trans-receiver-eventsource');
-var FacadeJS = require('./facade');
 var XHRLocalObject = require('./xhr-local');
 
-// w-iframe-eventsource
-var EventSourceTransport = FacadeJS['w-iframe-eventsource'] = function EventSourceTransport(ri, trans_url) {
+function EventSourceTransport(ri, trans_url) {
     this.run(ri, trans_url, '/eventsource', EventSourceReceiver, XHRLocalObject);
-};
+}
 EventSourceTransport.prototype = new AjaxBasedTransport();
 
 module.exports = EventSourceTransport;
\ No newline at end of file
diff --git a/lib/trans-htmlfile.js b/lib/trans-htmlfile.js
new file mode 100644
index 0000000..ff60c99
--- /dev/null
+++ b/lib/trans-htmlfile.js
@@ -0,0 +1,13 @@
+'use strict';
+
+var HtmlfileReceiver = require('./trans-receiver-htmlfile');
+var XHRLocalObject = require('./xhr-local');
+var AjaxBasedTransport = require('./ajax-based');
+
+function HtmlFileTransport(ri, trans_url) {
+    this.run(ri, trans_url, '/htmlfile', HtmlfileReceiver, XHRLocalObject);
+}
+
+HtmlFileTransport.prototype = new AjaxBasedTransport();
+
+module.exports = HtmlFileTransport;
\ No newline at end of file
diff --git a/lib/trans-iframe-htmlfile.js b/lib/trans-iframe-htmlfile.js
index 7356a70..4b98293 100644
--- a/lib/trans-iframe-htmlfile.js
+++ b/lib/trans-iframe-htmlfile.js
@@ -13,10 +13,6 @@
 // production it should be only run in IE.
 
 var IframeTransport = require('./trans-iframe');
-var AjaxBasedTransport = require('./ajax-based');
-var HtmlfileReceiver = require('./trans-receiver-htmlfile');
-var FacadeJS = require('./facade');
-var XHRLocalObject = require('./xhr-local');
 
 function HtmlFileIframeTransport() {
     var that = this;
@@ -34,11 +30,4 @@ HtmlFileIframeTransport.enabled = function() {
 HtmlFileIframeTransport.need_body = true;
 HtmlFileIframeTransport.roundTrips = 3; // html, javascript, htmlfile
 
-module.exports = HtmlFileIframeTransport;
-
-
-// w-iframe-htmlfile
-var HtmlFileTransport = FacadeJS['w-iframe-htmlfile'] = function(ri, trans_url) {
-    this.run(ri, trans_url, '/htmlfile', HtmlfileReceiver, XHRLocalObject);
-};
-HtmlFileTransport.prototype = new AjaxBasedTransport();
+module.exports = HtmlFileIframeTransport;
\ No newline at end of file
diff --git a/lib/trans-iframe-xhr-polling.js b/lib/trans-iframe-xhr-polling.js
index a63d36e..2588566 100644
--- a/lib/trans-iframe-xhr-polling.js
+++ b/lib/trans-iframe-xhr-polling.js
@@ -8,10 +8,6 @@
  */
 
 var IframeTransport = require('./trans-iframe');
-var AjaxBasedTransport = require('./ajax-based');
-var XhrReceiver = require('./trans-receiver-xhr');
-var FacadeJS = require('./facade');
-var XHRLocalObject = require('./xhr-local');
 
 function XhrPollingIframeTransport() {
     var that = this;
@@ -28,11 +24,4 @@ XhrPollingIframeTransport.enabled = function () {
 XhrPollingIframeTransport.need_body = true;
 XhrPollingIframeTransport.roundTrips = 3; // html, javascript, xhr
 
-module.exports = XhrPollingIframeTransport;
-
-// w-iframe-xhr-polling
-var XhrPollingITransport = FacadeJS['w-iframe-xhr-polling'] = function(ri, trans_url) {
-    this.run(ri, trans_url, '/xhr', XhrReceiver, XHRLocalObject);
-};
-
-XhrPollingITransport.prototype = new AjaxBasedTransport();
+module.exports = XhrPollingIframeTransport;
\ No newline at end of file
diff --git a/lib/trans-receiver-iframe.js b/lib/trans-receiver-iframe.js
new file mode 100644
index 0000000..8ef0fed
--- /dev/null
+++ b/lib/trans-receiver-iframe.js
@@ -0,0 +1,17 @@
+'use strict';
+
+var XHRLocalObject = require('./xhr-local');
+var JSON3 = require('json3');
+var InfoReceiver = require('./info-receiver');
+
+function WInfoReceiverIframe(ri, _trans_url, base_url) {
+    var ir = new InfoReceiver(base_url, XHRLocalObject);
+    ir.onfinish = function(info, rtt) {
+        ri._didMessage('m'+JSON3.stringify([info, rtt]));
+        ri._didClose();
+    };
+}
+
+WInfoReceiverIframe.prototype.doCleanup = function() {};
+
+module.exports = WInfoReceiverIframe;
\ No newline at end of file
diff --git a/lib/xhr-polling-iframe.js b/lib/xhr-polling-iframe.js
new file mode 100644
index 0000000..ca44568
--- /dev/null
+++ b/lib/xhr-polling-iframe.js
@@ -0,0 +1,14 @@
+'use strict';
+
+var XhrReceiver = require('./trans-receiver-xhr');
+var XHRLocalObject = require('./xhr-local');
+var AjaxBasedTransport = require('./ajax-based');
+
+// w-iframe-xhr-polling
+function XhrPollingITransport(ri, trans_url) {
+    this.run(ri, trans_url, '/xhr', XhrReceiver, XHRLocalObject);
+}
+
+XhrPollingITransport.prototype = new AjaxBasedTransport();
+
+module.exports = XhrPollingITransport;
\ No newline at end of file
diff --git a/tests/html/lib/domtests.js b/tests/html/lib/domtests.js
new file mode 100644
index 0000000..3106931
--- /dev/null
+++ b/tests/html/lib/domtests.js
@@ -0,0 +1,161 @@
+'use strict';
+/* global expect, ok, QUnit, start, test, asyncTest, SockJS, equal */
+var ajax_simple_factory, ajax_streaming_factory, ajax_wrong_port_factory, onunload_test_factory, test_wrong_url;
+
+QUnit.module('Dom');
+
+var u = require('../../../lib/utils');
+var testutils = require('./testutils');
+
+onunload_test_factory = function(code) {
+  return function() {
+    var hook;
+    expect(3);
+    hook = testutils.newIframe();
+    hook.open = function() {
+      ok(true, 'open hook called by an iframe');
+      return hook.callback(code);
+    };
+    hook.load = function() {
+      var f;
+      ok(true, 'onload hook called by an iframe');
+      f = function() {
+        return hook.iobj.cleanup();
+      };
+      return setTimeout(f, 1);
+    };
+    return hook.unload = function() {
+      ok(true, 'onunload hook called by an iframe');
+      hook.del();
+      return start();
+    };
+  };
+};
+
+if (navigator.userAgent.indexOf('Konqueror') !== -1 || navigator.userAgent.indexOf('Opera') !== -1) {
+  test("onunload [unsupported by client]", function() {
+    return ok(true);
+  });
+} else {
+  asyncTest('onunload', onunload_test_factory("var u = SockJS.getUtils();\nu.attachEvent('load', function(){\n    hook.load();\n});\nvar w = 0;\nvar run = function(){\n    if(w === 0) {\n        w = 1;\n        hook.unload();\n    }\n};\nu.attachEvent('beforeunload', run);\nu.attachEvent('unload', run);"));
+}
+
+if (!require('../../../lib/trans-iframe').enabled()) {
+  test("onmessage [unsupported by client]", function() {
+    return ok(true);
+  });
+} else {
+  asyncTest('onmessage', function() {
+    var hook;
+    expect(3);
+    hook = testutils.newIframe();
+    hook.open = function() {
+      ok(true, 'open hook called by an iframe');
+      return hook.callback("var u = SockJS.getUtils();\nu.attachMessage(function(e) {\n    var b = e.data;\n    parent.postMessage(window_id + ' ' + 'e', '*');\n});\nparent.postMessage(window_id + ' ' + 's', '*');");
+    };
+    return u.attachMessage(function(e) {
+      var data, origin, window_id, _ref;
+      _ref = e.data.split(' '), window_id = _ref[0], data = _ref[1];
+      if (window_id === hook.id) {
+        switch (data) {
+          case 's':
+            hook.iobj.loaded();
+            ok(true, 'start frame send');
+            origin = u.getOrigin(u.amendUrl('/'));
+            return hook.iobj.post(hook.id + ' ' + 's', origin);
+          case 'e':
+            ok(true, 'done hook called by an iframe');
+            hook.iobj.cleanup();
+            hook.del();
+            return start();
+        }
+      }
+    });
+  });
+}
+
+ajax_simple_factory = function(name, Obj) {
+  return asyncTest(name + ' simple', function() {
+    var x;
+    expect(2);
+    x = new Obj('GET', '/simple.txt', null);
+    return x.onfinish = function(status, text) {
+      equal(text.length, 2051);
+      equal(text.slice(-2), 'b\n');
+      return start();
+    };
+  });
+};
+
+ajax_streaming_factory = function(name, Obj) {
+  return asyncTest(name + ' streaming', function() {
+    var x;
+    expect(4);
+    x = new Obj('GET', '/streaming.txt', null);
+    x.onchunk = function(status, text) {
+      equal(status, 200);
+      ok(text.length <= 2049, 'Most likely you\'re behind a transparent Proxy that can\'t do streaming. QUnit tests won\'t work properly. Sorry!');
+      return delete x.onchunk;
+    };
+    return x.onfinish = function(status, text) {
+      equal(status, 200);
+      equal(text.slice(-4), 'a\nb\n');
+      return start();
+    };
+  });
+};
+
+test_wrong_url = function(name, Obj, url, statuses) {
+  var x;
+  if (window.console && console.log) {
+    console.log(' [*] Connecting to wrong url ' + url);
+  }
+  expect(2);
+  x = new Obj('GET', url, null);
+  x.onchunk = function() {
+    return ok(false, "chunk shall not be received");
+  };
+  return x.onfinish = function(status, text) {
+    ok(u.arrIndexOf(statuses, status) !== -1);
+    equal(text, '');
+    return start();
+  };
+};
+
+ajax_wrong_port_factory = function(name, Obj) {
+  var port, _i, _len, _ref, _results;
+  _ref = [25, 8999, 65300];
+  _results = [];
+  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+    port = _ref[_i];
+    _results.push(asyncTest(name + ' wrong port ' + port, function() {
+      return test_wrong_url(name, Obj, 'http://localhost:' + port + '/wrong_url_indeed.txt', [0]);
+    }));
+  }
+  return _results;
+};
+
+var XHRLocalObject = require('../../../lib/xhr-local');
+var XDRObject = require('../../../lib/xdr');
+
+ajax_simple_factory('XHRLocalObject', XHRLocalObject);
+
+if (window.XDomainRequest) ajax_simple_factory('XDRObject', XDRObject);
+
+if (!window.ActiveXObject) ajax_streaming_factory('XHRLocalObject', XHRLocalObject);
+
+if (window.XDomainRequest) ajax_streaming_factory('XDRObject', XDRObject);
+
+ajax_wrong_port_factory('XHRLocalObject', XHRLocalObject);
+
+if (window.XDomainRequest) ajax_wrong_port_factory('XDRObject', XDRObject);
+
+asyncTest('XHRLocalObject wrong url', function() {
+  return test_wrong_url('XHRLocalObject', XHRLocalObject, '/wrong_url_indeed.txt', [0, 404]);
+});
+
+if (window.XDomainRequest) {
+  asyncTest('XDRObject wrong url', function() {
+    return test_wrong_url('XDRObject', XDRObject, '/wrong_url_indeed.txt', [0]);
+  });
+}
diff --git a/tests/html/lib/endtoendtests.js b/tests/html/lib/endtoendtests.js
new file mode 100644
index 0000000..91b40e5
--- /dev/null
+++ b/tests/html/lib/endtoendtests.js
@@ -0,0 +1,153 @@
+'use strict';
+/* global expect, ok, QUnit, start, test, asyncTest, SockJS, equal, client_opts */
+var factory_body_check;
+
+var u = require('../../../lib/utils');
+var testutils = require('./testutils');
+
+QUnit.module('End to End');
+
+factory_body_check = function(protocol) {
+  var n;
+  if (!SockJS[protocol] || !SockJS[protocol].enabled(client_opts.sockjs_opts)) {
+    n = " " + protocol + " [unsupported by client]";
+    return test(n, function() {
+      return u.log('Unsupported protocol (by client): "' + protocol + '"');
+    });
+  } else {
+    return asyncTest(protocol, function() {
+      var code, hook, url;
+      expect(5);
+      url = client_opts.url + '/echo';
+      code = "hook.test_body(!!document.body, typeof document.body);\n\nvar sock = new SockJS('" + url + "', null,\n{protocols_whitelist:['" + protocol + "']});\nsock.onopen = function() {\n    var m = hook.onopen();\n    sock.send(m);\n};\nsock.onmessage = function(e) {\n    hook.onmessage(e.data);\n    sock.close();\n};";
+      hook = testutils.newIframe('sockjs-in-head.html');
+      hook.open = function() {
+        hook.iobj.loaded();
+        ok(true, 'open');
+        return hook.callback(code);
+      };
+      hook.test_body = function(is_body, type) {
+        return equal(is_body, false, 'body not yet loaded ' + type);
+      };
+      hook.onopen = function() {
+        ok(true, 'onopen');
+        return 'a';
+      };
+      return hook.onmessage = function(m) {
+        equal(m, 'a');
+        ok(true, 'onmessage');
+        hook.iobj.cleanup();
+        hook.del();
+        return start();
+      };
+    });
+  }
+};
+
+QUnit.module('connection errors');
+
+asyncTest("invalid url 404", function() {
+  var r;
+  expect(4);
+  r = testutils.newSockJS('/invalid_url', 'jsonp-polling');
+  ok(r);
+  r.onopen = function(e) {
+    return ok(false);
+  };
+  r.onmessage = function(e) {
+    return ok(false);
+  };
+  return r.onclose = function(e) {
+    if (u.isXHRCorsCapable() < 4) {
+      equal(e.code, 1002);
+      equal(e.reason, 'Can\'t connect to server');
+    } else {
+      equal(e.code, 2000);
+      equal(e.reason, 'All transports failed');
+    }
+    equal(e.wasClean, false);
+    return start();
+  };
+});
+
+asyncTest("invalid url port", function() {
+  var dl, r;
+  expect(4);
+  dl = document.location;
+  r = testutils.newSockJS(dl.protocol + '//' + dl.hostname + ':1079', 'jsonp-polling');
+  ok(r);
+  r.onopen = function(e) {
+    return ok(false);
+  };
+  return r.onclose = function(e) {
+    if (u.isXHRCorsCapable() < 4) {
+      equal(e.code, 1002);
+      equal(e.reason, 'Can\'t connect to server');
+    } else {
+      equal(e.code, 2000);
+      equal(e.reason, 'All transports failed');
+    }
+    equal(e.wasClean, false);
+    return start();
+  };
+});
+
+asyncTest("disabled websocket test", function() {
+  var r;
+  expect(3);
+  r = testutils.newSockJS('/disabled_websocket_echo', 'websocket');
+  r.onopen = function(e) {
+    return ok(false);
+  };
+  r.onmessage = function(e) {
+    return ok(false);
+  };
+  return r.onclose = function(e) {
+    equal(e.code, 2000);
+    equal(e.reason, "All transports failed");
+    equal(e.wasClean, false);
+    return start();
+  };
+});
+
+asyncTest("close on close", function() {
+  var r;
+  expect(4);
+  r = testutils.newSockJS('/close', 'jsonp-polling');
+  r.onopen = function(e) {
+    return ok(true);
+  };
+  r.onmessage = function(e) {
+    return ok(false);
+  };
+  return r.onclose = function(e) {
+    equal(e.code, 3000);
+    equal(e.reason, "Go away!");
+    equal(e.wasClean, true);
+    r.onclose = function() {
+      return ok(false);
+    };
+    r.close();
+    return u.delay(10, function() {
+      return start();
+    });
+  };
+});
+
+asyncTest("EventEmitter exception handling", function() {
+  var prev_onerror, r;
+  expect(1);
+  r = testutils.newSockJS('/echo', 'xhr-streaming');
+  prev_onerror = window.onerror;
+  window.onerror = function(e) {
+    ok(/onopen error/.test('' + e));
+    window.onerror = prev_onerror;
+    return r.close();
+  };
+  r.onopen = function(e) {
+    throw "onopen error";
+  };
+  return r.onclose = function() {
+    return start();
+  };
+});
diff --git a/tests/html/lib/tests.js b/tests/html/lib/tests.js
new file mode 100644
index 0000000..98f46d1
--- /dev/null
+++ b/tests/html/lib/tests.js
@@ -0,0 +1,333 @@
+'use strict';
+/* global expect, ok, QUnit, start, test, asyncTest, SockJS, equal, client_opts */
+var arrIndexOf, batch_factory_factory, batch_factory_factory_amp, echo_factory_factory, escapable, factor_batch_large, factor_batch_large_amp, factor_echo_basic, factor_echo_from_child, factor_echo_large_message, factor_echo_rich, factor_echo_special_chars, factor_echo_unicode, factor_echo_utf_encoding, factor_echo_utf_encoding_simple, factor_server_close, factor_user_close, generate_killer_string, test_protocol_messages;
+
+var u = require('../../../lib/utils');
+var testutils = require('./testutils');
+
+echo_factory_factory = function(protocol, messages) {
+  return function() {
+    var a, r;
+    expect(2 + messages.length);
+    a = messages.slice(0);
+    r = testutils.newSockJS('/echo', protocol);
+    r.onopen = function(e) {
+      ok(true);
+      return r.send(a[0]);
+    };
+    r.onmessage = function(e) {
+      var i, x, xx1, xx2, _ref;
+      x = '' + a[0];
+      if (e.data !== x) {
+        for (i = 0, _ref = e.data.length; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) {
+          if (e.data.charCodeAt(i) !== x.charCodeAt(i)) {
+            xx1 = ('0000' + x.charCodeAt(i).toString(16)).slice(-4);
+            xx2 = ('0000' + e.data.charCodeAt(i).toString(16)).slice(-4);
+            u.log('source: \\u' + xx1 + ' differs from: \\u' + xx2);
+            break;
+          }
+        }
+      }
+      equal(e.data, '' + a[0]);
+      a.shift();
+      if (typeof a[0] === 'undefined') {
+        return r.close();
+      } else {
+        return r.send(a[0]);
+      }
+    };
+    return r.onclose = function(e) {
+      if (a.length) {
+        ok(false, "Transport closed prematurely. " + e);
+      } else {
+        ok(true);
+      }
+      return start();
+    };
+  };
+};
+
+factor_echo_basic = function(protocol) {
+  var messages;
+  messages = ['data'];
+  return echo_factory_factory(protocol, messages);
+};
+
+factor_echo_rich = function(protocol) {
+  var messages;
+  messages = [
+    [1, 2, 3, 'data'], null, false, "data", 1, 12.0, {
+      a: 1,
+      b: 2
+    }
+  ];
+  return echo_factory_factory(protocol, messages);
+};
+
+factor_echo_from_child = function(protocol) {
+  return function() {
+    var code, hook, hookReady, r, sockJSReady, timeout;
+    timeout = void 0;
+    hookReady = false;
+    sockJSReady = false;
+    expect(4);
+    hook = testutils.newIframe("sockjs-in-parent.html");
+    r = testutils.newSockJS("/echo", protocol);
+    code = "hook.r.send('a'); hook.onsend();";
+    hook.open = function() {
+      hook.iobj.loaded();
+      ok(true, "iframe open");
+      hookReady = true;
+      hook.r = r;
+      return sockJSReady && hook.callback(code);
+    };
+    r.onopen = function(e) {
+      hook.iobj.loaded();
+      ok(true, "sockjs open");
+      sockJSReady = true;
+      return hookReady && hook.callback(code);
+    };
+    r.onmessage = function(e) {
+      clearTimeout(timeout);
+      equal(e.data, "a");
+      ok(true, "onmessage");
+      hook.iobj.cleanup();
+      hook.del();
+      return r.close();
+    };
+    hook.onsend = function(e) {
+      timeout = setTimeout(function() {
+        ok(false);
+        r.close();
+      }, 300);
+    };
+    return r.onclose = function() {
+      return start();
+    };
+  };
+};
+
+factor_echo_unicode = function(protocol) {
+  var messages;
+  messages = ["Τη γλώσσα μου έδωσαν ελληνική το σπίτι φτωχικό στις αμμουδιές του ", "ღმერთსი შემვედრე, ნუთუ კვლა დამხსნას სოფლისა შრომასა, ცეცხლს, წყალს", "⠊⠀⠉⠁⠝⠀⠑⠁⠞⠀⠛⠇⠁⠎⠎⠀⠁⠝⠙⠀⠊⠞⠀⠙⠕⠑⠎⠝⠞⠀⠓⠥⠗⠞⠀⠍⠑", "Би шил идэй чадна, надад хортой биш", "을", "나는 유리를 먹을 수 있어요. 그래도 아프지 않아요", "ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ", "Ég get etið gler án þess að meiða mig.", "Mogę jeść szkło, i mi nie szkodzi.", "\ufffd\u10102\u2f877", "Начало музыкальной карьеры\nБритни пела [...]
+  return echo_factory_factory(protocol, messages);
+};
+
+factor_echo_special_chars = function(protocol) {
+  var messages;
+  messages = [" ", "\u0000", "\xff", "\xff\x00", "\x00\xff", " \r ", " \n ", " \r\n ", "\r\n", "", "message\t", "\tmessage", "message ", " message", "message\r", "\rmessage", "message\n", "\nmessage", "message\xff", "\xffmessage", "A", "b", "c", "d", "e", "\ufffd", "\ufffd\u0000", "message\ufffd", "\ufffdmessage"];
+  return echo_factory_factory(protocol, messages);
+};
+
+factor_echo_large_message = function(protocol) {
+  var messages;
+  messages = [Array(Math.pow(2, 1)).join('x'), Array(Math.pow(2, 2)).join('x'), Array(Math.pow(2, 4)).join('x'), Array(Math.pow(2, 8)).join('x'), Array(Math.pow(2, 13)).join('x'), Array(Math.pow(2, 13)).join('x')];
+  return echo_factory_factory(protocol, messages);
+};
+
+batch_factory_factory = function(protocol, messages) {
+  return function() {
+    var counter, r;
+    expect(3 + messages.length);
+    r = testutils.newSockJS('/echo', protocol);
+    ok(r);
+    counter = 0;
+    r.onopen = function(e) {
+      var msg, _i, _len, _results;
+      ok(true);
+      _results = [];
+      for (_i = 0, _len = messages.length; _i < _len; _i++) {
+        msg = messages[_i];
+        _results.push(r.send(msg));
+      }
+      return _results;
+    };
+    r.onmessage = function(e) {
+      equal(e.data, messages[counter]);
+      counter += 1;
+      if (counter === messages.length) return r.close();
+    };
+    return r.onclose = function(e) {
+      if (counter !== messages.length) {
+        ok(false, "Transport closed prematurely. " + e);
+      } else {
+        ok(true);
+      }
+      return start();
+    };
+  };
+};
+
+factor_batch_large = function(protocol) {
+  var messages;
+  messages = [Array(Math.pow(2, 1)).join('x'), Array(Math.pow(2, 2)).join('x'), Array(Math.pow(2, 4)).join('x'), Array(Math.pow(2, 8)).join('x'), Array(Math.pow(2, 13)).join('x'), Array(Math.pow(2, 13)).join('x')];
+  return batch_factory_factory(protocol, messages);
+};
+
+batch_factory_factory_amp = function(protocol, messages) {
+  return function() {
+    var counter, r;
+    expect(3 + messages.length);
+    r = testutils.newSockJS('/amplify', protocol);
+    ok(r);
+    counter = 0;
+    r.onopen = function(e) {
+      var msg, _i, _len, _results;
+      ok(true);
+      _results = [];
+      for (_i = 0, _len = messages.length; _i < _len; _i++) {
+        msg = messages[_i];
+        _results.push(r.send('' + msg));
+      }
+      return _results;
+    };
+    r.onmessage = function(e) {
+      equal(e.data.length, Math.pow(2, messages[counter]), e.data);
+      counter += 1;
+      if (counter === messages.length) return r.close();
+    };
+    return r.onclose = function(e) {
+      if (counter !== messages.length) {
+        ok(false, "Transport closed prematurely. " + e);
+      } else {
+        ok(true);
+      }
+      return start();
+    };
+  };
+};
+
+factor_batch_large_amp = function(protocol) {
+  var messages;
+  messages = [1, 2, 4, 8, 13, 15, 15];
+  return batch_factory_factory_amp(protocol, messages);
+};
+
+escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u2000-\u20ff\ufeff\ufff0-\uffff\x00-\x1f\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0 [...]
+
+generate_killer_string = function(escapable) {
+  var c, i, s;
+  s = [];
+  c = (function() {
+    var _results;
+    _results = [];
+    for (i = 0; i <= 65535; i++) {
+      _results.push(String.fromCharCode(i));
+    }
+    return _results;
+  })();
+  escapable.lastIndex = 0;
+  c.join('').replace(escapable, function(a) {
+    s.push(a);
+    return '';
+  });
+  return s.join('');
+};
+
+factor_echo_utf_encoding_simple = function(protocol) {
+  var i, message;
+  message = (function() {
+    var _results;
+    _results = [];
+    for (i = 0; i <= 256; i++) {
+      _results.push(String.fromCharCode(i));
+    }
+    return _results;
+  })();
+  return echo_factory_factory(protocol, [message.join('')]);
+};
+
+factor_echo_utf_encoding = function(protocol) {
+  var message;
+  message = generate_killer_string(escapable);
+  return echo_factory_factory(protocol, [message]);
+};
+
+factor_user_close = function(protocol) {
+  return function() {
+    var counter, r;
+    expect(5);
+    r = testutils.newSockJS('/echo', protocol);
+    ok(r);
+    counter = 0;
+    r.onopen = function(e) {
+      counter += 1;
+      ok(counter === 1);
+      r.close(3000, "User message");
+      return ok(counter === 1);
+    };
+    r.onmessage = function() {
+      ok(false);
+      return counter += 1;
+    };
+    return r.onclose = function(e) {
+      counter += 1;
+      u.log('user_close ' + e.code + ' ' + e.reason);
+      equal(e.wasClean, true);
+      ok(counter === 2);
+      return start();
+    };
+  };
+};
+
+factor_server_close = function(protocol) {
+  return function() {
+    var r;
+    expect(5);
+    r = testutils.newSockJS('/close', protocol);
+    ok(r);
+    r.onopen = function(e) {
+      return ok(true);
+    };
+    r.onmessage = function(e) {
+      return ok(false);
+    };
+    return r.onclose = function(e) {
+      equal(e.code, 3000);
+      equal(e.reason, "Go away!");
+      equal(e.wasClean, true);
+      return start();
+    };
+  };
+};
+
+arrIndexOf = function(arr, obj) {
+  var i, _ref;
+  for (i = 0, _ref = arr.length; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) {
+    if (arr[i] === obj) return i;
+  }
+  return -1;
+};
+
+test_protocol_messages = function(protocol) {
+  QUnit.module(protocol);
+  if (!SockJS[protocol] || !SockJS[protocol].enabled()) {
+    return test("[unsupported by client]", function() {
+      return ok(true, 'Unsupported protocol (by client): "' + protocol + '"');
+    });
+  } else if (client_opts.disabled_transports && arrIndexOf(client_opts.disabled_transports, protocol) !== -1) {
+    return test("[disabled by config]", function() {
+      return ok(true, 'Disabled by config: "' + protocol + '"');
+    });
+  } else {
+    asyncTest("echo1", factor_echo_basic(protocol));
+    asyncTest("echo2", factor_echo_rich(protocol));
+    asyncTest("echo from child", factor_echo_from_child(protocol));
+    asyncTest("unicode", factor_echo_unicode(protocol));
+    asyncTest("utf encoding 0x00-0xFF", factor_echo_utf_encoding_simple(protocol));
+    asyncTest("utf encoding killer message", factor_echo_utf_encoding(protocol));
+    asyncTest("special_chars", factor_echo_special_chars(protocol));
+    asyncTest("large message (ping-pong)", factor_echo_large_message(protocol));
+    asyncTest("large message (batch)", factor_batch_large(protocol));
+    asyncTest("large download", factor_batch_large_amp(protocol));
+    asyncTest("user close", factor_user_close(protocol));
+    return asyncTest("server close", factor_server_close(protocol));
+  }
+};
+
+var protocols = ['websocket', 'xdr-streaming', 'xhr-streaming', 'iframe-eventsource', 'iframe-htmlfile', 'xdr-polling', 'xhr-polling', 'iframe-xhr-polling', 'jsonp-polling'];
+
+for (var _i = 0, _len = 0, _len = protocols.length; _i < _len; _i++) {
+  var protocol = protocols[_i];
+  test_protocol_messages(protocol);
+}
diff --git a/tests/html/lib/testutils.js b/tests/html/lib/testutils.js
new file mode 100644
index 0000000..aebc051
--- /dev/null
+++ b/tests/html/lib/testutils.js
@@ -0,0 +1,27 @@
+'use strict';
+/* global jQuery, client_opts, SockJS */
+
+var u = require('../../../lib/utils');
+
+module.exports = {
+
+newIframe: function(path) {
+  var err, hook;
+  if (!path) path = '/iframe.html';
+  hook = u.createHook();
+  err = function() {
+    return u.log('iframe error. bad.');
+  };
+  hook.iobj = u.createIframe(path + '?a=' + Math.random() + '#' + hook.id, err);
+  return hook;
+},
+
+newSockJS: function(path, protocol) {
+  var options, url;
+  url = /^http/.test(path) ? path : client_opts.url + path;
+  options = jQuery.extend({}, client_opts.sockjs_opts);
+  if (protocol) options.protocols_whitelist = [protocol];
+  return new SockJS(url, null, options);
+}
+
+};
\ No newline at end of file
diff --git a/tests/html/lib/unittests.js b/tests/html/lib/unittests.js
new file mode 100644
index 0000000..5521115
--- /dev/null
+++ b/tests/html/lib/unittests.js
@@ -0,0 +1,375 @@
+'use strict';
+/* global expect, ok, QUnit, test, SockJS, equal, notEqual, deepEqual, raises */
+
+QUnit.module('Utils');
+
+var u = require('../../../lib/utils');
+
+test('random_string', function() {
+  var i, _i, _len, _ref, _results;
+  notEqual(u.random_string(8), u.random_string(8));
+  _ref = [1, 2, 3, 128];
+  _results = [];
+  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+    i = _ref[_i];
+    _results.push(equal(u.random_string(i).length, i));
+  }
+  return _results;
+});
+
+test('random_number_string', function() {
+  var i, _results;
+  _results = [];
+  for (i = 0; i <= 10; i++) {
+    equal(u.random_number_string(10).length, 1);
+    equal(u.random_number_string(100).length, 2);
+    equal(u.random_number_string(1000).length, 3);
+    equal(u.random_number_string(10000).length, 4);
+    _results.push(equal(u.random_number_string(100000).length, 5));
+  }
+  return _results;
+});
+
+test('getOrigin', function() {
+  equal(u.getOrigin('http://a.b/'), 'http://a.b');
+  equal(u.getOrigin('http://a.b/c'), 'http://a.b');
+  return equal(u.getOrigin('http://a.b:123/c'), 'http://a.b:123');
+});
+
+test('isSameOriginUrl', function() {
+  ok(u.isSameOriginUrl('http://localhost', 'http://localhost/'));
+  ok(u.isSameOriginUrl('http://localhost', 'http://localhost/abc'));
+  ok(u.isSameOriginUrl('http://localhost/', 'http://localhost'));
+  ok(u.isSameOriginUrl('http://localhost', 'http://localhost'));
+  ok(u.isSameOriginUrl('http://localhost', 'http://localhost:8080') === false);
+  ok(u.isSameOriginUrl('http://localhost:8080', 'http://localhost') === false);
+  ok(u.isSameOriginUrl('http://localhost:8080', 'http://localhost:8080/'));
+  ok(u.isSameOriginUrl('http://127.0.0.1:80/', 'http://127.0.0.1:80/a'));
+  ok(u.isSameOriginUrl('http://127.0.0.1:80', 'http://127.0.0.1:80/a'));
+  ok(u.isSameOriginUrl('http://localhost', 'http://localhost:80') === false);
+  ok(u.isSameOriginUrl('http://127.0.0.1/', 'http://127.0.0.1:80/a') === false);
+  ok(u.isSameOriginUrl('http://127.0.0.1:9', 'http://127.0.0.1:9999') === false);
+  ok(u.isSameOriginUrl('http://127.0.0.1:99', 'http://127.0.0.1:9999') === false);
+  ok(u.isSameOriginUrl('http://127.0.0.1:999', 'http://127.0.0.1:9999') === false);
+  ok(u.isSameOriginUrl('http://127.0.0.1:9999', 'http://127.0.0.1:9999'));
+  return ok(u.isSameOriginUrl('http://127.0.0.1:99999', 'http://127.0.0.1:9999') === false);
+});
+
+test("getParentDomain", function() {
+  var domains, k, _results;
+  domains = {
+    'localhost': 'localhost',
+    '127.0.0.1': '127.0.0.1',
+    'a.b.c.d': 'b.c.d',
+    'a.b.c.d.e': 'b.c.d.e',
+    '[::1]': '[::1]',
+    'a.org': 'org',
+    'a2.a3.org': 'a3.org'
+  };
+  _results = [];
+  for (k in domains) {
+    _results.push(equal(u.getParentDomain(k), domains[k]));
+  }
+  return _results;
+});
+
+test('objectExtend', function() {
+  var a, b;
+  deepEqual(u.objectExtend({}, {}), {});
+  a = {
+    a: 1
+  };
+  equal(u.objectExtend(a, {}), a);
+  equal(u.objectExtend(a, {
+    b: 1
+  }), a);
+  a = {
+    a: 1
+  };
+  b = {
+    b: 2
+  };
+  deepEqual(u.objectExtend(a, b), {
+    a: 1,
+    b: 2
+  });
+  deepEqual(a, {
+    a: 1,
+    b: 2
+  });
+  return deepEqual(b, {
+    b: 2
+  });
+});
+
+test('bind', function() {
+  var bound_fun, fun, o;
+  o = {};
+  fun = function() {
+    return this;
+  };
+  deepEqual(fun(), window);
+  bound_fun = u.bind(fun, o);
+  return deepEqual(bound_fun(), o);
+});
+
+test('amendUrl', function() {
+  var dl, t;
+  dl = document.location;
+  equal(u.amendUrl('//blah:1/abc'), dl.protocol + '//blah:1/abc');
+  equal(u.amendUrl('/abc'), dl.protocol + '//' + dl.host + '/abc');
+  equal(u.amendUrl('/'), dl.protocol + '//' + dl.host);
+  equal(u.amendUrl('http://a:1/abc'), 'http://a:1/abc');
+  equal(u.amendUrl('http://a:1/abc/'), 'http://a:1/abc');
+  equal(u.amendUrl('http://a:1/abc//'), 'http://a:1/abc');
+  t = function() {
+    return u.amendUrl('');
+  };
+  raises(t, 'Wrong url');
+  t = function() {
+    return u.amendUrl(false);
+  };
+  raises(t, 'Wrong url');
+  t = function() {
+    return u.amendUrl('http://abc?a=a');
+  };
+  raises(t, 'Only basic urls are supported');
+  t = function() {
+    return u.amendUrl('http://abc#a');
+  };
+  raises(t, 'Only basic urls are supported');
+  equal(u.amendUrl('http://a:80/abc'), 'http://a/abc');
+  equal(u.amendUrl('https://a:443/abc'), 'https://a/abc');
+  equal(u.amendUrl('https://a:80/abc'), 'https://a:80/abc');
+  return equal(u.amendUrl('http://a:443/abc'), 'http://a:443/abc');
+});
+
+test('arrIndexOf', function() {
+  var a;
+  a = [1, 2, 3, 4, 5];
+  equal(u.arrIndexOf(a, 1), 0);
+  equal(u.arrIndexOf(a, 5), 4);
+  equal(u.arrIndexOf(a, null), -1);
+  return equal(u.arrIndexOf(a, 6), -1);
+});
+
+test('arrSkip', function() {
+  var a;
+  a = [1, 2, 3, 4, 5];
+  deepEqual(u.arrSkip(a, 1), [2, 3, 4, 5]);
+  deepEqual(u.arrSkip(a, 2), [1, 3, 4, 5]);
+  deepEqual(u.arrSkip(a, 11), [1, 2, 3, 4, 5]);
+  deepEqual(u.arrSkip(a, 'a'), [1, 2, 3, 4, 5]);
+  return deepEqual(u.arrSkip(a, '1'), [1, 2, 3, 4, 5]);
+});
+
+test('quote', function() {
+  var all_chars, c, i;
+  equal(u.quote(''), '""');
+  equal(u.quote('a'), '"a"');
+  ok(u.arrIndexOf(['"\\t"', '"\\u0009"'], u.quote('\t')) !== -1);
+  ok(u.arrIndexOf(['"\\n"', '"\\u000a"'], u.quote('\n')) !== -1);
+  equal(u.quote('\x00\udfff\ufffe\uffff'), '"\\u0000\\udfff\\ufffe\\uffff"');
+  equal(u.quote('\ud85c\udff7\ud800\ud8ff'), '"\\ud85c\\udff7\\ud800\\ud8ff"');
+  equal(u.quote('\u2000\u2001\u0300\u0301'), '"\\u2000\\u2001\\u0300\\u0301"');
+  c = (function() {
+    var _results;
+    _results = [];
+    for (i = 0; i <= 65535; i++) {
+      _results.push(String.fromCharCode(i));
+    }
+    return _results;
+  })();
+  all_chars = c.join('');
+  return ok(JSON.parse(u.quote(all_chars)) === all_chars, "Quote/unquote all 64K chars.");
+});
+
+test('detectProtocols', function() {
+  var chrome_probed, ie10_probed, ie6_probed, ie8_probed, opera_probed;
+  chrome_probed = {
+    'websocket': true,
+    'xdr-streaming': false,
+    'xhr-streaming': true,
+    'iframe-eventsource': true,
+    'iframe-htmlfile': true,
+    'xdr-polling': false,
+    'xhr-polling': true,
+    'iframe-xhr-polling': true,
+    'jsonp-polling': true
+  };
+  deepEqual(u.detectProtocols(chrome_probed, null, {}), ['websocket', 'xhr-streaming', 'xhr-polling']);
+  deepEqual(u.detectProtocols(chrome_probed, null, {
+    websocket: false
+  }), ['xhr-streaming', 'xhr-polling']);
+  opera_probed = {
+    'websocket': false,
+    'xdr-streaming': false,
+    'xhr-streaming': false,
+    'iframe-eventsource': true,
+    'iframe-htmlfile': true,
+    'xdr-polling': false,
+    'xhr-polling': false,
+    'iframe-xhr-polling': true,
+    'jsonp-polling': true
+  };
+  deepEqual(u.detectProtocols(opera_probed, null, {}), ['iframe-eventsource', 'iframe-xhr-polling']);
+  ie6_probed = {
+    'websocket': false,
+    'xdr-streaming': false,
+    'xhr-streaming': false,
+    'iframe-eventsource': false,
+    'iframe-htmlfile': false,
+    'xdr-polling': false,
+    'xhr-polling': false,
+    'iframe-xhr-polling': false,
+    'jsonp-polling': true
+  };
+  deepEqual(u.detectProtocols(ie6_probed, null, {}), ['jsonp-polling']);
+  ie8_probed = {
+    'websocket': false,
+    'xdr-streaming': true,
+    'xhr-streaming': false,
+    'iframe-eventsource': false,
+    'iframe-htmlfile': true,
+    'xdr-polling': true,
+    'xhr-polling': false,
+    'iframe-xhr-polling': true,
+    'jsonp-polling': true
+  };
+  deepEqual(u.detectProtocols(ie8_probed, null, {}), ['xdr-streaming', 'xdr-polling']);
+  deepEqual(u.detectProtocols(ie8_probed, null, {
+    cookie_needed: true
+  }), ['iframe-htmlfile', 'iframe-xhr-polling']);
+  ie10_probed = {
+    'websocket': true,
+    'xdr-streaming': true,
+    'xhr-streaming': true,
+    'iframe-eventsource': false,
+    'iframe-htmlfile': true,
+    'xdr-polling': true,
+    'xhr-polling': true,
+    'iframe-xhr-polling': true,
+    'jsonp-polling': true
+  };
+  deepEqual(u.detectProtocols(ie10_probed, null, {}), ['websocket', 'xhr-streaming', 'xhr-polling']);
+  deepEqual(u.detectProtocols(ie10_probed, null, {
+    cookie_needed: true
+  }), ['websocket', 'xhr-streaming', 'xhr-polling']);
+  deepEqual(u.detectProtocols(chrome_probed, null, {
+    null_origin: true
+  }), ['websocket', 'iframe-eventsource', 'iframe-xhr-polling']);
+  deepEqual(u.detectProtocols(chrome_probed, null, {
+    websocket: false,
+    null_origin: true
+  }), ['iframe-eventsource', 'iframe-xhr-polling']);
+  deepEqual(u.detectProtocols(opera_probed, null, {
+    null_origin: true
+  }), ['iframe-eventsource', 'iframe-xhr-polling']);
+  deepEqual(u.detectProtocols(ie6_probed, null, {
+    null_origin: true
+  }), ['jsonp-polling']);
+  deepEqual(u.detectProtocols(ie8_probed, null, {
+    null_origin: true
+  }), ['iframe-htmlfile', 'iframe-xhr-polling']);
+  return deepEqual(u.detectProtocols(ie10_probed, null, {
+    null_origin: true
+  }), ['websocket', 'iframe-htmlfile', 'iframe-xhr-polling']);
+});
+
+test("EventEmitter", function() {
+  var bluff, handler0, handler1, handler2, handler3, handler4, log, r, single;
+  expect(7);
+  r = new SockJS('//1.2.3.4/wrongurl', null, {
+    protocols_whitelist: []
+  });
+  r.addEventListener('message', function() {
+    return ok(true);
+  });
+  r.onmessage = function() {
+    return ok(false);
+  };
+  bluff = function() {
+    return ok(false);
+  };
+  r.addEventListener('message', bluff);
+  r.removeEventListener('message', bluff);
+  r.addEventListener('message', bluff);
+  r.addEventListener('message', function() {
+    return ok(true);
+  });
+  r.onmessage = function() {
+    return ok(true);
+  };
+  r.removeEventListener('message', bluff);
+  r.dispatchEvent({
+    type: 'message'
+  });
+  handler0 = function() {
+    return log.push(0);
+  };
+  handler1 = function() {
+    log.push(1);
+    r.removeEventListener('test', handler0);
+    r.removeEventListener('test', handler2);
+    r.addEventListener('test', handler3);
+    return r.addEventListener('test', handler4);
+  };
+  handler2 = function() {
+    return log.push(2);
+  };
+  handler3 = function() {
+    log.push(3);
+    r.removeEventListener('test', handler1);
+    r.removeEventListener('test', handler3);
+    return r.removeEventListener('test', handler4);
+  };
+  handler4 = function() {
+    return log.push(4);
+  };
+  r.addEventListener('test', handler0);
+  r.addEventListener('test', handler1);
+  r.addEventListener('test', handler2);
+  log = [];
+  r.dispatchEvent({
+    type: 'test'
+  });
+  deepEqual(log, [0, 1, 2]);
+  log = [];
+  r.dispatchEvent({
+    type: 'test'
+  });
+  deepEqual(log, [1, 3, 4]);
+  log = [];
+  r.dispatchEvent({
+    type: 'test'
+  });
+  deepEqual(log, []);
+  single = function() {
+    return ok(true);
+  };
+  r.addEventListener('close', single);
+  r.addEventListener('close', single);
+  r.dispatchEvent({
+    type: 'close'
+  });
+  r.removeEventListener('close', single);
+  r.dispatchEvent({
+    type: 'close'
+  });
+  return r.close();
+});
+
+test("NoConstructor", function() {
+  var r;
+  expect(2);
+  r = new SockJS('//1.2.3.4/blah', null, {
+    protocols_whitelist: []
+  });
+  ok(r instanceof SockJS);
+  r.close();
+  r = SockJS('//1.2.3.4/blah', null, {
+    protocols_whitelist: []
+  });
+  ok(r instanceof SockJS);
+  return r.close();
+});

-- 
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