Backed out changeset 4dbfa038c936 (bug 1469238) for causing test failures
authorGeoff Lankow <geoff@darktrojan.net>
Thu, 27 Sep 2018 14:19:32 +1200
changeset 33242 aa44e834870fc2310c0e3b19811e4f3c70bff036
parent 33241 4dbfa038c9362bbda2010c883f15688f50a9626e
child 33243 102bf0b97b0ab0cab19a71ca61d11fe35639d354
push id387
push userclokep@gmail.com
push dateMon, 10 Dec 2018 21:30:47 +0000
bugs1469238
backs out4dbfa038c9362bbda2010c883f15688f50a9626e
Backed out changeset 4dbfa038c936 (bug 1469238) for causing test failures
mail/components/extensions/.eslintrc.js
mail/components/extensions/ext-mail.json
mail/components/extensions/jar.mn
mail/components/extensions/moz.build
mail/components/extensions/parent/.eslintrc.js
mail/components/extensions/parent/ext-addressBook.js
mail/components/extensions/schemas/addressBook.json
mail/components/extensions/test/xpcshell/.eslintrc.js
mail/components/extensions/test/xpcshell/test_ext_addressBook.js
mail/components/extensions/test/xpcshell/xpcshell.ini
--- a/mail/components/extensions/.eslintrc.js
+++ b/mail/components/extensions/.eslintrc.js
@@ -1,12 +1,11 @@
 "use strict";
-/* eslint-env node */
 
