diff --git a/__mocks__/browser.ts b/__mocks__/browser.ts index 820f2e5..e8b143d 100644 --- a/__mocks__/browser.ts +++ b/__mocks__/browser.ts @@ -35,7 +35,9 @@ export const browser = { }, }, mailTabs: { - getSelectedMessages: jest.fn(async (_tabId) => { messages: [] }), + getSelectedMessages: jest.fn( + async (_tabId) => { messages: [], id: undefined } + ), }, menus: { create: jest.fn(), @@ -76,6 +78,10 @@ export const browser = { // Added by experiments: // https://webextension-api.thunderbird.net/en/91/how-to/experiments.html helper: { getSelectedText: jest.fn(async () => "") }, + // https://webextension-api.thunderbird.net/en/stable/tabs.html#get-tabid + tabs: { + get: jest.fn(async (_tabId) => { type: "mail" }), + }, }; export const messenger = { @@ -84,6 +90,9 @@ export const messenger = { addListener: jest.fn(), }, }, + messages: { + continueList: jest.fn(async (_id) => { messages: [], id: undefined }), + }, tabs: { query: jest.fn(), }, diff --git a/__tests__/test_background.ts b/__tests__/test_background.ts index 1cb3de3..49919bf 100644 --- a/__tests__/test_background.ts +++ b/__tests__/test_background.ts @@ -195,9 +195,9 @@ describe("handle button / hotkey / context menu", () => { test("invalid API token", async () => { await browser.storage.local.set({ joplinToken: "invalidToken" }); - browser.messageDisplay.getDisplayedMessages.mockResolvedValueOnce([ - { id: 0 }, - ]); + browser.mailTabs.getSelectedMessages.mockResolvedValueOnce({ + messages: [{ id: 0 }], + }); await getAndProcessMessages({ id: 0 }, {}); expect(browser.notifications.icon).toBe("../images/logo_96_red.png"); @@ -236,9 +236,9 @@ describe("handle button / hotkey / context menu", () => { // "{ id: 0 }" yields a successful export. // "null" triggers the error "Mail header is empty". - browser.messageDisplay.getDisplayedMessages.mockResolvedValueOnce( - exportSuccessful ? [{ id: 0 }] : [null] - ); + browser.mailTabs.getSelectedMessages.mockResolvedValueOnce({ + messages: exportSuccessful ? [{ id: 0 }] : [null], + }); await getAndProcessMessages({ id: 0 }, {}); @@ -277,9 +277,9 @@ describe("handle button / hotkey / context menu", () => { test("export by menu button", async () => { messenger.tabs.query.mockResolvedValueOnce([{ id: 1 }]); - browser.messageDisplay.getDisplayedMessages.mockResolvedValueOnce([ - { id: 1 }, - ]); + browser.mailTabs.getSelectedMessages.mockResolvedValueOnce({ + messages: [{ id: 1 }], + }); await handleMenuButton({ id: 1 }, { menuItemId: "export_to_joplin" }); @@ -293,9 +293,9 @@ describe("handle button / hotkey / context menu", () => { test("export by hotkey", async () => { messenger.tabs.query.mockResolvedValueOnce([{ id: 1 }]); - browser.messageDisplay.getDisplayedMessages.mockResolvedValueOnce([ - { id: 1 }, - ]); + browser.mailTabs.getSelectedMessages.mockResolvedValueOnce({ + messages: [{ id: 1 }], + }); await handleHotkey("export_to_joplin"); @@ -309,9 +309,9 @@ describe("handle button / hotkey / context menu", () => { test("export by context menu", async () => { messenger.tabs.query.mockResolvedValueOnce([{ id: 1 }]); - browser.messageDisplay.getDisplayedMessages.mockResolvedValueOnce([ - { id: 1 }, - ]); + browser.mailTabs.getSelectedMessages.mockResolvedValueOnce({ + messages: [{ id: 1 }], + }); await handleContextMenu({ menuItemId: "export_to_joplin" }, { id: 1 }); @@ -343,27 +343,7 @@ describe("handle displayed and selected mails", () => { test("no selected mail, one displayed mail", async () => { messenger.tabs.query.mockResolvedValueOnce([{ id: 1 }]); - browser.messageDisplay.getDisplayedMessages.mockResolvedValueOnce([ - { id: 1 }, - ]); - - await getAndProcessMessages({ id: 1 }, {}); - - expect(requests.length).toBe(1); - expectConsole({ - log: 1, - warn: 0, - error: 0, - }); - }); - - test("error at selected mail, one displayed mail", async () => { - messenger.tabs.query.mockResolvedValueOnce([{ id: 1 }]); - // This error gets thrown when querying the selected messages at a tab - // where are no messages selected. - browser.mailTabs.getSelectedMessages.mockImplementation(() => { - throw new Error(); - }); + browser.tabs.get.mockResolvedValueOnce({ type: "messageDisplay" }); browser.messageDisplay.getDisplayedMessages.mockResolvedValueOnce([ { id: 1 }, ]); diff --git a/manifest.json b/manifest.json index 64be384..1a07161 100644 --- a/manifest.json +++ b/manifest.json @@ -9,7 +9,7 @@ "gecko": { "id": "joplin-export@martin.doerfelt", "strict_min_version": "88.0", - "strict_max_version": "127.*" + "strict_max_version": "128.*" } }, "background": { diff --git a/src/background.ts b/src/background.ts index 4f4c44d..824f017 100644 --- a/src/background.ts +++ b/src/background.ts @@ -140,25 +140,32 @@ async function getAndProcessMessages(tab: { id: number }, info: any) { } } +async function getSelectedMessagesUnpaginated(tabId: number) { + let page = await browser.mailTabs.getSelectedMessages(tabId); + let messages = page.messages; + + while (page.id) { + page = await messenger.messages.continueList(page.id); + messages.push(...page.messages); + } + return messages; +} + async function getMessages(tabId: number) { - let messages = []; - try { - // Try to get selected messages when in the main mail tab. - const messageList = await browser.mailTabs.getSelectedMessages(tabId); - messages = messageList.messages; - if (messages.length === 0) { - console.debug( - "[Joplin Export] No selected messages. Try to get displayed messages." - ); + const tab = await browser.tabs.get(tabId); + let messages; + switch (tab.type) { + case "mail": + messages = await getSelectedMessagesUnpaginated(tabId); + break; + case "messageDisplay": messages = await browser.messageDisplay.getDisplayedMessages(tabId); - } - } catch (error: any) { - // Try to get a displayed message when in message tab. - console.debug( - `[Joplin Export] Error at selected messages (${error.message}). Try to get displayed messages.` - ); - messages = await browser.messageDisplay.getDisplayedMessages(tabId); + break; + default: + console.debug(`Unsupported tab type ${tab.type}.`); + messages = []; } + const logMessage = `[Joplin Export] Got ${messages.length} emails at tab ${tabId}.`; if (messages.length > 0) { console.debug(logMessage);