Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/browser/base/content/test/popupNotifications/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 11 kB image not shown  

Quelle  head.js   Sprache: JAVA

 
ChromeUtils.defineESModuleGetters(this, {
  PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
});

/**
 * Called after opening a new window or switching windows, this will wait until
 * we are sure that an attempt to display a notification will not fail.
 */

async function waitForWindowReadyForPopupNotifications(win) {
  // These are the same checks that PopupNotifications.sys.mjs makes before it
  // allows a notification to open.
  await TestUtils.waitForCondition(
    () => win.gBrowser.selectedBrowser.docShellIsActive,
    "The browser should be active"
  );
  await TestUtils.waitForCondition(
    () => Services.focus.activeWindow == win,
    "The window should be active"
  );
}

/**
 * Waits for a load (or custom) event to finish in a given tab. If provided
 * load an uri into the tab.
 *
 * @param tab
 *        The tab to load into.
 * @param [optional] url
 *        The url to load, or the current url.
 * @return {Promise} resolved when the event is handled.
 * @resolves to the received event
 * @rejects if a valid load event is not received within a meaningful interval
 */

function promiseTabLoadEvent(tab, url) {
  let browser = tab.linkedBrowser;

  if (url) {
    BrowserTestUtils.startLoadingURIString(browser, url);
  }

  return BrowserTestUtils.browserLoaded(browser, false, url);
}

// Tests that call setup() should have a `tests` array defined for the actual
// tests to be run.
/* global tests */
function setup() {
  // eslint-disable-next-line @microsoft/sdl/no-insecure-url
  BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/").then(
    goNext
  );
  registerCleanupFunction(() => {
    gBrowser.removeTab(gBrowser.selectedTab);
  });
}

function goNext() {
  executeSoon(() => executeSoon(runNextTest));
}

async function runNextTest() {
  if (!tests.length) {
    executeSoon(finish);
    return;
  }

  let nextTest = tests.shift();
  if (nextTest.onShown) {
    let shownState = false;
    onPopupEvent("popupshowing"function () {
      info("[" + nextTest.id + "] popup showing");
    });
    onPopupEvent("popupshown"function () {
      shownState = true;
      info("[" + nextTest.id + "] popup shown");
      (nextTest.onShown(this) || Promise.resolve()).then(undefined, ex =>
        Assert.ok(false"onShown failed: " + ex)
      );
    });
    onPopupEvent(
      "popuphidden",
      function () {
        info("[" + nextTest.id + "] popup hidden");
        (nextTest.onHidden(this) || Promise.resolve()).then(
          () => goNext(),
          ex => Assert.ok(false"onHidden failed: " + ex)
        );
      },
      () => shownState
    );
    info(
      "[" +
        nextTest.id +
        "] added listeners; panel is open: " +
        PopupNotifications.isPanelOpen
    );
  }

  info("[" + nextTest.id + "] running test");
  await nextTest.run();
}

function showNotification(notifyObj) {
  info("Showing notification " + notifyObj.id);
  return PopupNotifications.show(
    notifyObj.browser,
    notifyObj.id,
    notifyObj.message,
    notifyObj.anchorID,
    notifyObj.mainAction,
    notifyObj.secondaryActions,
    notifyObj.options
  );
}

function dismissNotification(popup) {
  info("Dismissing notification " + popup.childNodes[0].id);
  executeSoon(() => EventUtils.synthesizeKey("KEY_Escape"));
}

