// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

function debugClipFlavors(aClip)
{
  let xfer = Cc["@mozilla.org/widget/transferable;1"].
             createInstance(Ci.nsITransferable);
  xfer.init(null);
  aClip.getData(xfer, Ci.nsIClipboard.kGlobalClipboard);
  let array = xfer.flavorsTransferableCanExport();
  let count = array.Count();
  info("flavors:" + count);
  for (let idx = 0; idx < count; idx++) {
    let string = array.GetElementAt(idx).QueryInterface(Ci.nsISupportsString);
    info("[" + idx + "] " + string);
  }
}

function checkContextMenuPositionRange(aElement, aMinLeft, aMaxLeft, aMinTop, aMaxTop) {
  ok(aElement.left > aMinLeft && aElement.left < aMaxLeft,
    "Left position is " + aElement.left + ", expected between " + aMinLeft + " and " + aMaxLeft);

  ok(aElement.top > aMinTop && aElement.top < aMaxTop,
    "Top position is " + aElement.top + ", expected between " + aMinTop + " and " + aMaxTop);
}

gTests.push({
  desc: "text context menu",
  run: function test() {
    info(chromeRoot + "browser_context_menu_tests_02.html");
    yield addTab(chromeRoot + "browser_context_menu_tests_02.html");

    purgeEventQueue();
    emptyClipboard();

    let win = Browser.selectedTab.browser.contentWindow;

    yield hideContextUI();

    ////////////////////////////////////////////////////////////
    // Context menu in content on selected text

    // select some text
    let span = win.document.getElementById("text1");
    win.getSelection().selectAllChildren(span);

    yield waitForMs(0);

    // invoke selection context menu
    let promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(win, span);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    // selected text context:
    checkContextUIMenuItemVisibility(["context-copy",
                                      "context-search"]);

    let menuItem = document.getElementById("context-copy");
    promise = waitForEvent(document, "popuphidden");
    EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);

    yield promise;

    // The wait is needed to give time to populate the clipboard.
    let string = "";
    yield waitForCondition(function () {
      string = SpecialPowers.getClipboardData("text/unicode");
      return string === span.textContent;
    });
    ok(string === span.textContent, "copied selected text from span");

    win.getSelection().removeAllRanges();

    ////////////////////////////////////////////////////////////
    // Context menu in content on selected text that includes a link

    // invoke selection with link context menu
    let link = win.document.getElementById("text2-link");
    win.getSelection().selectAllChildren(link);
    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(win, link);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    // selected text context:
    checkContextUIMenuItemVisibility(["context-copy",
                                      "context-search",
                                      "context-open-in-new-tab",
                                      "context-copy-link"]);

    promise = waitForEvent(document, "popuphidden");
    win.scrollBy(0, 1);
    let hidden = yield promise;
    ok(hidden && !(hidden instanceof Error), "scrolling hides the context menu");
    win.getSelection().removeAllRanges();
    win.scrollBy(0, -1);

    ////////////////////////////////////////////////////////////
    // Context menu in content on a link

    link = win.document.getElementById("text2-link");
    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(win, link);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    // selected text context:
    checkContextUIMenuItemVisibility(["context-open-in-new-tab",
                                      "context-copy-link",
                                      "context-bookmark-link"]);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    ////////////////////////////////////////////////////////////
    // context in input with no selection, no data on clipboard

    emptyClipboard();

    let input = win.document.getElementById("text3-input");
    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(win, input);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    checkContextUIMenuItemVisibility(["context-select",
                                      "context-select-all"]);

    // copy menu item should not exist when no text is selected
    let menuItem = document.getElementById("context-copy");
    ok(menuItem && menuItem.hidden, "menu item is not visible");

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    ////////////////////////////////////////////////////////////
    // context in input with selection copied to clipboard

    let input = win.document.getElementById("text3-input");
    input.value = "hello, I'm sorry but I must be going.";
    input.setSelectionRange(0, 5);
    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(win, input, 20);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    checkContextUIMenuItemVisibility(["context-cut",
                                      "context-copy"]);

    let menuItem = document.getElementById("context-copy");
    let popupPromise = waitForEvent(document, "popuphidden");
    EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);

    yield popupPromise;

    // The wait is needed to give time to populate the clipboard.
    let string = "";
    yield waitForCondition(function () {
      string = SpecialPowers.getClipboardData("text/unicode");
      return string === "hello";
    });

    ok(string === "hello", "copied selected text");

    emptyClipboard();

    ////////////////////////////////////////////////////////////
    // context in input with text selection, no data on clipboard

    input = win.document.getElementById("text3-input");
    input.select();
    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(win, input, 20);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    // selected text context:
    checkContextUIMenuItemVisibility(["context-cut",
                                      "context-copy"]);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    ////////////////////////////////////////////////////////////
    // context in input with no selection, data on clipboard

    SpecialPowers.clipboardCopyString("foo");
    input = win.document.getElementById("text3-input");
    input.select();
    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(win, input, 20);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    // selected text context:
    checkContextUIMenuItemVisibility(["context-cut",
                                      "context-copy",
                                      "context-paste"]);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    ////////////////////////////////////////////////////////////
    // context in input with selection cut to clipboard

    emptyClipboard();

    let input = win.document.getElementById("text3-input");
    input.value = "hello, I'm sorry but I must be going.";
    input.setSelectionRange(0, 5);
    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(win, input, 20);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    checkContextUIMenuItemVisibility(["context-cut",
                                      "context-copy"]);

    let menuItem = document.getElementById("context-cut");
    let popupPromise = waitForEvent(document, "popuphidden");
    EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);

    yield popupPromise;

    // The wait is needed to give time to populate the clipboard.
    let string = "";
    yield waitForCondition(function () {
      string = SpecialPowers.getClipboardData("text/unicode");
      return string === "hello";
    });

    let inputValue = input.value;
    ok(string === "hello", "cut selected text in clipboard");
    ok(inputValue === ", I'm sorry but I must be going.", "cut selected text from input value");

    emptyClipboard();

    ////////////////////////////////////////////////////////////
    // context in empty input, data on clipboard (paste operation)

    SpecialPowers.clipboardCopyString("foo");
    input = win.document.getElementById("text3-input");
    input.value = "";

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(win, input, 20);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    // selected text context:
    checkContextUIMenuItemVisibility(["context-paste"]);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    ////////////////////////////////////////////////////////////
    // context in empty input, no data on clipboard (??)

    emptyClipboard();
    ContextUI.dismiss();

    input = win.document.getElementById("text3-input");
    input.value = "";

    promise = waitForEvent(Elements.tray, "transitionend");
    sendContextMenuClickToElement(win, input, 20);
    yield promise;

    // should *not* be visible
    ok(!ContextMenuUI._menuPopup.visible, "is visible");

    // the test above will invoke the app bar
    yield hideContextUI();

    Browser.closeTab(Browser.selectedTab, { forceClose: true });
    purgeEventQueue();
  }
});