-module.exports = {
+module.exports = { // eslint-disable-line no-undef
   "globals": {
     // These are defined in the WebExtension script scopes by ExtensionCommon.jsm.
     // From toolkit/components/extensions/.eslintrc.js.
     "Cc": true,
     "Ci": true,
     "Cr": true,
     "Cu": true,
     "AppConstants": true,
--- a/mail/components/extensions/ext-mail.json
+++ b/mail/components/extensions/ext-mail.json
@@ -1,17 +1,9 @@
 {
-  "addressBook": {
-    "url": "chrome://messenger/content/parent/ext-addressBook.js",
-    "schema": "chrome://messenger/content/schemas/addressBook.json",
-    "scopes": ["addon_parent"],
-    "paths": [
-      ["addressBooks"], ["contacts"], ["mailingLists"]
-    ]
-  },
   "legacy": {
     "url": "chrome://messenger/content/parent/ext-legacy.js",
     "schema": "chrome://messenger/content/schemas/legacy.json",
     "scopes": ["addon_parent"],
     "manifest": ["legacy"]
   },
   "tabs": {
     "url": "chrome://messenger/content/parent/ext-tabs.js",
--- a/mail/components/extensions/jar.mn
+++ b/mail/components/extensions/jar.mn
@@ -1,20 +1,18 @@
 # 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/.
 
 messenger.jar:
     content/messenger/ext-mail.json                (ext-mail.json)
 
-    content/messenger/parent/ext-addressBook.js    (parent/ext-addressBook.js)
     content/messenger/parent/ext-legacy.js         (parent/ext-legacy.js)
     content/messenger/parent/ext-mail.js           (parent/ext-mail.js)
     content/messenger/parent/ext-tabs.js           (parent/ext-tabs.js)
     content/messenger/parent/ext-windows.js        (parent/ext-windows.js)
 
     content/messenger/child/ext-tabs.js            (child/ext-tabs.js)
     content/messenger/child/ext-mail.js            (child/ext-mail.js)
 
-    content/messenger/schemas/addressBook.json     (schemas/addressBook.json)
-    content/messenger/schemas/legacy.json          (schemas/legacy.json)
-    content/messenger/schemas/tabs.json            (schemas/tabs.json)
-    content/messenger/schemas/windows.json         (schemas/windows.json)
+    content/messenger/schemas/legacy.json   (schemas/legacy.json)
+    content/messenger/schemas/tabs.json     (schemas/tabs.json)
+    content/messenger/schemas/windows.json  (schemas/windows.json)
--- a/mail/components/extensions/moz.build
+++ b/mail/components/extensions/moz.build
@@ -2,12 +2,8 @@
 # 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/.
 
 EXTRA_COMPONENTS += [
     'extensions-mail.manifest',
 ]
 
 JAR_MANIFESTS += ['jar.mn']
-
-XPCSHELL_TESTS_MANIFESTS += [
-    'test/xpcshell/xpcshell.ini',
-]
--- a/mail/components/extensions/parent/.eslintrc.js
+++ b/mail/components/extensions/parent/.eslintrc.js
@@ -1,12 +1,11 @@
 "use strict";
-/* eslint-env node */
 
-module.exports = {
+module.exports = { // eslint-disable-line no-undef
   "globals": {
     // From toolkit/components/extensions/parent/.eslintrc.js.
     "CONTAINER_STORE": true,
     "DEFAULT_STORE": true,
     "EventEmitter": true,
     "EventManager": true,
     "InputEventManager": true,
     "PRIVATE_STORE": true,
@@ -20,19 +19,18 @@ module.exports = {
     "getCookieStoreIdForContainer": true,
     "getCookieStoreIdForTab": true,
     "isContainerCookieStoreId": true,
     "isDefaultCookieStoreId": true,
     "isPrivateCookieStoreId": true,
     "isValidCookieStoreId": true,
 
     // These are defined in ext-mail.js.
-    "ExtensionError": true,
+    "tabGetSender": true,
+    "makeWidgetId": true,
+    "getTabBrowser": true,
+    "WindowEventManager": true,
+    "tabTracker": true,
+    "windowTracker": true,
     "Tab": true,
     "Window": true,
-    "WindowEventManager": true,
-    "getTabBrowser": true,
-    "makeWidgetId": true,
-    "tabGetSender": true,
-    "tabTracker": true,
-    "windowTracker": true,
   },
 };
deleted file mode 100644
--- a/mail/components/extensions/parent/ext-addressBook.js
+++ /dev/null
@@ -1,551 +0,0 @@
-/* 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/. */
-
-const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
-
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-ChromeUtils.import("resource:///modules/MailServices.jsm");
-
-const AB_WINDOW_TYPE = "mail:addressbook";
-const AB_WINDOW_URI = "chrome://messenger/content/addressbook/addressbook.xul";
-
-const kPABDirectory = 2; // defined in nsDirPrefs.h
-
-// nsIAbCard.idl contains a list of properties that Thunderbird uses. Extensions are not
-// restricted to using only these properties, but the following properties cannot
-// be modified by an extension.
-const hiddenProperties = [
-  "DbRowID", "LowercasePrimaryEmail", "LastModifiedDate",
-  "PopularityIndex", "RecordKey", "UID",
-];
-
-/**
- * Cache of items in the address book "tree". This cache is
- * completely blown away by most changes, so operations should
- * be as lightweight as possible.
- *
- * @implements {nsIAbListener}
- * @implements {nsIObserver}
- */
- var cache = new class extends EventEmitter {
-  _makeContactNode(contact, parent) {
-    contact.QueryInterface(Ci.nsIAbCard);
-    return {
-      id: contact.UID,
-      parentId: parent.UID,
-      type: "contact",
-      item: contact,
-    };
-  }
-  _makeDirectoryNode(directory, parent = null) {
-    directory.QueryInterface(Ci.nsIAbDirectory);
-    let node = {
-      id: directory.UID,
-      type: directory.isMailList ? "mailingList" : "addressBook",
-      item: directory,
-      get contacts() {
-        delete this.contacts;
-        if (directory.isMailList) {
-          this.contacts = [...directory.addressLists.enumerate()];
-        } else {
-          this.contacts = [...directory.childCards]
-            .filter(c => !c.isMailList);
-        }
-        this.contacts = this.contacts.map(c => cache._makeContactNode(c, directory));
-        return this.contacts;
-      },
-      get mailingLists() {
-        delete this.mailingLists;
-        if (directory.isMailList) {
-          return undefined;
-        }
-        this.mailingLists = [];
-        for (let al of directory.addressLists.enumerate()) {
-          this.mailingLists.push(cache._makeDirectoryNode(al, directory));
-        }
-        return this.mailingLists;
-      },
-    };
-    if (parent) {
-      node.parentId = parent.UID;
-    }
-    return node;
-  }
-  _rebuild() {
-    this._tree = [];
-    for (let tld of MailServices.ab.directories) {
-      if (!tld.readOnly) {
-        this._tree.push(this._makeDirectoryNode(tld));
-      }
-    }
-  }
-  get tree() {
-    if (!this._tree) {
-      this._rebuild();
-    }
-    return this._tree;
-  }
-  flush() {
-    this._tree = null;
-  }
-  _findObjectById(type, id) {
-    function checkNode(parentNode) {
-      if (type == parentNode.type && id == parentNode.id) {
-        return parentNode;
-      }
-      if (type == "contact") {
-        return parentNode.contacts.find(c => id == c.id);
-      }
-      return null;
-    }
-
-    for (let node of this.tree) {
-      let returnNode = checkNode(node);
-      if (returnNode) {
-        return returnNode;
-      }
-
-      if (type == "addressBook" || !node.mailingLists) {
-        continue;
-      }
-
-      for (let listNode of node.mailingLists) {
-        returnNode = checkNode(listNode);
-        if (returnNode) {
-          return returnNode;
-        }
-      }
-    }
-
-    throw new ExtensionError(`${type} with id=${id} could not be found.`);
-  }
-  findAddressBookById(id) {
-    return this._findObjectById("addressBook", id);
-  }
-  findContactById(id) {
-    return this._findObjectById("contact", id);
-  }
-  findMailingListById(id) {
-    return this._findObjectById("mailingList", id);
-  }
-  convert(node, complete) {
-    if (node === null) {
-      return node;
-    }
-    if (Array.isArray(node)) {
-      return node.map(i => this.convert(i, complete));
-    }
-
-    let copy = {};
-    for (let key of ["id", "parentId", "type"]) {
-      if (key in node) {
-        copy[key] = node[key];
-      }
-    }
-
-    if (complete) {
-      for (let key of ["contacts", "mailingLists"]) {
-        if (key in node && node[key]) {
-          copy[key] = this.convert(node[key], complete);
-        }
-      }
-    }
-
-    switch (node.type) {
-      case "addressBook":
-        copy.name = node.item.dirName;
-        copy.readOnly = node.item.readOnly;
-        break;
-      case "contact": {
-        copy.properties = {};
-        for (let property of node.item.properties) {
-          if (!hiddenProperties.includes(property.name)) {
-            // WebExtensions complains if we use numbers.
-            copy.properties[property.name] = "" + property.value;
-          }
-        }
-        break;
-      }
-      case "mailingList":
-        copy.name = node.item.dirName;
-        copy.nickName = node.item.listNickName;
-        copy.description = node.item.description;
-        break;
-    }
-
-    return copy;
-  }
-
-  // nsIAbListener
-  onItemAdded(parent, item) {
-    parent.QueryInterface(Ci.nsIAbDirectory);
-
-    if (item instanceof Ci.nsIAbDirectory) {
-      item.QueryInterface(Ci.nsIAbDirectory);
-      if (item.isMailList) {
-        this.emit("mailing-list-created", this._makeDirectoryNode(item, parent));
-      } else {
-        this.emit("address-book-created", this._makeDirectoryNode(item));
-      }
-    } else if (item instanceof Ci.nsIAbCard) {
-      item.QueryInterface(Ci.nsIAbCard);
-      if (!item.isMailList && parent.isMailList) {
-        this.emit("mailing-list-member-added", this._makeContactNode(item, parent));
-      }
-    }
-
-    this._tree = null;
-  }
-  // nsIAbListener
-  onItemRemoved(parent, item) {
-    parent = parent.QueryInterface(Ci.nsIAbDirectory);
-
-    if (item instanceof Ci.nsIAbDirectory) {
-      item.QueryInterface(Ci.nsIAbDirectory);
-      if (item.isMailList) {
-        this.emit("mailing-list-deleted", parent, item);
-      } else {
-        this.emit("address-book-deleted", item);
-      }
-    } else if (item instanceof Ci.nsIAbCard) {
-      item.QueryInterface(Ci.nsIAbCard);
-      if (!item.isMailList) {
-        this.emit(parent.isMailList ? "mailing-list-member-removed" : "contact-deleted", parent, item);
-      }
-    }
-
-    this._tree = null;
-  }
-  // nsIAbListener
-  onItemPropertyChanged(item, property, oldValue, newValue) {
-    if (item instanceof Ci.nsIAbDirectory) {
-      item.QueryInterface(Ci.nsIAbDirectory);
-      if (!item.isMailList) {
-        this.emit("address-book-updated", this._makeDirectoryNode(item));
-        this._tree = null;
-      }
-    }
-  }
-
-  // nsIObserver
-  observe(subject, topic, data) {
-    this._tree = null;
-
-    switch (topic) {
-      case "addrbook-contact-created": {
-        let parentNode = this.findAddressBookById(data);
-        this.emit("contact-created", this._makeContactNode(subject, parentNode.item));
-        break;
-      }
-      case "addrbook-contact-updated": {
-        let parentNode = this.findAddressBookById(data);
-        this.emit("contact-updated", this._makeContactNode(subject, parentNode.item));
-        break;
-      }
-      case "addrbook-list-updated": {
-        subject.QueryInterface(Ci.nsIAbDirectory);
-        this.emit("mailing-list-updated", this.findMailingListById(subject.UID));
-        break;
-      }
-      case "addrbook-list-member-added": {
-        let parentNode = this.findMailingListById(data);
-        this.emit("mailing-list-member-added", this._makeContactNode(subject, parentNode.item));
-        break;
-      }
-    }
-  }
-};
-MailServices.ab.addAddressBookListener(cache, Ci.nsIAbListener.all);
-Services.obs.addObserver(cache, "addrbook-contact-created");
-Services.obs.addObserver(cache, "addrbook-contact-updated");
-Services.obs.addObserver(cache, "addrbook-list-updated");
-Services.obs.addObserver(cache, "addrbook-list-member-added");
-
-this.addressBook = class extends ExtensionAPI {
-  getAPI(context) {
-    return {
-      addressBooks: {
-        openUI() {
-          let topWindow = Services.wm.getMostRecentWindow(AB_WINDOW_TYPE);
-          if (!topWindow) {
-            // TODO: wait until window is loaded before resolving
-            topWindow = Services.ww.openWindow(null, AB_WINDOW_URI, "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar", null);
-          }
-          topWindow.focus();
-        },
-        closeUI() {
-          for (let win of Services.wm.getEnumerator(AB_WINDOW_TYPE)) {
-            win.close();
-          }
-        },
-
-        list(complete = false) {
-          return cache.convert(cache.tree, complete);
-        },
-        get(id, complete = false) {
-          return cache.convert(cache.findAddressBookById(id), complete);
-        },
-        create({ name }) {
-          let dirName = MailServices.ab.newAddressBook(name, "", kPABDirectory);
-          let directory = MailServices.ab.getDirectoryFromId(dirName);
-          return directory.UID;
-        },
-        update(id, { name }) {
-          let node = cache.findAddressBookById(id);
-          node.item.dirName = name;
-        },
-        delete(id) {
-          let node = cache.findAddressBookById(id);
-          MailServices.ab.deleteAddressBook(node.item.URI);
-        },
-
-        onCreated: new EventManager({
-          context,
-          name: "addressBooks.onCreated",
-          register: fire => {
-            let listener = (event, node) => {
-              fire.sync(cache.convert(node));
-            };
-
-            cache.on("address-book-created", listener);
-            return () => {
-              cache.off("address-book-created", listener);
-            };
-          },
-        }).api(),
-        onUpdated: new EventManager({
-          context,
-          name: "addressBooks.onUpdated",
-          register: fire => {
-            let listener = (event, node) => {
-              fire.sync(cache.convert(node));
-            };
-
-            cache.on("address-book-updated", listener);
-            return () => {
-              cache.off("address-book-updated", listener);
-            };
-          },
-        }).api(),
-        onDeleted: new EventManager({
-          context,
-          name: "addressBooks.onDeleted",
-          register: fire => {
-            let listener = (event, item) => {
-              fire.sync(item.UID);
-            };
-
-            cache.on("address-book-deleted", listener);
-            return () => {
-              cache.off("address-book-deleted", listener);
-            };
-          },
-        }).api(),
-      },
-      contacts: {
-        list(parentId) {
-          let parentNode = cache.findAddressBookById(parentId);
-          return cache.convert(parentNode.contacts, false);
-        },
-        get(id) {
-          return cache.convert(cache.findContactById(id), false);
-        },
-        create(parentId, properties) {
-          let card = Cc["@mozilla.org/addressbook/cardproperty;1"].createInstance(Ci.nsIAbCard);
-          for (let [name, value] of Object.entries(properties)) {
-            if (!hiddenProperties.includes(name)) {
-              card.setProperty(name, value);
-            }
-          }
-          let parentNode = cache.findAddressBookById(parentId);
-          let newCard = parentNode.item.addCard(card);
-          return newCard.UID;
-        },
-        update(id, properties) {
-          let node = cache.findContactById(id);
-          let parentNode = cache.findAddressBookById(node.parentId);
-
-          for (let [name, value] of Object.entries(properties)) {
-            if (!hiddenProperties.includes(name)) {
-              node.item.setProperty(name, value);
-            }
-          }
-          parentNode.item.modifyCard(node.item);
-        },
-        delete(id) {
-          let node = cache.findContactById(id);
-          let parentNode = cache.findAddressBookById(node.parentId);
-
-          let cardArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
-          cardArray.appendElement(node.item);
-          parentNode.item.deleteCards(cardArray);
-        },
-
-        onCreated: new EventManager({
-          context,
-          name: "contacts.onCreated",
-          register: fire => {
-            let listener = (event, node) => {
-              fire.sync(cache.convert(node));
-            };
-
-            cache.on("contact-created", listener);
-            return () => {
-              cache.off("contact-created", listener);
-            };
-          },
-        }).api(),
-        onUpdated: new EventManager({
-          context,
-          name: "contacts.onUpdated",
-          register: fire => {
-            let listener = (event, node) => {
-              fire.sync(cache.convert(node));
-            };
-
-            cache.on("contact-updated", listener);
-            return () => {
-              cache.off("contact-updated", listener);
-            };
-          },
-        }).api(),
-        onDeleted: new EventManager({
-          context,
-          name: "contacts.onDeleted",
-          register: fire => {
-            let listener = (event, parent, item) => {
-              fire.sync(parent.UID, item.UID);
-            };
-
-            cache.on("contact-deleted", listener);
-            return () => {
-              cache.off("contact-deleted", listener);
-            };
-          },
-        }).api(),
-      },
-      mailingLists: {
-        list(parentId) {
-          let parentNode = cache.findAddressBookById(parentId);
-          return cache.convert(parentNode.mailingLists, false);
-        },
-        get(id) {
-          return cache.convert(cache.findMailingListById(id), false);
-        },
-        create(parentId, { name, nickName, description }) {
-          let mailList = Cc["@mozilla.org/addressbook/directoryproperty;1"].createInstance();
-          mailList.QueryInterface(Ci.nsIAbDirectory);
-          mailList.isMailList = true;
-          mailList.dirName = name;
-          mailList.listNickName = (nickName === null) ? "" : nickName;
-          mailList.description = (description === null) ? "" : description;
-
-          let parentNode = cache.findAddressBookById(parentId);
-          let newMailList = parentNode.item.addMailList(mailList);
-          return newMailList.UID;
-        },
-        update(id, { name, nickName, description }) {
-          let node = cache.findMailingListById(id);
-          node.item.dirName = name;
-          node.item.listNickName = (nickName === null) ? "" : nickName;
-          node.item.description = (description === null) ? "" : description;
-          node.item.editMailListToDatabase(null);
-        },
-        delete(id) {
-          let node = cache.findMailingListById(id);
-          MailServices.ab.deleteAddressBook(node.item.URI);
-        },
-
-        listMembers(id) {
-          let node = cache.findMailingListById(id);
-          return cache.convert(node.contacts, false);
-        },
-        addMember(id, contactId) {
-          let node = cache.findMailingListById(id);
-          let contactNode = cache.findContactById(contactId);
-          node.item.addCard(contactNode.item);
-        },
-        removeMember(id, contactId) {
-          let node = cache.findMailingListById(id);
-          let contactNode = cache.findContactById(contactId);
-
-          let cardArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
-          cardArray.appendElement(contactNode.item);
-          node.item.deleteCards(cardArray);
-        },
-
-        onCreated: new EventManager({
-          context,
-          name: "mailingLists.onCreated",
-          register: fire => {
-            let listener = (event, node) => {
-              fire.sync(cache.convert(node));
-            };
-
-            cache.on("mailing-list-created", listener);
-            return () => {
-              cache.off("mailing-list-created", listener);
-            };
-          },
-        }).api(),
-        onUpdated: new EventManager({
-          context,
-          name: "mailingLists.onUpdated",
-          register: fire => {
-            let listener = (event, node) => {
-              fire.sync(cache.convert(node));
-            };
-
-            cache.on("mailing-list-updated", listener);
-            return () => {
-              cache.off("mailing-list-updated", listener);
-            };
-          },
-        }).api(),
-        onDeleted: new EventManager({
-          context,
-          name: "mailingLists.onDeleted",
-          register: fire => {
-            let listener = (event, parent, item) => {
-              fire.sync(parent.UID, item.UID);
-            };
-
-            cache.on("mailing-list-deleted", listener);
-            return () => {
-              cache.off("mailing-list-deleted", listener);
-            };
-          },
-        }).api(),
-        onMemberAdded: new EventManager({
-          context,
-          name: "mailingLists.onMemberAdded",
-          register: fire => {
-            let listener = (event, node) => {
-              fire.sync(cache.convert(node));
-            };
-
-            cache.on("mailing-list-member-added", listener);
-            return () => {
-              cache.off("mailing-list-member-added", listener);
-            };
-          },
-        }).api(),
-        onMemberRemoved: new EventManager({
-          context,
-          name: "mailingLists.onMemberRemoved",
-          register: fire => {
-            let listener = (event, parent, item) => {
-              fire.sync(parent.UID, item.UID);
-            };
-
-            cache.on("mailing-list-member-removed", listener);
-            return () => {
-              cache.off("mailing-list-member-removed", listener);
-            };
-          },
-        }).api(),
-      },
-    };
-  }
-};
deleted file mode 100644
--- a/mail/components/extensions/schemas/addressBook.json
+++ /dev/null
@@ -1,600 +0,0 @@
-[
-  {
-    "namespace": "manifest",
-    "types": [
-      {
-        "$extend": "OptionalPermission",
-        "choices": [
-          {
-            "type": "string",
-            "enum": [
-              "addressBooks"
-            ]
-          }
-        ]
-      }
-    ]
-  },
-  {
-    "namespace": "addressBooks",
-    "permissions": [
-      "addressBooks"
-    ],
-    "types": [
-      {
-        "id": "NodeType",
-        "type": "string",
-        "enum": [
-          "addressBook",
-          "contact",
-          "mailingList"
-        ],
-        "description": "Indicates the type of a Node, which can be one of addressBook, contact, or mailingList."
-      },
-      {
-        "id": "Node",
-        "type": "object",
-        "description": "A node (either an address book, contact, or mailing list) in the address book hierarchy.",
-        "properties": {
-          "id": {
-            "type": "string",
-            "description": "The unique identifier for the node. IDs are unique within the current profile, and they remain valid even after the program is restarted."
-          },
-          "parentId": {
-            "type": "string",
-            "optional": true,
-            "description": "The <code>id</code> of the parent object."
-          },
-          "type": {
-            "$ref": "NodeType",
-            "description": "Indicates the type of a Node, which can be one of addressBook, contact, or mailingList."
-          },
-          "readOnly": {
-            "type": "boolean",
-            "optional": true,
-            "description": "Indicates if the object is read-only. Currently this returns false in all cases, as read-only address books are ignored by the API."
-          }
-        }
-      },
-      {
-        "id": "AddressBookNode",
-        "$extend": "Node",
-        "description": "A node representing an address book.",
-        "properties": {
-          "name": {
-            "type": "string"
-          },
-          "contacts": {
-            "type": "array",
-            "optional": true,
-            "items": {
-              "$ref": "Node"
-            },
-            "description": "A list of contacts held by this node's address book or mailing list."
-          },
-          "mailingLists": {
-            "type": "array",
-            "optional": true,
-            "items": {
-              "$ref": "Node"
-            },
-            "description": "A list of mailingLists in this node's address book."
-          }
-        }
-      }
-    ],
-    "functions": [
-      {
-        "name": "openUI",
-        "type": "function",
-        "description": "Opens the address book user interface.",
-        "parameters": []
-      },
-      {
-        "name": "closeUI",
-        "type": "function",
-        "description": "Closes the address book user interface.",
-        "parameters": []
-      },
-      {
-        "name": "list",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "complete",
-            "type": "boolean",
-            "optional": true,
-            "default": false,
-            "description": "If set to true, results will include contacts and mailing lists for each address book."
-          }
-        ],
-        "description": "Gets a list of the user's address books, optionally including all contacts and mailing lists."
-      },
-      {
-        "name": "get",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          },
-          {
-            "name": "complete",
-            "type": "boolean",
-            "optional": true,
-            "default": false,
-            "description": "If set to true, results will include contacts and mailing lists for this address book."
-          }
-        ],
-        "description": "Gets a single address book, optionally including all contacts and mailing lists."
-      },
-      {
-        "name": "create",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "properties",
-            "type": "object",
-            "properties": {
-              "name": {
-                "type": "string"
-              }
-            }
-          }
-        ],
-        "description": "Creates a new, empty address book."
-      },
-      {
-        "name": "update",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          },
-          {
-            "name": "properties",
-            "type": "object",
-            "properties": {
-              "name": {
-                "type": "string"
-              }
-            }
-          }
-        ],
-        "description": "Renames an address book."
-      },
-      {
-        "name": "delete",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          }
-        ],
-        "description": "Removes an address book, and all associated contacts and mailing lists."
-      }
-    ],
-    "events": [
-      {
-        "name": "onCreated",
-        "type": "function",
-        "description": "Fired when an address book is created.",
-        "parameters": [
-          {
-            "name": "node",
-            "$ref": "AddressBookNode"
-          }
-        ]
-      },
-      {
-        "name": "onUpdated",
-        "type": "function",
-        "description": "Fired when an address book is renamed.",
-        "parameters": [
-          {
-            "name": "node",
-            "$ref": "AddressBookNode"
-          }
-        ]
-      },
-      {
-        "name": "onDeleted",
-        "type": "function",
-        "description": "Fired when an addressBook is deleted.",
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          }
-        ]
-      }
-    ]
-  },
-  {
-    "namespace": "contacts",
-    "permissions": [
-      "addressBooks"
-    ],
-    "types": [
-      {
-        "id": "ContactNode",
-        "$extend": "Node",
-        "description": "A node representing a contact in an address book.",
-        "type": "object",
-        "properties": {
-          "properties": {
-            "$ref": "ContactProperties"
-          }
-        }
-      },
-      {
-        "id": "ContactProperties",
-        "type": "object",
-        "description": "A set of properties for a particular contact. For a complete list of properties that Thunderbird uses, see https://hg.mozilla.org/comm-central/file/tip/mailnews/addrbook/public/nsIAbCard.idl",
-        "patternProperties": {
-          "^\\w+$": {
-            "type": "string",
-            "optional": true
-          }
-        }
-      }
-    ],
-    "functions": [
-      {
-        "name": "list",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "parentId",
-            "type": "string"
-          }
-        ],
-        "description": "Gets all the contacts in the address book with the id <code>parentId</code>."
-      },
-      {
-        "name": "get",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          }
-        ],
-        "description": "Gets a single contact."
-      },
-      {
-        "name": "create",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "parentId",
-            "type": "string"
-          },
-          {
-            "name": "properties",
-            "$ref": "ContactProperties"
-          }
-        ],
-        "description": "Adds a new contact to the address book with the id <code>parentId</code>."
-      },
-      {
-        "name": "update",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          },
-          {
-            "name": "properties",
-            "$ref": "ContactProperties"
-          }
-        ],
-        "description": "Edits the properties of a contact. To remove a property, specify it as <code>null</code>."
-      },
-      {
-        "name": "delete",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          }
-        ],
-        "description": "Removes a contact from the address book. The contact is also removed from any mailing lists it is a member of."
-      }
-    ],
-    "events": [
-      {
-        "name": "onCreated",
-        "type": "function",
-        "description": "Fired when a contact is created.",
-        "parameters": [
-          {
-            "name": "node",
-            "$ref": "ContactNode"
-          },
-          {
-            "name": "id",
-            "type": "string"
-          }
-        ]
-      },
-      {
-        "name": "onUpdated",
-        "type": "function",
-        "description": "Fired when a contact is changed.",
-        "parameters": [
-          {
-            "name": "node",
-            "$ref": "ContactNode"
-          }
-        ]
-      },
-      {
-        "name": "onDeleted",
-        "type": "function",
-        "description": "Fired when a contact is removed from an address book.",
-        "parameters": [
-          {
-            "name": "parentId",
-            "type": "string"
-          },
-          {
-            "name": "id",
-            "type": "string"
-          }
-        ]
-      }
-    ]
-  },
-  {
-    "namespace": "mailingLists",
-    "permissions": [
-      "addressBooks"
-    ],
-    "types": [
-      {
-        "id": "MailingListNode",
-        "$extend": "Node",
-        "description": "A node representing a mailing list.",
-        "properties": {
-          "name": {
-            "type": "string"
-          },
-          "nickName": {
-            "type": "string"
-          },
-          "description": {
-            "type": "string"
-          },
-          "contacts": {
-            "type": "array",
-            "optional": true,
-            "items": {
-              "$ref": "Node"
-            },
-            "description": "A list of contacts held by this node's address book or mailing list."
-          }
-        }
-      }
-    ],
-    "functions": [
-      {
-        "name": "list",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "parentId",
-            "type": "string"
-          }
-        ],
-        "description": "Gets all the mailing lists in the address book with id <code>parentId</code>."
-      },
-      {
-        "name": "get",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          }
-        ],
-        "description": "Gets a single mailing list."
-      },
-      {
-        "name": "create",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "parentId",
-            "type": "string"
-          },
-          {
-            "name": "properties",
-            "type": "object",
-            "properties": {
-              "name": {
-                "type": "string"
-              },
-              "nickName": {
-                "type": "string",
-                "optional": true
-              },
-              "description": {
-                "type": "string",
-                "optional": true
-              }
-            }
-          }
-        ],
-        "description": "Creates a new mailing list in the address book with id <code>parentId</code>."
-      },
-      {
-        "name": "update",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          },
-          {
-            "name": "properties",
-            "type": "object",
-            "properties": {
-              "name": {
-                "type": "string"
-              },
-              "nickName": {
-                "type": "string",
-                "optional": true
-              },
-              "description": {
-                "type": "string",
-                "optional": true
-              }
-            }
-          }
-        ],
-        "description": "Edits the properties of a mailing list."
-      },
-      {
-        "name": "delete",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          }
-        ],
-        "description": "Removes the mailing list."
-      },
-      {
-        "name": "addMember",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          },
-          {
-            "name": "contactId",
-            "type": "string"
-          }
-        ],
-        "description": "Adds a contact to the mailing list with id <code>id</code>. If the contact and mailing list are in different address books, the contact will also be copied to the list's address book."
-      },
-      {
-        "name": "listMembers",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          }
-        ],
-        "description": "Gets all contacts that are members of the mailing list with id <code>id</code>."
-      },
-      {
-        "name": "removeMember",
-        "type": "function",
-        "async": true,
-        "parameters": [
-          {
-            "name": "id",
-            "type": "string"
-          },
-          {
-            "name": "contactId",
-            "type": "string"
-          }
-        ],
-        "description": "Removes a contact from the mailing list with id <code>id</code>. This does not delete the contact from the address book."
-      }
-    ],
-    "events": [
-      {
-        "name": "onCreated",
-        "type": "function",
-        "description": "Fired when a mailing list is created.",
-        "parameters": [
-          {
-            "name": "node",
-            "$ref": "MailingListNode"
-          }
-        ]
-      },
-      {
-        "name": "onUpdated",
-        "type": "function",
-        "description": "Fired when a mailing list is changed.",
-        "parameters": [
-          {
-            "name": "node",
-            "$ref": "MailingListNode"
-          }
-        ]
-      },
-      {
-        "name": "onDeleted",
-        "type": "function",
-        "description": "Fired when a mailing list is deleted.",
-        "parameters": [
-          {
-            "name": "parentId",
-            "type": "string"
-          },
-          {
-            "name": "id",
-            "type": "string"
-          }
-        ]
-      },
-      {
-        "name": "onMemberAdded",
-        "type": "function",
-        "description": "Fired when a contact is added to the mailing list.",
-        "parameters": [
-          {
-            "name": "node",
-            "$ref": "ContactNode"
-          }
-        ]
-      },
-      {
-        "name": "onMemberRemoved",
-        "type": "function",
-        "description": "Fired when a contact is removed from the mailing list.",
-        "parameters": [
-          {
-            "name": "parentId",
-            "type": "string"
-          },
-          {
-            "name": "id",
-            "type": "string"
-          }
-        ]
-      }
-    ]
-  }
-]
deleted file mode 100644
--- a/mail/components/extensions/test/xpcshell/.eslintrc.js
+++ /dev/null
@@ -1,12 +0,0 @@
-"use strict";
-/* eslint-env node */
-
-module.exports = {
-  "extends": "plugin:mozilla/xpcshell-test",
-
-  "env": {
-    // The tests in this folder are testing based on WebExtensions, so lets
-    // just define the webextensions environment here.
-    "webextensions": true,
-  },
-};
deleted file mode 100644
--- a/mail/components/extensions/test/xpcshell/test_ext_addressBook.js
+++ /dev/null
@@ -1,557 +0,0 @@
-/* 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://gre/modules/Services.jsm");
-ChromeUtils.import("resource:///modules/MailServices.jsm");
-ChromeUtils.import("resource://testing-common/ExtensionXPCShellUtils.jsm");
-
-ExtensionTestUtils.init(this);
-
-add_task(async function test_addressBooks() {
-  async function background() {
-    let firstBookId, secondBookId, newContactId;
-
-    let events = [];
-    for (let eventNamespace of ["addressBooks", "contacts", "mailingLists"]) {
-      for (let eventName of ["onCreated", "onUpdated", "onDeleted", "onMemberAdded", "onMemberRemoved"]) {
-        if (eventName in browser[eventNamespace]) {
-          browser[eventNamespace][eventName].addListener((...args) => {
-            events.push({ namespace: eventNamespace, name: eventName, args });
-          });
-        }
-      }
-    }
-
-    let checkEvents = function(...expectedEvents) {
-      browser.test.assertEq(expectedEvents.length, events.length, "Correct number of events");
-
-      if (expectedEvents.length != events.length) {
-        for (let event of events) {
-          let args = event.args.join(", ");
-          browser.test.log(`${event.namespace}.${event.name}(${args})`);
-        }
-        throw new Error("Wrong number of events, stopping.");
-      }
-
-      for (let [namespace, name, ...expectedArgs] of expectedEvents) {
-        let event = events.shift();
-        browser.test.assertEq(namespace, event.namespace, "Event namespace is correct");
-        browser.test.assertEq(name, event.name, "Event type is correct");
-        browser.test.assertEq(expectedArgs.length, event.args.length, "Argument count is correct");
-        for (let i = 0; i < expectedArgs.length; i++) {
-          if (typeof expectedArgs[i] == "object") {
-            for (let k of Object.keys(expectedArgs[i])) {
-              browser.test.assertEq(expectedArgs[i][k], event.args[i][k], `Property ${k} is correct`);
-            }
-          } else {
-            browser.test.assertEq(expectedArgs[i], event.args[i], `Argument ${i + 1} is correct`);
-          }
-        }
-        if (expectedEvents.length == 1) {
-          return event.args;
-        }
-      }
-
-      return null;
-    };
-
-    let awaitMessage = function() {
-      return new Promise(resolve => {
-        browser.test.onMessage.addListener(function listener(...args) {
-          browser.test.onMessage.removeListener(listener);
-          resolve(args);
-        });
-      });
-    };
-
-    async function addressBookTest() {
-      browser.test.log("Starting addressBookTest");
-      let list = await browser.addressBooks.list();
-      browser.test.assertEq(2, list.length);
-      for (let b of list) {
-        browser.test.assertEq(4, Object.keys(b).length);
-        browser.test.assertEq(36, b.id.length);
-        browser.test.assertEq("addressBook", b.type);
-        browser.test.assertTrue("name" in b);
-        browser.test.assertFalse(b.readOnly);
-      }
-
-      let completeList = await browser.addressBooks.list(true);
-      browser.test.assertEq(2, completeList.length);
-      for (let b of completeList) {
-        browser.test.assertEq(6, Object.keys(b).length);
-      }
-
-      firstBookId = list[0].id;
-      secondBookId = list[1].id;
-
-      let firstBook = await browser.addressBooks.get(firstBookId);
-      browser.test.assertEq(4, Object.keys(firstBook).length);
-
-      let secondBook = await browser.addressBooks.get(secondBookId, true);
-      browser.test.assertEq(6, Object.keys(secondBook).length);
-      browser.test.assertTrue(Array.isArray(secondBook.contacts));
-      browser.test.assertEq(0, secondBook.contacts.length);
-      browser.test.assertTrue(Array.isArray(secondBook.mailingLists));
-      browser.test.assertEq(0, secondBook.mailingLists.length);
-
-      let newBookId = await browser.addressBooks.create({ name: "test name" });
-      browser.test.assertEq(36, newBookId.length);
-      checkEvents(["addressBooks", "onCreated", { type: "addressBook", id: newBookId }]);
-
-      list = await browser.addressBooks.list();
-      browser.test.assertEq(3, list.length);
-
-      let newBook = await browser.addressBooks.get(newBookId);
-      browser.test.assertEq(newBookId, newBook.id);
-      browser.test.assertEq("addressBook", newBook.type);
-      browser.test.assertEq("test name", newBook.name);
-
-      await browser.addressBooks.update(newBookId, { name: "new name" });
-      checkEvents(["addressBooks", "onUpdated", { type: "addressBook", id: newBookId }]);
-      let updatedBook = await browser.addressBooks.get(newBookId);
-      browser.test.assertEq("new name", updatedBook.name);
-
-      list = await browser.addressBooks.list();
-      browser.test.assertEq(3, list.length);
-
-      await browser.addressBooks.delete(newBookId);
-      checkEvents(["addressBooks", "onDeleted", newBookId]);
-
-      list = await browser.addressBooks.list();
-      browser.test.assertEq(2, list.length);
-
-      for (let operation of ["get", "update", "delete"]) {
-        let args = [newBookId];
-        if (operation == "update") {
-          args.push({ name: "" });
-        }
-
-        try {
-          await browser.addressBooks[operation].apply(browser.addressBooks, args);
-          browser.test.fail(`Calling ${operation} on a non-existent address book should throw`);
-        } catch (ex) {
-          browser.test.assertEq(
-            `addressBook with id=${newBookId} could not be found.`,
-            ex.message, `browser.addressBooks.${operation} threw exception`
-          );
-        }
-      }
-
-      browser.test.assertEq(0, events.length, "No events left unconsumed");
-      browser.test.log("Completed addressBookTest");
-    }
-
-    async function contactsTest() {
-      browser.test.log("Starting contactsTest");
-      let contacts = await browser.contacts.list(firstBookId);
-      browser.test.assertTrue(Array.isArray(contacts));
-      browser.test.assertEq(0, contacts.length);
-
-      newContactId = await browser.contacts.create(firstBookId, {
-        FirstName: "first",
-        LastName: "last",
-      });
-      browser.test.assertEq(36, newContactId.length);
-      checkEvents(["contacts", "onCreated", { type: "contact", parentId: firstBookId, id: newContactId }]);
-
-      contacts = await browser.contacts.list(firstBookId);
-      browser.test.assertEq(1, contacts.length, "Contact added to first book.");
-      browser.test.assertEq(contacts[0].id, newContactId);
-
-      contacts = await browser.contacts.list(secondBookId);
-      browser.test.assertEq(0, contacts.length, "Contact not added to second book.");
-
-      let newContact = await browser.contacts.get(newContactId);
-      browser.test.assertEq(4, Object.keys(newContact).length);
-      browser.test.assertEq(newContactId, newContact.id);
-      browser.test.assertEq(firstBookId, newContact.parentId);
-      browser.test.assertEq("contact", newContact.type);
-      browser.test.assertEq(3, Object.keys(newContact.properties).length);
-      browser.test.assertEq("0", newContact.properties.PreferMailFormat);
-      browser.test.assertEq("first", newContact.properties.FirstName);
-      browser.test.assertEq("last", newContact.properties.LastName);
-
-      await browser.contacts.update(newContactId, {
-        PrimaryEmail: "first@last",
-        LastName: null,
-      });
-      checkEvents(["contacts", "onUpdated", { type: "contact", parentId: firstBookId, id: newContactId }]);
-
-      let updatedContact = await browser.contacts.get(newContactId);
-      browser.test.assertEq(3, Object.keys(updatedContact.properties).length);
-      browser.test.assertEq("0", updatedContact.properties.PreferMailFormat);
-      browser.test.assertEq("first", updatedContact.properties.FirstName);
-      browser.test.assertEq("first@last", updatedContact.properties.PrimaryEmail);
-      browser.test.assertTrue(!("LastName" in updatedContact.properties));
-
-      browser.test.assertEq(0, events.length, "No events left unconsumed");
-      browser.test.log("Completed contactsTest");
-    }
-
-    async function mailingListsTest() {
-      browser.test.log("Starting mailingListsTest");
-      let mailingLists = await browser.mailingLists.list(firstBookId);
-      browser.test.assertTrue(Array.isArray(mailingLists));
-      browser.test.assertEq(0, mailingLists.length);
-
-      let newMailingListId = await browser.mailingLists.create(firstBookId, { name: "name" });
-      browser.test.assertEq(36, newMailingListId.length);
-      checkEvents(
-        ["mailingLists", "onCreated", { type: "mailingList", parentId: firstBookId, id: newMailingListId }]
-      );
-
-      mailingLists = await browser.mailingLists.list(firstBookId);
-      browser.test.assertEq(1, mailingLists.length, "List added to first book.");
-
-      mailingLists = await browser.mailingLists.list(secondBookId);
-      browser.test.assertEq(0, mailingLists.length, "List not added to second book.");
-
-      let newAddressList = await browser.mailingLists.get(newMailingListId);
-      browser.test.assertEq(6, Object.keys(newAddressList).length);
-      browser.test.assertEq(newMailingListId, newAddressList.id);
-      browser.test.assertEq(firstBookId, newAddressList.parentId);
-      browser.test.assertEq("mailingList", newAddressList.type);
-      browser.test.assertEq("name", newAddressList.name);
-      browser.test.assertEq("", newAddressList.nickName);
-      browser.test.assertEq("", newAddressList.description);
-
-      await browser.mailingLists.update(newMailingListId, {
-        name: "name!",
-        nickName: "nickname!",
-        description: "description!",
-      });
-      checkEvents(
-        ["mailingLists", "onUpdated", { type: "mailingList", parentId: firstBookId, id: newMailingListId }]
-      );
-
-      let updatedMailingList = await browser.mailingLists.get(newMailingListId);
-      browser.test.assertEq("name!", updatedMailingList.name);
-      browser.test.assertEq("nickname!", updatedMailingList.nickName);
-      browser.test.assertEq("description!", updatedMailingList.description);
-
-      await browser.mailingLists.addMember(newMailingListId, newContactId);
-      checkEvents(
-        ["mailingLists", "onMemberAdded", { type: "contact", parentId: newMailingListId, id: newContactId }]
-      );
-
-      let listMembers = await browser.mailingLists.listMembers(newMailingListId);
-      browser.test.assertTrue(Array.isArray(listMembers));
-      browser.test.assertEq(1, listMembers.length);
-
-      let anotherContactId = await browser.contacts.create(firstBookId, {
-        FirstName: "second",
-        LastName: "last",
-        PrimaryEmail: "em@il",
-      });
-      checkEvents(["contacts", "onCreated", { type: "contact", parentId: firstBookId, id: anotherContactId }]);
-
-      await browser.mailingLists.addMember(newMailingListId, anotherContactId);
-      checkEvents(
-        ["mailingLists", "onMemberAdded", { type: "contact", parentId: newMailingListId, id: anotherContactId }]
-      );
-
-      listMembers = await browser.mailingLists.listMembers(newMailingListId);
-      browser.test.assertEq(2, listMembers.length);
-
-      await browser.contacts.delete(anotherContactId);
-      checkEvents(
-        ["contacts", "onDeleted", firstBookId, anotherContactId],
-        ["mailingLists", "onMemberRemoved", newMailingListId, anotherContactId]
-      );
-      listMembers = await browser.mailingLists.listMembers(newMailingListId);
-      browser.test.assertEq(1, listMembers.length);
-
-      await browser.mailingLists.removeMember(newMailingListId, newContactId);
-      checkEvents(
-        ["mailingLists", "onMemberRemoved", newMailingListId, newContactId]
-      );
-      listMembers = await browser.mailingLists.listMembers(newMailingListId);
-      browser.test.assertEq(0, listMembers.length);
-
-      await browser.mailingLists.delete(newMailingListId);
-      checkEvents(["mailingLists", "onDeleted", firstBookId, newMailingListId]);
-
-      mailingLists = await browser.mailingLists.list(firstBookId);
-      browser.test.assertEq(0, mailingLists.length);
-
-      for (let operation of ["get", "update", "delete", "listMembers", "addMember", "removeMember"]) {
-        let args = [newMailingListId];
-        switch (operation) {
-          case "update":
-            args.push({ name: "" });
-            break;
-          case "addMember":
-          case "removeMember":
-            args.push(newContactId);
-            break;
-        }
-
-        try {
-          await browser.mailingLists[operation].apply(browser.mailingLists, args);
-          browser.test.fail(`Calling ${operation} on a non-existent mailing list should throw`);
-        } catch (ex) {
-          browser.test.assertEq(
-            `mailingList with id=${newMailingListId} could not be found.`,
-            ex.message, `browser.mailingLists.${operation} threw exception`
-          );
-        }
-      }
-
-      browser.test.assertEq(0, events.length, "No events left unconsumed");
-      browser.test.log("Completed mailingListsTest");
-    }
-
-    async function contactRemovalTest() {
-      browser.test.log("Starting contactRemovalTest");
-      await browser.contacts.delete(newContactId);
-      checkEvents(["contacts", "onDeleted", firstBookId, newContactId]);
-
-      for (let operation of ["get", "update", "delete"]) {
-        let args = [newContactId];
-        if (operation == "update") {
-          args.push({});
-        }
-
-        try {
-          await browser.contacts[operation].apply(browser.contacts, args);
-          browser.test.fail(`Calling ${operation} on a non-existent contact should throw`);
-        } catch (ex) {
-          browser.test.assertEq(
-            `contact with id=${newContactId} could not be found.`,
-            ex.message, `browser.contacts.${operation} threw exception`
-          );
-        }
-      }
-
-      let contacts = await browser.contacts.list(firstBookId);
-      browser.test.assertEq(0, contacts.length);
-
-      browser.test.assertEq(0, events.length, "No events left unconsumed");
-      browser.test.log("Completed contactRemovalTest");
-    }
-
-    async function outsideEventsTest() {
-      browser.test.log("Starting outsideEventsTest");
-
-      browser.test.sendMessage("outsideEventsTest", "createAddressBook");
-      let [bookId, newBookPrefId] = await awaitMessage();
-      let [newBook] = checkEvents(["addressBooks", "onCreated", { type: "addressBook", id: bookId }]);
-      browser.test.assertEq("external add", newBook.name);
-
-      browser.test.sendMessage("outsideEventsTest", "updateAddressBook", newBookPrefId);
-      await awaitMessage();
-      let [updatedBook] = checkEvents(["addressBooks", "onUpdated", { type: "addressBook", id: bookId }]);
-      browser.test.assertEq("external edit", updatedBook.name);
-
-      browser.test.sendMessage("outsideEventsTest", "deleteAddressBook", newBookPrefId);
-      await awaitMessage();
-      checkEvents(["addressBooks", "onDeleted", bookId]);
-
-      browser.test.sendMessage("outsideEventsTest", "createContact");
-      let [parentId1, contactId] = await awaitMessage();
-      let [newContact] = checkEvents(
-        ["contacts", "onCreated", { type: "contact", parentId: parentId1, id: contactId }]
-      );
-      browser.test.assertEq("external", newContact.properties.FirstName);
-      browser.test.assertEq("add", newContact.properties.LastName);
-
-      browser.test.sendMessage("outsideEventsTest", "updateContact", contactId);
-      await awaitMessage();
-      let [updatedContact] = checkEvents(
-        ["contacts", "onUpdated", { type: "contact", parentId: parentId1, id: contactId }]
-      );
-      browser.test.assertEq("external", updatedContact.properties.FirstName);
-      browser.test.assertEq("edit", updatedContact.properties.LastName);
-
-      browser.test.sendMessage("outsideEventsTest", "createMailingList");
-      let [parentId2, listId] = await awaitMessage();
-      let [newList] = checkEvents(
-        ["mailingLists", "onCreated", { type: "mailingList", parentId: parentId2, id: listId }]
-      );
-      browser.test.assertEq("external add", newList.name);
-
-      browser.test.sendMessage("outsideEventsTest", "updateMailingList", listId);
-      await awaitMessage();
-      let [updatedList] = checkEvents(
-        ["mailingLists", "onUpdated", { type: "mailingList", parentId: parentId2, id: listId }]
-      );
-      browser.test.assertEq("external edit", updatedList.name);
-
-      browser.test.sendMessage("outsideEventsTest", "addMailingListMember", listId, contactId);
-      await awaitMessage();
-      checkEvents(
-        ["mailingLists", "onMemberAdded", { type: "contact", parentId: listId, id: contactId }]
-      );
-      let listMembers = await browser.mailingLists.listMembers(listId);
-      browser.test.assertEq(1, listMembers.length);
-
-      browser.test.sendMessage("outsideEventsTest", "removeMailingListMember", listId, contactId);
-      await awaitMessage();
-      checkEvents(
-        ["mailingLists", "onMemberRemoved", listId, contactId]
-      );
-
-      browser.test.sendMessage("outsideEventsTest", "deleteMailingList", listId);
-      await awaitMessage();
-      checkEvents(["mailingLists", "onDeleted", parentId2, listId]);
-
-      browser.test.sendMessage("outsideEventsTest", "deleteContact", contactId);
-      await awaitMessage();
-      checkEvents(["contacts", "onDeleted", parentId1, contactId]);
-
-      browser.test.log("Completed outsideEventsTest");
-    }
-
-    await addressBookTest();
-    await contactsTest();
-    await mailingListsTest();
-    await contactRemovalTest();
-    await outsideEventsTest();
-
-    browser.test.notifyPass("addressBooks");
-  }
-
-  let extension = ExtensionTestUtils.loadExtension({
-    background,
-    manifest: { permissions: ["addressBooks"] },
-  });
-
-  extension.onMessage("outsideEventsTest", (action, ...args) => {
-    function findContact(id) {
-      for (let child of parent.childCards) {
-        if (child.UID == id) {
-          return child;
-        }
-      }
-      return null;
-    }
-    function findMailingList(id) {
-      for (let list of parent.addressLists.enumerate()) {
-        if (list.UID == id) {
-          return list;
-        }
-      }
-      return null;
-    }
-
-    let parent = MailServices.ab.directories.getNext().QueryInterface(Ci.nsIAbDirectory);
-    switch (action) {
-      case "createAddressBook": {
-        const kPABDirectory = 2; // defined in nsDirPrefs.h
-        let dirPrefId = MailServices.ab.newAddressBook("external add", "", kPABDirectory);
-        let book = MailServices.ab.getDirectoryFromId(dirPrefId);
-        extension.sendMessage(book.UID, dirPrefId);
-        return;
-      }
-      case "updateAddressBook": {
-        let book = MailServices.ab.getDirectoryFromId(args[0]);
-        book.dirName = "external edit";
-        extension.sendMessage();
-        return;
-      }
-      case "deleteAddressBook": {
-        let book = MailServices.ab.getDirectoryFromId(args[0]);
-        MailServices.ab.deleteAddressBook(book.URI);
-        extension.sendMessage();
-        return;
-      }
-
-      case "createContact": {
-        let contact = Cc["@mozilla.org/addressbook/cardproperty;1"].createInstance(Ci.nsIAbCard);
-        contact.setProperty("FirstName", "external");
-        contact.setProperty("LastName", "add");
-        let newContact = parent.addCard(contact);
-        extension.sendMessage(parent.UID, newContact.UID);
-        return;
-      }
-      case "updateContact": {
-        let contact = findContact(args[0]);
-        if (contact) {
-          contact.setProperty("FirstName", "external");
-          contact.setProperty("LastName", "edit");
-          parent.modifyCard(contact);
-          extension.sendMessage();
-          return;
-        }
-        break;
-      }
-      case "deleteContact": {
-        let contact = findContact(args[0]);
-        if (contact) {
-          let cardArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
-          cardArray.appendElement(contact);
-          parent.deleteCards(cardArray);
-          extension.sendMessage();
-          return;
-        }
-        break;
-      }
-
-      case "createMailingList": {
-        let list = Cc["@mozilla.org/addressbook/directoryproperty;1"].createInstance();
-        list.QueryInterface(Ci.nsIAbDirectory);
-        list.isMailList = true;
-        list.dirName = "external add";
-
-        let newList = parent.addMailList(list);
-        extension.sendMessage(parent.UID, newList.UID);
-        return;
-      }
-      case "updateMailingList": {
-        let list = findMailingList(args[0]);
-        if (list) {
-          list.dirName = "external edit";
-          list.editMailListToDatabase(null);
-          extension.sendMessage();
-          return;
-        }
-        break;
-      }
-      case "deleteMailingList": {
-        let list = findMailingList(args[0]);
-        if (list) {
-          MailServices.ab.deleteAddressBook(list.URI);
-          extension.sendMessage();
-          return;
-        }
-        break;
-      }
-      case "addMailingListMember": {
-        let list = findMailingList(args[0]);
-        let contact = findContact(args[1]);
-
-        if (list && contact) {
-          list.addCard(contact);
-          equal(1, list.addressLists.Count());
-          extension.sendMessage();
-          return;
-        }
-        break;
-      }
-      case "removeMailingListMember": {
-        let list = findMailingList(args[0]);
-        let contact = findContact(args[1]);
-
-        if (list && contact) {
-          let cardArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
-          cardArray.appendElement(contact);
-          list.deleteCards(cardArray);
-          equal(0, list.addressLists.Count());
-          ok(findContact(args[1]), "Contact was not removed");
-          extension.sendMessage();
-          return;
-        }
-        break;
-      }
-    }
-    throw new Error(`Message "${action}" passed to handler didn't do anything.`);
-  });
-
-  await extension.startup();
-  await extension.awaitFinish("addressBooks");
-  await extension.unload();
-});
deleted file mode 100644
--- a/mail/components/extensions/test/xpcshell/xpcshell.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[default]
-tags = webextensions
-
-[test_ext_addressBook.js]