function BasicNotification(testId) {
  this.browser = gBrowser.selectedBrowser;
  this.id = "test-notification-" + testId;
  this.message = testId + ": Will you allow <> to perform this action?";
  this.anchorID = null;
  this.mainAction = {
    label: "Main Action",
    accessKey: "M",
    callback: ({ source }) => {
      this.mainActionClicked = true;
      this.mainActionSource = source;
    },
  };
  this.secondaryActions = [
    {
      label: "Secondary Action",
      accessKey: "S",
      callback: ({ source }) => {
        this.secondaryActionClicked = true;
        this.secondaryActionSource = source;
      },
    },
  ];
  this.options = {
    // eslint-disable-next-line @microsoft/sdl/no-insecure-url
    name: "http://example.com",
    eventCallback: eventName => {
      switch (eventName) {
        case "dismissed":
          this.dismissalCallbackTriggered = true;
          break;
        case "showing":
          this.showingCallbackTriggered = true;
          break;
        case "shown":
          this.shownCallbackTriggered = true;
          break;
        case "removed":
          this.removedCallbackTriggered = true;
          break;
        case "swapping":
          this.swappingCallbackTriggered = true;
          break;
      }
    },
  };
}

BasicNotification.prototype.addOptions = function (options) {
  for (let [name, value] of Object.entries(options)) {
    this.options[name] = value;
  }
};

function ErrorNotification(testId) {
  BasicNotification.call(this, testId);
  this.mainAction.callback = () => {
    this.mainActionClicked = true;
    throw new Error("Oops!");
  };
  this.secondaryActions[0].callback = () => {
    this.secondaryActionClicked = true;
    throw new Error("Oops!");
  };
}

ErrorNotification.prototype = BasicNotification.prototype;

function checkPopup(popup, notifyObj) {
  info("Checking notification " + notifyObj.id);

  ok(notifyObj.showingCallbackTriggered, "showing callback was triggered");
  ok(notifyObj.shownCallbackTriggered, "shown callback was triggered");

  let notifications = popup.childNodes;
  is(notifications.length, 1, "one notification displayed");
  let notification = notifications[0];
  if (!notification) {
    return;
  }

  // PopupNotifications are not expected to show icons
  // unless popupIconURL or popupIconClass is passed in the options object.
  if (notifyObj.options.popupIconURL || notifyObj.options.popupIconClass) {
    let icon = notification.querySelector(".popup-notification-icon");
    if (notifyObj.id == "geolocation") {
      isnot(icon.getBoundingClientRect().width, 0, "icon for geo displayed");
      ok(
        popup.anchorNode.classList.contains("notification-anchor-icon"),
        "notification anchored to icon"
      );
    }
  }

  let description = notifyObj.message.split("<>");
  let text = {};
  text.start = description[0];
  text.end = description[1];
  is(notification.getAttribute("label"), text.start, "message matches");
  is(
    notification.getAttribute("name"),
    notifyObj.options.name,
    "message matches"
  );
  is(notification.getAttribute("endlabel"), text.end, "message matches");

  is(notification.id, notifyObj.id + "-notification""id matches");
  if (notifyObj.mainAction) {
    is(
      notification.getAttribute("buttonlabel"),
      notifyObj.mainAction.label,
      "main action label matches"
    );
    is(
      notification.getAttribute("buttonaccesskey"),
      notifyObj.mainAction.accessKey,
      "main action accesskey matches"
    );
  }
  if (notifyObj.secondaryActions && notifyObj.secondaryActions.length) {
    let secondaryAction = notifyObj.secondaryActions[0];
    is(
      notification.getAttribute("secondarybuttonlabel"),
      secondaryAction.label,
      "secondary action label matches"
    );
    is(
      notification.getAttribute("secondarybuttonaccesskey"),
      secondaryAction.accessKey,
      "secondary action accesskey matches"
    );
  }
  // Additional secondary actions appear as menu items.
  let actualExtraSecondaryActions = Array.prototype.filter.call(
    notification.menupopup.childNodes,
    child => child.nodeName == "menuitem"
  );
  let extraSecondaryActions = notifyObj.secondaryActions
    ? notifyObj.secondaryActions.slice(1)
    : [];
  is(
    actualExtraSecondaryActions.length,
    extraSecondaryActions.length,
    "number of extra secondary actions matches"
  );
  extraSecondaryActions.forEach(function (a, i) {
    is(
      actualExtraSecondaryActions[i].getAttribute("label"),
      a.label,
      "label for extra secondary action " + i + " matches"
    );
    is(
      actualExtraSecondaryActions[i].getAttribute("accesskey"),
      a.accessKey,
      "accessKey for extra secondary action " + i + " matches"
    );
  });
}

