Bug 1347329 - Move the select tests to a forms subdirectory and split apart the color tests to their own file since the test was getting very long. r?mconley draft
authorJared Wein <jwein@mozilla.com>
Tue, 14 Mar 2017 19:27:33 -0400
changeset 498550 710e989852cb924c9ffd166d76af42258db4cb3d
parent 498540 daad56332d93cfb1877f9c41841c1ad2298ac863
child 499624 8a077990ca399c43d7c26a816e3c81757fac825a
push id49238
push userbmo:jaws@mozilla.com
push dateTue, 14 Mar 2017 23:32:59 +0000
reviewersmconley
bugs1347329
milestone55.0a1
Bug 1347329 - Move the select tests to a forms subdirectory and split apart the color tests to their own file since the test was getting very long. r?mconley MozReview-Commit-ID: IGjS2aiL4a2
browser/base/content/test/forms/browser.ini
browser/base/content/test/forms/browser_selectpopup.js
browser/base/content/test/forms/browser_selectpopup_colors.js
browser/base/content/test/forms/head.js
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_selectpopup.js
browser/base/moz.build
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/forms/browser.ini
@@ -0,0 +1,7 @@
+[DEFAULT]
+support-files =
+  head.js
+
+[browser_selectpopup.js]
+skip-if = os == "linux" # Bug 1329991 - test fails intermittently on Linux builds
+[browser_selectpopup_colors.js]
rename from browser/base/content/test/general/browser_selectpopup.js
rename to browser/base/content/test/forms/browser_selectpopup.js
--- a/browser/base/content/test/general/browser_selectpopup.js
+++ b/browser/base/content/test/forms/browser_selectpopup.js
@@ -74,102 +74,16 @@ const PAGECONTENT_SOMEHIDDEN =
 const PAGECONTENT_TRANSLATED =
   "<html><body>" +
   "<div id='div'>" +
   "<iframe id='frame' width='320' height='295' style='border: none;'" +
   "        src='data:text/html,<select id=select autofocus><option>he he he</option><option>boo boo</option><option>baz baz</option></select>'" +
   "</iframe>" +
   "</div></body></html>";
 
