зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1755614 - Clean up test_contenteditable_focus.html r=m_kato
It's not split to each chunk with IIFE nor the message explain what is the expected result. This just rewrites it without changing what's are tested except adding a call of `testFocusMove` with `<button>` in the main editor (i.e., editable button). Depends on D138876 Differential Revision: https://phabricator.services.mozilla.com/D138877
This commit is contained in:
Родитель
12810c2806
Коммит
b5778bbaf4
|
@ -1,9 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for contenteditable focus</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="/tests/SimpleTest/test.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="display">
|
||||
|
@ -12,7 +13,7 @@
|
|||
<input id="inputTextReadonly" type="text" readonly><br>
|
||||
<input id="inputButton" type="button" value="input[type=button]"><br>
|
||||
<button id="button">button</button><br>
|
||||
<div id="editor" contenteditable="true">
|
||||
<div id="primaryEditor" contenteditable="true">
|
||||
editable contents.<br>
|
||||
<input id="inputTextInEditor" type="text"><br>
|
||||
<input id="inputTextReadonlyInEditor" type="text" readonly><br>
|
||||
|
@ -37,154 +38,301 @@
|
|||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(runTests, window);
|
||||
SimpleTest.waitForFocus(() => {
|
||||
function getNodeDescription(aNode) {
|
||||
if (aNode === undefined) {
|
||||
return "undefined";
|
||||
}
|
||||
if (aNode === null) {
|
||||
return "null";
|
||||
}
|
||||
switch (aNode.nodeType) {
|
||||
case Node.TEXT_NODE:
|
||||
return `${aNode.nodeName}, "${aNode.data.replace(/\n/g, "\\n")}"`;
|
||||
case Node.ELEMENT_NODE:
|
||||
return `<${aNode.tagName.toLowerCase()}${
|
||||
aNode.getAttribute("id") !== null
|
||||
? ` id="${aNode.getAttribute("id")}"`
|
||||
: ""
|
||||
}${
|
||||
aNode.getAttribute("readonly") !== null
|
||||
? " readonly"
|
||||
: ""
|
||||
}${
|
||||
aNode.getAttribute("type") !== null
|
||||
? ` type="${aNode.getAttribute("type")}"`
|
||||
: ""
|
||||
}>`;
|
||||
}
|
||||
return aNode.nodeName;
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
runTestsInternal();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function runTestsInternal() {
|
||||
var fm = SpecialPowers.Services.focus;
|
||||
const fm = SpecialPowers.Services.focus;
|
||||
// XXX using selCon for checking the visibility of the caret, however,
|
||||
// selCon is shared in document, cannot get the element of owner of the
|
||||
// caret from javascript?
|
||||
var selCon = SpecialPowers.wrap(window).docShell.
|
||||
const selCon = SpecialPowers.wrap(window).docShell.
|
||||
QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
|
||||
getInterface(SpecialPowers.Ci.nsISelectionDisplay).
|
||||
QueryInterface(SpecialPowers.Ci.nsISelectionController);
|
||||
var selection = window.getSelection();
|
||||
|
||||
var editor = document.getElementById("editor");
|
||||
var inputTextInEditor = document.getElementById("inputTextInEditor");
|
||||
var spanInEditor = document.getElementById("spanInEditor");
|
||||
var otherEditor = document.getElementById("otherEditor");
|
||||
const primaryEditor = document.getElementById("primaryEditor");
|
||||
const spanInEditor = document.getElementById("spanInEditor");
|
||||
const otherEditor = document.getElementById("otherEditor");
|
||||
|
||||
// XXX if there is a contenteditable element, HTML editor sets dom selection
|
||||
// to first editable node, but this makes inconsistency with normal document
|
||||
// behavior.
|
||||
todo_is(selection.rangeCount, 0, "unexpected selection range is there");
|
||||
ok(!selCon.caretVisible, "caret is visible in the document");
|
||||
// Move focus to inputTextInEditor
|
||||
inputTextInEditor.focus();
|
||||
is(SpecialPowers.unwrap(fm.focusedElement), inputTextInEditor,
|
||||
"inputTextInEditor didn't get focus");
|
||||
todo_is(selection.rangeCount, 0, "unexpected selection range is there");
|
||||
ok(selCon.caretVisible, "caret isn't visible in the inputTextInEditor");
|
||||
(function test_initial_state_on_load() {
|
||||
// XXX if there is a contenteditable element, HTML editor sets dom selection
|
||||
// to first editable node, but this makes inconsistency with normal document
|
||||
// behavior.
|
||||
todo_is(
|
||||
getSelection().rangeCount,
|
||||
0,
|
||||
"There should be no selection range at start"
|
||||
);
|
||||
ok(!selCon.caretVisible, "The caret should not be visible in the document");
|
||||
// Move focus to <input type="text"> in the primary editor
|
||||
primaryEditor.querySelector("input[type=text]").focus();
|
||||
is(
|
||||
SpecialPowers.unwrap(fm.focusedElement),
|
||||
primaryEditor.querySelector("input[type=text]"),
|
||||
'<input type="text"> in the primary editor should get focus'
|
||||
);
|
||||
todo_is(
|
||||
getSelection().rangeCount,
|
||||
0,
|
||||
'There should be no selection range after calling focus() of <input type="text"> in the primary editor'
|
||||
);
|
||||
ok(
|
||||
selCon.caretVisible,
|
||||
'The caret should not be visible in the <input type="text"> in the primary editor'
|
||||
);
|
||||
})();
|
||||
// Move focus to the editor
|
||||
editor.focus();
|
||||
is(SpecialPowers.unwrap(fm.focusedElement), editor,
|
||||
"editor didn't get focus");
|
||||
is(selection.rangeCount, 1,
|
||||
"there is no selection range when editor has focus");
|
||||
var range = selection.getRangeAt(0);
|
||||
ok(range.collapsed, "the selection range isn't collapsed");
|
||||
var startNode = range.startContainer;
|
||||
is(startNode.nodeType, Node.TEXT_NODE, "the caret isn't set to the first text node");
|
||||
is(startNode, editor.firstChild, "the caret isn't set to the editor");
|
||||
ok(selCon.caretVisible, "caret isn't visible in the editor");
|
||||
(function test_move_focus_from_child_input_to_parent_editor() {
|
||||
primaryEditor.focus();
|
||||
is(
|
||||
SpecialPowers.unwrap(fm.focusedElement),
|
||||
primaryEditor,
|
||||
`The editor should steal focus from <input type="text"> in the primary editor with calling its focus() (got ${
|
||||
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
|
||||
}`
|
||||
);
|
||||
is(
|
||||
getSelection().rangeCount,
|
||||
1,
|
||||
"There should be one range after focus() of the editor is called"
|
||||
);
|
||||
const range = getSelection().getRangeAt(0);
|
||||
ok(
|
||||
range.collapsed,
|
||||
"The selection range should be collapsed (immediately after calling focus() of the editor)"
|
||||
);
|
||||
is(
|
||||
range.startContainer,
|
||||
primaryEditor.firstChild,
|
||||
`The selection range should be in the first text node of the editor (immediately after calling focus() of the editor, got ${
|
||||
getNodeDescription(range.startContainer)
|
||||
})`
|
||||
);
|
||||
ok(
|
||||
selCon.caretVisible,
|
||||
"The caret should be visible in the primary editor (immediately after calling focus() of the editor)"
|
||||
);
|
||||
})();
|
||||
// Move focus to other editor
|
||||
otherEditor.focus();
|
||||
is(SpecialPowers.unwrap(fm.focusedElement), otherEditor,
|
||||
"the other editor didn't get focus");
|
||||
is(selection.rangeCount, 1,
|
||||
"there is no selection range when the other editor has focus");
|
||||
range = selection.getRangeAt(0);
|
||||
ok(range.collapsed, "the selection range isn't collapsed");
|
||||
startNode = range.startContainer;
|
||||
is(startNode.nodeType, Node.TEXT_NODE, "the caret isn't set to the text node");
|
||||
is(startNode, otherEditor.firstChild, "the caret isn't set to the other editor");
|
||||
ok(selCon.caretVisible, "caret isn't visible in the other editor");
|
||||
// Move focus to inputTextInEditor
|
||||
inputTextInEditor.focus();
|
||||
is(SpecialPowers.unwrap(fm.focusedElement), inputTextInEditor,
|
||||
"inputTextInEditor didn't get focus #2");
|
||||
is(selection.rangeCount, 1, "selection range is lost from the document");
|
||||
range = selection.getRangeAt(0);
|
||||
ok(range.collapsed, "the selection range isn't collapsed");
|
||||
startNode = range.startContainer;
|
||||
is(startNode.nodeType, Node.TEXT_NODE, "the caret isn't set to the first text node");
|
||||
// XXX maybe, the caret can stay on the other editor if it's better.
|
||||
is(startNode, editor.firstChild,
|
||||
"the caret should stay on the other editor");
|
||||
ok(selCon.caretVisible,
|
||||
"caret isn't visible in the inputTextInEditor");
|
||||
(function test_move_focus_from_editor_to_the_other_editor() {
|
||||
otherEditor.focus();
|
||||
is(
|
||||
SpecialPowers.unwrap(fm.focusedElement),
|
||||
otherEditor,
|
||||
`The other editor should steal focus from the editor (got ${
|
||||
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
|
||||
}`
|
||||
);
|
||||
is(
|
||||
getSelection().rangeCount,
|
||||
1,
|
||||
"There should be one range after focus() of the other editor is called"
|
||||
);
|
||||
const range = getSelection().getRangeAt(0);
|
||||
ok(
|
||||
range.collapsed,
|
||||
"The selection range should be collapsed (immediately after calling focus() of the other editor)"
|
||||
);
|
||||
is(
|
||||
range.startContainer,
|
||||
otherEditor.firstChild,
|
||||
`The selection range should be in the first text node of the editor (immediately after calling focus() of the other editor, got ${
|
||||
getNodeDescription(range.startContainer)
|
||||
})`
|
||||
);
|
||||
ok(
|
||||
selCon.caretVisible,
|
||||
"The caret should be visible in the primary editor (immediately after calling focus() of the other editor)"
|
||||
);
|
||||
})();
|
||||
// Move focus to <input type="text"> in the primary editor
|
||||
(function test_move_focus_from_the_other_editor_to_input_in_the_editor() {
|
||||
primaryEditor.querySelector("input[type=text]").focus();
|
||||
is(
|
||||
SpecialPowers.unwrap(fm.focusedElement),
|
||||
primaryEditor.querySelector("input[type=text]"),
|
||||
`<input type="text"> in the primary editor should steal focus from the other editor (got ${
|
||||
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
|
||||
}`);
|
||||
is(
|
||||
getSelection().rangeCount,
|
||||
1,
|
||||
'There should be one range after focus() of the <input type="text"> in the primary editor is called'
|
||||
);
|
||||
const range = getSelection().getRangeAt(0);
|
||||
ok(
|
||||
range.collapsed,
|
||||
'The selection range should be collapsed (immediately after calling focus() of the <input type="text"> in the primary editor)'
|
||||
);
|
||||
// XXX maybe, the caret can stay on the other editor if it's better.
|
||||
is(
|
||||
range.startContainer,
|
||||
primaryEditor.firstChild,
|
||||
`The selection range should be in the first text node of the editor (immediately after calling focus() of the <input type="text"> in the primary editor, got ${
|
||||
getNodeDescription(range.startContainer)
|
||||
})`
|
||||
);
|
||||
ok(
|
||||
selCon.caretVisible,
|
||||
'The caret should be visible in the <input type="text"> (immediately after calling focus() of the <input type="text"> in the primary editor)'
|
||||
);
|
||||
})();
|
||||
// Move focus to the other editor again
|
||||
otherEditor.focus();
|
||||
is(SpecialPowers.unwrap(fm.focusedElement), otherEditor,
|
||||
"the other editor didn't get focus #2");
|
||||
// Set selection to the span element in the editor.
|
||||
range = document.createRange();
|
||||
range.setStart(spanInEditor.firstChild, 5);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
is(selection.rangeCount, 1, "selection range is lost from the document");
|
||||
is(SpecialPowers.unwrap(fm.focusedElement), editor,
|
||||
"the other editor should lose focus by selection range change");
|
||||
ok(selCon.caretVisible, "caret isn't visible in inputTextInEditor");
|
||||
(function test_move_focus_from_the_other_editor_to_the_editor_with_Selection_API() {
|
||||
otherEditor.focus();
|
||||
is(
|
||||
SpecialPowers.unwrap(fm.focusedElement),
|
||||
otherEditor,
|
||||
`The other editor should steal focus from the <input type="text"> in the primary editor with its focus() (got ${
|
||||
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
|
||||
})`
|
||||
);
|
||||
// Set selection to the span element in the primary editor.
|
||||
getSelection().collapse(spanInEditor.firstChild, 5);
|
||||
is(
|
||||
getSelection().rangeCount,
|
||||
1,
|
||||
"There should be one selection range after collapsing selection into the <span> in the primary editor when the other editor has focus"
|
||||
);
|
||||
is(
|
||||
SpecialPowers.unwrap(fm.focusedElement),
|
||||
primaryEditor,
|
||||
`The editor should steal focus from the other editor with Selection API (got ${
|
||||
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
|
||||
}`
|
||||
);
|
||||
ok(
|
||||
selCon.caretVisible,
|
||||
"The caret should be visible in the primary editor (immediately after moving focus with Selection API)"
|
||||
);
|
||||
})();
|
||||
// Move focus to the editor
|
||||
editor.focus();
|
||||
is(SpecialPowers.unwrap(fm.focusedElement), editor,
|
||||
"the editor didn't get focus #2");
|
||||
is(selection.rangeCount, 1, "selection range is lost from the document");
|
||||
range = selection.getRangeAt(0);
|
||||
ok(range.collapsed, "the selection range isn't collapsed");
|
||||
is(range.startOffset, 5,
|
||||
"the caret is moved when the editor was focused (offset)");
|
||||
startNode = range.startContainer;
|
||||
is(startNode.nodeType, 3, "the caret isn't in text node");
|
||||
is(startNode.parentNode, spanInEditor,
|
||||
"the caret is moved when the editor was focused (node)");
|
||||
ok(selCon.caretVisible, "caret isn't visible in the editor (spanInEditor)");
|
||||
(function test_move_focus() {
|
||||
primaryEditor.focus();
|
||||
is(
|
||||
SpecialPowers.unwrap(fm.focusedElement),
|
||||
primaryEditor,
|
||||
"The editor should keep having focus (immediately after calling focus() of the editor when it has focus)"
|
||||
);
|
||||
is(
|
||||
getSelection().rangeCount,
|
||||
1,
|
||||
"There should be one selection range in the primary editor (immediately after calling focus() of the editor when it has focus)"
|
||||
);
|
||||
const range = getSelection().getRangeAt(0);
|
||||
ok(
|
||||
range.collapsed,
|
||||
"The selection range should be collapsed in the primary editor (immediately after calling focus() of the editor when it has focus)"
|
||||
);
|
||||
is(
|
||||
range.startOffset,
|
||||
5,
|
||||
"The startOffset of the selection range shouldn't be changed (immediately after calling focus() of the editor when it has focus)"
|
||||
);
|
||||
is(
|
||||
range.startContainer.parentNode,
|
||||
spanInEditor,
|
||||
`The startContainer of the selection range shouldn't be changed (immediately after calling focus() of the editor when it has focus, got ${
|
||||
getNodeDescription(range.startContainer)
|
||||
})`);
|
||||
ok(
|
||||
selCon.caretVisible,
|
||||
"The caret should be visible in the primary editor (immediately after calling focus() of the editor when it has focus)"
|
||||
);
|
||||
})();
|
||||
|
||||
// Move focus to each focusable element in the editor.
|
||||
function testFocusMove(aSetFocusElementID, aFocusable, aCaretVisible) {
|
||||
editor.focus();
|
||||
is(SpecialPowers.unwrap(fm.focusedElement), editor,
|
||||
"testFocusMove: the editor didn't get focus at initializing (" +
|
||||
aSetFocusElementID + ")");
|
||||
var setFocusElement = document.getElementById(aSetFocusElementID);
|
||||
setFocusElement.focus();
|
||||
// Move focus to each focusable element in the primary editor.
|
||||
function test_move_focus_from_the_editor(aTargetElement, aFocusable, aCaretVisible) {
|
||||
primaryEditor.focus();
|
||||
is(
|
||||
SpecialPowers.unwrap(fm.focusedElement),
|
||||
primaryEditor,
|
||||
`The editor should have focus at preparing to move focus to ${
|
||||
getNodeDescription(aTargetElement)
|
||||
} (got ${
|
||||
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
|
||||
}`);
|
||||
aTargetElement.focus();
|
||||
if (aFocusable) {
|
||||
is(SpecialPowers.unwrap(fm.focusedElement), setFocusElement,
|
||||
"testFocusMove: the " + aSetFocusElementID +
|
||||
" didn't get focus");
|
||||
is(
|
||||
SpecialPowers.unwrap(fm.focusedElement),
|
||||
aTargetElement,
|
||||
`${
|
||||
getNodeDescription(aTargetElement)
|
||||
} should get focus with calling its focus() (got ${
|
||||
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
|
||||
}`
|
||||
);
|
||||
} else {
|
||||
is(SpecialPowers.unwrap(fm.focusedElement), editor,
|
||||
"testFocusMove: the editor lost focus by focus() of the " +
|
||||
aSetFocusElementID);
|
||||
}
|
||||
if (aCaretVisible) {
|
||||
ok(selCon.caretVisible,
|
||||
"testFocusMove: caret isn't visible when the " +
|
||||
aSetFocusElementID + " has focus");
|
||||
} else {
|
||||
ok(!selCon.caretVisible,
|
||||
"testFocusMove: caret is visible when the " +
|
||||
aSetFocusElementID + " has focus");
|
||||
is(
|
||||
SpecialPowers.unwrap(fm.focusedElement),
|
||||
primaryEditor,
|
||||
`${
|
||||
getNodeDescription(aTargetElement)
|
||||
} should not take focus with calling its focus() (got ${
|
||||
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
|
||||
}`
|
||||
);
|
||||
}
|
||||
is(
|
||||
selCon.caretVisible,
|
||||
aCaretVisible,
|
||||
`The caret ${
|
||||
aCaretVisible ? "should" : "should not"
|
||||
} visible after calling focus() of ${
|
||||
getNodeDescription(aTargetElement)
|
||||
}`
|
||||
);
|
||||
}
|
||||
testFocusMove("inputTextInEditor", true, true);
|
||||
testFocusMove("inputTextReadonlyInEditor", true, true);
|
||||
test_move_focus_from_the_editor(primaryEditor.querySelector("input[type=text]"), true, true);
|
||||
test_move_focus_from_the_editor(primaryEditor.querySelector("input[type=text][readonly]"), true, true);
|
||||
// XXX shouldn't the caret become invisible?
|
||||
testFocusMove("inputButtonInEditor", true, true);
|
||||
testFocusMove("noeditableInEditor", false, true);
|
||||
testFocusMove("spanInNoneditableInEditor", false, true);
|
||||
testFocusMove("inputTextInNoneditableInEditor", true, true);
|
||||
testFocusMove("inputTextReadonlyInNoneditableInEditor", true, true);
|
||||
testFocusMove("inputButtonInNoneditableInEditor", true, false);
|
||||
testFocusMove("buttonInNoneditableInEditor", true, false);
|
||||
testFocusMove("spanInEditor", false, true);
|
||||
testFocusMove("inputText", true, true);
|
||||
testFocusMove("inputTextReadonly", true, true);
|
||||
testFocusMove("inputButton", true, false);
|
||||
testFocusMove("button", true, false);
|
||||
}
|
||||
test_move_focus_from_the_editor(primaryEditor.querySelector("input[type=button]"), true, true);
|
||||
test_move_focus_from_the_editor(primaryEditor.querySelector("button"), true, true);
|
||||
test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false]"), false, true);
|
||||
test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > span"), false, true);
|
||||
test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > input[type=text]"), true, true);
|
||||
test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > input[type=text][readonly]"), true, true);
|
||||
test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > input[type=button]"), true, false);
|
||||
test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > button"), true, false);
|
||||
test_move_focus_from_the_editor(spanInEditor, false, true);
|
||||
test_move_focus_from_the_editor(document.querySelector("input[type=text]"), true, true);
|
||||
test_move_focus_from_the_editor(document.querySelector("input[type=text][readonly]"), true, true);
|
||||
test_move_focus_from_the_editor(document.querySelector("input[type=button]"), true, false);
|
||||
test_move_focus_from_the_editor(document.querySelector("button"), true, false);
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
Загрузка…
Ссылка в новой задаче