Files
sousa-gecko/testing/web-platform/tests/input-events/input-events-delete-selection.html
T
Pranav Modi 0aae417ed8 Bug 2008495 [wpt PR 56981] - [Editing] Fix InputEvent type for deletion commands with non-collapsed selection, a=testonly
Automatic update from web-platform-tests
[Editing] Fix InputEvent type for deletion commands with non-collapsed
selection

When deletion commands (Ctrl+Backspace, Ctrl+Delete, etc.) are executed
with a non-collapsed selection, the InputEvent type should be
deleteContentBackward/Forward, not deleteWordBackward/Forward or other
granularity-based types, per the W3C Input Events specification [1].

This CL fixes both beforeinput and input event generation:
i) InputTypeFromCommandType() now checks selection state to return
   content-based InputType for beforeinput events when a selection
   exists
ii) DeleteWithDirection() updated to use deleteContent* InputType for
   non-collapsed selections, bypassing granularity-based deletion logic

[1] - https://w3c.github.io/input-events/#interface-InputEvent-Attributes

Bug: 41423062
Change-Id: I7e9f05a3e049472b2855341d571d6df350821e6a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7266851
Reviewed-by: Sambamurthy Bandaru <sambamurthy.bandaru@microsoft.com>
Reviewed-by: Kent Tamura <tkent@chromium.org>
Commit-Queue: Pranav Modi <pranavmodi@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#1564205}

--

wpt-commits: 48866a98b0022b880d2221e2992fb606df817051
wpt-pr: 56981
2026-01-06 15:19:55 +00:00

241 lines
8.0 KiB
HTML

