From a221fcdf486c8ca2ac6c5753fac381df199250b7 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Wed, 4 Oct 2023 12:14:28 -0700 Subject: [PATCH] Update mutation event suppression for
to revised spec rules. The rules for mutation event suppression for
were revised during the process of reviewing the spec PR, based on the discussion starting at https://github.com/whatwg/html/pull/9400#discussion_r1340856291 . The updated spec says that mutation events are suppressed during the "ensure details exclusivity by closing other elements if needed" and "ensure details exclusivity by closing the given element if needed" algorithms. This updates the implementation and tests to follow that rule. (The "handling of insertion of elements into group" test is testing the case where the events were already suppressed.) This also renames the test to remove "tentative" from the name, since the spec PR is landed and the test is now (with this change) up-to-date with the spec. Bug: 1444057 Change-Id: I9078beeb3527f2515f6e10efbf93a94232221238 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4912273 Commit-Queue: David Baron Reviewed-by: Joey Arhar Cr-Commit-Position: refs/heads/main@{#1205367} --- ...ute.tentative.html => name-attribute.html} | 58 +++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) rename html/semantics/interactive-elements/the-details-element/{name-attribute.tentative.html => name-attribute.html} (83%) diff --git a/html/semantics/interactive-elements/the-details-element/name-attribute.tentative.html b/html/semantics/interactive-elements/the-details-element/name-attribute.html similarity index 83% rename from html/semantics/interactive-elements/the-details-element/name-attribute.tentative.html rename to html/semantics/interactive-elements/the-details-element/name-attribute.html index 6f45b3da089e3f..2685546e9b00cf 100644 --- a/html/semantics/interactive-elements/the-details-element/name-attribute.tentative.html +++ b/html/semantics/interactive-elements/the-details-element/name-attribute.html @@ -153,8 +153,8 @@ if (mutation_event_received_ids.length == 0) { // ok if mutation events are not supported } else { - assert_array_equals(mutation_event_received_ids, ["e0", "e1"], - "removal event followed by addition event"); + assert_array_equals(mutation_event_received_ids, ["e1"], + "mutation events received only for open attribute mutation and not for closing other element"); } assert_element_states(elements, [0, 1, 0, 0], "states after mutation"); assert_array_equals(toggle_event_received_ids, [], "toggle events received before awaiting promises"); @@ -205,8 +205,8 @@ assert_array_equals(received_ids, []); assert_element_states(elements, [1, 0, 0], "states before mutation"); elements[1].open = true; - assert_array_equals(received_ids, ["e0", "e1"], - "removal events received in tree order, followed by addition event, despite changes to name during mutation event"); + assert_array_equals(received_ids, ["e1"], + "mutation events received only for open attribute mutation and not for closing other element"); assert_element_states(elements, [0, 1, 0], "states after mutation"); }, "interaction of open attribute changes with mutation events"); @@ -336,14 +336,47 @@ document.getElementById("e1"), document.getElementById("e2") ]; + let mutation_received_ids = []; + let listener = event => { + mutation_received_ids.push(event.target.id); + }; + for (let element of elements) { + element.addEventListener("DOMSubtreeModified", listener); + } + assert_element_states(elements, [1, 0, 1], "states before first mutation"); + assert_array_equals(mutation_received_ids, [], "mutation events received before first mutation"); elements[2].name = "a"; assert_element_states(elements, [1, 0, 0], "states after first mutation"); + if (mutation_received_ids.length != 0) { + // OK to not support mutation events, or to send DOMSubtreeModified + // only for attribute addition/removal (open) but not for attribute + // change (name) + assert_array_equals(mutation_received_ids, ["e2"], "mutation events received after first mutation"); + } elements[0].name = "c"; elements[2].open = true; assert_element_states(elements, [1, 0, 1], "states before second mutation"); + if (mutation_received_ids.length != 0) { // OK to not support mutation events + if (mutation_received_ids.length == 1) { + // OK to receive DOMSubtreeModified for attribute addition/removal + // (open) but not for attribute change (name) + assert_array_equals(mutation_received_ids, ["e2"], "mutation events received before second mutation"); + } else { + assert_array_equals(mutation_received_ids, ["e2", "e0", "e2"], "mutation events received before second mutation"); + } + } elements[0].name = "a"; assert_element_states(elements, [0, 0, 1], "states after second mutation"); + if (mutation_received_ids.length != 0) { // OK to not support mutation events + if (mutation_received_ids.length == 1) { + // OK to receive DOMSubtreeModified for attribute addition/removal + // (open) but not for attribute change (name) + assert_array_equals(mutation_received_ids, ["e2"], "mutation events received before second mutation"); + } else { + assert_array_equals(mutation_received_ids, ["e2", "e0", "e2", "e0"], "mutation events received after second mutation"); + } + } }, "handling of name attribute changes"); promise_test(async t => { @@ -392,28 +425,45 @@ }); }; + let track_mutations = (element) => { + let result = { count: 0 }; + let listener = event => { + ++result.count; + }; + element.addEventListener("DOMSubtreeModified", listener); + return result; + } + await expect_opening(watch_e0); // Test appending an open element in the group. let new1 = make_details(); + let mutations1 = track_mutations(new1); let watch_new1 = new EventWatcher(t, new1, ['toggle']); new1.open = true; + assert_in_array(mutations1.count, [0, 1], "mutation events count before inserting new1"); await expect_opening(watch_new1); container.appendChild(new1); await expect_closing(watch_new1); + assert_in_array(mutations1.count, [0, 1], "mutation events count after inserting new1"); // Test appending a closed element in the group. let new2 = make_details(); + let mutations2 = track_mutations(new2); let watch_new2 = new EventWatcher(t, new2, ['toggle']); container.appendChild(new2); + assert_equals(mutations2.count, 0, "mutation events count after inserting new2"); // Test inserting an open element at the start of the group. let new3 = make_details(); + let mutations3 = track_mutations(new3); new3.open = true; // this time do this before creating the EventWatcher let watch_new3 = new EventWatcher(t, new3, ['toggle']); + assert_in_array(mutations3.count, [0, 1], "mutation events count before inserting new3"); await expect_opening(watch_new3); container.insertBefore(new3, elements[0]); await expect_closing(watch_new3); + assert_in_array(mutations3.count, [0, 1], "mutation events count after inserting new3"); }, "handling of insertion of elements into group");