ChromeUtils.defineLazyGetter(this"gActiveListeners", () => {
  let listeners = new Map();
  registerCleanupFunction(() => {
    for (let [listener, eventName] of listeners) {
      PopupNotifications.panel.removeEventListener(eventName, listener);
    }
  });
  return listeners;
});

function onPopupEvent(eventName, callback, condition) {
  let listener = event => {
    if (
      event.target != PopupNotifications.panel ||
      (condition && !condition())
    ) {
      return;
    }
    PopupNotifications.panel.removeEventListener(eventName, listener);
    gActiveListeners.delete(listener);
    executeSoon(() => callback.call(PopupNotifications.panel));
  };
  gActiveListeners.set(listener, eventName);
  PopupNotifications.panel.addEventListener(eventName, listener);
}

function waitForNotificationPanel() {
  return new Promise(resolve => {
    onPopupEvent("popupshown"function () {
      resolve(this);
    });
  });
}

function waitForNotificationPanelHidden() {
  return new Promise(resolve => {
    onPopupEvent("popuphidden"function () {
      resolve(this);
    });
  });
}

function triggerMainCommand(popup) {
  let notifications = popup.childNodes;
  ok(!!notifications.length, "at least one notification displayed");
  let notification = notifications[0];
  info("Triggering main command for notification " + notification.id);
  EventUtils.synthesizeMouseAtCenter(notification.button, {});
}

function triggerSecondaryCommand(popup, index) {
  let notifications = popup.childNodes;
  ok(!!notifications.length, "at least one notification displayed");
  let notification = notifications[0];
  info("Triggering secondary command for notification " + notification.id);

  if (index == 0) {
    EventUtils.synthesizeMouseAtCenter(notification.secondaryButton, {});
    return;
  }

  // Extra secondary actions appear in a menu.
  notification.secondaryButton.nextElementSibling.focus();

  popup.addEventListener(
    "popupshown",
    function () {
      info("Command popup open for notification " + notification.id);
      // Press down until the desired command is selected. Decrease index by one
      // since the secondary action was handled above.
      for (let i = 0; i <= index - 1; i++) {
        EventUtils.synthesizeKey("KEY_ArrowDown");
      }
      // Activate
      EventUtils.synthesizeKey("KEY_Enter");
    },
    { once: true }
  );

  // One down event to open the popup
  info(
    "Open the popup to trigger secondary command for notification " +
      notification.id
  );
  EventUtils.synthesizeKey("KEY_ArrowDown", {
    altKey: !navigator.platform.includes("Mac"),
  });
}

/**
 * The security delay calculation in PopupNotification.sys.mjs is dependent on
 * the monotonically increasing value of Cu.now. This timestamp is
 * not relative to a fixed date, but to runtime.
 * We need to wait for the value Cu.now() to be larger than the
 * security delay in order to observe the bug. Only then does the
 * timeSinceShown check in PopupNotifications.sys.mjs lead to a timeSinceShown
 * value that is unconditionally greater than lazy.buttonDelay for
 * notification.timeShown = null = 0.
 * See: https://searchfox.org/mozilla-central/rev/f32d5f3949a3f4f185122142b29f2e3ab776836e/toolkit/modules/PopupNotifications.sys.mjs#1870-1872
 *
 * When running in automation as part of a larger test suite Cu.now()
 * should usually be already sufficiently high in which case this check should
 * directly resolve.
 */

async function ensureSecurityDelayReady(timeNewWindowOpened = 0) {
  let secDelay = Services.prefs.getIntPref(
    "security.notification_enable_delay"
  );

  await TestUtils.waitForCondition(
    () => Cu.now() - timeNewWindowOpened > secDelay,
    "Wait for performance.now() > SECURITY_DELAY",
    500,
    50
  );
}

Messung V0.5
C=95 H=86 G=90

¤ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.