<!DOCTYPE html>
<title>Test that user activation propagation is fenced.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/common/utils.js"></script>
<script src="/common/dispatcher/dispatcher.js"></script>
<script src="resources/utils.js"></script>
<body>
<script>
// Simulate a click in frame context `frame`.
async function click(frame) {
var actions = new test_driver.Actions();
await actions.pointerMove(0, 0, {origin: frame})
.pointerDown()
.pointerUp()
.send();
}
assert_activation = (should_be_active, frame_name) => {
if (should_be_active) {
assert_true(navigator.userActivation.hasBeenActive,
frame_name + " has been activated.");
assert_true(navigator.userActivation.isActive,
frame_name + " is currently active.");
} else {
assert_false(navigator.userActivation.hasBeenActive,
frame_name + " has not been activated yet.");
assert_false(navigator.userActivation.isActive,
frame_name + " is not currently active.");
}
};
promise_test(async () => {
// This test ensures that user activations (e.g. click events) don't
// propagate across fenced frame boundaries. Specifically, activations
// are visible through the `navigator.userActivation` object.
//
// The layout of the page is as follows:
// A: top-level frame
// B: iframe
// C: fencedframe
// D: iframe
// E: fencedframe
//
// This order is chosen to test all kinds of fenced tree traversal. We:
// - Click in C and check that only C gets activated (not A, B, D, or E)
// - Click in A and check that only A, B, and D get activated (not E)
// - Click in B and D and check that E wasn't activated
const B = attachIFrameContext();
const C = attachFencedFrameContext();
const D = attachIFrameContext();
const E = attachFencedFrameContext();
// Define some helpers to check activations more concisely.
const frames = [[B, "B"], [C, "C"], [D, "D"], [E, "E"]];
const assert_activations = async (should_be_actives) => {
assert_equals(frames.length, should_be_actives.length);
for ([i, [frame, frame_name]] of frames.entries()) {
await frame.execute(assert_activation, [should_be_actives[i], frame_name]);
}
};
// Check that all the frames are inactive before we start.
assert_activation(false, "A");
await assert_activations([false/*B*/, false/*C*/, false/*D*/, false/*E*/]);
// Simulate a click in C (the first fenced frame).
await click(C.element);
// Check that only C has been activated.
assert_activation(false, "A");
await assert_activations([false/*B*/, true/*C*/, false/*D*/, false/*E*/]);
// Simulate a click in A (the top-level site).
await click(document.documentElement);
// Check that A, B, and D were activated.
assert_activation(true, "A");
await assert_activations([true/*B*/, true/*C*/, true/*D*/, false/*E*/]);
// Simulate a click in B and D (the two iframes).
await click(B.element);
await click(D.element);
// Check that E has still not been activated.
assert_activation(true, "A");
await assert_activations([true/*B*/, true/*C*/, true/*D*/, false/*E*/]);
}, 'user-activation');
</script>
</body>