gTests.push({
  desc: "checks for context menu positioning when browser shifts",
  run: function test() {
    info(chromeRoot + "browser_context_menu_tests_02.html");
    yield addTab(chromeRoot + "browser_context_menu_tests_02.html");

    purgeEventQueue();
    emptyClipboard();

    let browserwin = Browser.selectedTab.browser.contentWindow;

    yield hideContextUI();

    ////////////////////////////////////////////////////////////
    // test for proper context menu positioning when the browser
    // is offset by a notification box.

    yield showNotification();

    // select some text
    let span = browserwin.document.getElementById("text4");
    browserwin.getSelection().selectAllChildren(span);

    // invoke selection context menu
    let promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(browserwin, span);
    yield promise;

    // should be visible and at a specific position
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    let notificationBox = Browser.getNotificationBox();
    let notification = notificationBox.getNotificationWithValue("popup-blocked");
    let notificationHeight = notification.boxObject.height;

    checkContextMenuPositionRange(ContextMenuUI._panel, 0, 15, 220, 230);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    Browser.closeTab(Browser.selectedTab, { forceClose: true });
  }
});

/*
XXX code used to diagnose bug 880739

var observeLogger = {
  observe: function (aSubject, aTopic, aData) {
    info("observeLogger: " + aTopic);
  },
  QueryInterface: function (aIID) {
    if (!aIID.equals(Ci.nsIObserver) &&
        !aIID.equals(Ci.nsISupportsWeakReference) &&
        !aIID.equals(Ci.nsISupports)) {
      throw Components.results.NS_ERROR_NO_INTERFACE;
    }
    return this;
  },
  init: function init() {
    Services.obs.addObserver(observeLogger, "dl-start", true);
    Services.obs.addObserver(observeLogger, "dl-done", true);
    Services.obs.addObserver(observeLogger, "dl-failed", true);
    Services.obs.addObserver(observeLogger, "dl-scanning", true);
    Services.obs.addObserver(observeLogger, "dl-blocked", true);
    Services.obs.addObserver(observeLogger, "dl-dirty", true);
    Services.obs.addObserver(observeLogger, "dl-cancel", true);
  },
  shutdown: function shutdown() {
    Services.obs.removeObserver(observeLogger, "dl-start");
    Services.obs.removeObserver(observeLogger, "dl-done");
    Services.obs.removeObserver(observeLogger, "dl-failed");
    Services.obs.removeObserver(observeLogger, "dl-scanning");
    Services.obs.removeObserver(observeLogger, "dl-blocked");
    Services.obs.removeObserver(observeLogger, "dl-dirty");
    Services.obs.removeObserver(observeLogger, "dl-cancel");
  }
}
*/

