/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* vim: set sts=2 sw=2 et tw=80: */ "use strict"; loadTestSubscript("head_pageAction.js"); add_task(async function testTabSwitchContext() { await runTests({ manifest: { name: "Foo Extension", page_action: { default_icon: "default.png", default_popup: "__MSG_popup__", default_title: "Default __MSG_title__ \u263a", }, default_locale: "en", permissions: ["tabs"], }, files: { "_locales/en/messages.json": { popup: { message: "default.html", description: "Popup", }, title: { message: "Title", description: "Title", }, }, "_locales/es_ES/messages.json": { popup: { message: "default.html", description: "Popup", }, title: { message: "T\u00edtulo", description: "Title", }, }, "default.png": imageBuffer, "1.png": imageBuffer, "2.png": imageBuffer, }, getTests: function (tabs) { let defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg"; let details = [ { icon: browser.runtime.getURL("default.png"), popup: browser.runtime.getURL("default.html"), title: "Default T\u00edtulo \u263a", }, { icon: browser.runtime.getURL("1.png"), popup: browser.runtime.getURL("default.html"), title: "Default T\u00edtulo \u263a", }, { icon: browser.runtime.getURL("2.png"), popup: browser.runtime.getURL("2.html"), title: "Title 2", }, { icon: defaultIcon, popup: "", title: "" }, ]; let promiseTabLoad = details => { return new Promise(resolve => { browser.tabs.onUpdated.addListener(function listener(tabId, changed) { if (tabId == details.id && changed.url == details.url) { browser.tabs.onUpdated.removeListener(listener); resolve(); } }); }); }; return [ expect => { browser.test.log("Initial state. No icon visible."); expect(null); }, async expect => { browser.test.log( "Show the icon on the first tab, expect default properties." ); await browser.pageAction.show(tabs[0]); expect(details[0]); }, expect => { browser.test.log( "Change the icon. Expect default properties excluding the icon." ); browser.pageAction.setIcon({ tabId: tabs[0], path: "1.png" }); expect(details[1]); }, async expect => { browser.test.log("Create a new tab. No icon visible."); let tab = await browser.tabs.create({ active: true, url: "about:blank?0", }); tabs.push(tab.id); expect(null); }, async expect => { browser.test.log("Await tab load. No icon visible."); let promise = promiseTabLoad({ id: tabs[1], url: "about:blank?0" }); let { url } = await browser.tabs.get(tabs[1]); if (url === "about:blank") { await promise; } expect(null); }, async expect => { browser.test.log("Change properties. Expect new properties."); let tabId = tabs[1]; await browser.pageAction.show(tabId); browser.pageAction.setIcon({ tabId, path: "2.png" }); browser.pageAction.setPopup({ tabId, popup: "2.html" }); browser.pageAction.setTitle({ tabId, title: "Title 2" }); expect(details[2]); }, async expect => { browser.test.log("Change the hash. Expect same properties."); let promise = promiseTabLoad({ id: tabs[1], url: "about:blank?0#ref", }); browser.tabs.update(tabs[1], { url: "about:blank?0#ref" }); await promise; expect(details[2]); }, expect => { browser.test.log( "Set empty string values. Expect empty strings but default icon." ); browser.pageAction.setIcon({ tabId: tabs[1], path: "" }); browser.pageAction.setPopup({ tabId: tabs[1], popup: "" }); browser.pageAction.setTitle({ tabId: tabs[1], title: "" }); expect(details[3]); }, expect => { browser.test.log("Clear the values. Expect default ones."); browser.pageAction.setIcon({ tabId: tabs[1], path: null }); browser.pageAction.setPopup({ tabId: tabs[1], popup: null }); browser.pageAction.setTitle({ tabId: tabs[1], title: null }); expect(details[0]); }, async expect => { browser.test.log("Navigate to a new page. Expect icon hidden."); // TODO: This listener should not be necessary, but the |tabs.update| // callback currently fires too early in e10s windows. let promise = promiseTabLoad({ id: tabs[1], url: "about:blank?1" }); browser.tabs.update(tabs[1], { url: "about:blank?1" }); await promise; expect(null); }, async expect => { browser.test.log("Show the icon. Expect default properties again."); await browser.pageAction.show(tabs[1]); expect(details[0]); }, async expect => { browser.test.log( "Switch back to the first tab. Expect previously set properties." ); await browser.tabs.update(tabs[0], { active: true }); expect(details[1]); }, async expect => { browser.test.log( "Hide the icon on tab 2. Switch back, expect hidden." ); await browser.pageAction.hide(tabs[1]); await browser.tabs.update(tabs[1], { active: true }); expect(null); }, async expect => { browser.test.log( "Switch back to tab 1. Expect previous results again." ); await browser.tabs.remove(tabs[1]); expect(details[1]); }, async expect => { browser.test.log("Hide the icon. Expect hidden."); await browser.pageAction.hide(tabs[0]); expect(null); }, async expect => { browser.test.assertRejects( browser.pageAction.setPopup({ tabId: tabs[0], popup: "about:addons", }), /Access denied for URL about:addons/, "unable to set popup to about:addons" ); expect(null); }, ]; }, }); }); add_task(async function testMultipleWindows() { // Disable newtab preloading, so that the tabs.create call below will always // trigger a new load that can be detected by webNavigation.onCompleted. await SpecialPowers.pushPrefEnv({ set: [["browser.newtab.preload", false]], }); await runTests({ manifest: { page_action: { default_icon: "default.png", default_popup: "default.html", default_title: "Default Title", }, permissions: ["webNavigation"], }, files: { "default.png": imageBuffer, "tab.png": imageBuffer, }, getTests: function (tabs, windows) { let details = [ { icon: browser.runtime.getURL("default.png"), popup: browser.runtime.getURL("default.html"), title: "Default Title", }, { icon: browser.runtime.getURL("tab.png"), popup: browser.runtime.getURL("tab.html"), title: "tab", }, ]; function promiseWebNavigationCompleted(url) { return new Promise(resolve => { // The pageAction visibility state is reset when the location changes. // The webNavigation.onCompleted event is triggered when that happens. browser.webNavigation.onCompleted.addListener( function listener() { browser.webNavigation.onCompleted.removeListener(listener); resolve(); }, { url: [{ urlEquals: url }], } ); }); } return [ async expect => { browser.test.log("Create a new tab, expect hidden pageAction."); let promise = promiseWebNavigationCompleted("about:newtab"); let tab = await browser.tabs.create({ active: true }); await promise; tabs.push(tab.id); expect(null); }, async expect => { browser.test.log("Show the pageAction, expect default values."); await browser.pageAction.show(tabs[1]); expect(details[0]); }, async expect => { browser.test.log("Set tab-specific values, expect them."); await browser.pageAction.setIcon({ tabId: tabs[1], path: "tab.png" }); await browser.pageAction.setPopup({ tabId: tabs[1], popup: "tab.html", }); await browser.pageAction.setTitle({ tabId: tabs[1], title: "tab" }); expect(details[1]); }, async expect => { browser.test.log("Open a new window, expect hidden pageAction."); let { id } = await browser.windows.create(); windows.push(id); expect(null); }, async expect => { browser.test.log( "Move tab from old window to the new one, expect old values." ); await browser.tabs.move(tabs[1], { windowId: windows[1], index: -1 }); await browser.tabs.update(tabs[1], { active: true }); expect(details[1]); }, async expect => { browser.test.log("Close the initial tab of the new window."); let [{ id }] = await browser.tabs.query({ windowId: windows[1], index: 0, }); await browser.tabs.remove(id); expect(details[1]); }, async expect => { browser.test.log( "Move the previous tab to a 3rd window, the 2nd one will close." ); await browser.windows.create({ tabId: tabs[1] }); expect(details[1]); }, async expect => { browser.test.log("Close the tab, go back to the 1st window."); await browser.tabs.remove(tabs[1]); expect(null); }, ]; }, }); await SpecialPowers.popPrefEnv(); }); add_task(async function testNavigationClearsData() { let url = "http://example.com/"; let default_title = "Default title"; let tab_title = "Tab title"; const { Management: { global: { tabTracker }, }, } = ChromeUtils.importESModule("resource://gre/modules/Extension.sys.mjs"); let extension, tabs = []; async function addTab(...args) { let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, ...args); tabs.push(tab); return tab; } async function sendMessage(method, param, expect, msg) { extension.sendMessage({ method, param, expect, msg }); await extension.awaitMessage("done"); } async function expectTabSpecificData(tab, msg) { let tabId = tabTracker.getId(tab); await sendMessage("isShown", { tabId }, true, msg); await sendMessage("getTitle", { tabId }, tab_title, msg); } async function expectDefaultData(tab, msg) { let tabId = tabTracker.getId(tab); await sendMessage("isShown", { tabId }, false, msg); await sendMessage("getTitle", { tabId }, default_title, msg); } async function setTabSpecificData(tab) { let tabId = tabTracker.getId(tab); await expectDefaultData( tab, "Expect default data before setting tab-specific data." ); await sendMessage("show", tabId); await sendMessage("setTitle", { tabId, title: tab_title }); await expectTabSpecificData( tab, "Expect tab-specific data after setting it." ); } info("Load a tab before installing the extension"); let tab1 = await addTab(url, true, true); extension = ExtensionTestUtils.loadExtension({ manifest: { page_action: { default_title }, }, background: function () { browser.test.onMessage.addListener( async ({ method, param, expect, msg }) => { let result = await browser.pageAction[method](param); if (expect !== undefined) { browser.test.assertEq(expect, result, msg); } browser.test.sendMessage("done"); } ); }, }); await extension.startup(); info("Set tab-specific data to the existing tab."); await setTabSpecificData(tab1); info("Add a hash. Does not cause navigation."); await navigateTab(tab1, url + "#hash"); await expectTabSpecificData( tab1, "Adding a hash does not clear tab-specific data" ); info("Remove the hash. Causes navigation."); await navigateTab(tab1, url); await expectDefaultData(tab1, "Removing hash clears tab-specific data"); info("Open a new tab, set tab-specific data to it."); let tab2 = await addTab("about:newtab", false, false); await setTabSpecificData(tab2); info("Load a page in that tab."); await navigateTab(tab2, url); await expectDefaultData(tab2, "Loading a page clears tab-specific data."); info("Set tab-specific data."); await setTabSpecificData(tab2); info("Push history state. Does not cause navigation."); await historyPushState(tab2, url + "/path"); await expectTabSpecificData( tab2, "history.pushState() does not clear tab-specific data" ); info("Navigate when the tab is not selected"); gBrowser.selectedTab = tab1; await navigateTab(tab2, url); await expectDefaultData( tab2, "Navigating clears tab-specific data, even when not selected." ); for (let tab of tabs) { BrowserTestUtils.removeTab(tab); } await extension.unload(); });