Bug 1201535 - Test view source of srcdoc frames. r=mconley a=sylvestre
authorJ. Ryan Stinnett <jryans@gmail.com>
Wed, 23 Sep 2015 15:42:44 -0500
changeset 289388 e46b12a6d4564195bdb9b0af3b3365b64d486e9d
parent 289387 6c9982fcf3bc76e74d65a5e80ffc7f1e2daeb43d
child 289389 a8e5a52cb5ad9d23a34c9a69a3e1394c3b94d0d2
push id5099
push userjryans@gmail.com
push dateSat, 26 Sep 2015 07:41:27 +0000
treeherdermozilla-beta@e46b12a6d456 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley, sylvestre
bugs1201535
milestone42.0
Bug 1201535 - Test view source of srcdoc frames. r=mconley a=sylvestre
toolkit/components/viewsource/test/browser/browser.ini
toolkit/components/viewsource/test/browser/browser_bug464222.js
toolkit/components/viewsource/test/browser/browser_bug713810.js
toolkit/components/viewsource/test/browser/browser_contextmenu.js
toolkit/components/viewsource/test/browser/browser_srcdoc.js
toolkit/components/viewsource/test/browser/head.js
--- a/toolkit/components/viewsource/test/browser/browser.ini
+++ b/toolkit/components/viewsource/test/browser/browser.ini
@@ -3,10 +3,11 @@ support-files = head.js
   file_bug464222.html
 
 [browser_bug464222.js]
 [browser_bug699356.js]
 [browser_bug713810.js]
 [browser_contextmenu.js]
 skip-if = e10s # occasional timeouts with dead CPOW in console
 [browser_gotoline.js]
+[browser_srcdoc.js]
 [browser_viewsourceprefs.js]
 skip-if = e10s # Bug ?????? - obscure failure (Syntax highlighting off - Got true, expected false)
--- a/toolkit/components/viewsource/test/browser/browser_bug464222.js
+++ b/toolkit/components/viewsource/test/browser/browser_bug464222.js
@@ -1,14 +1,12 @@
 const source = "http://example.com/browser/toolkit/components/viewsource/test/browser/file_bug464222.html";
 
