301 lines
8.7 KiB
HTML
301 lines
8.7 KiB
HTML
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<!--
|
|
Test the searchbox and autocomplete-popup components
|
|
-->
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>SearchBox component test</title>
|
|
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
|
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
|
</head>
|
|
<body>
|
|
<script src="head.js"></script>
|
|
<script>
|
|
"use strict";
|
|
window.onload = async function () {
|
|
/**
|
|
* Takes a DOMNode with its children as list items,
|
|
* Typically UL > LI and each item's text value is
|
|
* compared with the reference item's value as a test
|
|
*
|
|
* @params {Node} - Node to be compared
|
|
* @reference {array} - Reference array for comparison. The selected index is
|
|
* highlighted as a single element array ie. ["[abc]", "ab", "abcPQR"],
|
|
* Here the element "abc" is highlighted
|
|
*/
|
|
function compareAutocompleteList(list, reference) {
|
|
const delimiter = " - ";
|
|
const observedList = [...list.children].map(el => {
|
|
return el.classList.contains("autocomplete-selected")
|
|
? `[${el.textContent}]`
|
|
: el.textContent
|
|
});
|
|
is(observedList.join(delimiter), reference.join(delimiter),
|
|
"Autocomplete items are rendered as expected");
|
|
}
|
|
|
|
function compareCursorPosition(initialElement) {
|
|
const initialPosition = initialElement.selectionStart;
|
|
return (element) => {
|
|
is(element.selectionStart, initialPosition, "Input cursor position is not changed");
|
|
}
|
|
}
|
|
|
|
const React = browserRequire("devtools/client/shared/vendor/react");
|
|
const SearchBox = React.createFactory(
|
|
browserRequire("devtools/client/shared/components/SearchBox")
|
|
);
|
|
const { component, $ } = await createComponentTest(SearchBox, {
|
|
type: "search",
|
|
autocompleteProvider: (filter) => {
|
|
const baseList = [
|
|
"foo",
|
|
"BAR",
|
|
"baZ",
|
|
"abc",
|
|
"pqr",
|
|
"xyz",
|
|
"ABC",
|
|
"a1",
|
|
"a2",
|
|
"a3",
|
|
"a4",
|
|
"a5",
|
|
];
|
|
if (!filter) {
|
|
return [];
|
|
}
|
|
|
|
const tokens = filter.split(/\s+/g);
|
|
const lastToken = tokens[tokens.length - 1];
|
|
const previousTokens = tokens.slice(0, tokens.length - 1);
|
|
|
|
if (!lastToken) {
|
|
return [];
|
|
}
|
|
|
|
return baseList
|
|
.filter((item) => {
|
|
return item.toLowerCase().startsWith(lastToken.toLowerCase())
|
|
&& item.toLowerCase() !== lastToken.toLowerCase();
|
|
})
|
|
.sort()
|
|
.map(item => ({
|
|
value: [...previousTokens, item].join(" "),
|
|
displayValue: item,
|
|
}));
|
|
},
|
|
onChange: () => null,
|
|
});
|
|
|
|
async function testSearchBoxWithAutocomplete() {
|
|
ok(!$(".devtools-autocomplete-popup"), "Autocomplete list not visible");
|
|
|
|
$(".devtools-searchinput").focus();
|
|
await forceRender(component); // Wait for state update
|
|
ok(!$(".devtools-autocomplete-popup"), "Autocomplete list not visible");
|
|
|
|
sendString("a");
|
|
await forceRender(component);
|
|
|
|
compareAutocompleteList($(".devtools-autocomplete-listbox"), [
|
|
"[ABC]",
|
|
"a1",
|
|
"a2",
|
|
"a3",
|
|
"a4",
|
|
"a5",
|
|
"abc",
|
|
]);
|
|
|
|
// Blur event
|
|
$(".devtools-searchinput").blur();
|
|
await forceRender(component);
|
|
ok(!component.state.focused, "focused state was properly set");
|
|
ok(!$(".devtools-autocomplete-popup"), "Autocomplete list removed from DOM");
|
|
}
|
|
|
|
async function testKeyEventsWithAutocomplete() {
|
|
// Clear the initial input
|
|
$(".devtools-searchinput").focus();
|
|
const cursorPositionIsNotChanged = compareCursorPosition($(".devtools-searchinput"));
|
|
|
|
// ArrowDown
|
|
synthesizeKey("KEY_ArrowDown");
|
|
await forceRender(component);
|
|
compareAutocompleteList($(".devtools-autocomplete-listbox"), [
|
|
"ABC",
|
|
"[a1]",
|
|
"a2",
|
|
"a3",
|
|
"a4",
|
|
"a5",
|
|
"abc",
|
|
]);
|
|
ok($(".devtools-autocomplete-listbox .autocomplete-item:nth-child(2)")
|
|
.className.includes("autocomplete-selected"),
|
|
"Selection class applied");
|
|
|
|
// A double ArrowUp should roll back to the bottom of the list
|
|
synthesizeKey("KEY_ArrowUp");
|
|
synthesizeKey("KEY_ArrowUp");
|
|
await forceRender(component);
|
|
compareAutocompleteList($(".devtools-autocomplete-listbox"), [
|
|
"ABC",
|
|
"a1",
|
|
"a2",
|
|
"a3",
|
|
"a4",
|
|
"a5",
|
|
"[abc]",
|
|
]);
|
|
cursorPositionIsNotChanged($(".devtools-searchinput"));
|
|
|
|
// PageDown should take -5 places up
|
|
synthesizeKey("KEY_PageUp");
|
|
await forceRender(component);
|
|
compareAutocompleteList($(".devtools-autocomplete-listbox"), [
|
|
"ABC",
|
|
"[a1]",
|
|
"a2",
|
|
"a3",
|
|
"a4",
|
|
"a5",
|
|
"abc",
|
|
]);
|
|
cursorPositionIsNotChanged($(".devtools-searchinput"));
|
|
|
|
// PageDown should take +5 places down
|
|
synthesizeKey("KEY_PageDown");
|
|
await forceRender(component);
|
|
compareAutocompleteList($(".devtools-autocomplete-listbox"), [
|
|
"ABC",
|
|
"a1",
|
|
"a2",
|
|
"a3",
|
|
"a4",
|
|
"a5",
|
|
"[abc]",
|
|
]);
|
|
cursorPositionIsNotChanged($(".devtools-searchinput"));
|
|
|
|
// Home should take to the top of the list
|
|
synthesizeKey("KEY_Home");
|
|
await forceRender(component);
|
|
compareAutocompleteList($(".devtools-autocomplete-listbox"), [
|
|
"[ABC]",
|
|
"a1",
|
|
"a2",
|
|
"a3",
|
|
"a4",
|
|
"a5",
|
|
"abc",
|
|
]);
|
|
cursorPositionIsNotChanged($(".devtools-searchinput"));
|
|
|
|
// End should take to the bottom of the list
|
|
synthesizeKey("KEY_End");
|
|
await forceRender(component);
|
|
compareAutocompleteList($(".devtools-autocomplete-listbox"), [
|
|
"ABC",
|
|
"a1",
|
|
"a2",
|
|
"a3",
|
|
"a4",
|
|
"a5",
|
|
"[abc]",
|
|
]);
|
|
cursorPositionIsNotChanged($(".devtools-searchinput"));
|
|
|
|
// Key down in existing state should rollover to the top
|
|
synthesizeKey("KEY_ArrowDown");
|
|
await forceRender(component);
|
|
// Tab should select the component and hide popup
|
|
synthesizeKey("KEY_Tab");
|
|
await forceRender(component);
|
|
is(component.state.value, "ABC", "Tab hit selects the item");
|
|
ok(!$(".devtools-autocomplete-popup"), "Tab hit hides the popup");
|
|
|
|
// Activate popup by removing a key
|
|
synthesizeKey("KEY_Backspace");
|
|
await forceRender(component);
|
|
ok($(".devtools-autocomplete-popup"), "Popup is up");
|
|
compareAutocompleteList($(".devtools-autocomplete-listbox"), [
|
|
"[ABC]",
|
|
"abc"
|
|
]);
|
|
|
|
// Enter key selection
|
|
synthesizeKey("KEY_ArrowUp");
|
|
await forceRender(component);
|
|
synthesizeKey("KEY_Enter");
|
|
is(component.state.value, "abc", "Enter selection");
|
|
ok(!$(".devtools-autocomplete-popup"), "Enter/Return hides the popup");
|
|
|
|
// Escape should remove the autocomplete component
|
|
synthesizeKey("KEY_Backspace");
|
|
await forceRender(component);
|
|
synthesizeKey("KEY_Escape");
|
|
await forceRender(component);
|
|
ok(!$(".devtools-autocomplete-popup"),
|
|
"Autocomplete list removed from DOM on Escape");
|
|
}
|
|
|
|
async function testMouseEventsWithAutocomplete() {
|
|
$(".devtools-searchinput").focus();
|
|
await setState(component, {
|
|
value: "",
|
|
focused: true,
|
|
});
|
|
await forceRender(component);
|
|
|
|
// ArrowDown
|
|
synthesizeKey("KEY_ArrowDown");
|
|
await forceRender(component);
|
|
synthesizeMouseAtCenter($(".devtools-searchinput"), {}, window);
|
|
await forceRender(component);
|
|
is(component.state.focused, true, "Component should now be focused");
|
|
|
|
sendString("pq");
|
|
await forceRender(component);
|
|
synthesizeMouseAtCenter(
|
|
$(".devtools-autocomplete-listbox .autocomplete-item:nth-child(1)"),
|
|
{}, window
|
|
);
|
|
await forceRender(component);
|
|
is(component.state.value, "pqr", "Mouse click selects the item.");
|
|
ok(!$(".devtools-autocomplete-popup"), "Mouse click on item hides the popup");
|
|
}
|
|
|
|
async function testTokenizedAutocomplete() {
|
|
// Test for string "pqr ab" which should show list of ABC, abc
|
|
sendString(" ab");
|
|
await forceRender(component);
|
|
compareAutocompleteList($(".devtools-autocomplete-listbox"), [
|
|
"[ABC]",
|
|
"abc"
|
|
]);
|
|
|
|
// Select the first element, value now should be "pqr ABC"
|
|
synthesizeMouseAtCenter(
|
|
$(".devtools-autocomplete-listbox .autocomplete-item:nth-child(1)"),
|
|
{}, window
|
|
);
|
|
is(component.state.value, "pqr ABC", "Post Tokenization value selection");
|
|
}
|
|
|
|
add_task(async function () {
|
|
await testSearchBoxWithAutocomplete();
|
|
await testKeyEventsWithAutocomplete();
|
|
await testMouseEventsWithAutocomplete();
|
|
await testTokenizedAutocomplete();
|
|
});
|
|
};
|
|
</script>
|
|
</body>
|
|
</html>
|