<!DOCTYPE html>
<meta charset="utf-8" />
<title>
Input Event tests for deletion with non-collapsed selection
</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<div id="rich" contenteditable></div>
<script>
let inputEventsLog = [];
const rich = document.getElementById("rich");
const isMacOS = navigator.platform.indexOf("Mac") === 0;
const MODIFIER_KEY = isMacOS ? "\uE00A" : "\uE009"; // Alt on Mac, Ctrl on others
function log(event) {
inputEventsLog.push({
type: event.type,
inputType: event.inputType,
data: event.data,
});
}
function resetRich() {
inputEventsLog = [];
rich.innerHTML = "";
}
function selectText(startNode, startOffset, endNode, endOffset) {
const selection = window.getSelection();
const range = document.createRange();
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);
selection.removeAllRanges();
selection.addRange(range);
}
rich.addEventListener("beforeinput", log);
rich.addEventListener("input", log);
// Test Ctrl+Backspace with non-collapsed selection
promise_test(async function () {
this.add_cleanup(resetRich);
rich.innerHTML = "hello world";
rich.focus();
const textNode = rich.firstChild;
// Select "or" in "world"
selectText(textNode, 6, textNode, 8);
// Simulate Ctrl+Backspace (Alt+Backspace on Mac)
await new test_driver.Actions()
.keyDown(MODIFIER_KEY)
.keyDown("\uE003") // Backspace
.keyUp("\uE003")
.keyUp(MODIFIER_KEY)
.send();
assert_equals(inputEventsLog.length, 2, "Should have 2 events");
const [beforeInputEvent, inputEvent] = inputEventsLog;
assert_equals(beforeInputEvent.type, "beforeinput");
assert_equals(inputEvent.type, "input");
// When deleting a selection, inputType should be deleteContentBackward
assert_equals(
beforeInputEvent.inputType,
"deleteContentBackward",
"Ctrl+Backspace with selection should report deleteContentBackward"
);
assert_equals(
inputEvent.inputType,
"deleteContentBackward",
"Ctrl+Backspace with selection should report deleteContentBackward"
);
}, "Ctrl+Backspace with non-collapsed selection should report deleteContentBackward");
// Test Ctrl+Backspace with caret (collapsed selection)
promise_test(async function () {
this.add_cleanup(resetRich);
rich.innerHTML = "hello world";
rich.focus();
const textNode = rich.firstChild;
// Place caret after "world"
selectText(textNode, 11, textNode, 11);
// Simulate Ctrl+Backspace (Alt+Backspace on Mac)
await new test_driver.Actions()
.keyDown(MODIFIER_KEY)
.keyDown("\uE003") // Backspace
.keyUp("\uE003")
.keyUp(MODIFIER_KEY)
.send();
assert_equals(inputEventsLog.length, 2, "Should have 2 events");
const [beforeInputEvent, inputEvent] = inputEventsLog;
assert_equals(beforeInputEvent.type, "beforeinput");
assert_equals(inputEvent.type, "input");
// With caret, should be deleteWordBackward
assert_equals(
beforeInputEvent.inputType,
"deleteWordBackward",
"Ctrl+Backspace with caret should report deleteWordBackward"
);
assert_equals(
inputEvent.inputType,
"deleteWordBackward",
"Ctrl+Backspace with caret should report deleteWordBackward"
);
}, "Ctrl+Backspace with caret should report deleteWordBackward");
// Test Ctrl+Delete with non-collapsed selection
promise_test(async function () {
this.add_cleanup(resetRich);
rich.innerHTML = "hello world";
rich.focus();
const textNode = rich.firstChild;
// Select "ell" in "hello"
selectText(textNode, 1, textNode, 4);
// Simulate Ctrl+Delete (Alt+Delete on Mac)
await new test_driver.Actions()
.keyDown(MODIFIER_KEY)
.keyDown("\uE017") // Delete
.keyUp("\uE017")
.keyUp(MODIFIER_KEY)
.send();
assert_equals(inputEventsLog.length, 2, "Should have 2 events");
const [beforeInputEvent, inputEvent] = inputEventsLog;
assert_equals(beforeInputEvent.type, "beforeinput");
assert_equals(inputEvent.type, "input");
// When deleting a selection, inputType should be deleteContentForward
assert_equals(
beforeInputEvent.inputType,
"deleteContentForward",
"Ctrl+Delete with selection should report deleteContentForward"
);
assert_equals(
inputEvent.inputType,
"deleteContentForward",
"Ctrl+Delete with selection should report deleteContentForward"
);
}, "Ctrl+Delete with non-collapsed selection should report deleteContentForward");
// Test Ctrl+Delete with caret (collapsed selection)
promise_test(async function () {
this.add_cleanup(resetRich);
rich.innerHTML = "hello world";
rich.focus();
const textNode = rich.firstChild;
// Place caret before "world"
selectText(textNode, 6, textNode, 6);
// Simulate Ctrl+Delete (Alt+Delete on Mac)
await new test_driver.Actions()
.keyDown(MODIFIER_KEY)
.keyDown("\uE017") // Delete
.keyUp("\uE017")
.keyUp(MODIFIER_KEY)
.send();
assert_equals(inputEventsLog.length, 2, "Should have 2 events");
const [beforeInputEvent, inputEvent] = inputEventsLog;
assert_equals(beforeInputEvent.type, "beforeinput");
assert_equals(inputEvent.type, "input");
// With caret, should be deleteWordForward
assert_equals(
beforeInputEvent.inputType,
"deleteWordForward",
"Ctrl+Delete with caret should report deleteWordForward"
);
assert_equals(
inputEvent.inputType,
"deleteWordForward",
"Ctrl+Delete with caret should report deleteWordForward"
);
}, "Ctrl+Delete with caret should report deleteWordForward");
// Test regular Backspace with non-collapsed selection (should still be deleteContentBackward)
promise_test(async function () {
this.add_cleanup(resetRich);
rich.innerHTML = "hello world";
rich.focus();
const textNode = rich.firstChild;
// Select "lo wo"
selectText(textNode, 3, textNode, 8);
// Simulate Backspace (without Ctrl)
await test_driver.send_keys(rich, "\uE003"); // Backspace
assert_equals(inputEventsLog.length, 2, "Should have 2 events");
const [beforeInputEvent, inputEvent] = inputEventsLog;
assert_equals(beforeInputEvent.type, "beforeinput");
assert_equals(inputEvent.type, "input");
assert_equals(
beforeInputEvent.inputType,
"deleteContentBackward",
"Regular Backspace with selection should report deleteContentBackward"
);
assert_equals(
inputEvent.inputType,
"deleteContentBackward",
"Regular Backspace with selection should report deleteContentBackward"
);
}, "Regular Backspace with non-collapsed selection should report deleteContentBackward");
// Test regular Delete with non-collapsed selection (should be deleteContentForward)
promise_test(async function () {
this.add_cleanup(resetRich);
rich.innerHTML = "hello world";
rich.focus();
const textNode = rich.firstChild;
// Select "lo wo"
selectText(textNode, 3, textNode, 8);
// Simulate Delete (without Ctrl)
await test_driver.send_keys(rich, "\uE017"); // Delete
assert_equals(inputEventsLog.length, 2, "Should have 2 events");
const [beforeInputEvent, inputEvent] = inputEventsLog;
assert_equals(beforeInputEvent.type, "beforeinput");
assert_equals(inputEvent.type, "input");
assert_equals(
beforeInputEvent.inputType,
"deleteContentForward",
"Regular Delete with selection should report deleteContentForward"
);
assert_equals(
inputEvent.inputType,
"deleteContentForward",
"Regular Delete with selection should report deleteContentForward"
);
}, "Regular Delete with non-collapsed selection should report deleteContentForward");
</script>