-function test() {
-  waitForExplicitFinish();
-  testSelection();
-}
+add_task(function *() {
+  let viewSourceTab = yield* openDocumentSelect(source, "a");
 
-function testSelection() {
-  openDocumentSelect(source, "a", function(aWindow) {
-    let aTags = aWindow.gBrowser.contentDocument.querySelectorAll("a[href]");
-    is(aTags[0].href, "view-source:" + source, "Relative links broken?");
-    closeViewSourceWindow(aWindow, finish);
+  let href = yield ContentTask.spawn(viewSourceTab.linkedBrowser, { }, function* () {
+    return content.document.querySelectorAll("a[href]")[0].href;
   });
-}
+
+  is(href, "view-source:" + source, "Relative links broken?");
+  gBrowser.removeTab(viewSourceTab);
+});
--- a/toolkit/components/viewsource/test/browser/browser_bug713810.js
+++ b/toolkit/components/viewsource/test/browser/browser_bug713810.js
@@ -1,28 +1,23 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-var source = '<html xmlns="http://www.w3.org/1999/xhtml"><body><p>This is a paragraph.</p></body></html>';
+const source = '<html xmlns="http://www.w3.org/1999/xhtml"><body><p>This is a paragraph.</p></body></html>';
 
-function test() {
-  waitForExplicitFinish();
-  testHTML();
-}
+add_task(function *() {
+  let viewSourceTab = yield* openDocumentSelect("data:text/html," + source, "p");
+  let text = yield ContentTask.spawn(viewSourceTab.linkedBrowser, { }, function* () {
+    return content.document.body.textContent;
+  });
+  is(text, "<p>This is a paragraph.</p>", "Correct source for text/html");
+  gBrowser.removeTab(viewSourceTab);
 
-function testHTML() {
-  openDocumentSelect("data:text/html," + source, "p", function(aWindow) {
-    is(aWindow.gBrowser.contentDocument.body.textContent,
-       "<p>This is a paragraph.</p>",
-       "Correct source for text/html");
-    closeViewSourceWindow(aWindow, testXHTML);
+  viewSourceTab = yield* openDocumentSelect("data:application/xhtml+xml," + source, "p");
+  text = yield ContentTask.spawn(viewSourceTab.linkedBrowser, { }, function* () {
+    return content.document.body.textContent;
   });
-}
+  is(text, '<p xmlns="http://www.w3.org/1999/xhtml">This is a paragraph.</p>',
+     "Correct source for application/xhtml+xml");
+  gBrowser.removeTab(viewSourceTab);
+});
 
-function testXHTML() {
-  openDocumentSelect("data:application/xhtml+xml," + source, "p", function(aWindow) {
-    is(aWindow.gBrowser.contentDocument.body.textContent,
-       '<p xmlns="http://www.w3.org/1999/xhtml">This is a paragraph.</p>',
-       "Correct source for application/xhtml+xml");
-    closeViewSourceWindow(aWindow, finish);
-  });
-}
--- a/toolkit/components/viewsource/test/browser/browser_contextmenu.js
+++ b/toolkit/components/viewsource/test/browser/browser_contextmenu.js
@@ -1,83 +1,90 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-let source = "data:text/html,text<link%20href='http://example.com/'%20/>more%20text<a%20href='mailto:abc@def.ghi'>email</a>";
-let gViewSourceWindow, gContextMenu, gCopyLinkMenuItem, gCopyEmailMenuItem;
+var source = "data:text/html,text<link%20href='http://example.com/'%20/>more%20text<a%20href='mailto:abc@def.ghi'>email</a>";
+var gViewSourceWindow, gContextMenu, gCopyLinkMenuItem, gCopyEmailMenuItem;
+
+var expectedData = [];
 
-let expectedData = [];
-let currentTest = 0;
-let partialTestRunning = false;
+add_task(function *() {
+  let newWindow = yield loadViewSourceWindow(source);
+  yield SimpleTest.promiseFocus(newWindow);
+
+  yield* onViewSourceWindowOpen(newWindow, false);
+
+  let contextMenu = gViewSourceWindow.document.getElementById("viewSourceContextMenu");
+
+  for (let test of expectedData) {
+    yield* checkMenuItems(contextMenu, false, test[0], test[1], test[2], test[3]);
+  }
 
-function test() {
-  waitForExplicitFinish();
-  openViewSourceWindow(source, onViewSourceWindowOpen);
-}
+  yield new Promise(resolve => {
+    closeViewSourceWindow(newWindow, resolve);
+  });
+
+  expectedData = [];
+  let newTab = yield openDocumentSelect(source, "body");
+  yield* onViewSourceWindowOpen(window, true);
+
+  contextMenu = document.getElementById("contentAreaContextMenu");
 
-function onViewSourceWindowOpen(aWindow) {
+  // Prepend view-source to this one as it opens in a tab.
+  expectedData[0][3] = "view-source:" + expectedData[0][3];
+  for (let test of expectedData) {
+    yield* checkMenuItems(contextMenu, true, test[0], test[1], test[2], test[3]);
+  }
+
+  gBrowser.removeTab(newTab);
+});
+
+function* onViewSourceWindowOpen(aWindow, aIsTab) {
   gViewSourceWindow = aWindow;
 
-  gContextMenu = aWindow.document.getElementById("viewSourceContextMenu");
-  gCopyLinkMenuItem = aWindow.document.getElementById("context-copyLink");
-  gCopyEmailMenuItem = aWindow.document.getElementById("context-copyEmail");
+  gCopyLinkMenuItem = aWindow.document.getElementById(aIsTab ? "context-copylink" : "context-copyLink");
+  gCopyEmailMenuItem = aWindow.document.getElementById(aIsTab ? "context-copyemail" : "context-copyEmail");
 
-  let aTags = aWindow.gBrowser.contentDocument.querySelectorAll("a[href]");
-  is(aTags[0].href, "view-source:http://example.com/", "Link has correct href");
-  is(aTags[1].href, "mailto:abc@def.ghi", "Link has correct href");
-  let spanTag = aWindow.gBrowser.contentDocument.querySelector("span");
+  let browser = aIsTab ? gBrowser.selectedBrowser : gViewSourceWindow.gBrowser;
+  let items = yield ContentTask.spawn(browser, { }, function* (arg) {
+    let tags = content.document.querySelectorAll("a[href]");
+    return [tags[0].href, tags[1].href];
+  });
 
-  expectedData.push([aTags[0], true, false, "http://example.com/"]);
-  expectedData.push([aTags[1], false, true, "abc@def.ghi"]);
-  expectedData.push([spanTag, false, false, null]);
+  is(items[0], "view-source:http://example.com/", "Link has correct href");
+  is(items[1], "mailto:abc@def.ghi", "Link has correct href");
 
-  waitForFocus(runNextTest, aWindow);
+  expectedData.push(["a[href]", true, false, "http://example.com/"]);
+  expectedData.push(["a[href^=mailto]", false, true, "abc@def.ghi"]);
+  expectedData.push(["span", false, false, null]);
 }
 
-function runNextTest() {
-  if (currentTest == expectedData.length) {
-    closeViewSourceWindow(gViewSourceWindow, function() {
-      if (partialTestRunning) {
-        finish();
-        return;
-      }
-      partialTestRunning = true;
-      currentTest = 0;
-      expectedData = [];
-      openDocumentSelect(source, "body", onViewSourceWindowOpen);
-    });
-    return;
-  }
-  let test = expectedData[currentTest++];
-  checkMenuItems(test[0], test[1], test[2], test[3]);
-}
+function checkMenuItems(contextMenu, isTab, selector, copyLinkExpected, copyEmailExpected, expectedClipboardContent) {
 
-function checkMenuItems(popupNode, copyLinkExpected, copyEmailExpected, expectedClipboardContent) {
-  popupNode.scrollIntoView();
+  let browser = isTab ? gBrowser.selectedBrowser : gViewSourceWindow.gBrowser;
+  yield ContentTask.spawn(browser, { selector: selector }, function* (arg) {
+    content.document.querySelector(arg.selector).scrollIntoView();
+  });
 
-  let cachedEvent = null;
-  let mouseFn = function(event) {
-    cachedEvent = event;
-  };
-
-  gViewSourceWindow.gBrowser.contentWindow.addEventListener("mousedown", mouseFn, false);
-  EventUtils.synthesizeMouseAtCenter(popupNode, { type: "contextmenu", button: 2 }, gViewSourceWindow.gBrowser.contentWindow);
-  gViewSourceWindow.gBrowser.contentWindow.removeEventListener("mousedown", mouseFn, false);
-
-  gContextMenu.openPopup(popupNode, "after_start", 0, 0, false, false, cachedEvent);
+  let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
+  yield BrowserTestUtils.synthesizeMouseAtCenter(selector,
+          { type: "contextmenu", button: 2}, browser);
+  yield popupShownPromise;
 
   is(gCopyLinkMenuItem.hidden, !copyLinkExpected, "Copy link menuitem is " + (copyLinkExpected ? "not hidden" : "hidden"));
   is(gCopyEmailMenuItem.hidden, !copyEmailExpected, "Copy email menuitem is " + (copyEmailExpected ? "not hidden" : "hidden"));
 
-  if (!copyLinkExpected && !copyEmailExpected) {
-    runNextTest();
-    return;
+  if (copyLinkExpected || copyEmailExpected) {
+    yield new Promise((resolve, reject) => {
+      waitForClipboard(expectedClipboardContent, function() {
+        if (copyLinkExpected)
+          gCopyLinkMenuItem.click();
+        else
+          gCopyEmailMenuItem.click();
+      }, resolve, reject);
+    });
   }
 
-  waitForClipboard(expectedClipboardContent, function() {
-    if (copyLinkExpected)
-      gCopyLinkMenuItem.doCommand();
-    else
-      gCopyEmailMenuItem.doCommand();
-    gContextMenu.hidePopup();
-  }, runNextTest, runNextTest);
+  let popupHiddenPromise = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
+  contextMenu.hidePopup();
+  yield popupHiddenPromise;
 }
new file mode 100644
--- /dev/null
+++ b/toolkit/components/viewsource/test/browser/browser_srcdoc.js
@@ -0,0 +1,30 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const frameSource = `<a href="about:mozilla">good</a>`;
+const source = `<html><iframe srcdoc='${frameSource}' id="f"></iframe></html>`;
+
+add_task(function*() {
+  let url = `data:text/html,${source}`;
+  yield BrowserTestUtils.withNewTab({ gBrowser, url }, checkFrameSource);
+});
+
+function* checkFrameSource() {
+  let sourceTab = yield openViewFrameSourceTab("#f");
+  registerCleanupFunction(function() {
+    gBrowser.removeTab(sourceTab);
+  });
+
+  yield waitForSourceLoaded(sourceTab);
+
+  let browser = gBrowser.selectedBrowser;
+  let textContent = yield ContentTask.spawn(browser, {}, function*() {
+    return content.document.body.textContent;
+  });
+  is(textContent, frameSource, "Correct content loaded");
+  let id = yield ContentTask.spawn(browser, {}, function*() {
+    return content.document.body.id;
+  });
+  is(id, "viewsource", "View source mode enabled")
+}
--- a/toolkit/components/viewsource/test/browser/head.js
+++ b/toolkit/components/viewsource/test/browser/head.js
@@ -35,56 +35,124 @@ function closeViewSourceWindow(aWindow, 
 
 function testViewSourceWindow(aURI, aTestCallback, aCloseCallback) {
   openViewSourceWindow(aURI, function(aWindow) {
     aTestCallback(aWindow);
     closeViewSourceWindow(aWindow, aCloseCallback);
   });
 }
 
-function openViewPartialSourceWindow(aReference, aCallback) {
-  let viewSourceWindow = openDialog("chrome://global/content/viewPartialSource.xul",
-                                    null, null, null, null, aReference, "selection");
-  viewSourceWindow.addEventListener("pageshow", function pageShowHandler(event) {
-    // Wait for the inner window to load, not viewSourceWindow.
-    if (/^view-source:/.test(event.target.location)) {
-      info("View source window opened: " + event.target.location);
-      viewSourceWindow.removeEventListener("pageshow", pageShowHandler, false);
-      aCallback(viewSourceWindow);
-    }
-  }, false);
+/**
+ * Opens a view source tab for a selection (View Selection Source) within the
+ * currently selected browser in gBrowser.
+ *
+ * @param aCSSSelector - used to specify a node within the selection to
+ *                       view the source of. It is expected that this node is
+ *                       within an existing selection.
+ * @returns the new tab which shows the source.
+ */
+function* openViewPartialSourceTab(aCSSSelector) {
+  let contentAreaContextMenuPopup =
+    document.getElementById("contentAreaContextMenu");
+  let popupShownPromise =
+    BrowserTestUtils.waitForEvent(contentAreaContextMenuPopup, "popupshown");
+  yield BrowserTestUtils.synthesizeMouseAtCenter(aCSSSelector,
+          { type: "contextmenu", button: 2 }, gBrowser.selectedBrowser);
+  yield popupShownPromise;
+
+  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, null);
+
+  let popupHiddenPromise =
+    BrowserTestUtils.waitForEvent(contentAreaContextMenuPopup, "popuphidden");
+  let item = document.getElementById("context-viewpartialsource-selection");
+  EventUtils.synthesizeMouseAtCenter(item, {});
+  yield popupHiddenPromise;
+
+  return (yield newTabPromise);
+}
+
+/**
+ * Opens a view source tab for a frame (View Frame Source) within the
+ * currently selected browser in gBrowser.
+ *
+ * @param aCSSSelector - used to specify the frame to view the source of.
+ * @returns the new tab which shows the source.
+ */
+function* openViewFrameSourceTab(aCSSSelector) {
+  let contentAreaContextMenuPopup =
+    document.getElementById("contentAreaContextMenu");
+  let popupShownPromise =
+    BrowserTestUtils.waitForEvent(contentAreaContextMenuPopup, "popupshown");
+  yield BrowserTestUtils.synthesizeMouseAtCenter(aCSSSelector,
+          { type: "contextmenu", button: 2 }, gBrowser.selectedBrowser);
+  yield popupShownPromise;
+
+  let frameContextMenu = document.getElementById("frame");
+  popupShownPromise =
+    BrowserTestUtils.waitForEvent(frameContextMenu, "popupshown");
+  EventUtils.synthesizeMouseAtCenter(frameContextMenu, {});
+  yield popupShownPromise;
+
+  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, null);
+
+  let popupHiddenPromise =
+    BrowserTestUtils.waitForEvent(frameContextMenu, "popuphidden");
+  let item = document.getElementById("context-viewframesource");
+  EventUtils.synthesizeMouseAtCenter(item, {});
+  yield popupHiddenPromise;
+
+  return (yield newTabPromise);
 }
 
 registerCleanupFunction(function() {
   var windows = Services.wm.getEnumerator("navigator:view-source");
   ok(!windows.hasMoreElements(), "No remaining view source windows still open");
   while (windows.hasMoreElements())
     windows.getNext().close();
 });
 
-function openDocument(aURI, aCallback) {
-  let tab = gBrowser.addTab(aURI);
-  let browser = tab.linkedBrowser;
-  browser.addEventListener("DOMContentLoaded", function pageLoadedListener() {
-    browser.removeEventListener("DOMContentLoaded", pageLoadedListener, false);
-    aCallback(tab);
-  }, false);
+/**
+ * For a given view source tab, wait for the source loading step to complete.
+ */
+function waitForSourceLoaded(tab) {
+  return new Promise(resolve => {
+    let mm = tab.linkedBrowser.messageManager;
+    mm.addMessageListener("ViewSource:SourceLoaded", function sourceLoaded() {
+      mm.removeMessageListener("ViewSource:SourceLoaded", sourceLoaded);
+      setTimeout(resolve, 0);
+    });
+  });
+}
+
+/**
+ * Open a new document in a new tab, select part of it, and view the source of
+ * that selection. The document is not closed afterwards.
+ *
+ * @param aURI - url to load
+ * @param aCSSSelector - used to specify a node to select. All of this node's
+ *                       children will be selected.
+ * @returns the new tab which shows the source.
+ */
+function* openDocumentSelect(aURI, aCSSSelector) {
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, aURI);
   registerCleanupFunction(function() {
     gBrowser.removeTab(tab);
   });
-}
+
+  yield ContentTask.spawn(gBrowser.selectedBrowser, { selector: aCSSSelector }, function* (arg) {
+    let element = content.document.querySelector(arg.selector);
+    content.getSelection().selectAllChildren(element);
+  });
 
-function openDocumentSelect(aURI, aCSSSelector, aCallback) {
-  openDocument(aURI, function(aTab) {
-    let element = aTab.linkedBrowser.contentDocument.querySelector(aCSSSelector);
-    let selection = aTab.linkedBrowser.contentWindow.getSelection();
-    selection.selectAllChildren(element);
+  let newtab = yield openViewPartialSourceTab(aCSSSelector);
 
-    openViewPartialSourceWindow(selection, aCallback);
-  });
+  // Wait until the source has been loaded.
+  yield waitForSourceLoaded(newtab);
+
+  return newtab;
 }
 
 function waitForPrefChange(pref) {
   let deferred = PromiseUtils.defer();
   let observer = () => {
     Preferences.ignore(pref, observer);
     deferred.resolve();
   };