UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

640 lines (500 loc) 14.2 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2004-2011 1&1 Internet AG, Germany, http://www.1und1.de License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Tristan Koch (tristankoch) ************************************************************************ */ /** * * @asset(qx/test/jsonp_primitive.php) * @asset(qx/test/script.js) * @asset(qx/test/xmlhttp/sample.txt) * @ignore(SCRIPT_LOADED) */ /* global SCRIPT_LOADED */ qx.Class.define("qx.test.bom.request.Script", { extend: qx.dev.unit.TestCase, include: [ qx.test.io.MRemoteTest, qx.dev.unit.MRequirements, qx.dev.unit.MMock ], members: { setUp() { var req = (this.req = new qx.bom.request.Script()); this.url = this.getUrl("qx/test/script.js"); // Assume timeout after 1s in Opera (no error!) if (qx.core.Environment.get("engine.name") === "opera") { req.timeout = 1000; } }, tearDown() { this.getSandbox().restore(); this.req.dispose(); }, // // General // "test: create instance"() { this.assertObject(this.req); }, "test: dispose() removes script from DOM"() { var script; this.req.open(); this.req.send(); script = this.req._getScriptElement(); this.req.dispose(); this.assertFalse(this.isInDom(script)); }, "test: isDisposed()"() { this.assertFalse(this.req.isDisposed()); this.req.dispose(); this.assertTrue(this.req.isDisposed()); }, "test: allow many requests with same object"() { var count = 0, that = this; this.req.onload = function () { count += 1; if (count == 2) { that.resume(function () {}); return; } that.request(); }; this.request(); this.wait(); }, // // Event helper // "test: call event handler"() { var req = this.req; req.onevent = this.spy(); req._emit("event"); this.assertCalled(req.onevent); }, "test: fire event"() { var req = this.req; var event = this.spy(); req.onevent = this.spy(); req.on("event", event); req._emit("event"); this.assertCalled(event); }, // // Properties // "test: properties indicate success when request completed"() { var that = this, req = this.req; req.onload = function () { that.resume(function () { that.assertEquals(4, req.readyState); that.assertEquals(200, req.status); that.assertEquals("200", req.statusText); }); }; this.request(); this.wait(); }, /** * @ignore(SCRIPT_LOADED) */ "test: status indicates success when determineSuccess returns true"() { var that = this; this.req.onload = function () { that.resume(function () { that.assertEquals(200, that.req.status); }); }; this.req.setDetermineSuccess(function () { return SCRIPT_LOADED === true; }); this.request(this.getUrl("qx/test/script.js")); this.wait(); }, // Error handling "test: properties indicate failure when request failed"() { // Known to fail in legacy IEs if (this.isIeBelow(9)) { this.skip(); } var that = this, req = this.req; req.onerror = function () { that.resume(function () { that.assertEquals(4, req.readyState); that.assertEquals(0, req.status); that.assertNull(req.statusText); }); }; this.request("http://fail.tld"); this.wait(15000); }, "test: properties indicate failure when request timed out"() { // Known to fail in legacy IEs if (this.isIeBelow(9)) { this.skip(); } var that = this, req = this.req; req.timeout = 25; req.ontimeout = function () { that.resume(function () { that.assertEquals(4, req.readyState); that.assertEquals(0, req.status); that.assertNull(req.statusText); }); }; this.requestPending(); this.wait(); }, "test: status indicates failure when determineSuccess returns false"() { var that = this; this.req.onload = function () { that.resume(function () { that.assertEquals(500, that.req.status); }); }; this.req.setDetermineSuccess(function () { return false; }); this.request(); this.wait(); }, "test: reset XHR properties when reopened"() { var req = this.req, that = this; req.onload = function () { that.resume(function () { req.open("GET", "/url"); that.assertIdentical(1, req.readyState); that.assertIdentical(0, req.status); that.assertIdentical("", req.statusText); }); }; this.request(); this.wait(); }, // // open() // "test: open() stores URL"() { this.req.open("GET", this.url); this.assertEquals(this.url, this.req._getUrl()); }, // // send() // "test: send() adds script element to DOM"() { var req = this.req; // Helper triggers send() this.request(); this.assert( this.isInDom(req._getScriptElement()), "Script element not in DOM" ); }, "test: send() sets script src to URL"() { this.request(); this.assertMatch( this.req._getScriptElement().src, /qx\/test\/script.js$/ ); }, "test: send() with data"() { this.skip(); }, // // abort() // "test: abort() removes script element"() { var req = this.req; this.requestPending(); req.abort(); this.assertFalse( this.isInDom(req._getScriptElement()), "Script element in DOM" ); }, "test: abort() makes request not fire load"() { var req = this.req; this.spy(req, "onload"); if (this.isIe()) { this.request(this.noCache(this.url)); } else { this.request(); } req.abort(); this.wait( 300, function () { this.assertNotCalled(req.onload); }, this ); }, // // setRequestHeader() // "test: setRequestHeader() throws error when other than OPENED"() { var req = this.req; this.assertException( function () { req.setRequestHeader(); }, null, "Invalid state" ); }, "test: setRequestHeader() appends to URL"() { var req = this.req; req.open("GET", "/affe"); req.setRequestHeader("key1", "value1"); req.setRequestHeader("key2", "value2"); this.assertMatch(req._getUrl(), /key1=value1/); this.assertMatch(req._getUrl(), /key2=value2/); }, // // Event handlers // "test: call onload"() { // More precisely, the request completes when the browser // has loaded and parsed the script var that = this; this.req.onload = function () { that.resume(function () {}); }; this.request(); this.wait(); }, "test: call onreadystatechange and have appropriate readyState"() { var req = this.req, readyStates = [], that = this; req.onreadystatechange = function () { readyStates.push(req.readyState); if (req.readyState === 4) { that.resume(function () { that.assertArrayEquals([1, 2, 3, 4], readyStates); }); } }; if (this.isIe()) { this.request(this.noCache(this.url)); } else { this.request(); } this.wait(); }, // Error handling "test: call onloadend on network error"() { var that = this; this.req.onloadend = function () { that.resume(function () {}); }; this.request("http://fail.tld"); this.wait(15000); }, "test: call onloadend when request completes"() { var that = this; this.req.onloadend = function () { that.resume(function () {}); }; this.request(); this.wait(); }, "test: not call onload when loading failed because of network error"() { // Known to fail in IE < 9, // i.e. all browsers using onreadystatechange event handlerattribute // // After a short delay, readyState progresses to "loaded" even // though the resource could not be loaded. if (this.isIeBelow(9)) { this.skip(); } var that = this; this.req.onload = function () { that.resume(function () { throw Error("Called onload"); }); }; this.req.onerror = function () { that.resume(); }; this.request("http://fail.tld"); this.wait(15000); }, "test: call onerror on network error"() { // Known to fail in legacy IEs if (this.isIeBelow(9)) { this.skip(); } var that = this; this.req.onerror = function () { that.resume(function () {}); }; this.request("http://fail.tld"); this.wait(15000); }, "test: call onerror on invalid script"() { // Known to fail in all browsers tested // Native "error" event not fired for script element. // // A possible work-around is to listen to the global "error" // event dispatched on the window. this.skip(); var that = this; this.req.onerror = function () { that.resume(function () {}); }; // Invalid JavaScript this.request(this.getUrl("qx/test/xmlhttp/sample.txt")); this.wait(); }, "test: not call onerror when request exceeds timeout limit"() { var req = this.req; // Known to fail in browsers not supporting the error event // because timeouts are used to fake the "error" if (!this.supportsErrorHandler()) { this.skip(); } this.spy(req, "onerror"); req.timeout = 25; this.requestPending(); this.wait( 20, function () { this.assertNotCalled(req.onerror); }, this ); }, "test: call ontimeout when request exceeds timeout limit"() { // Known to fail in legacy IEs if (this.isIeBelow(9)) { this.skip(); } var that = this; this.req.timeout = 25; this.req.ontimeout = function () { that.resume(function () {}); }; this.requestPending(); this.wait(); }, "test: not call ontimeout when request is within timeout limit"() { var req = this.req, that = this; this.spy(req, "ontimeout"); req.onload = function () { that.resume(function () { // Assert that onload() cancels timeout that.wait(350, function () { that.assertNotCalled(req.ontimeout); }); }); }; req.timeout = 300; this.request(); this.wait(); }, "test: call onabort when request was aborted"() { var req = this.req; this.spy(req, "onabort"); this.request(); req.abort(); this.assertCalled(req.onabort); }, // // Clean-Up // "test: remove script from DOM when request completed"() { var script, that = this; this.req.onload = function () { that.resume(function () { script = this.req._getScriptElement(); that.assertFalse(that.isInDom(script)); }); }; this.request(); this.wait(); }, "test: remove script from DOM when request failed"() { var script, that = this; // In IE < 9, "load" is fired instead of "error" this.req.onerror = this.req.onload = function () { that.resume(function () { script = this.req._getScriptElement(); that.assertFalse(that.isInDom(script)); }); }; this.request("http://fail.tld"); this.wait(15000); }, "test: remove script from DOM when request timed out"() { // Known to fail in legacy IEs if (this.isIeBelow(9)) { this.skip(); } var script, that = this; this.req.timeout = 25; this.req.ontimeout = function () { that.resume(function () { script = that.req._getScriptElement(); that.assertFalse(that.isInDom(script)); }); }; this.requestPending(); this.wait(); }, request(customUrl) { this.req.open("GET", customUrl || this.url, true); this.req.send(); }, requestPending(sleep) { this.require(["php"]); var url = this.noCache(this.getUrl("qx/test/jsonp_primitive.php")); // In legacy browser, a long running script request blocks subsequent requests // even if the script element is removed. Keep duration very low to work around. // // Sleep 50ms url += "&sleep=" + (sleep || 50); this.request(url); }, isInDom(elem) { return elem.parentNode ? true : false; }, isIe(version) { return qx.core.Environment.get("engine.name") === "mshtml"; }, isIeBelow(version) { return ( qx.core.Environment.get("engine.name") === "mshtml" && qx.core.Environment.get("browser.documentmode") < version ); }, supportsErrorHandler() { var isLegacyIe = qx.core.Environment.get("engine.name") === "mshtml" && qx.core.Environment.get("browser.documentmode") < 9; var isOpera = qx.core.Environment.get("engine.name") === "opera"; return !(isLegacyIe || isOpera); }, noCache(url) { return url + "?nocache=" + new Date().valueOf(); }, skip(msg) { throw new qx.dev.unit.RequirementError(null, msg); } } });