-const PAGECONTENT_COLORS =
-  "<html><head><style>" +
-  "  .blue { color: #fff; background-color: #00f; }" +
-  "  .green { color: #800080; background-color: green; }" +
-  "  .defaultColor { color: -moz-ComboboxText; }" +
-  "  .defaultBackground { background-color: -moz-Combobox; }" +
-  "</style>" +
-  "<body><select id='one'>" +
-  '  <option value="One" style="color: #fff; background-color: #f00;">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgb(255, 0, 0)"}</option>' +
-  '  <option value="Two" class="blue">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgb(0, 0, 255)"}</option>' +
-  '  <option value="Three" class="green">{"color": "rgb(128, 0, 128)", "backgroundColor": "rgb(0, 128, 0)"}</option>' +
-  '  <option value="Four" class="defaultColor defaultBackground">{"color": "-moz-ComboboxText", "backgroundColor": "rgba(0, 0, 0, 0)", "unstyled": "true"}</option>' +
-  '  <option value="Five" class="defaultColor">{"color": "-moz-ComboboxText", "backgroundColor": "rgba(0, 0, 0, 0)", "unstyled": "true"}</option>' +
-  '  <option value="Six" class="defaultBackground">{"color": "-moz-ComboboxText", "backgroundColor": "rgba(0, 0, 0, 0)", "unstyled": "true"}</option>' +
-  '  <option value="Seven" selected="true">{"unstyled": "true"}</option>' +
-  "</select></body></html>";
-
-const PAGECONTENT_COLORS_ON_SELECT =
-  "<html><head><style>" +
-  "  #one { background-color: #7E3A3A; color: #fff }" +
-  "</style>" +
-  "<body><select id='one'>" +
-  '  <option value="One">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '  <option value="Two">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '  <option value="Three">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '  <option value="Four" selected="true">{"end": "true"}</option>' +
-  "</select></body></html>";
-
-const TRANSPARENT_SELECT =
-  "<html><head><style>" +
-  "  #one { background-color: transparent; }" +
-  "</style>" +
-  "<body><select id='one'>" +
-  '  <option value="One">{"unstyled": "true"}</option>' +
-  '  <option value="Two" selected="true">{"end": "true"}</option>' +
-  "</select></body></html>";
-
-const OPTION_COLOR_EQUAL_TO_UABACKGROUND_COLOR_SELECT =
-  "<html><head><style>" +
-  "  #one { background-color: black; color: white; }" +
-  "</style>" +
-  "<body><select id='one'>" +
-  '  <option value="One" style="background-color: white; color: black;">{"color": "rgb(0, 0, 0)", "backgroundColor": "rgb(255, 255, 255)"}</option>' +
-  '  <option value="Two" selected="true">{"end": "true"}</option>' +
-  "</select></body></html>";
-
-const GENERIC_OPTION_STYLED_AS_IMPORTANT =
-  "<html><head><style>" +
-  "  option { background-color: black !important; color: white !important; }" +
-  "</style>" +
-  "<body><select id='one'>" +
-  '  <option value="One">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgb(0, 0, 0)"}</option>' +
-  '  <option value="Two" selected="true">{"end": "true"}</option>' +
-  "</select></body></html>";
-
-const TRANSLUCENT_SELECT_BECOMES_OPAQUE =
-  "<html><head>" +
-  "<body><select id='one' style='background-color: rgba(255,255,255,.55);'>" +
-  '  <option value="One">{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '  <option value="Two" selected="true">{"end": "true"}</option>' +
-  "</select></body></html>";
-
-const DISABLED_OPTGROUP_AND_OPTIONS =
-  "<html><head>" +
-  "<body><select id='one'>" +
-  "  <optgroup label='{\"color\": \"rgb(0, 0, 0)\", \"backgroundColor\": \"buttonface\"}'>" +
-  '    <option disabled="">{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '    <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '    <option disabled="">{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '    <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '    <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '    <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '    <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  "  </optgroup>" +
-  "  <optgroup label='{\"color\": \"GrayText\", \"backgroundColor\": \"buttonface\"}' disabled=''>" +
-  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
-  "  </optgroup>" +
-  '  <option value="Two" selected="true">{"end": "true"}</option>' +
-  "</select></body></html>";
-
 function openSelectPopup(selectPopup, mode = "key", selector = "select", win = window) {
   let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
 
   if (mode == "click" || mode == "mousedown") {
     let mousePromise;
     if (mode == "click") {
       mousePromise = BrowserTestUtils.synthesizeMouseAtCenter(selector, { }, win.gBrowser.selectedBrowser);
     } else {
@@ -178,34 +92,16 @@ function openSelectPopup(selectPopup, mo
 
     return Promise.all([popupShownPromise, mousePromise]);
   }
 
   EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true, code: "ArrowDown" }, win);
   return popupShownPromise;
 }
 
-function hideSelectPopup(selectPopup, mode = "enter", win = window) {
-  let browser = win.gBrowser.selectedBrowser;
-  let selectClosedPromise = ContentTask.spawn(browser, null, function*() {
-    Cu.import("resource://gre/modules/SelectContentHelper.jsm");
-    return ContentTaskUtils.waitForCondition(() => !SelectContentHelper.open);
-  });
-
-  if (mode == "escape") {
-    EventUtils.synthesizeKey("KEY_Escape", { code: "Escape" }, win);
-  } else if (mode == "enter") {
-    EventUtils.synthesizeKey("KEY_Enter", { code: "Enter" }, win);
-  } else if (mode == "click") {
-    EventUtils.synthesizeMouseAtCenter(selectPopup.lastChild, { }, win);
-  }
-
-  return selectClosedPromise;
-}
-
 function getInputEvents() {
   return ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
     return content.wrappedJSObject.gInputEvents;
   });
 }
 
 function getChangeEvents() {
   return ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
@@ -214,95 +110,16 @@ function getChangeEvents() {
 }
 
 function getClickEvents() {
   return ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
     return content.wrappedJSObject.gClickEvents;
   });
 }
 