// Image context menu tests
gTests.push({
  desc: "image context menu",
  setUp: function() {
    // XXX code used to diagnose bug 880739
    //observeLogger.init();
  },
  tearDown: function() {
    // XXX code used to diagnose bug 880739
    //observeLogger.shutdown();
  },
  run: function test() {
    info(chromeRoot + "browser_context_menu_tests_01.html");
    yield addTab(chromeRoot + "browser_context_menu_tests_01.html");

    let win = Browser.selectedTab.browser.contentWindow;

    purgeEventQueue();

    yield hideContextUI();

    // If we don't do this, sometimes the first sendContextMenuClickToWindow
    // will trigger the app bar.
    yield waitForImageLoad(win, "image01");

    ////////////////////////////////////////////////////////////
    // Context menu options
    /*
    XXX disabled temporarily due to bug 880739

    // image01 - 1x1x100x100
    let promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToWindow(win, 10, 10);
    yield promise;

    purgeEventQueue();

    ok(ContextMenuUI._menuPopup.visible, "is visible");

    checkContextUIMenuItemVisibility(["context-save-image-lib",
                                      "context-copy-image",
                                      "context-copy-image-loc",
                                      "context-open-image-tab"]);

    ////////////////////////////////////////////////////////////
    // Save to image library

    let dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
                           .getService(Components.interfaces.nsIProperties);
    let saveLocationPath = dirSvc.get("Pict", Components.interfaces.nsIFile);
    saveLocationPath.append("image01.png");

    registerCleanupFunction(function () {
      saveLocationPath.remove(false);
    });

    if (saveLocationPath.exists()) {
      info("had to remove old image!");
      saveLocationPath.remove(false);
    }

    let menuItem = document.getElementById("context-save-image-lib");
    ok(menuItem, "menu item exists");
    ok(!menuItem.hidden, "menu item visible");

    // dl-start, dl-failed, dl-scanning, dl-blocked, dl-dirty, dl-cancel
    let downloadPromise = waitForObserver("dl-done", 10000);

    let popupPromise = waitForEvent(document, "popuphidden");
    EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
    yield popupPromise;
    yield downloadPromise;

    purgeEventQueue();

    ok(saveLocationPath.exists(), "image saved");
    */
    ////////////////////////////////////////////////////////////
    // Copy image

    let promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToWindow(win, 20, 20);
    yield promise;
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    let menuItem = document.getElementById("context-copy-image");
    ok(menuItem, "menu item exists");
    ok(!menuItem.hidden, "menu item visible");
    let popupPromise = waitForEvent(document, "popuphidden");
    EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
    yield popupPromise;

    purgeEventQueue();

    let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
    let flavors = ["image/png"];
    ok(clip.hasDataMatchingFlavors(flavors, flavors.length, Ci.nsIClipboard.kGlobalClipboard), "clip has my png flavor");

    ////////////////////////////////////////////////////////////
    // Copy image location

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToWindow(win, 30, 30);
    yield promise;
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    menuItem = document.getElementById("context-copy-image-loc");
    ok(menuItem, "menu item exists");
    ok(!menuItem.hidden, "menu item visible");
    popupPromise = waitForEvent(document, "popuphidden");
    EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
    yield popupPromise;

    purgeEventQueue();

    let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
    let flavors = ["text/unicode"];
    ok(clip.hasDataMatchingFlavors(flavors, flavors.length, Ci.nsIClipboard.kGlobalClipboard), "clip has my text flavor");

    let xfer = Cc["@mozilla.org/widget/transferable;1"].
               createInstance(Ci.nsITransferable);
    xfer.init(null);
    xfer.addDataFlavor("text/unicode");
    clip.getData(xfer, Ci.nsIClipboard.kGlobalClipboard);
    let str = new Object();
    let strLength = new Object();
    xfer.getTransferData("text/unicode", str, strLength);
    str = str.value.QueryInterface(Components.interfaces.nsISupportsString);

    ok(str == chromeRoot + "res/image01.png", "url copied");

    ////////////////////////////////////////////////////////////
    // Open image in new tab

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToWindow(win, 40, 40);
    yield promise;
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    menuItem = document.getElementById("context-open-image-tab");
    ok(menuItem, "menu item exists");
    ok(!menuItem.hidden, "menu item visible");
    let tabPromise = waitForEvent(document, "TabOpen");
    popupPromise = waitForEvent(document, "popuphidden");
    EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
    yield popupPromise;
    let event = yield tabPromise;

    purgeEventQueue();

    let imagetab = Browser.getTabFromChrome(event.originalTarget);
    ok(imagetab != null, "tab created");

    Browser.closeTab(imagetab, { forceClose: true });
  }
});

