[Pkg-javascript-commits] [sockjs-client] 100/350: tests for jsonp receiver logic
tonnerre at ancient-solutions.com
tonnerre at ancient-solutions.com
Fri Aug 5 01:03:47 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 a459b62d194db2be7d8b151f5bdf122419112bce
Author: Bryce Kahle <bkahle at gmail.com>
Date: Thu Oct 9 19:33:45 2014 -0400
tests for jsonp receiver logic
---
.jshintrc | 3 +
lib/main.js | 2 +-
lib/transport/lib/polling.js | 10 ++--
lib/transport/receiver/jsonp.js | 100 +++++++++++++++++----------------
package.json | 2 +-
tests/receivers.js | 119 ++++++++++++++++++++++++++++++++++++++++
6 files changed, 182 insertions(+), 54 deletions(-)
diff --git a/.jshintrc b/.jshintrc
index b31c343..b70c17c 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -11,5 +11,8 @@
"ActiveXObject"
, "XDomainRequest"
, "EventSource"
+ , "describe"
+ , "it"
+ , "before"
]
}
\ No newline at end of file
diff --git a/lib/main.js b/lib/main.js
index 55fcb64..ddc2d1e 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -134,7 +134,7 @@ SockJS.prototype._receiveInfo = function(info, 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;
+ info.nullOrigin = global.document && !global.document.domain;
// determine list of desired and supported transports
var enabledTransports = transports(this.url, this._transportsWhitelist, info);
this._transports = enabledTransports.main;
diff --git a/lib/transport/lib/polling.js b/lib/transport/lib/polling.js
index 36d75d8..802ce84 100644
--- a/lib/transport/lib/polling.js
+++ b/lib/transport/lib/polling.js
@@ -25,13 +25,13 @@ Polling.prototype._scheduleReceiver = function() {
poll.onclose = function(e) {
self.poll = poll = poll.onmessage = poll.onclose = null;
if (!self.pollIsClosing) {
- if (e.reason === 'permanent') {
+ if (e.reason === 'network') {
+ self._scheduleReceiver();
+ } else {
var ce = new CloseEvent();
- ce.code = 1006;
- ce.reason = 'Polling error (' + e.reason + ')';
+ ce.code = e.code || 1000;
+ ce.reason = e.reason;
self.dispatchEvent(ce);
- } else {
- self._scheduleReceiver();
}
}
};
diff --git a/lib/transport/receiver/jsonp.js b/lib/transport/receiver/jsonp.js
index 83a9f61..a6f5a72 100644
--- a/lib/transport/receiver/jsonp.js
+++ b/lib/transport/receiver/jsonp.js
@@ -7,22 +7,39 @@ var utils = require('../../utils')
;
function JsonpReceiver(url) {
+ var self = this;
EventTarget.call(this);
utils.polluteGlobalNamespace();
this.id = 'a' + utils.randomString(6);
- var urlId = url + '?c=' + encodeURIComponent(utils.WPrefix + '.' + this.id);
+ var urlWithId = url + '?c=' + encodeURIComponent(utils.WPrefix + '.' + this.id);
+
+ global[utils.WPrefix][this.id] = this._callback.bind(this);
+ this._createScript(urlWithId);
- window[utils.WPrefix][this.id] = this.callback.bind(this);
- this.createScript(urlId);
+ // Fallback mostly for Konqueror - stupid timer, 35 seconds shall be plenty.
+ this.timeoutId = setTimeout(function() {
+ self._abort(new Error('JSONP script loaded abnormally (timeout)'));
+ }, JsonpReceiver.timeout);
}
util.inherits(JsonpReceiver, EventTarget);
-JsonpReceiver.prototype.callback = function (data) {
- this.deleteScript();
- delete window[utils.WPrefix][this.id];
+JsonpReceiver.prototype.abort = function () {
+ if (global[utils.WPrefix][this.id]) {
+ var err = new Error('JSONP user aborted read');
+ err.code = 1000;
+ this._abort(err);
+ }
+};
+
+JsonpReceiver.timeout = 35000;
+JsonpReceiver.scriptErrorTimeout = 1000;
+
+JsonpReceiver.prototype._callback = function (data) {
+ this._cleanup();
+ delete global[utils.WPrefix][this.id];
if (this.aborting) {
return;
@@ -32,32 +49,24 @@ JsonpReceiver.prototype.callback = function (data) {
this.dispatchEvent(new SimpleEvent('message', { data: data }));
}
this.dispatchEvent(new SimpleEvent('close', { reason: 'network' }));
+ this.onmessage = this.onclose = null;
};
-JsonpReceiver.prototype.abort = function () {
- if (window[utils.WPrefix][this.id]) {
- var err = new Error('JSONP user aborted read');
- err.code = 1000;
- this._abort(err);
- }
-};
-
-module.exports = JsonpReceiver;
-
JsonpReceiver.prototype._abort = function (err) {
- this.deleteScript();
+ this._cleanup();
this.aborting = true;
- this.dispatchEvent(new SimpleEvent('close', { reason: 'permanent' }));
+ this.dispatchEvent(new SimpleEvent('close', { code: err.code, reason: err.message }));
+ this.onmessage = this.onclose = null;
};
-JsonpReceiver.prototype.deleteScript = function () {
+JsonpReceiver.prototype._cleanup = function () {
+ clearTimeout(this.timeoutId);
if (this.script2) {
this.script2.parentNode.removeChild(this.script2);
this.script2 = null;
}
if (this.script) {
var script = this.script;
- clearTimeout(this.tref);
// Unfortunately, you can't really abort script loading of
// the script.
script.parentNode.removeChild(script);
@@ -67,40 +76,40 @@ JsonpReceiver.prototype.deleteScript = function () {
}
};
-JsonpReceiver.prototype.createScript = function (url) {
+JsonpReceiver.prototype._scriptError = function () {
+ var self = this;
+ if (this.errorTimer) return;
+
+ this.errorTimer = setTimeout(function() {
+ if (!self.loadedOkay) {
+ self._abort(new Error('JSONP script loaded abnormally (onerror)'));
+ }
+ }, JsonpReceiver.scriptErrorTimeout);
+};
+
+JsonpReceiver.prototype._createScript = function (url) {
var self = this;
var script = this.script = global.document.createElement('script');
var script2; // Opera synchronous load trick.
- // IE9 fires 'error' event after orsc or before, in random order.
- var loadedOkay = false;
- var errorTimer = null;
-
script.id = 'a' + utils.randomString(8);
script.src = url;
script.type = 'text/javascript';
script.charset = 'UTF-8';
- script.onerror = function() {
- if (!errorTimer) {
- // Delay firing closeScript.
- errorTimer = setTimeout(function() {
- if (!loadedOkay) {
- self._abort(new Error('JSONP script loaded abnormally (onerror)'));
- }
- }, 1000);
- }
- };
+ script.onerror = this._scriptError.bind(this);
script.onload = function() {
self._abort(new Error('JSONP script loaded abnormally (onload)'));
};
+ // IE9 fires 'error' event after onreadystatechange or before, in random order.
+ // Use loadedOkay to determine if actually errored
script.onreadystatechange = function() {
if (/loaded|closed/.test(script.readyState)) {
if (script && script.htmlFor && script.onclick) {
- loadedOkay = true;
+ self.loadedOkay = true;
try {
- // In IE, actually execute the script.
- script.onclick();
+ // In IE, actually execute the script.
+ script.onclick();
} catch (x) {}
}
if (script) {
@@ -118,11 +127,11 @@ JsonpReceiver.prototype.createScript = function (url) {
// http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html
// Also, read on that about script ordering:
// http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
- if (typeof script.async === 'undefined' && document.attachEvent) {
+ if (typeof script.async === 'undefined' && global.document.attachEvent) {
// According to mozilla docs, in recent browsers script.async defaults
// to 'true', so we may use it to detect a good browser:
// https://developer.mozilla.org/en/HTML/Element/script
- if (!/opera/i.test(navigator.userAgent)) {
+ if (!/opera/i.test(global.navigator.userAgent)) {
// Naively assume we're in IE
try {
script.htmlFor = script.id;
@@ -131,7 +140,7 @@ JsonpReceiver.prototype.createScript = function (url) {
script.async = true;
} else {
// Opera, second sync script hack
- script2 = this.script2 = document.createElement('script');
+ script2 = this.script2 = global.document.createElement('script');
script2.text = "try{var a = document.getElementById('" + script.id + "'); if(a)a.onerror();}catch(x){};";
script.async = script2.async = false;
}
@@ -140,14 +149,11 @@ JsonpReceiver.prototype.createScript = function (url) {
script.async = true;
}
- // Fallback mostly for Konqueror - stupid timer, 35 seconds shall be plenty.
- this.tref = setTimeout(function() {
- self._abort(new Error('JSONP script loaded abnormally (timeout)'));
- }, 35000);
-
- var head = document.getElementsByTagName('head')[0];
+ var head = global.document.getElementsByTagName('head')[0];
head.insertBefore(script, head.firstChild);
if (script2) {
head.insertBefore(script2, head.firstChild);
}
};
+
+module.exports = JsonpReceiver;
diff --git a/package.json b/package.json
index f909e3f..30f73c1 100644
--- a/package.json
+++ b/package.json
@@ -53,7 +53,7 @@
"url": "https://github.com/sockjs/sockjs-client.git"
},
"scripts": {
- "t": "node ./node_modules/mocha/bin/mocha tests/main.js tests/transports.js",
+ "t": "node ./node_modules/mocha/bin/mocha tests/main.js tests/transports.js tests/receivers.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/receivers.js b/tests/receivers.js
new file mode 100644
index 0000000..4cb8393
--- /dev/null
+++ b/tests/receivers.js
@@ -0,0 +1,119 @@
+'use strict';
+
+var expect = require('expect.js')
+ , JsonpReceiver = require('../lib/transport/receiver/jsonp')
+ , utils = require('../lib/utils')
+ ;
+
+describe('Receivers', function () {
+ describe('jsonp', function () {
+ before(function () {
+ JsonpReceiver.prototype._createScript = function () {};
+ JsonpReceiver.timeout = 300;
+ });
+
+ it('receives data', function (done) {
+ JsonpReceiver.prototype._createScript = function () {
+ var self = this;
+ setTimeout(function () {
+ global[utils.WPrefix][self.id]('datadata');
+ }, 5);
+ };
+ var jpr = new JsonpReceiver('test');
+ jpr.onclose = function (e) {
+ expect(e.reason).to.eql('network');
+ done();
+ };
+ jpr.onmessage = function (e) {
+ expect(e.data).to.eql('datadata');
+ };
+ });
+
+ it('will timeout', function (done) {
+ this.timeout(500);
+ JsonpReceiver.prototype._createScript = function () {
+ var self = this;
+ setTimeout(function () {
+ global[utils.WPrefix][self.id]('datadata');
+ }, 400);
+ };
+
+ var jpr = new JsonpReceiver('test');
+ jpr.onclose = function (e) {
+ expect(e.reason).to.contain('timeout');
+ done();
+ };
+ jpr.onmessage = function () {
+ expect().fail('No message should be sent');
+ };
+ });
+
+ it('will abort without sending a message', function (done) {
+ JsonpReceiver.prototype._createScript = function () {
+ var self = this;
+ setTimeout(function () {
+ global[utils.WPrefix][self.id]('datadata');
+ }, 200);
+ };
+ var jpr = new JsonpReceiver('test');
+ jpr.onclose = function (e) {
+ expect(e.reason).to.contain('aborted');
+ done();
+ };
+ jpr.onmessage = function () {
+ expect().fail('No message should be sent');
+ };
+ jpr.abort();
+ });
+
+ it('will not report error if onerror triggered right before onreadystatechange (IE9)', function (done) {
+ JsonpReceiver.scriptErrorTimeout = 300;
+ JsonpReceiver.prototype._createScript = function () {
+ var self = this;
+ // simulate a normal JSONP response
+ setTimeout(function () {
+ self.loadedOkay = true;
+ global[utils.WPrefix][self.id]('datadata');
+ }, 200);
+ };
+
+ var jpr = new JsonpReceiver('test');
+ jpr.onclose = function (e) {
+ expect(e.reason).to.eql('network');
+ done();
+ };
+ jpr.onmessage = function (e) {
+ expect(e.data).to.eql('datadata');
+ };
+
+ // simulate script error
+ jpr._scriptError();
+ });
+
+ it('will not report error if onerror triggered right after onreadystatechange (IE9)', function (done) {
+ JsonpReceiver.scriptErrorTimeout = 100;
+ JsonpReceiver.prototype._createScript = function () {
+ var self = this;
+ // simulate a normal JSONP response
+ setTimeout(function () {
+ self.loadedOkay = true;
+ global[utils.WPrefix][self.id]('datadata');
+ }, 100);
+ };
+
+ var jpr = new JsonpReceiver('test');
+ jpr.onclose = function (e) {
+ expect(e.reason).to.eql('network');
+ done();
+ };
+ jpr.onmessage = function (e) {
+ expect(e.data).to.eql('datadata');
+ };
+
+ // simulate script error
+ setTimeout(function () {
+ jpr._scriptError();
+ }, 150);
+ });
+ });
+});
--
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