-function getSystemColor(color) {
-  // Need to convert system color to RGB color.
-  let textarea = document.createElementNS("http://www.w3.org/1999/xhtml", "textarea");
-  textarea.style.color = color;
-  return getComputedStyle(textarea).color;
-}
-
-function testOptionColors(index, item, menulist) {
-  // The label contains a JSON string of the expected colors for
-  // `color` and `background-color`.
-  let expected;
-  try {
-    expected = JSON.parse(item.label);
-  } catch (ex) {
-    info(`Failed parsing: ${item.label}`);
-    info(`Failed parsing element with outerHTML: ${item.outerHTML}`);
-    ok(false, ex.message);
-    return;
-  }
-
-  for (let color of Object.keys(expected)) {
-    if (color.toLowerCase().includes("color") &&
-        !expected[color].startsWith("rgb")) {
-      expected[color] = getSystemColor(expected[color]);
-    }
-  }
-
-  // Press Down to move the selected item to the next item in the
-  // list and check the colors of this item when it's not selected.
-  EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
-
-  if (expected.end) {
-    return;
-  }
-
-  if (expected.unstyled) {
-    ok(!item.hasAttribute("customoptionstyling"),
-      `Item ${index} should not have any custom option styling`);
-  } else {
-    is(getComputedStyle(item).color, expected.color,
-       "Item " + (index) + " has correct foreground color");
-    is(getComputedStyle(item).backgroundColor, expected.backgroundColor,
-       "Item " + (index) + " has correct background color");
-  }
-}
-
-function* testSelectColors(select, itemCount, options) {
-  const pageUrl = "data:text/html," + escape(select);
-  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
-
-  let menulist = document.getElementById("ContentSelectDropdown");
-  let selectPopup = menulist.menupopup;
-
-  let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
-  yield BrowserTestUtils.synthesizeMouseAtCenter("#one", { type: "mousedown" }, gBrowser.selectedBrowser);
-  yield popupShownPromise;
-
-  is(selectPopup.parentNode.itemCount, itemCount, "Correct number of items");
-  let child = selectPopup.firstChild;
-  let idx = 1;
-
-  if (!options.skipSelectColorTest) {
-    is(getComputedStyle(selectPopup).color, options.selectColor,
-      "popup has expected foreground color");
-    is(getComputedStyle(selectPopup).backgroundColor, options.selectBgColor,
-      "popup has expected background color");
-  }
-
-  ok(!child.selected, "The first child should not be selected");
-  while (child) {
-    testOptionColors(idx, child, menulist);
-    idx++;
-    child = child.nextSibling;
-  }
-
-  yield hideSelectPopup(selectPopup, "escape");
-
-  yield BrowserTestUtils.removeTab(tab);
-}
 function* doSelectTests(contentType, dtd) {
   const pageUrl = "data:" + contentType + "," + escape(dtd + "\n" + PAGECONTENT);
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
 
   let menulist = document.getElementById("ContentSelectDropdown");
   let selectPopup = menulist.menupopup;
 
   yield openSelectPopup(selectPopup);
@@ -889,40 +706,16 @@ add_task(function* test_somehidden() {
        "Item " + (idx++) + " is visible");
     child = child.nextSibling;
   }
 
   yield hideSelectPopup(selectPopup, "escape");
   yield BrowserTestUtils.removeTab(tab);
 });
 