gTests.push({
  desc: "tests for subframe positioning",
  run: function test() {
    info(chromeRoot + "browser_context_menu_tests_03.html");
    yield addTab(chromeRoot + "browser_context_menu_tests_03.html");

    let win = Browser.selectedTab.browser.contentWindow;

    // Sometimes the context ui is visible, sometimes it isn't.
    try {
      yield waitForCondition(function () {
        return ContextUI.isVisible;
      }, 500, 50);
    } catch (ex) {}

    ContextUI.dismiss();

    let frame1 = win.document.getElementById("frame1");
    let link1 = frame1.contentDocument.getElementById("link1");

    let promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(frame1.contentDocument.defaultView, link1, 85, 10);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    checkContextMenuPositionRange(ContextMenuUI._panel, 265, 280, 175, 190);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    frame1.contentDocument.defaultView.scrollBy(0, 200);

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(frame1.contentDocument.defaultView, link1, 85, 10);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    checkContextMenuPositionRange(ContextMenuUI._panel, 265, 280, 95, 110);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    let rlink1 = win.document.getElementById("rlink1");

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(win, rlink1, 40, 10);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    checkContextMenuPositionRange(ContextMenuUI._panel, 295, 310, 540, 555);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    win.scrollBy(0, 200);

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(win, rlink1, 40, 10);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    checkContextMenuPositionRange(ContextMenuUI._panel, 295, 310, 340, 355);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    let link2 = frame1.contentDocument.getElementById("link2");

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(frame1.contentDocument.defaultView, link2, 85, 10);
    yield promise;

    // should be visible
    ok(ContextMenuUI._menuPopup.visible, "is visible");

    checkContextMenuPositionRange(ContextMenuUI._panel, 265, 280, 110, 125);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    Browser.closeTab(Browser.selectedTab, { forceClose: true });
  }
});

function reopenSetUp() {
  info(chromeRoot + "browser_context_menu_tests_04.html");
  yield addTab(chromeRoot + "browser_context_menu_tests_04.html");

  // Sometimes the context UI won't actually show up.
  // Since we're just normalizing, we don't want waitForCondition
  // to cause an orange, so we're putting a try/catch here.
  try {
    yield waitForCondition(() => ContextUI.isVisible);
    ContextUI.dismiss();
  } catch(e) {}
}

function reopenTearDown() {
  let promise = waitForEvent(document, "popuphidden")
  ContextMenuUI.hide();
  yield promise;
  ok(!ContextMenuUI._menuPopup.visible, "popup is actually hidden");

  Browser.closeTab(Browser.selectedTab, { forceClose: true });
}

