summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/siteIdentity/browser_geolocation_indicator.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/test/siteIdentity/browser_geolocation_indicator.js')
-rw-r--r--browser/base/content/test/siteIdentity/browser_geolocation_indicator.js381
1 files changed, 381 insertions, 0 deletions
diff --git a/browser/base/content/test/siteIdentity/browser_geolocation_indicator.js b/browser/base/content/test/siteIdentity/browser_geolocation_indicator.js
new file mode 100644
index 0000000000..078b7ab975
--- /dev/null
+++ b/browser/base/content/test/siteIdentity/browser_geolocation_indicator.js
@@ -0,0 +1,381 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+const { PermissionUI } = ChromeUtils.importESModule(
+ "resource:///modules/PermissionUI.sys.mjs"
+);
+
+const { PermissionTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/PermissionTestUtils.sys.mjs"
+);
+
+const CP = Cc["@mozilla.org/content-pref/service;1"].getService(
+ Ci.nsIContentPrefService2
+);
+
+const EXAMPLE_PAGE_URL = "https://example.com";
+const EXAMPLE_PAGE_URI = Services.io.newURI(EXAMPLE_PAGE_URL);
+const EXAMPLE_PAGE_PRINCIPAL =
+ Services.scriptSecurityManager.createContentPrincipal(EXAMPLE_PAGE_URI, {});
+const GEO_CONTENT_PREF_KEY = "permissions.geoLocation.lastAccess";
+const POLL_INTERVAL_FALSE_STATE = 50;
+
+async function testGeoSharingIconVisible(state = true) {
+ let sharingIcon = document.getElementById("geo-sharing-icon");
+ ok(sharingIcon, "Geo sharing icon exists");
+
+ try {
+ await TestUtils.waitForCondition(
+ () => sharingIcon.hasAttribute("sharing") === true,
+ "Waiting for geo sharing icon visibility state",
+ // If we wait for sharing icon to *not* show, waitForCondition will always timeout on correct state.
+ // In these cases we want to reduce the wait time from 5 seconds to 2.5 seconds to prevent test duration timeouts
+ !state ? POLL_INTERVAL_FALSE_STATE : undefined
+ );
+ } catch (e) {
+ ok(!state, "Geo sharing icon not showing");
+ return;
+ }
+ ok(state, "Geo sharing icon showing");
+}
+
+async function checkForDOMElement(state, id) {
+ info(`Testing state ${state} of element ${id}`);
+ let el;
+ try {
+ await TestUtils.waitForCondition(
+ () => {
+ el = document.getElementById(id);
+ return el != null;
+ },
+ `Waiting for ${id}`,
+ !state ? POLL_INTERVAL_FALSE_STATE : undefined
+ );
+ } catch (e) {
+ ok(!state, `${id} has correct state`);
+ return el;
+ }
+ ok(state, `${id} has correct state`);
+
+ return el;
+}
+
+async function testPermissionPopupGeoContainer(
+ containerVisible,
+ timestampVisible
+) {
+ // The container holds the timestamp element, therefore we can't have a
+ // visible timestamp without the container.
+ if (timestampVisible && !containerVisible) {
+ ok(false, "Can't have timestamp without container");
+ }
+
+ // Only call openPermissionPopup if popup is closed, otherwise it does not resolve
+ if (!gPermissionPanel._identityPermissionBox.hasAttribute("open")) {
+ await openPermissionPopup();
+ }
+
+ let checkContainer = checkForDOMElement(
+ containerVisible,
+ "permission-popup-geo-container"
+ );
+
+ if (containerVisible && timestampVisible) {
+ // Wait for the geo container to be fully populated.
+ // The time label is computed async.
+ let container = await checkContainer;
+ await TestUtils.waitForCondition(
+ () => container.childElementCount == 2,
+ "permission-popup-geo-container should have two elements."
+ );
+ is(
+ container.childNodes[0].classList[0],
+ "permission-popup-permission-item",
+ "Geo container should have permission item."
+ );
+ is(
+ container.childNodes[1].id,
+ "geo-access-indicator-item",
+ "Geo container should have indicator item."
+ );
+ }
+ let checkAccessIndicator = checkForDOMElement(
+ timestampVisible,
+ "geo-access-indicator-item"
+ );
+
+ return Promise.all([checkContainer, checkAccessIndicator]);
+}
+
+function openExamplePage(tabbrowser = gBrowser) {
+ return BrowserTestUtils.openNewForegroundTab(tabbrowser, EXAMPLE_PAGE_URL);
+}
+
+function requestGeoLocation(browser) {
+ return SpecialPowers.spawn(browser, [], () => {
+ return new Promise(resolve => {
+ content.navigator.geolocation.getCurrentPosition(
+ () => resolve(true),
+ error => resolve(error.code !== 1) // PERMISSION_DENIED = 1
+ );
+ });
+ });
+}
+
+function answerGeoLocationPopup(allow, remember = false) {
+ let notification = PopupNotifications.getNotification("geolocation");
+ ok(
+ PopupNotifications.isPanelOpen && notification,
+ "Geolocation notification is open"
+ );
+
+ let rememberCheck = PopupNotifications.panel.querySelector(
+ ".popup-notification-checkbox"
+ );
+ rememberCheck.checked = remember;
+
+ let popupHidden = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphidden"
+ );
+ if (allow) {
+ let allowBtn = PopupNotifications.panel.querySelector(
+ ".popup-notification-primary-button"
+ );
+ allowBtn.click();
+ } else {
+ let denyBtn = PopupNotifications.panel.querySelector(
+ ".popup-notification-secondary-button"
+ );
+ denyBtn.click();
+ }
+ return popupHidden;
+}
+
+function setGeoLastAccess(browser, state) {
+ return new Promise(resolve => {
+ let host = browser.currentURI.host;
+ let handler = {
+ handleCompletion: () => resolve(),
+ };
+
+ if (!state) {
+ CP.removeByDomainAndName(
+ host,
+ GEO_CONTENT_PREF_KEY,
+ browser.loadContext,
+ handler
+ );
+ return;
+ }
+ CP.set(
+ host,
+ GEO_CONTENT_PREF_KEY,
+ new Date().toString(),
+ browser.loadContext,
+ handler
+ );
+ });
+}
+
+async function testGeoLocationLastAccessSet(browser) {
+ let timestamp = await new Promise(resolve => {
+ let lastAccess = null;
+ CP.getByDomainAndName(
+ gBrowser.currentURI.spec,
+ GEO_CONTENT_PREF_KEY,
+ browser.loadContext,
+ {
+ handleResult(pref) {
+ lastAccess = pref.value;
+ },
+ handleCompletion() {
+ resolve(lastAccess);
+ },
+ }
+ );
+ });
+
+ ok(timestamp != null, "Geo last access timestamp set");
+
+ let parseSuccess = true;
+ try {
+ timestamp = new Date(timestamp);
+ } catch (e) {
+ parseSuccess = false;
+ }
+ ok(
+ parseSuccess && !isNaN(timestamp),
+ "Geo last access timestamp is valid Date"
+ );
+}
+
+async function cleanup(tab) {
+ await setGeoLastAccess(tab.linkedBrowser, false);
+ SitePermissions.removeFromPrincipal(
+ tab.linkedBrowser.contentPrincipal,
+ "geo",
+ tab.linkedBrowser
+ );
+ gBrowser.resetBrowserSharing(tab.linkedBrowser);
+ BrowserTestUtils.removeTab(tab);
+}
+
+async function testIndicatorGeoSharingState(active) {
+ let tab = await openExamplePage();
+ gBrowser.updateBrowserSharing(tab.linkedBrowser, { geo: active });
+ await testGeoSharingIconVisible(active);
+
+ await cleanup(tab);
+}
+
+async function testIndicatorExplicitAllow(persistent) {
+ let tab = await openExamplePage();
+
+ let popupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+ info("Requesting geolocation");
+ let request = requestGeoLocation(tab.linkedBrowser);
+ await popupShown;
+ info("Allowing geolocation via popup");
+ answerGeoLocationPopup(true, persistent);
+ await request;
+
+ await Promise.all([
+ testGeoSharingIconVisible(true),
+ testPermissionPopupGeoContainer(true, true),
+ testGeoLocationLastAccessSet(tab.linkedBrowser),
+ ]);
+
+ await cleanup(tab);
+}
+
+// Indicator and permission popup entry shown after explicit PermissionUI geolocation allow
+add_task(function test_indicator_and_timestamp_after_explicit_allow() {
+ return testIndicatorExplicitAllow(false);
+});
+add_task(function test_indicator_and_timestamp_after_explicit_allow_remember() {
+ return testIndicatorExplicitAllow(true);
+});
+
+// Indicator and permission popup entry shown after auto PermissionUI geolocation allow
+add_task(async function test_indicator_and_timestamp_after_implicit_allow() {
+ PermissionTestUtils.add(
+ EXAMPLE_PAGE_URI,
+ "geo",
+ Services.perms.ALLOW_ACTION,
+ Services.perms.EXPIRE_NEVER
+ );
+ let tab = await openExamplePage();
+ let result = await requestGeoLocation(tab.linkedBrowser);
+ ok(result, "Request should be allowed");
+
+ await Promise.all([
+ testGeoSharingIconVisible(true),
+ testPermissionPopupGeoContainer(true, true),
+ testGeoLocationLastAccessSet(tab.linkedBrowser),
+ ]);
+
+ await cleanup(tab);
+});
+
+// Indicator shown when manually setting sharing state to true
+add_task(function test_indicator_sharing_state_active() {
+ return testIndicatorGeoSharingState(true);
+});
+
+// Indicator not shown when manually setting sharing state to false
+add_task(function test_indicator_sharing_state_inactive() {
+ return testIndicatorGeoSharingState(false);
+});
+
+// Permission popup shows permission if geo permission is set to persistent allow
+add_task(async function test_permission_popup_permission_scope_permanent() {
+ PermissionTestUtils.add(
+ EXAMPLE_PAGE_URI,
+ "geo",
+ Services.perms.ALLOW_ACTION,
+ Services.perms.EXPIRE_NEVER
+ );
+ let tab = await openExamplePage();
+
+ await testPermissionPopupGeoContainer(true, false); // Expect permission to be visible, but not lastAccess indicator
+
+ await cleanup(tab);
+});
+
+// Sharing state set, but no permission
+add_task(async function test_permission_popup_permission_sharing_state() {
+ let tab = await openExamplePage();
+ gBrowser.updateBrowserSharing(tab.linkedBrowser, { geo: true });
+ await testPermissionPopupGeoContainer(true, false);
+
+ await cleanup(tab);
+});
+
+// Permission popup has correct state if sharing state and last geo access timestamp are set
+add_task(
+ async function test_permission_popup_permission_sharing_state_timestamp() {
+ let tab = await openExamplePage();
+ gBrowser.updateBrowserSharing(tab.linkedBrowser, { geo: true });
+ await setGeoLastAccess(tab.linkedBrowser, true);
+
+ await testPermissionPopupGeoContainer(true, true);
+
+ await cleanup(tab);
+ }
+);
+
+// Clicking permission clear button clears permission and resets geo sharing state
+add_task(async function test_permission_popup_permission_clear() {
+ PermissionTestUtils.add(
+ EXAMPLE_PAGE_URI,
+ "geo",
+ Services.perms.ALLOW_ACTION,
+ Services.perms.EXPIRE_NEVER
+ );
+ let tab = await openExamplePage();
+ gBrowser.updateBrowserSharing(tab.linkedBrowser, { geo: true });
+
+ await openPermissionPopup();
+
+ let clearButton = document.querySelector(
+ "#permission-popup-geo-container button"
+ );
+ ok(clearButton, "Clear button is visible");
+ clearButton.click();
+
+ await Promise.all([
+ testGeoSharingIconVisible(false),
+ testPermissionPopupGeoContainer(false, false),
+ TestUtils.waitForCondition(() => {
+ let sharingState = tab._sharingState;
+ return (
+ sharingState == null ||
+ sharingState.geo == null ||
+ sharingState.geo === false
+ );
+ }, "Waiting for geo sharing state to reset"),
+ ]);
+ await cleanup(tab);
+});
+
+/**
+ * Tests that we only show the last access label once when the sharing
+ * state is updated multiple times while the popup is open.
+ */
+add_task(async function test_permission_no_duplicate_last_access_label() {
+ let tab = await openExamplePage();
+ await setGeoLastAccess(tab.linkedBrowser, true);
+ await openPermissionPopup();
+ gBrowser.updateBrowserSharing(tab.linkedBrowser, { geo: true });
+ gBrowser.updateBrowserSharing(tab.linkedBrowser, { geo: true });
+ await testPermissionPopupGeoContainer(true, true);
+ await cleanup(tab);
+});