summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/extensions/test/browser/browser_ext_compose_details.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/extensions/test/browser/browser_ext_compose_details.js')
-rw-r--r--comm/mail/components/extensions/test/browser/browser_ext_compose_details.js725
1 files changed, 725 insertions, 0 deletions
diff --git a/comm/mail/components/extensions/test/browser/browser_ext_compose_details.js b/comm/mail/components/extensions/test/browser/browser_ext_compose_details.js
new file mode 100644
index 0000000000..3eb16102c5
--- /dev/null
+++ b/comm/mail/components/extensions/test/browser/browser_ext_compose_details.js
@@ -0,0 +1,725 @@
+/* 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/. */
+
+let account = createAccount();
+let defaultIdentity = addIdentity(account);
+let nonDefaultIdentity = addIdentity(account);
+defaultIdentity.attachVCard = false;
+nonDefaultIdentity.attachVCard = true;
+
+let gRootFolder = account.incomingServer.rootFolder;
+
+gRootFolder.createSubfolder("test", null);
+let gTestFolder = gRootFolder.getChildNamed("test");
+createMessages(gTestFolder, 4);
+
+// TODO: Figure out why naming this folder drafts is problematic.
+gRootFolder.createSubfolder("something", null);
+let gDraftsFolder = gRootFolder.getChildNamed("something");
+gDraftsFolder.flags = Ci.nsMsgFolderFlags.Drafts;
+createMessages(gDraftsFolder, 2);
+let gDrafts = [...gDraftsFolder.messages];
+
+// Verifies ComposeDetails of a given composer can be applied to a different
+// composer, even if they have different compose formats. The composer should pick
+// the matching body/plaintextBody value, if both are specified. The value for
+// isPlainText is ignored by setComposeDetails.
+add_task(async function testIsReflexive() {
+ let files = {
+ "background.js": async () => {
+ // Start a new TEXT message.
+ let createdTextWindowPromise = window.waitForEvent("windows.onCreated");
+ await browser.compose.beginNew({
+ plainTextBody: "This is some PLAIN text.",
+ isPlainText: true,
+ });
+ let [createdTextWindow] = await createdTextWindowPromise;
+ let [createdTextTab] = await browser.tabs.query({
+ windowId: createdTextWindow.id,
+ });
+
+ // Get details, TEXT message.
+ let textDetails = await browser.compose.getComposeDetails(
+ createdTextTab.id
+ );
+ browser.test.assertTrue(textDetails.isPlainText);
+ browser.test.assertTrue(
+ textDetails.body.includes("This is some PLAIN text")
+ );
+ browser.test.assertEq(
+ "This is some PLAIN text.",
+ textDetails.plainTextBody
+ );
+
+ // Start a new HTML message.
+ let createdHtmlWindowPromise = window.waitForEvent("windows.onCreated");
+ await browser.compose.beginNew({
+ body: "<p>This is some <i>HTML</i> text.</p>",
+ isPlainText: false,
+ });
+ let [createdHtmlWindow] = await createdHtmlWindowPromise;
+ let [createdHtmlTab] = await browser.tabs.query({
+ windowId: createdHtmlWindow.id,
+ });
+
+ // Get details, HTML message.
+ let htmlDetails = await browser.compose.getComposeDetails(
+ createdHtmlTab.id
+ );
+ browser.test.assertFalse(htmlDetails.isPlainText);
+ browser.test.assertTrue(
+ htmlDetails.body.includes("<p>This is some <i>HTML</i> text.</p>")
+ );
+ browser.test.assertEq(
+ "This is some /HTML/ text.",
+ htmlDetails.plainTextBody
+ );
+
+ // Set HTML details on HTML composer. It should not throw.
+ await browser.compose.setComposeDetails(createdHtmlTab.id, htmlDetails);
+
+ // Set TEXT details on TEXT composer. It should not throw.
+ await browser.compose.setComposeDetails(createdTextTab.id, textDetails);
+
+ // Set TEXT details on HTML composer and verify the changed content.
+ await browser.compose.setComposeDetails(createdHtmlTab.id, textDetails);
+ let htmlDetails2 = await browser.compose.getComposeDetails(
+ createdHtmlTab.id
+ );
+ browser.test.assertFalse(htmlDetails2.isPlainText);
+ browser.test.assertTrue(
+ htmlDetails2.body.includes("This is some PLAIN text")
+ );
+ browser.test.assertEq(
+ "This is some PLAIN text.",
+ htmlDetails2.plainTextBody
+ );
+
+ // Set HTML details on TEXT composer and verify the changed content.
+ await browser.compose.setComposeDetails(createdTextTab.id, htmlDetails);
+ let textDetails2 = await browser.compose.getComposeDetails(
+ createdTextTab.id
+ );
+ browser.test.assertTrue(textDetails2.isPlainText);
+ browser.test.assertTrue(
+ textDetails2.body.includes("This is some /HTML/ text.")
+ );
+ browser.test.assertEq(
+ "This is some /HTML/ text.",
+ textDetails2.plainTextBody
+ );
+
+ // Clean up.
+
+ let removedHtmlWindowPromise = window.waitForEvent("windows.onRemoved");
+ browser.windows.remove(createdHtmlWindow.id);
+ await removedHtmlWindowPromise;
+
+ let removedTextWindowPromise = window.waitForEvent("windows.onRemoved");
+ browser.windows.remove(createdTextWindow.id);
+ await removedTextWindowPromise;
+
+ browser.test.notifyPass("finished");
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["accountsRead", "compose"],
+ },
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("finished");
+ await extension.unload();
+});
+
+add_task(async function testType() {
+ let files = {
+ "background.js": async () => {
+ let accounts = await browser.accounts.list();
+ browser.test.assertEq(1, accounts.length, "number of accounts");
+
+ let testFolder = accounts[0].folders.find(f => f.name == "test");
+ let messages = (await browser.messages.list(testFolder)).messages;
+ browser.test.assertEq(4, messages.length, "number of messages");
+
+ let draftFolder = accounts[0].folders.find(f => f.name == "something");
+ let drafts = (await browser.messages.list(draftFolder)).messages;
+ browser.test.assertEq(2, drafts.length, "number of drafts");
+
+ async function checkComposer(tab, expected) {
+ browser.test.assertEq("object", typeof tab, "type of tab");
+ browser.test.assertEq("number", typeof tab.id, "type of tab ID");
+ browser.test.assertEq(
+ "number",
+ typeof tab.windowId,
+ "type of window ID"
+ );
+
+ let details = await browser.compose.getComposeDetails(tab.id);
+ browser.test.assertEq(expected.type, details.type, "type of composer");
+ browser.test.assertEq(
+ expected.relatedMessageId,
+ details.relatedMessageId,
+ `related message id (${details.type})`
+ );
+ await browser.windows.remove(tab.windowId);
+ }
+
+ let tests = [
+ {
+ funcName: "beginNew",
+ args: [],
+ expected: { type: "new", relatedMessageId: null },
+ },
+ {
+ funcName: "beginReply",
+ args: [messages[0].id],
+ expected: { type: "reply", relatedMessageId: messages[0].id },
+ },
+ {
+ funcName: "beginReply",
+ args: [messages[1].id, "replyToAll"],
+ expected: { type: "reply", relatedMessageId: messages[1].id },
+ },
+ {
+ funcName: "beginReply",
+ args: [messages[2].id, "replyToList"],
+ expected: { type: "reply", relatedMessageId: messages[2].id },
+ },
+ {
+ funcName: "beginReply",
+ args: [messages[3].id, "replyToSender"],
+ expected: { type: "reply", relatedMessageId: messages[3].id },
+ },
+ {
+ funcName: "beginForward",
+ args: [messages[0].id],
+ expected: { type: "forward", relatedMessageId: messages[0].id },
+ },
+ {
+ funcName: "beginForward",
+ args: [messages[1].id, "forwardAsAttachment"],
+ expected: { type: "forward", relatedMessageId: messages[1].id },
+ },
+ // Uses a different code path.
+ {
+ funcName: "beginForward",
+ args: [messages[2].id, "forwardInline"],
+ expected: { type: "forward", relatedMessageId: messages[2].id },
+ },
+ {
+ funcName: "beginNew",
+ args: [messages[3].id],
+ expected: { type: "new", relatedMessageId: messages[3].id },
+ },
+ ];
+ for (let test of tests) {
+ browser.test.log(test.funcName);
+ let tab = await browser.compose[test.funcName](...test.args);
+ await checkComposer(tab, test.expected);
+ }
+
+ browser.tabs.onCreated.addListener(async tab => {
+ // Bug 1702957, if composeWindow.GetComposeDetails() is not delayed
+ // until the compose window is ready, it will overwrite the compose
+ // fields.
+ let details = await browser.compose.getComposeDetails(tab.id);
+ browser.test.assertEq(
+ "Johnny Jones <johnny@jones.invalid>",
+ details.to.pop(),
+ "Check Recipients in draft after calling getComposeDetails()"
+ );
+
+ let window = await browser.windows.get(tab.windowId);
+ if (window.type == "messageCompose") {
+ await checkComposer(tab, {
+ type: "draft",
+ relatedMessageId: drafts[0].id,
+ });
+ browser.test.notifyPass("Finish");
+ }
+ });
+ browser.test.sendMessage("openDrafts");
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["compose", "accountsRead", "messagesRead"],
+ },
+ });
+
+ await extension.startup();
+
+ // The first part of the test is done in the background script using the
+ // compose API to open compose windows. For the second part we need to open
+ // a draft, which is not possible with the compose API.
+ await extension.awaitMessage("openDrafts");
+ window.ComposeMessage(
+ Ci.nsIMsgCompType.Draft,
+ Ci.nsIMsgCompFormat.Default,
+ gDraftsFolder,
+ [gDraftsFolder.generateMessageURI(gDrafts[0].messageKey)]
+ );
+
+ await extension.awaitFinish("Finish");
+ await extension.unload();
+});
+
+add_task(async function testFcc() {
+ let files = {
+ "background.js": async () => {
+ async function checkWindow(createdTab, expected) {
+ let state = await browser.compose.getComposeDetails(createdTab.id);
+
+ browser.test.assertEq(
+ expected.overrideDefaultFcc,
+ state.overrideDefaultFcc,
+ "overrideDefaultFcc should be correct"
+ );
+
+ if (expected.overrideDefaultFccFolder) {
+ window.assertDeepEqual(
+ state.overrideDefaultFccFolder,
+ expected.overrideDefaultFccFolder,
+ "overrideDefaultFccFolder should be correct"
+ );
+ } else {
+ browser.test.assertEq(
+ expected.overrideDefaultFccFolder,
+ state.overrideDefaultFccFolder,
+ "overrideDefaultFccFolder should be correct"
+ );
+ }
+
+ if (expected.additionalFccFolder) {
+ window.assertDeepEqual(
+ state.additionalFccFolder,
+ expected.additionalFccFolder,
+ "additionalFccFolder should be correct"
+ );
+ } else {
+ browser.test.assertEq(
+ expected.additionalFccFolder,
+ state.additionalFccFolder,
+ "additionalFccFolder should be correct"
+ );
+ }
+
+ await window.sendMessage("checkWindow", expected);
+ }
+
+ let [account] = await browser.accounts.list();
+ let folder1 = account.folders.find(f => f.name == "Trash");
+ let folder2 = account.folders.find(f => f.name == "something");
+
+ // Start a new message.
+
+ let createdWindowPromise = window.waitForEvent("windows.onCreated");
+ await browser.compose.beginNew();
+ let [createdWindow] = await createdWindowPromise;
+ let [createdTab] = await browser.tabs.query({
+ windowId: createdWindow.id,
+ });
+
+ await checkWindow(createdTab, {
+ overrideDefaultFcc: false,
+ overrideDefaultFccFolder: null,
+ additionalFccFolder: "",
+ });
+
+ await browser.test.assertRejects(
+ browser.compose.setComposeDetails(createdTab.id, {
+ overrideDefaultFcc: true,
+ }),
+ "Setting overrideDefaultFcc to true requires setting overrideDefaultFccFolder as well",
+ "browser.compose.setComposeDetails() should reject setting overrideDefaultFcc to true."
+ );
+
+ // Set folders.
+ await browser.compose.setComposeDetails(createdTab.id, {
+ overrideDefaultFccFolder: folder1,
+ additionalFccFolder: folder2,
+ });
+ await checkWindow(createdTab, {
+ overrideDefaultFcc: true,
+ overrideDefaultFccFolder: folder1,
+ additionalFccFolder: folder2,
+ });
+
+ // Setting overrideDefaultFcc true while it is already true should not change any values.
+ await browser.compose.setComposeDetails(createdTab.id, {
+ overrideDefaultFcc: true,
+ });
+ await checkWindow(createdTab, {
+ overrideDefaultFcc: true,
+ overrideDefaultFccFolder: folder1,
+ additionalFccFolder: folder2,
+ });
+
+ // A no-op should not change any values.
+ await browser.compose.setComposeDetails(createdTab.id, {});
+ await checkWindow(createdTab, {
+ overrideDefaultFcc: true,
+ overrideDefaultFccFolder: folder1,
+ additionalFccFolder: folder2,
+ });
+
+ // Disable fcc.
+ await browser.compose.setComposeDetails(createdTab.id, {
+ overrideDefaultFccFolder: "",
+ });
+ await checkWindow(createdTab, {
+ overrideDefaultFcc: true,
+ overrideDefaultFccFolder: "",
+ additionalFccFolder: folder2,
+ });
+
+ // Disable additional fcc.
+ await browser.compose.setComposeDetails(createdTab.id, {
+ additionalFccFolder: "",
+ });
+ await checkWindow(createdTab, {
+ overrideDefaultFcc: true,
+ overrideDefaultFccFolder: "",
+ additionalFccFolder: "",
+ });
+
+ // Clear override.
+ await browser.compose.setComposeDetails(createdTab.id, {
+ overrideDefaultFcc: false,
+ });
+ await checkWindow(createdTab, {
+ overrideDefaultFcc: false,
+ overrideDefaultFccFolder: null,
+ additionalFccFolder: "",
+ });
+
+ await browser.test.assertRejects(
+ browser.compose.setComposeDetails(createdTab.id, {
+ overrideDefaultFccFolder: {
+ path: "/bad",
+ accountId: folder1.accountId,
+ },
+ }),
+ `Invalid MailFolder: {accountId:${folder1.accountId}, path:/bad}`,
+ "browser.compose.setComposeDetails() should reject, if an invalid folder is set as overrideDefaultFccFolder."
+ );
+
+ await browser.test.assertRejects(
+ browser.compose.setComposeDetails(createdTab.id, {
+ additionalFccFolder: { path: "/bad", accountId: folder1.accountId },
+ }),
+ `Invalid MailFolder: {accountId:${folder1.accountId}, path:/bad}`,
+ "browser.compose.setComposeDetails() should reject, if an invalid folder is set as additionalFccFolder."
+ );
+
+ // Clean up.
+
+ let removedWindowPromise = window.waitForEvent("windows.onRemoved");
+ browser.windows.remove(createdWindow.id);
+ await removedWindowPromise;
+
+ browser.test.notifyPass("finished");
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["accountsRead", "compose", "messagesRead"],
+ },
+ });
+
+ extension.onMessage("checkWindow", async expected => {
+ await checkComposeHeaders(expected);
+ extension.sendMessage();
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("finished");
+ await extension.unload();
+});
+
+add_task(async function testSimpleDetails() {
+ let files = {
+ "background.js": async () => {
+ async function checkWindow(createdTab, expected) {
+ let state = await browser.compose.getComposeDetails(createdTab.id);
+
+ if (expected.priority) {
+ browser.test.assertEq(
+ expected.priority,
+ state.priority,
+ "priority should be correct"
+ );
+ }
+
+ if (expected.hasOwnProperty("returnReceipt")) {
+ browser.test.assertEq(
+ expected.returnReceipt,
+ state.returnReceipt,
+ "returnReceipt should be correct"
+ );
+ }
+
+ if (expected.hasOwnProperty("deliveryStatusNotification")) {
+ browser.test.assertEq(
+ expected.deliveryStatusNotification,
+ state.deliveryStatusNotification,
+ "deliveryStatusNotification should be correct"
+ );
+ }
+
+ if (expected.hasOwnProperty("attachVCard")) {
+ browser.test.assertEq(
+ expected.attachVCard,
+ state.attachVCard,
+ "attachVCard should be correct"
+ );
+ }
+
+ if (expected.deliveryFormat) {
+ browser.test.assertEq(
+ expected.deliveryFormat,
+ state.deliveryFormat,
+ "deliveryFormat should be correct"
+ );
+ }
+
+ await window.sendMessage("checkWindow", expected);
+ }
+
+ // Start a new message.
+
+ let createdWindowPromise = window.waitForEvent("windows.onCreated");
+ await browser.compose.beginNew();
+ let [createdWindow] = await createdWindowPromise;
+ let [createdTab] = await browser.tabs.query({
+ windowId: createdWindow.id,
+ });
+
+ let accounts = await browser.accounts.list();
+ browser.test.assertEq(1, accounts.length, "number of accounts");
+ let localAccount = accounts.find(a => a.type == "none");
+ browser.test.assertEq(
+ 2,
+ localAccount.identities.length,
+ "number of identities"
+ );
+ let [defaultIdentity, nonDefaultIdentity] = localAccount.identities;
+
+ let expected = {
+ priority: "normal",
+ returnReceipt: false,
+ deliveryStatusNotification: false,
+ deliveryFormat: "auto",
+ attachVCard: false,
+ identityId: defaultIdentity.id,
+ };
+
+ async function changeDetail(key, value, _expected = {}) {
+ await browser.compose.setComposeDetails(createdTab.id, {
+ [key]: value,
+ });
+ expected[key] = value;
+ for (let [k, v] of Object.entries(_expected)) {
+ expected[k] = v;
+ }
+ await checkWindow(createdTab, expected);
+ }
+
+ // Confirm initial condition.
+ await checkWindow(createdTab, expected);
+
+ // Changing the identity without having made any changes, should load the
+ // defaults of the second identity.
+ await changeDetail("identityId", nonDefaultIdentity.id, {
+ attachVCard: true,
+ });
+
+ // Switching back should restore the defaults of the first identity.
+ await changeDetail("identityId", defaultIdentity.id, {
+ attachVCard: false,
+ });
+
+ await changeDetail("priority", "highest");
+ await changeDetail("deliveryFormat", "html");
+ await changeDetail("returnReceipt", true);
+ await changeDetail("deliveryFormat", "plaintext");
+ await changeDetail("priority", "lowest");
+ await changeDetail("attachVCard", true);
+ await changeDetail("priority", "high");
+ await changeDetail("deliveryFormat", "both");
+ await changeDetail("deliveryStatusNotification", true);
+ await changeDetail("priority", "low");
+
+ await changeDetail("priority", "normal");
+ await changeDetail("deliveryFormat", "auto");
+ await changeDetail("attachVCard", false);
+ await changeDetail("returnReceipt", false);
+ await changeDetail("deliveryStatusNotification", false);
+
+ // Changing the identity should not load the defaults of the second identity,
+ // after the values had been changed.
+ await changeDetail("identityId", nonDefaultIdentity.id);
+
+ // Clean up.
+
+ let removedWindowPromise = window.waitForEvent("windows.onRemoved");
+ browser.windows.remove(createdWindow.id);
+ await removedWindowPromise;
+
+ browser.test.notifyPass("finished");
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["accountsRead", "compose", "messagesRead"],
+ },
+ });
+
+ extension.onMessage("checkWindow", async expected => {
+ await checkComposeHeaders(expected);
+ extension.sendMessage();
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("finished");
+ await extension.unload();
+});
+
+add_task(async function testAutoComplete() {
+ let files = {
+ "background.js": async () => {
+ async function checkWindow(createdTab, expected) {
+ let state = await browser.compose.getComposeDetails(createdTab.id);
+
+ for (let [id, value] of Object.entries(expected.pills)) {
+ browser.test.assertEq(
+ value,
+ state[id].length ? state[id][0] : "",
+ `value for ${id} should be correct`
+ );
+ }
+
+ await window.sendMessage("checkWindow", expected);
+ }
+
+ // Start a new message.
+ let createdWindowPromise = window.waitForEvent("windows.onCreated");
+ await browser.compose.beginNew();
+ let [createdWindow] = await createdWindowPromise;
+ let [createdTab] = await browser.tabs.query({
+ windowId: createdWindow.id,
+ });
+
+ // Create a test contact.
+ let [addressBook] = await browser.addressBooks.list(true);
+ let contactId = await browser.contacts.create(addressBook.id, {
+ PrimaryEmail: "autocomplete@invalid",
+ DisplayName: "Autocomplete Test",
+ });
+
+ // Confirm the addrTo field has focus and addrTo and replyTo fields are empty.
+ await checkWindow(createdTab, {
+ activeElement: "toAddrInput",
+ pills: { to: "", replyTo: "" },
+ values: { toAddrInput: "", replyAddrInput: "" },
+ });
+
+ // Set the replyTo field, which should not break autocomplete for the currently active addrTo
+ // field.
+ await browser.compose.setComposeDetails(createdTab.id, {
+ replyTo: "test@user.net",
+ });
+
+ // Confirm the addrTo field has focus and replyTo field is set.
+ await checkWindow(createdTab, {
+ activeElement: "toAddrInput",
+ pills: { to: "", replyTo: "test@user.net" },
+ values: { toAddrInput: "", replyAddrInput: "" },
+ });
+
+ // Manually type "Autocomplete" into the active field, which should be the toAddr field and it
+ // should autocomplete.
+ await window.sendMessage("typeIntoActiveAddrField", "Autocomplete");
+
+ // Confirm the addrTo field has focus and replyTo field is set and the addrTo field has been
+ // autocompleted.
+ await checkWindow(createdTab, {
+ activeElement: "toAddrInput",
+ pills: { to: "", replyTo: "test@user.net" },
+ values: {
+ toAddrInput: "Autocomplete Test <autocomplete@invalid>",
+ replyAddrInput: "",
+ },
+ });
+
+ // Clean up.
+ await browser.contacts.delete(contactId);
+ let removedWindowPromise = window.waitForEvent("windows.onRemoved");
+ browser.windows.remove(createdWindow.id);
+ await removedWindowPromise;
+
+ browser.test.notifyPass("finished");
+ },
+ "utils.js": await getUtilsJS(),
+ };
+ let extension = ExtensionTestUtils.loadExtension({
+ files,
+ manifest: {
+ background: { scripts: ["utils.js", "background.js"] },
+ permissions: ["accountsRead", "compose", "addressBooks"],
+ },
+ });
+
+ extension.onMessage("typeIntoActiveAddrField", async value => {
+ let composeWindows = [...Services.wm.getEnumerator("msgcompose")];
+ is(composeWindows.length, 1);
+
+ for (const s of value) {
+ EventUtils.synthesizeKey(s, {}, composeWindows[0]);
+ await new Promise(r => composeWindows[0].setTimeout(r));
+ }
+
+ extension.sendMessage();
+ });
+
+ extension.onMessage("checkWindow", async expected => {
+ let composeWindows = [...Services.wm.getEnumerator("msgcompose")];
+ is(composeWindows.length, 1);
+ let composeDocument = composeWindows[0].document;
+ await new Promise(resolve => composeWindows[0].setTimeout(resolve));
+
+ Assert.equal(
+ composeDocument.activeElement.id,
+ expected.activeElement,
+ `Active element should be correct`
+ );
+
+ for (let [id, value] of Object.entries(expected.values)) {
+ await TestUtils.waitForCondition(
+ () => composeDocument.getElementById(id).value == value,
+ `Value of field ${id} should be correct`
+ );
+ }
+
+ extension.sendMessage();
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("finished");
+ await extension.unload();
+});