Bug 1348050 - Part 2: Create a chrome mochitest for Fetch and XHR to ensure we set the urgent-start flag only when they are triggered by user input events. r=mayhemer, baku
Create a test to guarantee current behaviors. We should only set urgent-start
when it is triggered by user input events rather the other events or no any
events.
MozReview-Commit-ID: 1ehiD3ua5Kl
MozReview-Commit-ID: H6bL8PpzijJ
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -25,9 +25,10 @@ subsuite = clipboard
[test_messagemanager_principal.html]
[test_messagemanager_send_principal.html]
skip-if = buildapp == 'mulet'
[test_mozbrowser_apis_allowed.html]
[test_navigator_resolve_identity_xrays.xul]
support-files = file_navigator_resolve_identity_xrays.xul
[test_sandboxed_blob_uri.html]
[test_sendQueryContentAndSelectionSetEvent.html]
+[test_urgent_start.html]
[test_websocket_frame.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_urgent_start.html
@@ -0,0 +1,220 @@
+<!DOCTYPE HTML>
+<!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1348050
+ Test for fetch and xhr to guarantee we only mark channel as urgent-start when
+ it is triggered by user input events.
+
+ For { Fetch, XHR }, do the test as following:
+ Step 1: Verify them not mark the channel when there is no any input event.
+ Step 2: Verify them mark the channel there is a user input event.
+ Step 3: Verify them not mark the channel when there is a non input event.
+
+ In each steps, it shows that we only mark channel on direct triggering task.
+ We won't mark the channel for additional task(setTimeout) or
+ micro-task(promise).
+-->
+<html>
+<head>
+ <title>Test for urgent-start on Fetch and XHR</title>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet"
+ type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+const { classes: Cc, interfaces: Ci } = Components;
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTest);
+
+const topic = "http-on-opening-request";
+const url = "http://mochi.test:8888/chrome/dom/base/test/file_empty.html";
+
+let expectedResults = [];
+let testcases = [
+ "fetch",
+ "xhr",
+];
+let testcase;
+
+function isUrgentStart(aClassFlags) {
+ if (!aClassFlags) {
+ return false;
+ }
+
+ const urgentStartFlag = 1 << 6;
+ return !!(urgentStartFlag & aClassFlags);
+}
+
+// Test for setTimeout (task)
+function testSetTimeout() {
+ return new Promise(aResolve =>
+ setTimeout(function() {
+ testSimple().then(aResolve);
+ }, 0));
+}
+
+// Test for promise chain (micro-task)
+function testPromise() {
+ return Promise.resolve().then(testSimple);
+}
+
+function testSimple() {
+ if (testcase == "fetch") {
+ return fetch(url);
+ } else if (testcase == "xhr") {
+ return new Promise(aResolve => {
+ let xhr = new XMLHttpRequest();
+ xhr.open("GET", url, false);
+ xhr.send(null);
+ aResolve();
+ });
+ }
+
+ ok(false, "Shouldn't go here.");
+}
+
+function sendRequsetAndCheckUrgentStart() {
+ info("SendRequsetAndCheckUrgentStart");
+
+ let promise_resolve;
+ let promise = new Promise(aResolve => { promise_resolve = aResolve; });
+
+ function checkUrgentStart(aSubject) {
+ var channel = aSubject.QueryInterface(Ci.nsIChannel);
+ if (!channel.URI.spec.endsWith(url)) {
+ return;
+ }
+
+ info("CheckUrgentStart");
+
+ let cos = channel.QueryInterface(Ci.nsIClassOfService);
+
+ let expectedResult = expectedResults.shift();
+ is(isUrgentStart(cos.classFlags), expectedResult,
+ "Expect get: " + expectedResult + ", get: " +
+ isUrgentStart(cos.classFlags) + " in the " +
+ (9 - expectedResults.length) + " test of " + testcase);
+
+ // Resolve if we've tested each three conditions
+ // (simple, promise, setTimeout).
+ if (expectedResults.length % 3 === 0) {
+ SpecialPowers.removeObserver(checkUrgentStart, topic);
+ promise_resolve();
+ }
+ }
+
+ SpecialPowers.addObserver(checkUrgentStart, topic);
+
+ return Promise.all([testSimple(), testSetTimeout(), testPromise(), promise]);
+}
+
+function userInputEventTriggerRequestCheckUrgentStart() {
+ info("UserInputEventTriggerRequestCheckUrgentStart");
+
+ let promise_resolve;
+ let promise = new Promise(aResolve => { promise_resolve = aResolve; });
+
+ info("AddUserInputEventListener");
+
+ let eventHandle = function () {
+ sendRequsetAndCheckUrgentStart().then(_ => promise_resolve());
+ }
+ // User Input Event
+ window.addEventListener("mousedown", eventHandle, {once: true});
+
+ info("SendUserInputEvent");
+
+ var utils = SpecialPowers.getDOMWindowUtils(window);
+ utils.sendMouseEvent("mousedown", 1, 1, 0, 1, 0);
+
+ return promise;
+}
+
+function nonUserInputEventTriggerRequestCheckUrgentStart() {
+ info("NonUserInputEventTriggerRequestCheckUrgentStart");
+
+ let promise_resolve;
+ let promise = new Promise(aResolve => { promise_resolve = aResolve; });
+
+ info("AddNonUserInputEventListener");
+
+ let eventHandle = function () {
+ sendRequsetAndCheckUrgentStart().then(_ => promise_resolve());
+ }
+ // Non user Input Event
+ window.addEventListener("message", eventHandle, {once: true});
+
+ info("SendNonUserInputEvent");
+
+ window.postMessage("hello", "*");
+
+ return promise;
+}
+
+function executeTest() {
+ is(expectedResults.length, 0, "expectedResults should be 0 be executeTest.");
+
+ // We will test fetch first and then xhr.
+ testcase = testcases.shift();
+ info("Verify " + testcase);
+
+ expectedResults = [
+ /* SimpleTest without any events */ false,
+ /* PromiseTest without any events */ false,
+ /* SetTimeoutTest without any events */ false,
+ /* SimpleTest with a user input event */ true,
+ /* PromiseTest with a user input event */ false,
+ /* SetTimeoutTest with user input event */ false,
+ /* SimpleTest with a non user input event */ false,
+ /* PromiseTest with a non user input event */ false,
+ /* SetTimeoutTest with a non user input event */ false,
+ ];
+
+ return Promise.resolve()
+ // Verify urgent-start is not set when the request is not triggered by any
+ // events.
+ .then(sendRequsetAndCheckUrgentStart)
+
+ // Verify urgent-start is set only when the request is triggered by a user
+ // input event. (not for another microtask (e.g. promise-chain) and
+ // task (e.g. setTimeout)).
+ .then(userInputEventTriggerRequestCheckUrgentStart)
+
+ // Verify urgent-start is not set when the request is triggered by a non user
+ // input event.
+ .then(nonUserInputEventTriggerRequestCheckUrgentStart)
+ .then(_ => {
+ if (testcases.length !== 0) {
+ // Run the other test if we still have tests needed to be run.
+ return executeTest();
+ }
+
+ return Promise.resolve();
+ });
+}
+
+function endCheck() {
+ info("End Check: make sure that we've done all the tests.");
+
+ is(testcases.length, 0, "All the tests should be executed.");
+ is(expectedResults.length, 0, "All the tests should be executed.");
+
+ return Promise.resolve();
+}
+
+function runTest() {
+ return Promise.resolve()
+ .then(executeTest)
+ .then(endCheck)
+ .catch(aError => ok(false, "Some test failed with error " + aError))
+ .then(SimpleTest.finish);
+}
+</script>
+</pre>
+</body>
+</html>