Bug 1522799 - Fix test_prompt_async.html to better handle two HTTP auth dialogs at once. r=jaws, a=test-only
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Thu, 07 Feb 2019 03:53:28 +0000
changeset 515799 a7a132f180899962a3af0e3e82bbc03790ed89bb
parent 515798 4db5256e25c945715be752ded2e7a145d8f067c5
child 515800 9b74b2602df1bb9f25a35b1fd3a47017c07aac0b
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws, test-only
bugs1522799
milestone66.0
Bug 1522799 - Fix test_prompt_async.html to better handle two HTTP auth dialogs at once. r=jaws, a=test-only Try push: https://treeherder.mozilla.org/#/jobs?repo=try&revision=e7c6898e996602b8db292c97ff48073cc46d8bb8 Differential Revision: https://phabricator.services.mozilla.com/D18908
toolkit/components/passwordmgr/test/mochitest/test_prompt_async.html
toolkit/components/prompts/test/prompt_common.js
--- a/toolkit/components/passwordmgr/test/mochitest/test_prompt_async.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_prompt_async.html
@@ -171,29 +171,53 @@
           focused: "textField",
           defButton: "button0",
         };
         let action = {
           buttonClick: "ok",
         };
         await handlePrompt(state, action);
 
-        Object.assign(state, {
+        // We don't know what order these prompts appear in so get both states and check them.
+        // We can't use Promise.all here since we can't start the 2nd timer in chromeScript.js until
+        // the first timer is done since the timer variable gets clobbered, plus we don't want
+        // different actions racing each other.
+        let promptStates = [
+          await handlePromptWithoutChecks(action),
+          await handlePromptWithoutChecks(action),
+        ];
+
+        let expected1 = Object.assign({}, state, {
           msg: "http://example.com is requesting your username and password. WARNING: Your password will not be sent to the website you are currently visiting!",
           textValue: "user1name",
           passValue: "user1pass",
         });
-        await handlePrompt(state, action);
 
-        Object.assign(state, {
+        let expected2 = Object.assign({}, state, {
           msg: "http://example.org is requesting your username and password. WARNING: Your password will not be sent to the website you are currently visiting!",
           textValue: "user2name",
           passValue: "user2pass",
         });
-        await handlePrompt(state, action);
+
+        // The order isn't important.
+        let expectedPromptStates = [
+          expected1,
+          expected2,
+        ];
+
+        is(promptStates.length, expectedPromptStates.length,
+           "Check we handled the right number of prompts");
+        for (let promptState of promptStates) {
+          let expectedStateIndexForMessage = expectedPromptStates.findIndex(eps => {
+            return eps.msg == promptState.msg;
+          });
+          isnot(expectedStateIndexForMessage, -1, "Check state message was found in expected array");
+          let expectedPromptState = expectedPromptStates.splice(expectedStateIndexForMessage, 1)[0];
+          checkPromptState(promptState, expectedPromptState);
+        }
 
         let iframe1Doc = await iframe1DocPromise;
         let iframe2aDoc = await iframe2aDocPromise;
         let iframe2bDoc = await iframe2bDocPromise;
 
         authok1 = iframe1Doc.getElementById("ok").textContent;
         proxyok1 = iframe1Doc.getElementById("proxy").textContent;
 
--- a/toolkit/components/prompts/test/prompt_common.js
+++ b/toolkit/components/prompts/test/prompt_common.js
@@ -19,29 +19,41 @@ function onloadPromiseFor(id) {
   var iframe = document.getElementById(id);
   return new Promise(resolve => {
     iframe.addEventListener("load", function(e) {
       resolve(true);
     }, {once: true});
   });
 }
 
-function handlePrompt(state, action) {
+/**
+ * Take an action on the next prompt that appears without checking the state in advance.
+ * This is useful when the action doesn't depend on which prompt is shown and you
+ * are expecting multiple prompts at once in an indeterminate order.
+ * If you know the state of the prompt you expect you should use `handlePrompt` instead.
+ * @param {object} action defining how to handle the prompt
+ * @returns {Promise} resolving with the prompt state.
+*/
+function handlePromptWithoutChecks(action) {
   return new Promise(resolve => {
     gChromeScript.addMessageListener("promptHandled", function handled(msg) {
       gChromeScript.removeMessageListener("promptHandled", handled);
-      checkPromptState(msg.promptState, state);
-      resolve(true);
+      resolve(msg.promptState);
     });
     gChromeScript.sendAsyncMessage("handlePrompt", { action, isTabModal});
   });
 }
 
+async function handlePrompt(state, action) {
+  let actualState = await handlePromptWithoutChecks(action);
+  checkPromptState(actualState, state);
+}
+
 function checkPromptState(promptState, expectedState) {
-    info(`checkPromptState: ${expectedState.msg}`);
+    info(`checkPromptState: Expected: ${expectedState.msg}`);
     // XXX check title? OS X has title in content
     is(promptState.msg, expectedState.msg, "Checking expected message");
     if (isOSX && !isTabModal)
       ok(!promptState.titleHidden, "Checking title always visible on OS X");
     else
       is(promptState.titleHidden, expectedState.titleHidden, "Checking title visibility");
     is(promptState.textHidden, expectedState.textHidden, "Checking textbox visibility");
     is(promptState.passHidden, expectedState.passHidden, "Checking passbox visibility");