summaryrefslogtreecommitdiffstats
path: root/comm/mail/test/browser/content-tabs/browser_aboutSupport.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/test/browser/content-tabs/browser_aboutSupport.js')
-rw-r--r--comm/mail/test/browser/content-tabs/browser_aboutSupport.js587
1 files changed, 587 insertions, 0 deletions
diff --git a/comm/mail/test/browser/content-tabs/browser_aboutSupport.js b/comm/mail/test/browser/content-tabs/browser_aboutSupport.js
new file mode 100644
index 0000000000..9be3cf0eab
--- /dev/null
+++ b/comm/mail/test/browser/content-tabs/browser_aboutSupport.js
@@ -0,0 +1,587 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+var utils = ChromeUtils.import("resource://testing-common/mozmill/utils.jsm");
+var { close_compose_window, wait_for_compose_window } = ChromeUtils.import(
+ "resource://testing-common/mozmill/ComposeHelpers.jsm"
+);
+var {
+ assert_content_tab_element_hidden,
+ assert_content_tab_element_visible,
+ assert_content_tab_text_absent,
+ assert_content_tab_text_present,
+ content_tab_e,
+ get_content_tab_element_display,
+ get_element_by_text,
+ open_content_tab_with_click,
+ wait_for_content_tab_element_display,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/ContentTabHelpers.jsm"
+);
+
+var { close_tab, mc } = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+var { click_menus_in_sequence, plan_for_new_window } = ChromeUtils.import(
+ "resource://testing-common/mozmill/WindowHelpers.jsm"
+);
+
+var warningText = new Map();
+
+add_setup(function () {
+ // The wording of the warning message when private data is being exported
+ // from the about:support page.
+ let bundle = Services.strings.createBundle(
+ "chrome://messenger/locale/aboutSupportMail.properties"
+ );
+ // In HTML the warning label and text comprise the textContent of a single element.
+ warningText.set(
+ "text/html",
+ bundle.GetStringFromName("warningLabel") +
+ " " +
+ bundle.GetStringFromName("warningText")
+ );
+ // In plain text the warning label may end up on a separate line so do not match it.
+ warningText.set("text/plain", bundle.GetStringFromName("warningText"));
+});
+
+// After every test we want to close the about:support tab so that failures
+// don't cascade.
+function teardownTest(module) {
+ let tabmail = mc.window.document.getElementById("tabmail");
+ tabmail.closeOtherTabs(tabmail.tabInfo[0]);
+}
+
+/**
+ * Strings found in the about:support HTML or text that should clearly mark the
+ * data as being from about:support.
+ */
+const ABOUT_SUPPORT_STRINGS = [
+ "Application Basics",
+ "Mail and News Accounts",
+ "Add-ons",
+ "Important Modified Preferences",
+ "Graphics",
+ "Accessibility",
+ "Library Versions",
+];
+
+/**
+ * Strings that if found in the about:support text or HTML usually indicate an
+ * error.
+ */
+const ABOUT_SUPPORT_ERROR_STRINGS = new Map([
+ ["text/html", ["undefined", "null"]],
+ ["text/plain", ["undefined"]],
+]);
+
+/*
+ * Helpers
+ */
+
+/**
+ * Opens about:support and waits for it to load.
+ *
+ * @returns the about:support tab.
+ */
+async function open_about_support() {
+ let openAboutSupport = async function () {
+ if (AppConstants.platform == "macosx") {
+ mc.window.document.getElementById("aboutsupport_open").click();
+ } else {
+ // Show menubar so we can click it.
+ document.getElementById("toolbar-menubar").removeAttribute("autohide");
+ let helpMenu = mc.window.document.getElementById("helpMenu");
+ EventUtils.synthesizeMouseAtCenter(helpMenu, {}, helpMenu.ownerGlobal);
+ await click_menus_in_sequence(
+ mc.window.document.getElementById("menu_HelpPopup"),
+ [{ id: "aboutsupport_open" }]
+ );
+ }
+ };
+ let tab = open_content_tab_with_click(openAboutSupport, "about:support");
+
+ // Make sure L10n is done.
+ let l10nDone = false;
+ tab.browser.contentDocument.l10n.ready.then(
+ () => (l10nDone = true),
+ console.error
+ );
+ utils.waitFor(() => l10nDone, "Timeout waiting for L10n to complete.");
+
+ // We have one variable that's asynchronously populated -- wait for it to be
+ // populated.
+ utils.waitFor(
+ () => tab.browser.contentWindow.gAccountDetails !== undefined,
+ "Timeout waiting for about:support's gAccountDetails to populate."
+ );
+
+ utils.waitFor(
+ () => content_tab_e(tab, "accounts-tbody").children.length > 1,
+ "Accounts sections didn't load."
+ );
+ // The population of the info fields is async, so we must wait until
+ // the last one is done.
+ utils.waitFor(
+ () =>
+ content_tab_e(tab, "intl-osprefs-regionalprefs").textContent.trim() != "",
+ "Regional prefs section didn't load."
+ );
+
+ // Wait an additional half-second for some more localisation caused by
+ // runtime changes to the page.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, 500));
+ return tab;
+}
+
+/**
+ * Opens a compose window containing the troubleshooting information.
+ *
+ * @param aTab The about:support tab.
+ */
+function open_send_via_email(aTab) {
+ let button = content_tab_e(aTab, "send-via-email");
+ plan_for_new_window("msgcompose");
+ EventUtils.synthesizeMouseAtCenter(
+ button,
+ { clickCount: 1 },
+ button.ownerGlobal
+ );
+ let cwc = wait_for_compose_window();
+ return cwc;
+}
+
+/**
+ * Find some element marked as private data.
+ */
+function find_private_element(aTab) {
+ // We use the identity name as an example of a private-only element.
+ // It is currently the second td element with class="data-private" in the table.
+ // The content string must be something unique that is not found anywhere else.
+ let elem = aTab.browser.contentDocument.querySelector(
+ "#accounts-table td.data-private~td.data-private"
+ );
+ Assert.ok(elem != null);
+ Assert.ok(elem.textContent.length > 0);
+ Assert.equal(get_content_tab_element_display(aTab, elem), "none");
+ return elem;
+}
+
+/*
+ * Tests
+ */
+
+/**
+ * Test displaying the about:support page. Also perform a couple of basic tests
+ * to check that no major errors have occurred. The basic tests are by no means
+ * comprehensive.
+ */
+add_task(async function test_display_about_support() {
+ let tab = await open_about_support();
+ // Check that the document has a few strings that indicate that we've loaded
+ // the right page.
+ for (let str of ABOUT_SUPPORT_STRINGS) {
+ assert_content_tab_text_present(tab, str);
+ }
+
+ // Check that error strings aren't present anywhere
+ for (let str of ABOUT_SUPPORT_ERROR_STRINGS.get("text/html")) {
+ assert_content_tab_text_absent(tab, str);
+ }
+
+ // Bug 1339436
+ // Test that the tables in the page are all populated with at least one row
+ // in the tbody element.
+ // An exception in the code could cause some to be empty.
+ let tables = tab.browser.contentDocument.querySelectorAll("tbody");
+ let emptyTables = [
+ "graphics-failures-tbody",
+ "graphics-tbody",
+ "locked-prefs-tbody",
+ "sandbox-syscalls-tbody",
+ "crashes-tbody",
+ "processes-tbody",
+ "support-printing-prefs-tbody",
+ "chat-tbody",
+ ]; // some tables may be empty
+ for (let table of tables) {
+ if (!emptyTables.includes(table.id)) {
+ Assert.ok(
+ table.querySelectorAll("tr").length > 0,
+ "Troubleshooting table '" + table.id + "' is empty!"
+ );
+ }
+ }
+
+ // Mozmill uses a user.js file in the profile, so the warning about the file
+ // should be visible here.
+ let userjsElem = tab.browser.contentDocument.getElementById(
+ "prefs-user-js-section"
+ );
+ Assert.ok(userjsElem.hasChildNodes);
+ Assert.ok(
+ tab.browser.contentDocument.defaultView.getComputedStyle(userjsElem)
+ .display == "block"
+ );
+ Assert.ok(
+ tab.browser.contentDocument.defaultView.getComputedStyle(userjsElem)
+ .visibility == "visible"
+ );
+
+ close_tab(tab);
+});
+
+/**
+ * Test that our accounts are displayed in order.
+ */
+add_task(async function test_accounts_in_order() {
+ let tab = await open_about_support();
+ // This is a really simple test and by no means comprehensive -- test that
+ // "account1" appears before "account2" in the HTML content.
+ assert_content_tab_text_present(tab, "account1");
+ assert_content_tab_text_present(tab, "account2");
+ let html = tab.browser.contentDocument.documentElement.innerHTML;
+ if (html.indexOf("account1") > html.indexOf("account2")) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ "account1 found after account2 in the HTML page"
+ );
+ }
+ close_tab(tab);
+});
+
+var UNIQUE_ID = "3a9e1694-7115-4237-8b1e-1cabe6e35073";
+
+/**
+ * Test that a modified preference on the whitelist but not on the blacklist
+ * shows up.
+ */
+add_task(async function test_modified_pref_on_whitelist() {
+ const PREFIX = "accessibility.";
+ let prefName = PREFIX + UNIQUE_ID;
+ Services.prefs.setBoolPref(prefName, true);
+ let tab = await open_about_support();
+
+ assert_content_tab_text_present(tab, prefName);
+ close_tab(tab);
+ Services.prefs.clearUserPref(prefName);
+});
+
+/**
+ * Test that a modified preference not on the whitelist doesn't show up.
+ */
+add_task(async function test_modified_pref_not_on_whitelist() {
+ Services.prefs.setBoolPref(UNIQUE_ID, true);
+ let tab = await open_about_support();
+ assert_content_tab_text_absent(tab, UNIQUE_ID);
+ close_tab(tab);
+ Services.prefs.clearUserPref(UNIQUE_ID);
+});
+
+/**
+ * Test that a modified preference on the blacklist doesn't show up.
+ */
+add_task(async function test_modified_pref_on_blacklist() {
+ const PREFIX = "network.proxy.";
+ let prefName = PREFIX + UNIQUE_ID;
+ Services.prefs.setBoolPref(prefName, true);
+ let tab = await open_about_support();
+
+ assert_content_tab_text_absent(tab, prefName);
+ close_tab(tab);
+ Services.prefs.clearUserPref(prefName);
+});
+
+/**
+ * Test that private data isn't displayed by default, and that when it is
+ * displayed, it actually shows up.
+ */
+add_task(async function test_private_data() {
+ let tab = await open_about_support();
+ let checkbox = content_tab_e(tab, "check-show-private-data");
+
+ // We use the profile path and some other element as an example
+ // of a private-only element.
+ let privateElem1 = find_private_element(tab);
+ let privateElem2 = content_tab_e(tab, "profile-dir-box");
+ // We use the profile button as an example of a public element.
+ let publicElem = content_tab_e(tab, "profile-dir-button");
+
+ Assert.ok(
+ !checkbox.checked,
+ "Private data checkbox shouldn't be checked by default"
+ );
+ assert_content_tab_element_visible(tab, publicElem);
+ assert_content_tab_element_hidden(tab, privateElem1);
+ assert_content_tab_element_hidden(tab, privateElem2);
+
+ // Now check the checkbox and see what happens.
+ EventUtils.synthesizeMouseAtCenter(
+ checkbox,
+ { clickCount: 1 },
+ checkbox.ownerGlobal
+ );
+ wait_for_content_tab_element_display(tab, privateElem1);
+ wait_for_content_tab_element_display(tab, privateElem2);
+ close_tab(tab);
+});
+
+/**
+ * Checks if text fragment exists in the document.
+ * If it is a node tree, find the element whole contents is the searched text.
+ * If it is plain text string, just check in text is anywhere in it.
+ *
+ * @param aDocument A node tree or a string of plain text data.
+ * @param aText The text to find in the document.
+ */
+function check_text_in_body(aDocument, aText) {
+ if (typeof aDocument == "object") {
+ return get_element_by_text(aDocument, aText) != null;
+ }
+ return aDocument.includes(aText);
+}
+
+/**
+ * Test (well, sort of) the copy to clipboard function with public data.
+ */
+add_task(async function test_copy_to_clipboard_public() {
+ let tab = await open_about_support();
+ let privateElem = find_private_element(tab);
+ // To avoid destroying the current contents of the clipboard, instead of
+ // actually copying to it, we just retrieve what would have been copied to it
+ let transferable = tab.browser.contentWindow.getClipboardTransferable();
+ for (let flavor of ["text/html", "text/plain"]) {
+ let data = {};
+ transferable.getTransferData(flavor, data);
+ let text = data.value.QueryInterface(Ci.nsISupportsString).data;
+ let contentBody;
+ if (flavor == "text/html") {
+ let parser = new DOMParser();
+ contentBody = parser.parseFromString(text, "text/html").body;
+ } else {
+ contentBody = text;
+ }
+
+ for (let str of ABOUT_SUPPORT_STRINGS) {
+ if (!check_text_in_body(contentBody, str)) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ `Unable to find "${str}" in flavor "${flavor}"`
+ );
+ }
+ }
+
+ for (let str of ABOUT_SUPPORT_ERROR_STRINGS.get(flavor)) {
+ if (check_text_in_body(contentBody, str)) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ `Found "${str}" in flavor "${flavor}"`
+ );
+ }
+ }
+
+ // Check that private data isn't in the output.
+ if (check_text_in_body(contentBody, privateElem.textContent)) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ `Found private data in flavor "${flavor}"`
+ );
+ }
+ }
+ close_tab(tab);
+});
+
+/**
+ * Test (well, sort of) the copy to clipboard function with private data.
+ */
+add_task(async function test_copy_to_clipboard_private() {
+ let tab = await open_about_support();
+
+ // Display private data.
+ let privateElem = find_private_element(tab);
+ let show = content_tab_e(tab, "check-show-private-data");
+ EventUtils.synthesizeMouseAtCenter(show, { clickCount: 1 }, show.ownerGlobal);
+ wait_for_content_tab_element_display(tab, privateElem);
+
+ // To avoid destroying the current contents of the clipboard, instead of
+ // actually copying to it, we just retrieve what would have been copied to it
+ let transferable = tab.browser.contentWindow.getClipboardTransferable();
+ for (let flavor of ["text/html", "text/plain"]) {
+ let data = {};
+ transferable.getTransferData(flavor, data);
+ let text = data.value.QueryInterface(Ci.nsISupportsString).data;
+ let contentBody;
+ if (flavor == "text/html") {
+ let parser = new DOMParser();
+ contentBody = parser.parseFromString(text, "text/html").body;
+ } else {
+ contentBody = text;
+ }
+
+ for (let str of ABOUT_SUPPORT_STRINGS) {
+ if (!check_text_in_body(contentBody, str)) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ `Unable to find "${str}" in flavor "${flavor}"`
+ );
+ }
+ }
+
+ for (let str of ABOUT_SUPPORT_ERROR_STRINGS.get(flavor)) {
+ if (check_text_in_body(contentBody, str)) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ `Found "${str}" in flavor "${flavor}"`
+ );
+ }
+ }
+
+ // Check that private data is in the output.
+ if (!check_text_in_body(contentBody, privateElem.textContent)) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ `Unable to find private data in flavor "${flavor}"`
+ );
+ }
+
+ // Check that the warning text is in the output.
+ if (!check_text_in_body(contentBody, warningText.get(flavor))) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ `Unable to find warning text in flavor "${flavor}"`
+ );
+ }
+ }
+ close_tab(tab);
+});
+
+/**
+ * Test opening the compose window with public data.
+ */
+add_task(async function test_send_via_email_public() {
+ let tab = await open_about_support();
+ let privateElem = find_private_element(tab);
+
+ let cwc = open_send_via_email(tab);
+
+ let contentBody =
+ cwc.window.document.getElementById("messageEditor").contentDocument.body;
+
+ for (let str of ABOUT_SUPPORT_STRINGS) {
+ if (!check_text_in_body(contentBody, str)) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ `Unable to find "${str}" in compose window`
+ );
+ }
+ }
+
+ for (let str of ABOUT_SUPPORT_ERROR_STRINGS.get("text/html")) {
+ if (check_text_in_body(contentBody, str)) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ `Found "${str}" in compose window`
+ );
+ }
+ }
+
+ // Check that private data isn't in the output.
+ if (check_text_in_body(contentBody, privateElem.textContent)) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ `Found private data in compose window`
+ );
+ }
+
+ close_compose_window(cwc);
+ close_tab(tab);
+});
+
+/**
+ * Test opening the compose window with private data.
+ */
+add_task(async function test_send_via_email_private() {
+ let tab = await open_about_support();
+
+ // Display private data.
+ let privateElem = find_private_element(tab);
+ let show = content_tab_e(tab, "check-show-private-data");
+ EventUtils.synthesizeMouseAtCenter(show, { clickCount: 1 }, show.ownerGlobal);
+ wait_for_content_tab_element_display(tab, privateElem);
+
+ let cwc = open_send_via_email(tab);
+
+ let contentBody =
+ cwc.window.document.getElementById("messageEditor").contentDocument.body;
+
+ for (let str of ABOUT_SUPPORT_STRINGS) {
+ if (!check_text_in_body(contentBody, str)) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ `Unable to find "${str}" in compose window`
+ );
+ }
+ }
+
+ for (let str of ABOUT_SUPPORT_ERROR_STRINGS.get("text/html")) {
+ if (check_text_in_body(contentBody, str)) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ `Found "${str}" in compose window`
+ );
+ }
+ }
+
+ // Check that private data is in the output.
+ if (!check_text_in_body(contentBody, privateElem.textContent)) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ "Unable to find private data in compose window"
+ );
+ }
+
+ // Check that the warning text is in the output.
+ if (!check_text_in_body(contentBody, warningText.get("text/html"))) {
+ Assert.report(
+ true,
+ undefined,
+ undefined,
+ "Unable to find warning text in compose window"
+ );
+ }
+
+ close_compose_window(cwc);
+ close_tab(tab);
+});