-// This test checks when a <select> element has styles applied to <option>s within it.
-add_task(function* test_colors_applied_to_popup_items() {
-  yield testSelectColors(PAGECONTENT_COLORS, 7,
-                         {skipSelectColorTest: true});
-});
-
-// This test checks when a <select> element has styles applied to itself.
-add_task(function* test_colors_applied_to_popup() {
-  let options = {
-    selectColor: "rgb(255, 255, 255)",
-    selectBgColor: "rgb(126, 58, 58)"
-  };
-  yield testSelectColors(PAGECONTENT_COLORS_ON_SELECT, 4, options);
-});
-
-// This test checks when a <select> element has a transparent background applied to itself.
-add_task(function* test_transparent_applied_to_popup() {
-  let options = {
-    selectColor: getSystemColor("-moz-ComboboxText"),
-    selectBgColor: getSystemColor("-moz-Combobox")
-  };
-  yield testSelectColors(TRANSPARENT_SELECT, 2, options);
-});
-
 // This test checks that the popup is closed when the select element is blurred.
 add_task(function* test_blur_hides_popup() {
   const pageUrl = "data:text/html," + escape(PAGECONTENT_SMALL);
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
 
   yield ContentTask.spawn(tab.linkedBrowser, null, function*() {
     content.addEventListener("blur", function(event) {
       event.preventDefault();
@@ -944,54 +737,8 @@ add_task(function* test_blur_hides_popup
   });
 
   yield popupHiddenPromise;
 
   ok(true, "Blur closed popup");
 
   yield BrowserTestUtils.removeTab(tab);
 });
-
-// This test checks when a <select> element has a background set, and the
-// options have their own background set which is equal to the default
-// user-agent background color, but should be used because the select
-// background color has been changed.
-add_task(function* test_options_inverted_from_select_background() {
-  // The popup has a black background and white text, but the
-  // options inside of it have flipped the colors.
-  let options = {
-    selectColor: "rgb(255, 255, 255)",
-    selectBgColor: "rgb(0, 0, 0)"
-  };
-  yield testSelectColors(OPTION_COLOR_EQUAL_TO_UABACKGROUND_COLOR_SELECT,
-                         2, options);
-});
-
-// This test checks when a <select> element has a background set using !important,
-// which was affecting how we calculated the user-agent styling.
-add_task(function* test_select_background_using_important() {
-  yield testSelectColors(GENERIC_OPTION_STYLED_AS_IMPORTANT, 2,
-                         {skipSelectColorTest: true});
-});
-
-// This test checks when a <select> element has a background set, and the
-// options have their own background set which is equal to the default
-// user-agent background color, but should be used because the select
-// background color has been changed.
-add_task(function* test_translucent_select_becomes_opaque() {
-  // The popup is requested to show a translucent background
-  // but we force the alpha channel to 1 on the popup.
-  let options = {
-    selectColor: "rgb(0, 0, 0)",
-    selectBgColor: "rgb(255, 255, 255)"
-  };
-  yield testSelectColors(TRANSLUCENT_SELECT_BECOMES_OPAQUE, 2, options);
-});
-
-add_task(function* test_disabled_optgroup_and_options() {
-  // The colors used by this test are platform-specific.
-  if (AppConstants.platform != "win") {
-    return;
-  }
-
-  yield testSelectColors(DISABLED_OPTGROUP_AND_OPTIONS, 17,
-                         {skipSelectColorTest: true});
-});
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/forms/browser_selectpopup_colors.js
@@ -0,0 +1,227 @@
+const PAGECONTENT_COLORS =
+  "<html><head><style>" +
+  "  .blue { color: #fff; background-color: #00f; }" +
+  "  .green { color: #800080; background-color: green; }" +
+  "  .defaultColor { color: -moz-ComboboxText; }" +
+  "  .defaultBackground { background-color: -moz-Combobox; }" +
+  "</style>" +
+  "<body><select id='one'>" +
+  '  <option value="One" style="color: #fff; background-color: #f00;">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgb(255, 0, 0)"}</option>' +
+  '  <option value="Two" class="blue">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgb(0, 0, 255)"}</option>' +
+  '  <option value="Three" class="green">{"color": "rgb(128, 0, 128)", "backgroundColor": "rgb(0, 128, 0)"}</option>' +
+  '  <option value="Four" class="defaultColor defaultBackground">{"color": "-moz-ComboboxText", "backgroundColor": "rgba(0, 0, 0, 0)", "unstyled": "true"}</option>' +
+  '  <option value="Five" class="defaultColor">{"color": "-moz-ComboboxText", "backgroundColor": "rgba(0, 0, 0, 0)", "unstyled": "true"}</option>' +
+  '  <option value="Six" class="defaultBackground">{"color": "-moz-ComboboxText", "backgroundColor": "rgba(0, 0, 0, 0)", "unstyled": "true"}</option>' +
+  '  <option value="Seven" selected="true">{"unstyled": "true"}</option>' +
+  "</select></body></html>";
+
+const PAGECONTENT_COLORS_ON_SELECT =
+  "<html><head><style>" +
+  "  #one { background-color: #7E3A3A; color: #fff }" +
+  "</style>" +
+  "<body><select id='one'>" +
+  '  <option value="One">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '  <option value="Two">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '  <option value="Three">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '  <option value="Four" selected="true">{"end": "true"}</option>' +
+  "</select></body></html>";
+
+const TRANSPARENT_SELECT =
+  "<html><head><style>" +
+  "  #one { background-color: transparent; }" +
+  "</style>" +
+  "<body><select id='one'>" +
+  '  <option value="One">{"unstyled": "true"}</option>' +
+  '  <option value="Two" selected="true">{"end": "true"}</option>' +
+  "</select></body></html>";
+
+const OPTION_COLOR_EQUAL_TO_UABACKGROUND_COLOR_SELECT =
+  "<html><head><style>" +
+  "  #one { background-color: black; color: white; }" +
+  "</style>" +
+  "<body><select id='one'>" +
+  '  <option value="One" style="background-color: white; color: black;">{"color": "rgb(0, 0, 0)", "backgroundColor": "rgb(255, 255, 255)"}</option>' +
+  '  <option value="Two" selected="true">{"end": "true"}</option>' +
+  "</select></body></html>";
+
+const GENERIC_OPTION_STYLED_AS_IMPORTANT =
+  "<html><head><style>" +
+  "  option { background-color: black !important; color: white !important; }" +
+  "</style>" +
+  "<body><select id='one'>" +
+  '  <option value="One">{"color": "rgb(255, 255, 255)", "backgroundColor": "rgb(0, 0, 0)"}</option>' +
+  '  <option value="Two" selected="true">{"end": "true"}</option>' +
+  "</select></body></html>";
+
+const TRANSLUCENT_SELECT_BECOMES_OPAQUE =
+  "<html><head>" +
+  "<body><select id='one' style='background-color: rgba(255,255,255,.55);'>" +
+  '  <option value="One">{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '  <option value="Two" selected="true">{"end": "true"}</option>' +
+  "</select></body></html>";
+
+const DISABLED_OPTGROUP_AND_OPTIONS =
+  "<html><head>" +
+  "<body><select id='one'>" +
+  "  <optgroup label='{\"color\": \"rgb(0, 0, 0)\", \"backgroundColor\": \"buttonface\"}'>" +
+  '    <option disabled="">{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '    <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '    <option disabled="">{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '    <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '    <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '    <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '    <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  "  </optgroup>" +
+  "  <optgroup label='{\"color\": \"GrayText\", \"backgroundColor\": \"buttonface\"}' disabled=''>" +
+  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '    <option>{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  "  </optgroup>" +
+  '  <option value="Two" selected="true">{"end": "true"}</option>' +
+  "</select></body></html>";
+
+function getSystemColor(color) {
+  // Need to convert system color to RGB color.
+  let textarea = document.createElementNS("http://www.w3.org/1999/xhtml", "textarea");
+  textarea.style.color = color;
+  return getComputedStyle(textarea).color;
+}
+
+function testOptionColors(index, item, menulist) {
+  // The label contains a JSON string of the expected colors for
+  // `color` and `background-color`.
+  let expected = JSON.parse(item.label);
+
+  for (let color of Object.keys(expected)) {
+    if (color.toLowerCase().includes("color") &&
+        !expected[color].startsWith("rgb")) {
+      expected[color] = getSystemColor(expected[color]);
+    }
+  }
+
+  // Press Down to move the selected item to the next item in the
+  // list and check the colors of this item when it's not selected.
+  EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
+
+  if (expected.end) {
+    return;
+  }
+
+  if (expected.unstyled) {
+    ok(!item.hasAttribute("customoptionstyling"),
+      `Item ${index} should not have any custom option styling`);
+  } else {
+    is(getComputedStyle(item).color, expected.color,
+       "Item " + (index) + " has correct foreground color");
+    is(getComputedStyle(item).backgroundColor, expected.backgroundColor,
+       "Item " + (index) + " has correct background color");
+  }
+}
+
+function* testSelectColors(select, itemCount, options) {
+  const pageUrl = "data:text/html," + escape(select);
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
+
+  let menulist = document.getElementById("ContentSelectDropdown");
+  let selectPopup = menulist.menupopup;
+
+  let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
+  yield BrowserTestUtils.synthesizeMouseAtCenter("#one", { type: "mousedown" }, gBrowser.selectedBrowser);
+  yield popupShownPromise;
+
+  is(selectPopup.parentNode.itemCount, itemCount, "Correct number of items");
+  let child = selectPopup.firstChild;
+  let idx = 1;
+
+  if (!options.skipSelectColorTest) {
+    is(getComputedStyle(selectPopup).color, options.selectColor,
+      "popup has expected foreground color");
+    is(getComputedStyle(selectPopup).backgroundColor, options.selectBgColor,
+      "popup has expected background color");
+  }
+
+  ok(!child.selected, "The first child should not be selected");
+  while (child) {
+    testOptionColors(idx, child, menulist);
+    idx++;
+    child = child.nextSibling;
+  }
+
+  yield hideSelectPopup(selectPopup, "escape");
+
+  yield BrowserTestUtils.removeTab(tab);
+}
+
+// This test checks when a <select> element has styles applied to <option>s within it.
+add_task(function* test_colors_applied_to_popup_items() {
+  yield testSelectColors(PAGECONTENT_COLORS, 7,
+                         {skipSelectColorTest: true});
+});
+
+// This test checks when a <select> element has styles applied to itself.
+add_task(function* test_colors_applied_to_popup() {
+  let options = {
+    selectColor: "rgb(255, 255, 255)",
+    selectBgColor: "rgb(126, 58, 58)"
+  };
+  yield testSelectColors(PAGECONTENT_COLORS_ON_SELECT, 4, options);
+});
+
+// This test checks when a <select> element has a transparent background applied to itself.
+add_task(function* test_transparent_applied_to_popup() {
+  let options = {
+    selectColor: getSystemColor("-moz-ComboboxText"),
+    selectBgColor: getSystemColor("-moz-Combobox")
+  };
+  yield testSelectColors(TRANSPARENT_SELECT, 2, options);
+});
+
+// This test checks when a <select> element has a background set, and the
+// options have their own background set which is equal to the default
+// user-agent background color, but should be used because the select
+// background color has been changed.
+add_task(function* test_options_inverted_from_select_background() {
+  // The popup has a black background and white text, but the
+  // options inside of it have flipped the colors.
+  let options = {
+    selectColor: "rgb(255, 255, 255)",
+    selectBgColor: "rgb(0, 0, 0)"
+  };
+  yield testSelectColors(OPTION_COLOR_EQUAL_TO_UABACKGROUND_COLOR_SELECT,
+                         2, options);
+});
+
+// This test checks when a <select> element has a background set using !important,
+// which was affecting how we calculated the user-agent styling.
+add_task(function* test_select_background_using_important() {
+  yield testSelectColors(GENERIC_OPTION_STYLED_AS_IMPORTANT, 2,
+                         {skipSelectColorTest: true});
+});
+
+// This test checks when a <select> element has a background set, and the
+// options have their own background set which is equal to the default
+// user-agent background color, but should be used because the select
+// background color has been changed.
+add_task(function* test_translucent_select_becomes_opaque() {
+  // The popup is requested to show a translucent background
+  // but we force the alpha channel to 1 on the popup.
+  let options = {
+    selectColor: "rgb(0, 0, 0)",
+    selectBgColor: "rgb(255, 255, 255)"
+  };
+  yield testSelectColors(TRANSLUCENT_SELECT_BECOMES_OPAQUE, 2, options);
+});
+
+add_task(function* test_disabled_optgroup_and_options() {
+  // The colors used by this test are platform-specific.
+  if (AppConstants.platform != "win") {
+    return;
+  }
+
+  yield testSelectColors(DISABLED_OPTGROUP_AND_OPTIONS, 17,
+                         {skipSelectColorTest: true});
+});
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/forms/head.js
@@ -0,0 +1,19 @@
+/* eslint-env mozilla/frame-script */
+
+function hideSelectPopup(selectPopup, mode = "enter", win = window) {
+  let browser = win.gBrowser.selectedBrowser;
+  let selectClosedPromise = ContentTask.spawn(browser, null, function*() {
+    Cu.import("resource://gre/modules/SelectContentHelper.jsm");
+    return ContentTaskUtils.waitForCondition(() => !SelectContentHelper.open);
+  });
+
+  if (mode == "escape") {
+    EventUtils.synthesizeKey("KEY_Escape", { code: "Escape" }, win);
+  } else if (mode == "enter") {
+    EventUtils.synthesizeKey("KEY_Enter", { code: "Enter" }, win);
+  } else if (mode == "click") {
+    EventUtils.synthesizeMouseAtCenter(selectPopup.lastChild, { }, win);
+  }
+
+  return selectClosedPromise;
+}
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -319,18 +319,16 @@ skip-if = e10s && debug && os == "win" #
 [browser_save_link_when_window_navigates.js]
 [browser_save_video.js]
 [browser_save_video_frame.js]
 [browser_scope.js]
 [browser_contentSearchUI.js]
 support-files =
   contentSearchUI.html
   contentSearchUI.js
-[browser_selectpopup.js]
-skip-if = os == "linux" # Bug 1329991 - test fails intermittently on Linux builds
 [browser_selectTabAtIndex.js]
 [browser_ssl_error_reports.js]
 [browser_star_hsts.js]
 [browser_storagePressure_notification.js]
 [browser_subframe_favicons_not_used.js]
 [browser_syncui.js]
 skip-if = os == 'linux' # Bug 1304272
 [browser_tab_close_dependent_window.js]
--- a/browser/base/moz.build
+++ b/browser/base/moz.build
@@ -12,16 +12,17 @@ MOCHITEST_MANIFESTS += [
 
 MOCHITEST_CHROME_MANIFESTS += [
     'content/test/chrome/chrome.ini',
 ]
 
 BROWSER_CHROME_MANIFESTS += [
     'content/test/alerts/browser.ini',
     'content/test/captivePortal/browser.ini',
+    'content/test/forms/browser.ini',
     'content/test/general/browser.ini',
     'content/test/newtab/browser.ini',
     'content/test/pageinfo/browser.ini',
     'content/test/plugins/browser.ini',
     'content/test/popupNotifications/browser.ini',
     'content/test/referrer/browser.ini',
     'content/test/siteIdentity/browser.ini',
     'content/test/social/browser.ini',