Bug 1488176 - Accounts and messages WebExtensions API - tests; r=Fallen
authorGeoff Lankow <geoff@darktrojan.net>
Mon, 14 Jan 2019 14:22:59 +1300
changeset 34186 7acd73ce23af98db7f9d338741d252e8fcd964fc
parent 34185 18f7dcdd1bedc765d73cccc18fe72f43c80342b5
child 34187 02def84cbd9c578b7f345ae4301b34f1fe5f1374
push id389
push userclokep@gmail.com
push dateMon, 18 Mar 2019 19:01:53 +0000
reviewersFallen
bugs1488176
Bug 1488176 - Accounts and messages WebExtensions API - tests; r=Fallen
mail/components/extensions/test/browser/browser_ext_mailTabs.js
mail/components/extensions/test/xpcshell/.eslintrc.js
mail/components/extensions/test/xpcshell/head.js
mail/components/extensions/test/xpcshell/test_ext_accounts.js
mail/components/extensions/test/xpcshell/test_ext_messages.js
mail/components/extensions/test/xpcshell/xpcshell.ini
--- a/mail/components/extensions/test/browser/browser_ext_mailTabs.js
+++ b/mail/components/extensions/test/browser/browser_ext_mailTabs.js
@@ -4,18 +4,23 @@
 
 let account, rootFolder, subFolders;
 
 add_task(async function setup() {
   account = createAccount();
   rootFolder = account.incomingServer.rootFolder;
   subFolders = [...rootFolder.subFolders];
   createMessages(subFolders[0], 10);
+  createMessages(subFolders[1], 50);
 
   window.gFolderTreeView.selectFolder(rootFolder);
+  Services.prefs.setIntPref("extensions.webextensions.messagesPerPage", 10);
+  registerCleanupFunction(() => {
+    Services.prefs.clearUserPref("extensions.webextensions.messagesPerPage");
+  });
   await new Promise(executeSoon);
 });
 
 add_task(async function test_update() {
   async function background() {
     function awaitMessage(messageToSend, ...sendArgs) {
       return new Promise(resolve => {
         browser.test.onMessage.addListener(function listener(...args) {
@@ -113,17 +118,18 @@ add_task(async function test_update() {
     for (let value of ["wide", "vertical", "standard"]) {
       await browser.mailTabs.update({ layout: value });
       state.layout = value;
       await checkCurrent(state);
       await awaitMessage("checkRealLayout", state);
     }
 
     let selectedMessages = await browser.mailTabs.getSelectedMessages();
-    browser.test.assertEq(0, selectedMessages.length);
+    browser.test.assertEq(null, selectedMessages.id);
+    browser.test.assertEq(0, selectedMessages.messages.length);
 
     browser.test.notifyPass("mailTabs");
   }
 
   let extension = ExtensionTestUtils.loadExtension({
     background,
     manifest: { permissions: ["accountsRead", "messagesRead"] },
   });
@@ -156,17 +162,17 @@ add_task(async function test_update() {
   await extension.startup();
   extension.sendMessage(account.key);
   await extension.awaitFinish("mailTabs");
   await extension.unload();
 
   window.gFolderTreeView.selectFolder(rootFolder);
 });
 
-add_task(async function test_events() {
+add_task(async function test_displayedFolderChanged() {
   async function background() {
     function awaitMessage() {
       return new Promise(resolve => {
         browser.test.onMessage.addListener(function listener(...args) {
           browser.test.onMessage.removeListener(listener);
           resolve(args);
         });
       });
@@ -206,64 +212,115 @@ add_task(async function test_events() {
         browser.mailTabs.update({ displayedFolder: { accountId, path: newFolderPath } });
       });
     }
     await selectFolderByUpdate("/Trash");
     await selectFolderByUpdate("/Unsent Messages");
     await selectFolderByUpdate("/");
     await selectFolderByUpdate("/Trash");
 
-    async function selectMessage(...newMessages) {
-      return new Promise(resolve => {
-        browser.mailTabs.onSelectedMessagesChanged.addListener(function listener(tabId, messages) {
-          browser.mailTabs.onSelectedMessagesChanged.removeListener(listener);
-          browser.test.assertEq(newMessages.length, messages.length);
-          browser.mailTabs.getSelectedMessages().then(selectedMessages => {
-            browser.test.assertEq(newMessages.length, selectedMessages.length);
-            resolve();
-          });
-        });
-        browser.test.sendMessage("selectMessage", newMessages);
-      });
-    }
-    await selectMessage(3);
-    await selectMessage(7);
-    await selectMessage(4, 6);
-    await selectMessage();
-
     await new Promise(setTimeout);
     browser.test.notifyPass("mailTabs");
   }
 
   let folderMap = new Map([
     ["/", rootFolder],
     ["/Trash", subFolders[0]],
     ["/Unsent Messages", subFolders[1]],
   ]);
 
   let extension = ExtensionTestUtils.loadExtension({
     background,
     manifest: { permissions: ["accountsRead", "messagesRead"] },
   });
 
-  extension.onMessage("selectFolder", (newFolderPath) => {
+  extension.onMessage("selectFolder", async (newFolderPath) => {
     window.gFolderTreeView.selectFolder(folderMap.get(newFolderPath));
+    await new Promise(executeSoon);
   });
 
+  await extension.startup();
+  extension.sendMessage(account.key);
+  await extension.awaitFinish("mailTabs");
+  await extension.unload();
+
+  window.gFolderTreeView.selectFolder(rootFolder);
+});
+
+add_task(async function test_selectedMessagesChanged() {
+  async function background() {
+    function checkMessageList(expectedId, expectedCount, actual) {
+      if (expectedId) {
+        browser.test.assertEq(36, actual.id.length);
+      } else {
+        browser.test.assertEq(null, actual.id);
+      }
+      browser.test.assertEq(expectedCount, actual.messages.length);
+    }
+
+    // Because of bad design, we must wait for the WebExtensions mechanism to load ext-mailTabs.js,
+    // or when we call addListener below, it won't happen before the event is fired.
+    // This only applies if none of the earlier tests are run, but I'm saving you from wasting
+    // time figuring out what's going on like I did.
+    await browser.mailTabs.query({});
+
+    async function selectMessages(...newMessages) {
+      return new Promise(resolve => {
+        browser.mailTabs.onSelectedMessagesChanged.addListener(function listener(tabId, messageList) {
+          browser.mailTabs.onSelectedMessagesChanged.removeListener(listener);
+          resolve(messageList);
+        });
+        browser.test.sendMessage("selectMessage", newMessages);
+      });
+    }
+
+    let messageList;
+    messageList = await selectMessages(3);
+    checkMessageList(false, 1, messageList);
+    messageList = await selectMessages(7);
+    checkMessageList(false, 1, messageList);
+    messageList = await selectMessages(4, 6);
+    checkMessageList(false, 2, messageList);
+    messageList = await selectMessages();
+    checkMessageList(false, 0, messageList);
+    messageList = await selectMessages(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37);
+    checkMessageList(true, 10, messageList);
+    messageList = await browser.messages.continueList(messageList.id);
+    checkMessageList(false, 2, messageList);
+    messageList = await browser.mailTabs.getSelectedMessages();
+    checkMessageList(true, 10, messageList);
+    messageList = await browser.messages.continueList(messageList.id);
+    checkMessageList(false, 2, messageList);
+
+    await new Promise(setTimeout);
+    browser.test.notifyPass("mailTabs");
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    background,
+    manifest: { permissions: ["accountsRead", "messagesRead"] },
+  });
+
+  window.gFolderTreeView.selectFolder(subFolders[1]);
+  if (!window.IsMessagePaneCollapsed()) {
+    window.MsgToggleMessagePane();
+  }
+  let allMessages = [...window.gFolderDisplay.displayedFolder.messages];
+
   extension.onMessage("selectMessage", (newMessages) => {
-    let allMessages = [...window.gFolderDisplay.displayedFolder.messages];
     window.gFolderDisplay.selectMessages(newMessages.map(i => allMessages[i]));
   });
 
   await extension.startup();
   extension.sendMessage(account.key);
   await extension.awaitFinish("mailTabs");
   await extension.unload();
 
   window.gFolderTreeView.selectFolder(rootFolder);
+  window.MsgToggleMessagePane();
 });
 
 add_task(async function test_background_tab() {
   async function background() {
     function awaitMessage(messageToSend, ...sendArgs) {
       return new Promise(resolve => {
         browser.test.onMessage.addListener(function listener(...args) {
           browser.test.onMessage.removeListener(listener);
--- a/mail/components/extensions/test/xpcshell/.eslintrc.js
+++ b/mail/components/extensions/test/xpcshell/.eslintrc.js
@@ -6,10 +6,11 @@ module.exports = {
   "env": {
     // The tests in this folder are testing based on WebExtensions, so lets
     // just define the webextensions environment here.
     "webextensions": true,
   },
 
   "rules": {
     "func-names": "off",
+    "mozilla/import-headjs-globals": "error",
   },
 };
--- a/mail/components/extensions/test/xpcshell/head.js
+++ b/mail/components/extensions/test/xpcshell/head.js
@@ -8,8 +8,37 @@ ChromeUtils.defineModuleGetter(this, "Ma
 // Ensure the profile directory is set up
 do_get_profile();
 
 // Windows (Outlook Express) Address Book deactivation. (Bug 448859)
 Services.prefs.deleteBranch("ldap_2.servers.oe.");
 
 // OSX Address Book deactivation (Bug 955842)
 Services.prefs.deleteBranch("ldap_2.servers.osx.");
+
+function createAccount() {
+  registerCleanupFunction(() => {
+    [...MailServices.accounts.accounts.enumerate()].forEach(cleanUpAccount);
+  });
+
+  MailServices.accounts.createLocalMailAccount();
+  let account = MailServices.accounts.accounts.enumerate().getNext().QueryInterface(Ci.nsIMsgAccount);
+  account.incomingServer = MailServices.accounts.localFoldersServer;
+  info(`Created account ${account.toString()}`);
+
+  return account;
+}
+
+function cleanUpAccount(account) {
+  info(`Cleaning up account ${account.toString()}`);
+  MailServices.accounts.removeIncomingServer(account.incomingServer, true);
+  MailServices.accounts.removeAccount(account, true);
+}
+
+function createMessages(folder, count) {
+  const {
+    MessageGenerator,
+  } = ChromeUtils.import("resource://testing-common/mailnews/messageGenerator.js", null);
+  let messages = new MessageGenerator().makeMessages({ count });
+  let messageStrings = messages.map(message => message.toMboxString());
+  folder.QueryInterface(Ci.nsIMsgLocalMailFolder);
+  folder.addMessageBatch(messageStrings.length, messageStrings);
+}
new file mode 100644
--- /dev/null
+++ b/mail/components/extensions/test/xpcshell/test_ext_accounts.js
@@ -0,0 +1,138 @@
+/* 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";
+
+ChromeUtils.import("resource://testing-common/ExtensionXPCShellUtils.jsm");
+ExtensionTestUtils.init(this);
+
+add_task(async function test_accounts() {
+  let extension = ExtensionTestUtils.loadExtension({
+    async background() {
+      function awaitMessage(messageToSend) {
+        return new Promise(resolve => {
+          browser.test.onMessage.addListener(function listener(...args) {
+            browser.test.onMessage.removeListener(listener);
+            resolve(args);
+          });
+          if (messageToSend) {
+            browser.test.sendMessage(messageToSend);
+          }
+        });
+      }
+
+      function assertDeepEqual(expected, actual) {
+        if (Array.isArray(expected)) {
+          browser.test.assertTrue(Array.isArray(actual));
+          browser.test.assertEq(expected.length, actual.length);
+          for (let i = 0; i < expected.length; i++) {
+            assertDeepEqual(expected[i], actual[i]);
+          }
+          return;
+        }
+
+        let expectedKeys = Object.keys(expected);
+        let actualKeys = Object.keys(actual);
+        // Ignore any extra keys on the actual object.
+        browser.test.assertTrue(expectedKeys.length <= actualKeys.length);
+
+        for (let key of expectedKeys) {
+          browser.test.assertTrue(actualKeys.includes(key), `Key ${key} exists`);
+          if (expected[key] === null) {
+            browser.test.assertTrue(actual[key] === null);
+            continue;
+          }
+          if (["array", "object"].includes(typeof expected[key])) {
+            assertDeepEqual(expected[key], actual[key]);
+            continue;
+          }
+          browser.test.assertEq(expected[key], actual[key]);
+        }
+      }
+
+      let [account1Id] = await awaitMessage();
+      let result1 = await browser.accounts.list();
+      browser.test.assertEq(1, result1.length);
+      assertDeepEqual({
+        id: account1Id,
+        name: "Local Folders",
+        type: "none",
+        folders: [{
+          accountId: account1Id,
+          name: "Trash",
+          path: "/Trash",
+        }, {
+          accountId: account1Id,
+          name: "Outbox",
+          path: "/Unsent Messages",
+        }],
+      }, result1[0]);
+
+      let [account2Id] = await awaitMessage("create account 2");
+      let result2 = await browser.accounts.list();
+      browser.test.assertEq(2, result2.length);
+      assertDeepEqual(result1[0], result2[0]);
+      assertDeepEqual({
+        id: account2Id,
+        name: "Mail for username@hostname",
+        type: "imap",
+        folders: [{
+          accountId: account2Id,
+          name: "Inbox",
+          path: "/INBOX",
+        }],
+      }, result2[1]);
+
+      let result3 = await browser.accounts.get(account1Id);
+      assertDeepEqual(result1[0], result3);
+      let result4 = await browser.accounts.get(account2Id);
+      assertDeepEqual(result2[1], result4);
+
+      await awaitMessage("create folders");
+      let result5 = await browser.accounts.get(account1Id);
+      assertDeepEqual([{
+          accountId: account1Id,
+          name: "Trash",
+          path: "/Trash",
+        }, {
+          accountId: account1Id,
+          name: "foo bar",
+          path: "/Trash/foo bar",
+        }, {
+          accountId: account1Id,
+          name: "Ϟ",
+          path: "/Trash/Ϟ",
+        }, {
+          accountId: account1Id,
+          name: "Outbox",
+          path: "/Unsent Messages",
+        }], result5.folders);
+
+      browser.test.notifyPass("finished");
+    },
+    manifest: {
+      permissions: ["accountsRead"],
+    },
+  });
+
+  let account1 = createAccount();
+
+  await extension.startup();
+  extension.sendMessage(account1.key);
+
+  await extension.awaitMessage("create account 2");
+  let account2 = MailServices.accounts.createAccount();
+  account2.incomingServer =
+    MailServices.accounts.createIncomingServer("username", "hostname", "imap");
+  extension.sendMessage(account2.key);
+
+  await extension.awaitMessage("create folders");
+  let inbox1 = [...account1.incomingServer.rootFolder.subFolders][0];
+  inbox1.createSubfolder("foo bar", null); // Test our code can handle spaces.
+  inbox1.createSubfolder("Ϟ", null); // Test our code can handle unicode.
+  extension.sendMessage();
+
+  await extension.awaitFinish("finished");
+  await extension.unload();
+});
new file mode 100644
--- /dev/null
+++ b/mail/components/extensions/test/xpcshell/test_ext_messages.js
@@ -0,0 +1,179 @@
+/* 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";
+
+ChromeUtils.import("resource://testing-common/ExtensionXPCShellUtils.jsm");
+ExtensionTestUtils.init(this);
+
+let account, rootFolder, subFolders;
+async function run_test() {
+  account = createAccount();
+  rootFolder = account.incomingServer.rootFolder;
+  subFolders = [...rootFolder.subFolders];
+  createMessages(subFolders[0], 99);
+  createMessages(subFolders[1], 1);
+
+  run_next_test();
+}
+
+add_task(async function test_pagination() {
+  let extension = ExtensionTestUtils.loadExtension({
+    background: async () => {
+      function awaitMessage(messageToSend) {
+        return new Promise(resolve => {
+          browser.test.onMessage.addListener(function listener(...args) {
+            browser.test.onMessage.removeListener(listener);
+            resolve(args);
+          });
+          if (messageToSend) {
+            browser.test.sendMessage(messageToSend);
+          }
+        });
+      }
+
+      // Test a response of 99 messages at 10 messages per page.
+      let [folder] = await awaitMessage();
+      let page = await browser.messages.list(folder);
+      browser.test.assertEq(36, page.id.length);
+      browser.test.assertEq(10, page.messages.length);
+
+      let originalPageId = page.id;
+      let numPages = 1;
+      let numMessages = 10;
+      while (page.id) {
+        page = await browser.messages.continueList(page.id);
+        browser.test.assertTrue(page.messages.length > 0);
+        numPages++;
+        numMessages += page.messages.length;
+        if (numMessages < 99) {
+          browser.test.assertEq(originalPageId, page.id);
+        } else {
+          browser.test.assertEq(null, page.id);
+        }
+      }
+      browser.test.assertEq(10, numPages);
+      browser.test.assertEq(99, numMessages);
+
+      browser.test.assertRejects(browser.messages.continueList(originalPageId), null);
+
+      await awaitMessage("setPref");
+
+      // Do the same test, but with the default 100 messages per page.
+      page = await browser.messages.list(folder);
+      browser.test.assertEq(null, page.id);
+      browser.test.assertEq(99, page.messages.length);
+
+      browser.test.notifyPass("finished");
+    },
+    manifest: { permissions: ["accountsRead", "messagesRead"] },
+  });
+
+  Services.prefs.setIntPref("extensions.webextensions.messagesPerPage", 10);
+
+  await extension.startup();
+  extension.sendMessage({ accountId: account.key, path: "/Trash" });
+
+  await extension.awaitMessage("setPref");
+  Services.prefs.clearUserPref("extensions.webextensions.messagesPerPage");
+  extension.sendMessage();
+
+  await extension.awaitFinish("finished");
+  await extension.unload();
+});
+
+add_task(async function test_update() {
+  let extension = ExtensionTestUtils.loadExtension({
+    async background() {
+      function awaitMessage(messageToSend) {
+        return new Promise(resolve => {
+          browser.test.onMessage.addListener(function listener(...args) {
+            browser.test.onMessage.removeListener(listener);
+            resolve(args);
+          });
+          if (messageToSend) {
+            browser.test.sendMessage(messageToSend);
+          }
+        });
+      }
+
+      let tags = await browser.messages.listTags();
+      let [folder] = await awaitMessage();
+      let messageList = await browser.messages.list(folder);
+      browser.test.assertEq(1, messageList.messages.length);
+      let message = messageList.messages[0];
+      browser.test.assertFalse(message.flagged);
+      browser.test.assertFalse(message.read);
+      browser.test.assertEq(0, message.tags.length);
+
+      // Test that setting flagged works.
+      await browser.messages.update(message.id, { flagged: true });
+      await awaitMessage("flagged");
+
+      // Test that setting read works.
+      await browser.messages.update(message.id, { read: true });
+      await awaitMessage("read");
+
+      // Test that setting one tag works.
+      await browser.messages.update(message.id, { tags: [tags[0].key] });
+      await awaitMessage("tags1");
+
+      // Test that setting two tags works.
+      await browser.messages.update(message.id, { tags: [tags[1].key, tags[2].key] });
+      await awaitMessage("tags2");
+
+      // Test that unspecified properties aren't changed.
+      await browser.messages.update(message.id, {});
+      await awaitMessage("empty");
+
+      // Test that clearing properties works.
+      await browser.messages.update(message.id, { flagged: false, read: false, tags: [] });
+      await awaitMessage("clear");
+
+      browser.test.notifyPass("finished");
+    },
+    manifest: {
+      permissions: ["messagesRead"],
+    },
+  });
+
+  let message = [...subFolders[1].messages][0];
+  ok(!message.isFlagged);
+  ok(!message.isRead);
+  equal(message.getProperty("keywords"), "");
+
+  await extension.startup();
+  extension.sendMessage({ accountId: account.key, path: "/Unsent Messages" });
+
+  await extension.awaitMessage("flagged");
+  ok(message.isFlagged);
+  extension.sendMessage();
+
+  await extension.awaitMessage("read");
+  ok(message.isRead);
+  extension.sendMessage();
+
+  await extension.awaitMessage("tags1");
+  equal(message.getProperty("keywords"), "$label1");
+  extension.sendMessage();
+
+  await extension.awaitMessage("tags2");
+  equal(message.getProperty("keywords"), "$label2 $label3");
+  extension.sendMessage();
+
+  await extension.awaitMessage("empty");
+  ok(message.isFlagged);
+  ok(message.isRead);
+  equal(message.getProperty("keywords"), "$label2 $label3");
+  extension.sendMessage();
+
+  await extension.awaitMessage("clear");
+  ok(!message.isFlagged);
+  ok(!message.isRead);
+  equal(message.getProperty("keywords"), "");
+  extension.sendMessage();
+
+  await extension.awaitFinish("finished");
+  await extension.unload();
+});
--- a/mail/components/extensions/test/xpcshell/xpcshell.ini
+++ b/mail/components/extensions/test/xpcshell/xpcshell.ini
@@ -1,7 +1,9 @@
 [default]
 head = head.js
 tags = webextensions
 
+[test_ext_accounts.js]
 [test_ext_addressBook.js]
 [test_ext_cloudFile.js]
 support-files = data/cloudFile1.txt data/cloudFile2.txt
+[test_ext_messages.js]