From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../browser_treeWidget_keyboard_interaction.js | 291 +++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 devtools/client/shared/test/browser_treeWidget_keyboard_interaction.js (limited to 'devtools/client/shared/test/browser_treeWidget_keyboard_interaction.js') diff --git a/devtools/client/shared/test/browser_treeWidget_keyboard_interaction.js b/devtools/client/shared/test/browser_treeWidget_keyboard_interaction.js new file mode 100644 index 0000000000..05f1f95b4e --- /dev/null +++ b/devtools/client/shared/test/browser_treeWidget_keyboard_interaction.js @@ -0,0 +1,291 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests that keyboard interaction works fine with the tree widget + +const TEST_URI = + "data:text/html;charset=utf-8," + + "
"; +const { + TreeWidget, +} = require("resource://devtools/client/shared/widgets/TreeWidget.js"); + +add_task(async function () { + await SpecialPowers.pushPrefEnv({ + set: [["security.allow_unsafe_parent_loads", true]], + }); + + await addTab("about:blank"); + const { host, win, doc } = await createHost("bottom", TEST_URI); + + // Creating a host is not correctly waiting when DevTools run in content frame + // See Bug 1571421. + await wait(1000); + + const tree = new TreeWidget(doc.querySelector("div"), { + defaultType: "store", + }); + + populateTree(tree, doc); + + await testKeyboardInteraction(tree, win); + + tree.destroy(); + host.destroy(); + gBrowser.removeCurrentTab(); +}); + +function populateTree(tree, doc) { + tree.add([ + { + id: "level1", + label: "Level 1", + }, + { + id: "level2-1", + label: "Level 2", + }, + { + id: "level3-1", + label: "Level 3 - Child 1", + type: "dir", + }, + ]); + tree.add([ + "level1", + "level2-1", + { id: "level3-2", label: "Level 3 - Child 2" }, + ]); + tree.add([ + "level1", + "level2-1", + { id: "level3-3", label: "Level 3 - Child 3" }, + ]); + tree.add([ + "level1", + { + id: "level2-2", + label: "Level 2.1", + }, + { + id: "level3-1", + label: "Level 3.1", + }, + ]); + tree.add([ + { + id: "level1", + label: "Level 1", + }, + { + id: "level2", + label: "Level 2", + }, + { + id: "level3", + label: "Level 3", + type: "js", + }, + ]); + tree.add(["level1.1", "level2", { id: "level3", type: "url" }]); + + // Adding a new non text item in the tree. + const node = doc.createElement("div"); + node.textContent = "Foo Bar"; + node.className = "foo bar"; + tree.add([ + { + id: "level1.2", + node, + attachment: { + foo: "bar", + }, + }, + ]); +} + +// Sends a click event on the passed DOM node in an async manner +function click(node) { + const win = node.ownerDocument.defaultView; + executeSoon(() => EventUtils.synthesizeMouseAtCenter(node, {}, win)); +} + +/** + * Tests if pressing navigation keys on the tree items does the expected behavior + */ +async function testKeyboardInteraction(tree, win) { + info("Testing keyboard interaction with the tree"); + const waitForSelect = () => + new Promise(resolve => { + tree.once("select", (d, a) => resolve({ data: d, attachment: a })); + }); + + info("clicking on first top level item"); + let node = tree.root.children.firstChild.firstChild; + + // The select event handler will be called before the click event hasn't + // fully finished, so wait for both of them. + const clicked = once(node, "click"); + let onTreeSelect = waitForSelect(); + click(node); + + info("Wait for the click event"); + await clicked; + + info("Wait for the select event on tree"); + await onTreeSelect; + + node = tree.root.children.firstChild.nextSibling.firstChild; + // node should not have selected class + ok( + !node.classList.contains("theme-selected"), + "Node should not have selected class" + ); + ok(!node.hasAttribute("expanded"), "Node is not expanded"); + + info("Pressing down key to select next item"); + onTreeSelect = waitForSelect(); + EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); + + let { data, attachment } = await onTreeSelect; + is(data.length, 1, "Correct level item was selected after keydown"); + is(data[0], "level1", "Correct item was selected after pressing down"); + ok(!attachment, "null attachment was emitted"); + ok(node.classList.contains("theme-selected"), "Node has selected class"); + ok(node.hasAttribute("expanded"), "Node is expanded now"); + + info("Pressing down key again to select next item"); + onTreeSelect = waitForSelect(); + EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); + ({ data, attachment } = await onTreeSelect); + is( + data.length, + 2, + "Correct level item was selected after second down keypress" + ); + is(data[0], "level1", "Correct parent level"); + is(data[1], "level2", "Correct second level"); + + info("Pressing down key again to select next item"); + onTreeSelect = waitForSelect(); + EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); + ({ data, attachment } = await onTreeSelect); + is( + data.length, + 3, + "Correct level item was selected after third down keypress" + ); + is(data[0], "level1", "Correct parent level"); + is(data[1], "level2", "Correct second level"); + is(data[2], "level3", "Correct third level"); + + info("Pressing down key again to select next item"); + onTreeSelect = waitForSelect(); + EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); + ({ data, attachment } = await onTreeSelect); + is( + data.length, + 2, + "Correct level item was selected after fourth down keypress" + ); + is(data[0], "level1", "Correct parent level"); + is(data[1], "level2-1", "Correct second level"); + + const waitForKeydown = () => + new Promise(resolve => { + tree.root.children.addEventListener( + "keydown", + () => { + // executeSoon so that other listeners on the same method are executed first + executeSoon(() => resolve()); + }, + { once: true } + ); + }); + + // pressing left to check expand collapse feature. + // This does not emit any event, so listening for keypress + let onTreeKeydown = waitForKeydown(); + info("Pressing left key to collapse the item"); + node = tree._selectedLabel; + ok(node.hasAttribute("expanded"), "Item is expanded before left keypress"); + EventUtils.synthesizeKey("KEY_ArrowLeft", {}, win); + await onTreeKeydown; + + ok( + !node.hasAttribute("expanded"), + "Item is not expanded after left keypress" + ); + + // pressing left on collapsed item should select the previous item + + info("Pressing left key on collapsed item to select previous"); + onTreeSelect = waitForSelect(); + // parent node should have no effect of this keypress + node = tree.root.children.firstChild.nextSibling.firstChild; + ok(node.hasAttribute("expanded"), "Parent is expanded"); + EventUtils.synthesizeKey("KEY_ArrowLeft", {}, win); + ({ data } = await onTreeSelect); + is( + data.length, + 3, + "Correct level item was selected after second left keypress" + ); + is(data[0], "level1", "Correct parent level"); + is(data[1], "level2", "Correct second level"); + is(data[2], "level3", "Correct third level"); + ok( + node.hasAttribute("expanded"), + "Parent is still expanded after left keypress" + ); + + // pressing down again + + info("Pressing down key to select next item"); + onTreeSelect = waitForSelect(); + EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); + ({ data, attachment } = await onTreeSelect); + is( + data.length, + 2, + "Correct level item was selected after fifth down keypress" + ); + is(data[0], "level1", "Correct parent level"); + is(data[1], "level2-1", "Correct second level"); + + // collapsing the item to check expand feature. + onTreeKeydown = waitForKeydown(); + info("Pressing left key to collapse the item"); + node = tree._selectedLabel; + ok(node.hasAttribute("expanded"), "Item is expanded before left keypress"); + EventUtils.synthesizeKey("KEY_ArrowLeft", {}, win); + await onTreeKeydown; + ok(!node.hasAttribute("expanded"), "Item is collapsed after left keypress"); + + // pressing right should expand this now. + onTreeKeydown = waitForKeydown(); + info("Pressing right key to expend the collapsed item"); + node = tree._selectedLabel; + ok(!node.hasAttribute("expanded"), "Item is collapsed before right keypress"); + EventUtils.synthesizeKey("KEY_ArrowRight", {}, win); + await onTreeKeydown; + ok(node.hasAttribute("expanded"), "Item is expanded after right keypress"); + + // selecting last item node to test edge navigation case + + tree.selectedItem = ["level1.1", "level2", "level3"]; + node = tree._selectedLabel; + // pressing down again should not change selection + onTreeKeydown = waitForKeydown(); + info("Pressing down key on last item of the tree"); + EventUtils.synthesizeKey("KEY_ArrowDown", {}, win); + await onTreeKeydown; + + ok( + tree.isSelected(["level1.1", "level2", "level3"]), + "Last item is still selected after pressing down on last item of the tree" + ); +} -- cgit v1.2.3