function getReopenTest(aElementInputFn, aWindowInputFn) {
  return function () {
    let win = Browser.selectedTab.browser.contentWindow;
    let panel = ContextMenuUI._menuPopup._panel;

    let link1 = win.document.getElementById("text1-link");
    let link2 = win.document.getElementById("text2-link");

    // Show the menu on link 1
    let showpromise = waitForEvent(panel, "popupshown");
    aElementInputFn(win, link1);

    ok((yield showpromise), "popupshown event fired");
    ok(ContextMenuUI._menuPopup.visible, "initial popup is visible");

    // Show the menu on link 2
    let hidepromise = waitForEvent(panel, "popuphidden");
    showpromise = waitForEvent(panel, "popupshown");
    aElementInputFn(win, link2);

    ok((yield hidepromise), "popuphidden event fired");
    ok((yield showpromise), "popupshown event fired");
    ok(ContextMenuUI._menuPopup.visible, "popup is still visible");

    // Hide the menu
    hidepromise = waitForEvent(panel, "popuphidden")
    aWindowInputFn(win, 10, 10);

    ok((yield hidepromise), "popuphidden event fired");
    ok(!ContextMenuUI._menuPopup.visible, "popup is no longer visible");
  }
}

gTests.push({
  desc: "bug 856264 - mouse - context menu should reopen on other links",
  setUp: reopenSetUp,
  tearDown: reopenTearDown,
  run: getReopenTest(sendContextMenuMouseClickToElement, sendMouseClick)
});

gTests.push({
  desc: "bug 856264 - touch - context menu should reopen on other links",
  setUp: reopenSetUp,
  tearDown: reopenTearDown,
  run: getReopenTest(sendContextMenuClickToElement, sendTap)
});

gTests.push({
  desc: "Bug 947505 - Right-click in a designMode document should display a " +
        "context menu",
  run: function test() {
    info(chromeRoot + "browser_context_menu_tests_02.html");
    yield addTab(chromeRoot + "browser_context_menu_tests_02.html");

    purgeEventQueue();
    emptyClipboard();
    ContextUI.dismiss();

    yield waitForCondition(() => !ContextUI.navbarVisible);

    let tabWindow = Browser.selectedTab.browser.contentWindow;
    let testSpan = tabWindow.document.getElementById("text1");

    // Case #1: Document isn't in design mode and nothing is selected.
    tabWindow.document.designMode = "off";

    // Simulate right mouse click to reproduce the same step as noted in the
    // appropriate bug. It's valid for non-touch case only.
    synthesizeNativeMouseRDown(Browser.selectedTab.browser, 10, 10);
    synthesizeNativeMouseRUp(Browser.selectedTab.browser, 10, 10);

    yield waitForCondition(() => ContextUI.navbarVisible);

    ok(ContextUI.navbarVisible, "Navbar is visible on context menu action.");
    ok(ContextUI.tabbarVisible, "Tabbar is visible on context menu action.");

    ContextUI.dismiss();
    yield waitForCondition(() => !ContextUI.navbarVisible);

    // Case #2: Document isn't in design mode and text is selected.
    tabWindow.getSelection().selectAllChildren(testSpan);

    let promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToSelection(tabWindow);
    yield promise;

    checkContextUIMenuItemVisibility(["context-copy", "context-search"]);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    // Case #3: Document is in design mode and nothing is selected.
    tabWindow.document.designMode = "on";
    tabWindow.getSelection().removeAllRanges();

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(tabWindow, testSpan);
    yield promise;

    checkContextUIMenuItemVisibility(["context-select-all", "context-select"]);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    // Case #4: Document is in design mode and text is selected.
    tabWindow.getSelection().selectAllChildren(testSpan);

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToSelection(tabWindow);
    yield promise;

    checkContextUIMenuItemVisibility(["context-cut", "context-copy",
                                      "context-select-all", "context-select",
                                      "context-search"]);

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    Browser.closeTab(Browser.selectedTab, { forceClose: true });
  }
});

