diff options
Diffstat (limited to '')
-rw-r--r-- | dom/tests/mochitest/fetch/test_response.js | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/dom/tests/mochitest/fetch/test_response.js b/dom/tests/mochitest/fetch/test_response.js new file mode 100644 index 0000000000..80ed1fb996 --- /dev/null +++ b/dom/tests/mochitest/fetch/test_response.js @@ -0,0 +1,346 @@ +function testDefaultCtor() { + var res = new Response(); + is(res.type, "default", "Default Response type is default"); + ok( + res.headers instanceof Headers, + "Response should have non-null Headers object" + ); + is(res.url, "", "URL should be empty string"); + is(res.status, 200, "Default status is 200"); + is(res.statusText, "", "Default statusText is an empty string"); +} + +function testClone() { + var orig = new Response("This is a body", { + status: 404, + statusText: "Not Found", + headers: { "Content-Length": 5 }, + }); + var clone = orig.clone(); + is(clone.status, 404, "Response status is 404"); + is(clone.statusText, "Not Found", "Response statusText is POST"); + ok( + clone.headers instanceof Headers, + "Response should have non-null Headers object" + ); + + is( + clone.headers.get("content-length"), + "5", + "Response content-length should be 5." + ); + orig.headers.set("content-length", 6); + is( + clone.headers.get("content-length"), + "5", + "Response content-length should be 5." + ); + + ok(!orig.bodyUsed, "Original body is not consumed."); + ok(!clone.bodyUsed, "Clone body is not consumed."); + + var origBody = null; + var clone2 = null; + return orig + .text() + .then(function(body) { + origBody = body; + is(origBody, "This is a body", "Original body string matches"); + ok(orig.bodyUsed, "Original body is consumed."); + ok(!clone.bodyUsed, "Clone body is not consumed."); + + try { + orig.clone(); + ok(false, "Cannot clone Response whose body is already consumed"); + } catch (e) { + is( + e.name, + "TypeError", + "clone() of consumed body should throw TypeError" + ); + } + + clone2 = clone.clone(); + return clone.text(); + }) + .then(function(body) { + is(body, origBody, "Clone body matches original body."); + ok(clone.bodyUsed, "Clone body is consumed."); + + try { + clone.clone(); + ok(false, "Cannot clone Response whose body is already consumed"); + } catch (e) { + is( + e.name, + "TypeError", + "clone() of consumed body should throw TypeError" + ); + } + + return clone2.text(); + }) + .then(function(body) { + is(body, origBody, "Clone body matches original body."); + ok(clone2.bodyUsed, "Clone body is consumed."); + + try { + clone2.clone(); + ok(false, "Cannot clone Response whose body is already consumed"); + } catch (e) { + is( + e.name, + "TypeError", + "clone() of consumed body should throw TypeError" + ); + } + }); +} + +function testCloneUnfiltered() { + var url = + "http://example.com/tests/dom/security/test/cors/file_CrossSiteXHR_server.sjs?status=200"; + return fetch(url, { mode: "no-cors" }).then(function(response) { + // By default the chrome-only function should not be available. + is(response.type, "opaque", "response should be opaque"); + is( + response.cloneUnfiltered, + undefined, + "response.cloneUnfiltered should be undefined" + ); + + // When the test is run in a worker context we can't actually try to use + // the chrome-only function. SpecialPowers is not defined. + if (typeof SpecialPowers !== "object") { + return; + } + + // With a chrome code, however, should be able to get an unfiltered response. + var chromeResponse = SpecialPowers.wrap(response); + is( + typeof chromeResponse.cloneUnfiltered, + "function", + "chromeResponse.cloneFiltered should be a function" + ); + var unfiltered = chromeResponse.cloneUnfiltered(); + is(unfiltered.type, "default", "unfiltered response should be default"); + is(unfiltered.status, 200, "unfiltered response should have 200 status"); + }); +} + +function testError() { + var res = Response.error(); + is(res.status, 0, "Error response status should be 0"); + try { + res.headers.set("someheader", "not allowed"); + ok(false, "Error response should have immutable headers"); + } catch (e) { + ok(true, "Error response should have immutable headers"); + } +} + +function testRedirect() { + var res = Response.redirect("./redirect.response"); + is(res.status, 302, "Default redirect has status code 302"); + is(res.statusText, "", "Default redirect has status text empty"); + var h = res.headers.get("location"); + ok( + h === new URL("./redirect.response", self.location.href).href, + "Location header should be correct absolute URL" + ); + try { + res.headers.set("someheader", "not allowed"); + ok(false, "Redirects should have immutable headers"); + } catch (e) { + ok(true, "Redirects should have immutable headers"); + } + + var successStatus = [301, 302, 303, 307, 308]; + for (var i = 0; i < successStatus.length; ++i) { + var res = Response.redirect("./redirect.response", successStatus[i]); + is(res.status, successStatus[i], "Status code should match"); + } + + var failStatus = [300, 0, 304, 305, 306, 309, 500]; + for (var i = 0; i < failStatus.length; ++i) { + try { + var res = Response.redirect(".", failStatus[i]); + ok(false, "Invalid status code should fail " + failStatus[i]); + } catch (e) { + is( + e.name, + "RangeError", + "Invalid status code should fail " + failStatus[i] + ); + } + } +} + +function testOk() { + var r1 = new Response("", { status: 200 }); + ok(r1.ok, "Response with status 200 should have ok true"); + + var r2 = new Response(undefined, { status: 204 }); + ok(r2.ok, "Response with status 204 should have ok true"); + + var r3 = new Response("", { status: 299 }); + ok(r3.ok, "Response with status 299 should have ok true"); + + var r4 = new Response("", { status: 302 }); + ok(!r4.ok, "Response with status 302 should have ok false"); +} + +function testBodyUsed() { + var res = new Response("Sample body"); + ok(!res.bodyUsed, "bodyUsed is initially false."); + return res + .text() + .then(v => { + is(v, "Sample body", "Body should match"); + ok(res.bodyUsed, "After reading body, bodyUsed should be true."); + }) + .then(() => { + return res.blob().then( + v => { + ok(false, "Attempting to read body again should fail."); + }, + e => { + ok(true, "Attempting to read body again should fail."); + } + ); + }); +} + +function testBodyCreation() { + var text = "κόσμε"; + var res1 = new Response(text); + var p1 = res1.text().then(function(v) { + ok(typeof v === "string", "Should resolve to string"); + is(text, v, "Extracted string should match"); + }); + + var res2 = new Response(new Uint8Array([72, 101, 108, 108, 111])); + var p2 = res2.text().then(function(v) { + is("Hello", v, "Extracted string should match"); + }); + + var res2b = new Response(new Uint8Array([72, 101, 108, 108, 111]).buffer); + var p2b = res2b.text().then(function(v) { + is("Hello", v, "Extracted string should match"); + }); + + var resblob = new Response(new Blob([text])); + var pblob = resblob.text().then(function(v) { + is(v, text, "Extracted string should match"); + }); + + var params = new URLSearchParams(); + params.append("item", "Geckos"); + params.append("feature", "stickyfeet"); + params.append("quantity", "700"); + var res3 = new Response(params); + var p3 = res3.text().then(function(v) { + var extracted = new URLSearchParams(v); + is(extracted.get("item"), "Geckos", "Param should match"); + is(extracted.get("feature"), "stickyfeet", "Param should match"); + is(extracted.get("quantity"), "700", "Param should match"); + }); + + return Promise.all([p1, p2, p2b, pblob, p3]); +} + +function testBodyExtraction() { + var text = "κόσμε"; + var newRes = function() { + return new Response(text); + }; + return newRes() + .text() + .then(function(v) { + ok(typeof v === "string", "Should resolve to string"); + is(text, v, "Extracted string should match"); + }) + .then(function() { + return newRes() + .blob() + .then(function(v) { + ok(v instanceof Blob, "Should resolve to Blob"); + return readAsText(v).then(function(result) { + is(result, text, "Decoded Blob should match original"); + }); + }); + }) + .then(function() { + return newRes() + .json() + .then( + function(v) { + ok(false, "Invalid json should reject"); + }, + function(e) { + ok(true, "Invalid json should reject"); + } + ); + }) + .then(function() { + return newRes() + .arrayBuffer() + .then(function(v) { + ok(v instanceof ArrayBuffer, "Should resolve to ArrayBuffer"); + var dec = new TextDecoder(); + is( + dec.decode(new Uint8Array(v)), + text, + "UTF-8 decoded ArrayBuffer should match original" + ); + }); + }); +} + +function testNullBodyStatus() { + [204, 205, 304].forEach(function(status) { + try { + var res = new Response(new Blob(), { status }); + ok( + false, + "Response body provided but status code does not permit a body" + ); + } catch (e) { + ok(true, "Response body provided but status code does not permit a body"); + } + }); + + [204, 205, 304].forEach(function(status) { + try { + var res = new Response(undefined, { status }); + ok(true, "Response body provided but status code does not permit a body"); + } catch (e) { + ok( + false, + "Response body provided but status code does not permit a body" + ); + } + }); +} + +function runTest() { + testDefaultCtor(); + testError(); + testRedirect(); + testOk(); + testNullBodyStatus(); + + return ( + Promise.resolve() + .then(testBodyCreation) + .then(testBodyUsed) + .then(testBodyExtraction) + .then(testClone) + .then(testCloneUnfiltered) + // Put more promise based tests here. + .catch(function(e) { + dump("### ### " + e + "\n"); + ok(false, "got unexpected error!"); + }) + ); +} |