<!DOCTYPE HTML>
<html>
<head>
  <title>User activation test: consume transient flag</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script src="/tests/SimpleTest/EventUtils.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe></iframe>
<iframe></iframe>
<script>

SimpleTest.requestFlakyTimeout("Timeouts are needed to test transient user_activation");

let timeout = SpecialPowers.getIntPref("dom.user_activation.transient.timeout") + 1000;

function waitForEvent(aTarget, aEvent, aCallback) {
  return new Promise((aResolve) => {
    aTarget.addEventListener(aEvent, function listener(event) {
      aCallback(event);
      aResolve();
    }, { once: true });
  });
}

function doCheck(aDocument, aName, aHasBeenUserGestureActivated,
                 aHasValidTransientUserGestureActivation,
                 aLastUserGestureTimeStamp) {
  is(SpecialPowers.wrap(aDocument).hasBeenUserGestureActivated,
     aHasBeenUserGestureActivated,
     `check has-been-user-activated on the ${aName}`);
  is(SpecialPowers.wrap(aDocument).hasValidTransientUserGestureActivation,
     aHasValidTransientUserGestureActivation,
     `check has-valid-transient-user-activation on the ${aName}`);
  is(SpecialPowers.wrap(aDocument).lastUserGestureTimeStamp,
     aLastUserGestureTimeStamp,
     `check last-user-gesture-timestamp on the ${aName}`);
}

add_task(async function checkInitialStatus() {
  doCheck(document, "top-level document", false, false, 0);
  ok(!SpecialPowers.wrap(document).consumeTransientUserGestureActivation(),
     "consume transient-user-activation on top-level document");

  doCheck(frames[0].document, "first iframe", false, false, 0);
  ok(!SpecialPowers.wrap(frames[0].document).consumeTransientUserGestureActivation(),
     "consume transient-user-activation on first iframe");

  doCheck(frames[1].document, "second iframe", false, false, 0);
  ok(!SpecialPowers.wrap(frames[1].document).consumeTransientUserGestureActivation(),
     "consume transient-user-activation on second iframe");
});

add_task(async function consumeTransientUserActivation() {
  // Trigger user activation on the first iframe.
  SpecialPowers.wrap(frames[0].document).notifyUserGestureActivation();
  let lastTimeStampTop = SpecialPowers.wrap(document).lastUserGestureTimeStamp;
  let lastTimeStampFirst = SpecialPowers.wrap(frames[0].document).lastUserGestureTimeStamp;

  // Try to consume transient user activation.
  ok(!SpecialPowers.wrap(frames[1].document).consumeTransientUserGestureActivation(),
     "consume transient-user-activation on second iframe");
  ok(SpecialPowers.wrap(frames[0].document).consumeTransientUserGestureActivation(),
     "consume transient-user-activation on first iframe");
  // Consuming a transient-user-activation should affect all tree.
  ok(!SpecialPowers.wrap(document).consumeTransientUserGestureActivation(),
     "consume transient-user-activation on top-level document");

  // Check has-valid-transient-user-activation and should not affect
  // has-been-user-activated
  doCheck(document, "top-level document", true, false, lastTimeStampTop);
  doCheck(frames[0].document, "first iframe", true, false, lastTimeStampFirst);
  doCheck(frames[1].document, "second iframe", false, false, 0);
});

add_task(async function consumeTransientUserActivationTimeout() {
  // Trigger user activation on the first iframe.
  SpecialPowers.wrap(frames[0].document).notifyUserGestureActivation();

  // Should not able to consume successfully after timeout.
  await new Promise((aResolve) => {
    setTimeout(() => {
      ok(!SpecialPowers.wrap(document).consumeTransientUserGestureActivation(),
         "consume transient-user-activation on top-level document");
      ok(!SpecialPowers.wrap(frames[0].document).consumeTransientUserGestureActivation(),
         "consume transient-user-activation on first iframe");
      ok(!SpecialPowers.wrap(frames[1].document).consumeTransientUserGestureActivation(),
         "consume transient-user-activation on second iframe");
      aResolve();
    }, timeout);
  });

  // Trigger user activation again.
  SpecialPowers.wrap(frames[0].document).notifyUserGestureActivation();

  // Try to consume transient user activation.
  ok(!SpecialPowers.wrap(frames[1].document).consumeTransientUserGestureActivation(),
     "consume transient-user-activation on second iframe");
  ok(SpecialPowers.wrap(frames[0].document).consumeTransientUserGestureActivation(),
     "consume transient-user-activation on first iframe");
  // Consuming a transient-user-activation should affect all tree.
  ok(!SpecialPowers.wrap(document).consumeTransientUserGestureActivation(),
     "consume transient-user-activation on top-level document");
});

add_task(async function iframeNavigation() {
  // Trigger user activation on the first iframe.
  SpecialPowers.wrap(frames[0].document).notifyUserGestureActivation();

  // Navigate away from current page.
  frames[0].frameElement.src = "file_empty.html";
  await waitForEvent(frames[0].frameElement, "load", () => {});

  // Try to consume transient user activation.
  ok(!SpecialPowers.wrap(frames[1].document).consumeTransientUserGestureActivation(),
     "consume transient-user-activation on second iframe");
  ok(!SpecialPowers.wrap(frames[0].document).consumeTransientUserGestureActivation(),
     "consume transient-user-activation on first iframe");
  ok(SpecialPowers.wrap(document).consumeTransientUserGestureActivation(),
     "consume transient-user-activation on top-level document");
});

add_task(async function triggerUserActivationOnCrossOriginFrame() {
  // Reset the activation flag.
  SpecialPowers.wrap(document).clearUserGestureActivation();

  // load cross-origin test page on iframe.
  frames[0].frameElement.src = "https://example.com/tests/dom/base/test/useractivation/file_iframe_consume_user_activation.html";
  await waitForEvent(window, "message", (event) => {
    if (event.data === "done") {
      ok(!SpecialPowers.wrap(document).consumeTransientUserGestureActivation(),
         "consume transient-user-activation on top-level document");
      ok(!SpecialPowers.wrap(document).hasValidTransientUserGestureActivation,
         "check has-valid-transient-user-activation on the top-level document");
      ok(!SpecialPowers.wrap(frames[1].document).hasValidTransientUserGestureActivation,
         "check has-valid-transient-user-activation on the second iframe");
    } else {
      ok(false, "receive unexpected message: " + event.data);
    }
  });
});

add_task(async function endTests() {
  // Reset the activation flag in order not to interfere following test in the
  // verify mode which would run the test using same document couple times.
  SpecialPowers.wrap(document).clearUserGestureActivation();
});

</script>
</body>
