-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix flaky consumption-sameorigin.html iframe loading #36304
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,7 +26,7 @@ | |
assert_false(navigator.userActivation.hasBeenActive); | ||
}, "Parent frame initial state"); | ||
|
||
test_driver.click(document.getElementById("child-so")); | ||
return test_driver.click(document.getElementById("child-so")); | ||
} | ||
|
||
function finishReportPhase() { | ||
|
@@ -40,7 +40,7 @@ | |
consumption_test.done(); | ||
} | ||
|
||
window.addEventListener("message", event => { | ||
window.addEventListener("message", async event => { | ||
var msg = JSON.parse(event.data); | ||
|
||
if (msg.type == 'child-one-loaded') { | ||
|
@@ -84,25 +84,32 @@ | |
// Phase switching. | ||
if (msg.type.endsWith("-loaded")) { | ||
if (--num_children_to_load == 0) | ||
finishLoadPhase(); | ||
await finishLoadPhase(); | ||
} else if (msg.type.endsWith("-report")) { | ||
if (--num_children_to_report == 0) | ||
finishReportPhase(); | ||
} | ||
}); | ||
async function createIframes() { | ||
const child1 = document.createElement("iframe"); | ||
child1.src = "resources/child-one.html"; | ||
child1.id = "child1"; | ||
document.body.appendChild(child1); | ||
|
||
await new Promise((resolve) => (child1.onload = resolve)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would be more correct, yes. However, my testing this on a few hundred runs seems to confirm it's fine (all that is needed here is that the child1 loads first). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're misreading that note @mustaqahmed. That's just about event propagation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Questions for @annevk: Does the dispatching algorithm enforce a "load" event order across a frame boundary (even with a possibly slow cross-origin frame)? I am asking because a "yes" here means the test could be simpler because it would be sufficient to wait for only the top There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's correct. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mustaqahmed, can you help me understand what cause the consumption of the user activation here? I'd still prefer not to rewrite the test if I can avoid it. However, if I flatten the test to: async function runTest() {
promise_test(async (t) => {
const child1 = document.getElementById("child1");
const child1Activation = child1.contentWindow.navigator.userActivation;
const child2 = document.getElementById("child2");
const child2Activation = child2.contentWindow.navigator.userActivation;
const grandChild = child2.contentDocument.getElementById("grandchild");
const grandChildActivation = grandChild.contentWindow.navigator.userActivation;
assert_false(navigator.userActivation.isActive, "Parent frame isActive initial state");
assert_false(navigator.userActivation.hasBeenActive, "Parent frame hasBeenActive initial state");
assert_false(child1Activation.isActive, "Child1 frame isActive initial state");
assert_false(child1Activation.hasBeenActive, "Child1 frame hasBeenActive initial state");
assert_false(child2Activation.isActive, "Child2 frame isActive initial state");
assert_false(child2Activation.hasBeenActive, "Child2 frame hasBeenActive initial state");
assert_false(grandChildActivation.isActive, "Grandchild frame isActive initial state");
assert_false(grandChildActivation.hasBeenActive, "Grandchild frame hasBeenActive initial state");
await test_driver.bless("click", null, child1.contentWindow);
assert_true(navigator.userActivation.isActive, "Parent frame isActive after click");
assert_true(navigator.userActivation.hasBeenActive, "Parent frame hasBeenActive after click");
assert_true(child1Activation.isActive, "Child1 frame isActive after click");
assert_true(child1Activation.hasBeenActive, "Child1 frame hasBeenActive after click");
assert_true(child2Activation.isActive, "Child2 frame isActive after click");
assert_true(child2Activation.hasBeenActive, "Child2 frame hasBeenActive after click");
assert_true(grandChildActivation.isActive, "Grandchild frame isActive after click");
assert_true(grandChildActivation.hasBeenActive, "Grandchild frame hasBeenActive after click");
});
} I get different results? I can't see anything in the iframes that consume the user activation? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We shouldn't get a different result, because a consumption call affects the whole frame tree. Could you please elaborate which assertions are different between flattened vs un-flattened frame load code? Is there a chance test_driver implementation is causing the flake here? This same-origin test is not flaky in Chrome's internal bots, but the cross-origin one is flaky and we can't fix that because of a test_driver impl limitation. In any case, I think a virtual meeting would be more efficient here to share our thoughts. Let's plan one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Oh, wait! But the test again does something non-standard: window.open().close(); That shouldn't consume the user activation: at least, there is nothing in HTML saying that either The flattened version should be this (all false, click(), all true): async function runTest() {
promise_test(async (t) => {
const child1 = document.getElementById("child1");
const child1Activation = child1.contentWindow.navigator.userActivation;
const child2 = document.getElementById("child2");
const child2Activation = child2.contentWindow.navigator.userActivation;
const grandChild = child2.contentDocument.getElementById("grandchild");
const grandChildActivation = grandChild.contentWindow.navigator.userActivation;
assert_false(navigator.userActivation.isActive, "Parent frame isActive initial state");
assert_false(navigator.userActivation.hasBeenActive, "Parent frame hasBeenActive initial state");
assert_false(child1Activation.isActive, "Child1 frame isActive initial state");
assert_false(child1Activation.hasBeenActive, "Child1 frame hasBeenActive initial state");
assert_false(child2Activation.isActive, "Child2 frame isActive initial state");
assert_false(child2Activation.hasBeenActive, "Child2 frame hasBeenActive initial state");
assert_false(grandChildActivation.isActive, "Grandchild frame isActive initial state");
assert_false(grandChildActivation.hasBeenActive, "Grandchild frame hasBeenActive initial state");
await test_driver.bless("click", null, child1.contentWindow);
assert_true(navigator.userActivation.isActive, "Parent frame isActive after click");
assert_true(navigator.userActivation.hasBeenActive, "Parent frame hasBeenActive after click");
assert_true(child1Activation.isActive, "Child1 frame isActive after click");
assert_true(child1Activation.hasBeenActive, "Child1 frame hasBeenActive after click");
assert_true(child2Activation.isActive, "Child2 frame isActive after click");
assert_true(child2Activation.hasBeenActive, "Child2 frame hasBeenActive after click");
assert_true(grandChildActivation.isActive, "Grandchild frame isActive after click");
assert_true(grandChildActivation.hasBeenActive, "Grandchild frame hasBeenActive after click");
});
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Happy to chat, but I think the biggest points of contention are that we don't have a consistent way of consuming the user activation. So far, the tests have used two non-standard ways to try to consume it:
We should also avoid I'm thinking we should remove or "-tentative" such tests until we have an actual solution to prevent codifying non-standard behavior. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
const childSO = document.createElement("iframe"); | ||
childSO.id = "child-so"; | ||
childSO.src = "resources/consumption-sameorigin-child.html"; | ||
document.body.appendChild(childSO); | ||
await new Promise((resolve) => (childSO.onload = resolve)); | ||
marcoscaceres marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like we are still relying on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed this line. There is no need to await for it to load. What matters is just that the first iframe loads in order. I've made similar changes to all the other dual iframe tests. I'll have them re-viewed upstream as part of my WebKit patch and will just send them reviewed as part of that.
marcoscaceres marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
</script> | ||
</head> | ||
<body> | ||
<body onload="createIframes()" > | ||
<h1>User activation consumption across same-origin frame boundary</h1> | ||
<p>Tests that user activation consumption resets the transient states in all same-origin frames.</p> | ||
<ol id="instructions"> | ||
<li>Click anywhere on the green area (child frame). | ||
</ol> | ||
<iframe id="child1" width="300px" height="40px" | ||
src="resources/child-one.html"> | ||
</iframe> | ||
<iframe id="child-so" width="300px" height="140px" | ||
src="resources/consumption-sameorigin-child.html"> | ||
</iframe> | ||
</body> | ||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this really improve the flakes? I am asking because the block in Line 46-55 already handles the case added here: the child frames pings the top frame when they see
load
events.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes. The problem is that the (html) iframes were randomly in different order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In L85-87, the "load phase" ends after all 3 frames are loaded in any order.