gTests.push({
  desc: "Bug 961702 - 'Copy' context menu action does not copy rich content " +
        "while document in design mode (or inside container that allows to " +
        "edit its content)",
  run: function test() {
    info(chromeRoot + "browser_context_menu_tests_05.html");
    yield addTab(chromeRoot + "browser_context_menu_tests_05.html");

    purgeEventQueue();
    emptyClipboard();
    ContextUI.dismiss();

    yield waitForCondition(() => !ContextUI.navbarVisible);

    let tabWindow = Browser.selectedTab.browser.contentWindow;
    let testDiv = tabWindow.document.getElementById("div1");

    // Case #1: Document is in design mode.
    tabWindow.document.designMode = "on";

    let promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(tabWindow, testDiv);
    yield promise;

    let selectAllMenuItem = document.getElementById("context-select-all");
    promise = waitForEvent(document, "popuphidden");
    sendNativeTap(selectAllMenuItem);
    yield promise;

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToSelection(tabWindow);
    yield promise;

    let copyMenuItem = document.getElementById("context-copy");
    promise = waitForEvent(document, "popuphidden");
    sendNativeTap(copyMenuItem);
    yield promise;

    // The wait is needed to give time to populate the clipboard.
    let clipboardContent = "";
    let contentToCopy = tabWindow.document.body.innerHTML;
    yield waitForCondition(function () {
      clipboardContent = SpecialPowers.getClipboardData("text/html");
      return clipboardContent == contentToCopy;
    });
    ok(clipboardContent == contentToCopy, "Rich content copied.");

    // Case #2: Container with editable content.
    emptyClipboard();
    tabWindow.document.designMode = "off";
    tabWindow.getSelection().removeAllRanges();

    promise = waitForEvent(tabWindow.document.body, "focus");
    sendNativeTap(testDiv);
    yield promise;

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(tabWindow, testDiv);
    yield promise;

    selectAllMenuItem = document.getElementById("context-select-all");
    promise = waitForEvent(document, "popuphidden");
    sendNativeTap(selectAllMenuItem);
    yield promise;

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToSelection(tabWindow);
    yield promise;

    copyMenuItem = document.getElementById("context-copy");
    promise = waitForEvent(document, "popuphidden");
    sendNativeTap(copyMenuItem);
    yield promise;

     // The wait is needed to give time to populate the clipboard.
    clipboardContent = "";
    contentToCopy = testDiv.innerHTML;
    yield waitForCondition(function () {
      clipboardContent = SpecialPowers.getClipboardData("text/html");
      return clipboardContent == contentToCopy;
    });
    ok(clipboardContent == contentToCopy, "Rich content copied.");

    Browser.closeTab(Browser.selectedTab, { forceClose: true });
  }
});

gTests.push({
  desc: "Bug 963067 - 'Cut' in the cut, copy, paste menu is always active " +
        "after a browser launch.",
  run: function test() {
    info(chromeRoot + "browser_context_menu_tests_02.html");
    yield addTab(chromeRoot + "browser_context_menu_tests_02.html");

    purgeEventQueue();
    emptyClipboard();

    ContextUI.dismiss();
    yield waitForCondition(() => !ContextUI.navbarVisible);

    let tabWindow = Browser.selectedTab.browser.contentWindow;
    let input = tabWindow.document.getElementById("text3-input");
    let cutMenuItem = document.getElementById("context-cut");

    input.select();

    // Emulate RichListBox's behavior and set first item selected by default.
    cutMenuItem.selected = true;

    let promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(tabWindow, input);
    yield promise;

    ok(!cutMenuItem.hidden && !cutMenuItem.selected,
       "Cut menu item is visible and not selected.");

    promise = waitForEvent(document, "popuphidden");
    ContextMenuUI.hide();
    yield promise;

    Browser.closeTab(Browser.selectedTab, { forceClose: true });
  }
});

gTests.push({
  desc: "Bug 867499 - Selecting 'copy' from context menu for selected text " +
        "dismisses selection.",
  run: function test() {
    info(chromeRoot + "browser_context_menu_tests_02.html");
    yield addTab(chromeRoot + "browser_context_menu_tests_02.html");

    emptyClipboard();
    ContextUI.dismiss();

    yield waitForCondition(() => !ContextUI.navbarVisible);

    let tabWindow = Browser.selectedTab.browser.contentWindow;
    let testSpan = tabWindow.document.getElementById("text1");

    let promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToElement(tabWindow, testSpan, 5, 5);
    yield promise;

    yield waitForCondition(()=>SelectionHelperUI.isSelectionUIVisible);

    promise = waitForEvent(document, "popupshown");
    sendContextMenuClickToSelection(tabWindow);
    yield promise;

    let copyMenuItem = document.getElementById("context-copy");

    ok(!copyMenuItem.hidden, "Copy menu item should be visible.");

    promise = waitForEvent(document, "popuphidden");
    sendNativeTap(copyMenuItem, 5, 5);
    yield promise;
    yield waitForCondition(() =>
        !!SpecialPowers.getClipboardData("text/unicode"));

    ok(SelectionHelperUI.isSelectionUIVisible,
        "Selection monocles should stay active after copy action.");

    Browser.closeTab(Browser.selectedTab, { forceClose: true });
  }
});

function test() {
  setDevPixelEqualToPx();
  runTests();
}
