diff options
Diffstat (limited to 'dom/tests/mochitest/keyhandling')
-rw-r--r-- | dom/tests/mochitest/keyhandling/browsertest.html | 108 | ||||
-rw-r--r-- | dom/tests/mochitest/keyhandling/chrome.ini | 17 | ||||
-rw-r--r-- | dom/tests/mochitest/keyhandling/mochitest.ini | 6 | ||||
-rw-r--r-- | dom/tests/mochitest/keyhandling/test_browser.xhtml | 252 | ||||
-rw-r--r-- | dom/tests/mochitest/keyhandling/test_editor.xhtml | 268 | ||||
-rw-r--r-- | dom/tests/mochitest/keyhandling/test_input.html | 226 | ||||
-rw-r--r-- | dom/tests/mochitest/keyhandling/test_textarea.html | 226 | ||||
-rw-r--r-- | dom/tests/mochitest/keyhandling/test_windowed.xhtml | 33 |
8 files changed, 1136 insertions, 0 deletions
diff --git a/dom/tests/mochitest/keyhandling/browsertest.html b/dom/tests/mochitest/keyhandling/browsertest.html new file mode 100644 index 0000000000..7121e6b02f --- /dev/null +++ b/dom/tests/mochitest/keyhandling/browsertest.html @@ -0,0 +1,108 @@ +<!DOCTYPE html> + +<html> +<body> +<p style="white-space: nowrap"> + A long paragraph to make a horizontal scrollbar. + A long paragraph to make a horizontal scrollbar. + A long paragraph to make a horizontal scrollbar. + A long paragraph to make a horizontal scrollbar. + A long paragraph to make a horizontal scrollbar. + A long paragraph to make a horizontal scrollbar. + A long paragraph to make a horizontal scrollbar. + A long paragraph to make a horizontal scrollbar. + A long paragraph to make a horizontal scrollbar. + A long paragraph to make a horizontal scrollbar. +</p> +<p id="paragraph">Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +<p>Lots of paragraphs to make a vertical scrollbar.</p> +</body> +</html> diff --git a/dom/tests/mochitest/keyhandling/chrome.ini b/dom/tests/mochitest/keyhandling/chrome.ini new file mode 100644 index 0000000000..e8a9aeffdd --- /dev/null +++ b/dom/tests/mochitest/keyhandling/chrome.ini @@ -0,0 +1,17 @@ +[DEFAULT] +# test_input.html and test_textarea.html are also used as mochitests, hence +# we have to flip the skip assertion flag for the chrome tests here. +prefs = + dom.security.skip_remote_script_assertion_in_system_priv_context=true + +# nsIWidget::SynthesizeNativeKeyEvent() required (Bug 1410525 for headless) +skip-if = os == 'linux' || os == 'android' || headless + +[test_browser.xhtml] +support-files = + browsertest.html +[test_editor.xhtml] +[test_windowed.xhtml] +support-files = + test_input.html + test_textarea.html diff --git a/dom/tests/mochitest/keyhandling/mochitest.ini b/dom/tests/mochitest/keyhandling/mochitest.ini new file mode 100644 index 0000000000..c919397659 --- /dev/null +++ b/dom/tests/mochitest/keyhandling/mochitest.ini @@ -0,0 +1,6 @@ +[DEFAULT] +# nsIWidget::SynthesizeNativeKeyEvent() required (Bug 1410525 for headless) +skip-if = os == 'linux' || os == 'android' || headless + +[test_input.html] +[test_textarea.html] diff --git a/dom/tests/mochitest/keyhandling/test_browser.xhtml b/dom/tests/mochitest/keyhandling/test_browser.xhtml new file mode 100644 index 0000000000..3cddf5ba76 --- /dev/null +++ b/dom/tests/mochitest/keyhandling/test_browser.xhtml @@ -0,0 +1,252 @@ +<?xml version="1.0"?> + +<window title="Browser element keyhandling tests" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="test();"> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/> + <script src="chrome://mochikit/content/tests/SimpleTest/NativeKeyCodes.js"/> + + <script type="application/javascript"> + <![CDATA[ + SimpleTest.waitForExplicitFinish(); + + const IS_MAC = navigator.platform.indexOf("Mac") === 0; + const VK = {}; + const CHARS = {}; + + // Copied values from NativeKeyCodes.js and EventUtils.js + if (IS_MAC) { + VK.LEFT = MAC_VK_LeftArrow; + CHARS.LEFT = "\uF702"; + VK.RIGHT = MAC_VK_RightArrow; + CHARS.RIGHT = "\uF703"; + VK.UP = MAC_VK_UpArrow; + CHARS.UP = "\uF700"; + VK.DOWN = MAC_VK_DownArrow; + CHARS.DOWN = "\uF701"; + VK.SPACE = MAC_VK_Space; + VK.PGDOWN = MAC_VK_PageDown; + CHARS.PGDOWN = "\uF72D"; + VK.PGUP = MAC_VK_PageUp; + CHARS.PGUP = "\uF72C"; + VK.C = MAC_VK_ANSI_C; + VK.HOME = MAC_VK_Home; + CHARS.HOME = "\uF729"; + VK.END = MAC_VK_End; + CHARS.END = "\uF72B"; + } else { + VK.LEFT = WIN_VK_LEFT; + CHARS.LEFT = ""; + VK.RIGHT = WIN_VK_RIGHT; + CHARS.RIGHT = ""; + VK.UP = WIN_VK_UP; + CHARS.UP = ""; + VK.DOWN = WIN_VK_DOWN; + CHARS.DOWN = ""; + VK.SPACE = WIN_VK_SPACE; + VK.PGDOWN = WIN_VK_NEXT; + CHARS.PGDOWN = ""; + VK.PGUP = WIN_VK_PRIOR; + CHARS.PGUP = ""; + VK.C = WIN_VK_C; + VK.HOME = WIN_VK_HOME; + CHARS.HOME = ""; + VK.END = WIN_VK_END; + CHARS.END = ""; + } + + function waitForEvent(target, event) { + info(`Waiting for ${event} event.`); + return new Promise(resolve => { + browser.addEventListener(event, resolve, { once: true }); + }); + } + + function synthesizeKey(keyCode, modifiers, chars) { + return new Promise((resolve, reject) => { + if (!synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, keyCode, modifiers, chars, chars, resolve)) { + reject(); + } + }); + } + + function getWindowProperties(browser, properties) { + let results = {}; + for (let prop of properties) { + results[prop] = browser.contentWindow[prop]; + } + + return results; + } + + function getScrollPosition(browser) { + return getWindowProperties(browser, ["scrollX", "scrollY"]); + } + + async function test() { + // Smooth scrolling makes scroll events take time and it's difficult to know + // when they've ended, so turn it off for this test. + await SpecialPowers.pushPrefEnv({"set": [["general.smoothScroll", false]] }); + + let browser = document.getElementById("browser"); + browser.focus(); + let { scrollX, scrollY } = await getScrollPosition(browser); + is(scrollX, 0, "Should not be scrolled"); + is(scrollY, 0, "Should not be scrolled"); + + info("down"); + await synthesizeKey(VK.DOWN, {}, CHARS.DOWN); + await waitForEvent(browser.contentWindow, "scroll"); + let { scrollX: lineScrollX, scrollY: lineScrollY } = await getScrollPosition(browser); + is(lineScrollX, 0, "Should not be scrolled"); + ok(lineScrollY > 0, "Should be scrolled"); + + info("up"); + await synthesizeKey(VK.UP, {}, CHARS.UP); + await waitForEvent(browser.contentWindow, "scroll"); + { + let { scrollX, scrollY } = await getScrollPosition(browser); + is(scrollX, 0, "Should not be scrolled"); + is(scrollY, 0, "Should not be scrolled"); + } + + info("right"); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await waitForEvent(browser.contentWindow, "scroll"); + let { scrollX: rightScrollX, scrollY: rightScrollY } = await getScrollPosition(browser); + ok(rightScrollX > 0, "Should be scrolled"); + is(rightScrollY, 0, "Should not be scrolled"); + + info("left"); + await synthesizeKey(VK.LEFT, {}, CHARS.LEFT); + await waitForEvent(browser.contentWindow, "scroll"); + { + let { scrollX, scrollY } = await getScrollPosition(browser); + is(scrollX, 0, "Should not be scrolled"); + is(scrollY, 0, "Should not be scrolled"); + } + + info("space"); + await synthesizeKey(VK.SPACE, {}, " "); + await waitForEvent(browser.contentWindow, "scroll"); + let { scrollX: pageScrollX, scrollY: pageScrollY } = await getScrollPosition(browser); + is(pageScrollX, 0, "Should not be scrolled"); + ok(pageScrollY > lineScrollY, "Should be scrolled more than a single line"); + + info("shift+space"); + await synthesizeKey(VK.SPACE, { shiftKey: true }, " "); + await waitForEvent(browser.contentWindow, "scroll"); + { + let { scrollX, scrollY } = await getScrollPosition(browser); + is(scrollX, 0, "Should not be scrolled"); + is(scrollY, 0, "Should not be scrolled"); + } + + info("page down"); + await synthesizeKey(VK.PGDOWN, {}, CHARS.PGDOWN); + await waitForEvent(browser.contentWindow, "scroll"); + { + let { scrollX, scrollY } = await getScrollPosition(browser); + is(scrollX, 0, "Should not be scrolled"); + is(scrollY, pageScrollY, "Should be scrolled a page"); + } + + info("page up"); + await synthesizeKey(VK.PGUP, {}, CHARS.PGUP); + await waitForEvent(browser.contentWindow, "scroll"); + { + let { scrollX, scrollY } = await getScrollPosition(browser); + is(scrollX, 0, "Should not be scrolled"); + is(scrollY, 0, "Should not be scrolled"); + } + + info("accel+down"); + await synthesizeKey(VK.DOWN, { accelKey: true }, CHARS.DOWN); + await waitForEvent(browser.contentWindow, "scroll"); + { + let { scrollX, scrollY, innerHeight } = await getWindowProperties(browser, ["scrollX", "scrollY", "innerHeight"]); + is(scrollX, 0, "Should not be scrolled"); + // We can't know the scrollbar height so check that we're scrolled to within 100px of what we expect. + isfuzzy(scrollY, browser.contentDocument.body.clientHeight - innerHeight, 100, "Should be scrolled to the end."); + } + + info("accel+up"); + await synthesizeKey(VK.UP, { accelKey: true }, CHARS.UP); + await waitForEvent(browser.contentWindow, "scroll"); + { + let { scrollX, scrollY } = await getScrollPosition(browser); + is(scrollX, 0, "Should not be scrolled"); + is(scrollY, 0, "Should not be scrolled"); + } + + info("end"); + await synthesizeKey(VK.END, {}, CHARS.END); + await waitForEvent(browser.contentWindow, "scroll"); + { + let { scrollX, scrollY, innerHeight } = await getWindowProperties(browser, ["scrollX", "scrollY", "innerHeight"]); + is(scrollX, 0, "Should not be scrolled"); + // We can't know the scrollbar height so check that we're scrolled to within 100px of what we expect. + isfuzzy(scrollY, browser.contentDocument.body.clientHeight - innerHeight, 100, "Should be scrolled to the end."); + } + + info("home"); + await synthesizeKey(VK.HOME, {}, CHARS.HOME); + await waitForEvent(browser.contentWindow, "scroll"); + { + let { scrollX, scrollY } = await getScrollPosition(browser); + is(scrollX, 0, "Should not be scrolled"); + is(scrollY, 0, "Should not be scrolled"); + } + + // Select the start of the first paragraph + let paragraph = browser.contentDocument.getElementById("paragraph"); + let selection = browser.contentWindow.getSelection(); + selection.setBaseAndExtent(paragraph.firstChild, 0, paragraph.firstChild, "Lots of".length); + + info("copy"); + await SimpleTest.promiseClipboardChange("Lots of", () => { + synthesizeKey(VK.C, { accelKey: true }, "c"); + }); + + for (let i = 0; i < " paragraphs".length; i++) { + info("select right"); + await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); + } + + info("copy"); + await SimpleTest.promiseClipboardChange("Lots of paragraphs", () => { + synthesizeKey(VK.C, { accelKey: true }, "c"); + }); + + for (let i = 0; i < " paragraphs".length; i++) { + info("select left"); + await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); + } + + info("copy"); + await SimpleTest.promiseClipboardChange("Lots of", () => { + synthesizeKey(VK.C, { accelKey: true }, "c"); + }); + + info("select down"); + await synthesizeKey(VK.DOWN, { shiftKey: true }, CHARS.DOWN); + + info("copy"); + await SimpleTest.promiseClipboardChange("Lots of paragraphs to make a vertical scrollbar.\n\nLots of", () => { + synthesizeKey(VK.C, { accelKey: true }, "c"); + }); + + SimpleTest.finish(); + } + ]]> + </script> + + <body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display:none;"></div> + <pre id="test"></pre> + </body> + <browser id="browser" src="browsertest.html" style="height: 500px"/> +</window> diff --git a/dom/tests/mochitest/keyhandling/test_editor.xhtml b/dom/tests/mochitest/keyhandling/test_editor.xhtml new file mode 100644 index 0000000000..f8fdee4130 --- /dev/null +++ b/dom/tests/mochitest/keyhandling/test_editor.xhtml @@ -0,0 +1,268 @@ +<?xml version="1.0"?> + +<window title="Browser element keyhandling tests" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="test();"> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/> + <script src="chrome://mochikit/content/tests/SimpleTest/NativeKeyCodes.js"/> + + <script type="application/javascript"> + <![CDATA[ + SimpleTest.waitForExplicitFinish(); + + const IS_MAC = navigator.platform.indexOf("Mac") === 0; + const VK = {}; + const CHARS = {}; + + // Copied values from NativeKeyCodes.js and EventUtils.js + if (IS_MAC) { + VK.LEFT = MAC_VK_LeftArrow; + CHARS.LEFT = "\uF702"; + VK.RIGHT = MAC_VK_RightArrow; + CHARS.RIGHT = "\uF703"; + VK.UP = MAC_VK_UpArrow; + CHARS.UP = "\uF700"; + VK.DOWN = MAC_VK_DownArrow; + CHARS.DOWN = "\uF701"; + VK.SPACE = MAC_VK_Space; + VK.X = MAC_VK_ANSI_X; + VK.V = MAC_VK_ANSI_V; + VK.A = MAC_VK_ANSI_A; + VK.Z = MAC_VK_ANSI_Z; + VK.F = MAC_VK_ANSI_F; + VK.O = MAC_VK_ANSI_O; + VK.BACKSPACE = MAC_VK_PC_Backspace; + CHARS.BACKSPACE = "\u007F"; + } else { + VK.LEFT = WIN_VK_LEFT; + CHARS.LEFT = ""; + VK.RIGHT = WIN_VK_RIGHT; + CHARS.RIGHT = ""; + VK.HOME = WIN_VK_HOME; + CHARS.HOME = ""; + VK.END = WIN_VK_END; + CHARS.END = ""; + VK.SPACE = WIN_VK_SPACE; + VK.X = WIN_VK_X; + VK.V = WIN_VK_V; + VK.A = WIN_VK_A; + VK.Z = WIN_VK_Z; + VK.Y = WIN_VK_Y; + VK.F = WIN_VK_F; + VK.O = WIN_VK_O; + VK.BACKSPACE = WIN_VK_BACK; + CHARS.BACKSPACE = ""; + } + + function waitForEvent(target, event) { + info(`Waiting for ${event} event.`); + return new Promise(resolve => { + browser.addEventListener(event, resolve, { once: true }); + }); + } + + function synthesizeKey(keyCode, modifiers, chars) { + return new Promise((resolve, reject) => { + if (!synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, keyCode, modifiers, chars, chars, resolve)) { + reject(); + } + }); + } + + function* nodes(element) { + let node = element.firstChild; + while (node) { + yield node; + + if (node.nodeType === Node.ELEMENT_NODE) { + yield* nodes(node); + } + + node = node.nextSibling; + } + } + + async function checkElement(element, start, selectedText, content = "Test text") { + selectionPosition = (element, range) => { + let pos = 0; + for (let node of nodes(element)) { + if (node.nodeType === Node.TEXT_NODE) { + if (node === range.startContainer) { + return pos + range.startOffset; + } else { + pos += node.nodeValue.length; + } + } else if (node === range.startContainer) { + for (let i = 0; i < range.startOffset; i++) { + pos += node.childNodes[i].textContent.length; + } + + return pos; + } + } + + throw new Error("startContainer of range never found."); + } + + isReady = () => { + let selection = element.contentWindow.getSelection(); + let range = selection.getRangeAt(0); + let pos = selectionPosition(element.contentDocument.documentElement, range); + + if (start != pos) { + return false; + } + if (selectedText != selection.toString()) { + return false; + } + if (content != element.contentDocument.documentElement.textContent) { + return false; + } + return true; + }; + + for (let i = 0; i < 10; i++) { + if (isReady()) { + return; + } + + SimpleTest.requestFlakyTimeout("Polling for changes to apply"); + await new Promise(resolve => setTimeout(resolve, 50)); + } + ok(false, `Timed out waiting for state ${start} "${selectedText}" "${content}"`); + let selection = element.contentWindow.getSelection(); + let range = selection.getRangeAt(0); + info(`${selectionPosition(element.contentDocument.documentElement, range)} "${selection.toString()}" "${element.contentDocument.documentElement.textContent}"`); + } + + async function test() { + let editor = document.getElementById("editor"); + editor.contentDocument.designMode = "on"; + editor.contentWindow.focus(); + let edit = editor.getEditor(editor.contentWindow); + edit.beginningOfDocument(); + + await checkElement(editor, 0, ""); + + info("right"); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await checkElement(editor, 1, ""); + + info("shift+right"); + await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); + await checkElement(editor, 1, "e"); + + info("shift+right"); + await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); + await checkElement(editor, 1, "es"); + + info("shift+left"); + await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); + await checkElement(editor, 1, "e"); + + info("shift+left"); + await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); + await checkElement(editor, 1, ""); + + info("shift+left"); + await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); + await checkElement(editor, 0, "T"); + + info("shift+right"); + await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); + await checkElement(editor, 1, ""); + + info("left"); + await synthesizeKey(VK.LEFT, {}, CHARS.LEFT); + await checkElement(editor, 0, ""); + + if (IS_MAC) { + info("down"); + await synthesizeKey(VK.DOWN, { shiftKey: true }, CHARS.DOWN); + } else { + info("end"); + await synthesizeKey(VK.END, { shiftKey: true }, CHARS.END); + } + await checkElement(editor, 0, "Test text"); + + info("cut"); + await synthesizeKey(VK.X, { accelKey: true }, "x"); + await checkElement(editor, 0, "", ""); + let text = SpecialPowers.getClipboardData("text/unicode"); + is(text, "Test text", "Should have cut to the clipboard"); + SpecialPowers.clipboardCopyString("New text"); + + info("paste"); + await synthesizeKey(VK.V, { accelKey: true }, "v"); + await checkElement(editor, 8, "", "New text"); + + if (IS_MAC) { + info("up"); + await synthesizeKey(VK.UP, {}, CHARS.UP); + } else { + info("home"); + await synthesizeKey(VK.HOME, {}, CHARS.HOME); + } + await checkElement(editor, 0, "", "New text"); + + info("select all"); + await synthesizeKey(VK.A, { accelKey: true}, "a", "select"); + await checkElement(editor, 0, "New text", "New text"); + + info("right"); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await checkElement(editor, 8, "", "New text"); + + info("word left"); + if (IS_MAC) { + await synthesizeKey(VK.LEFT, { altKey: true }, CHARS.LEFT); + } else { + await synthesizeKey(VK.LEFT, { ctrlKey: true }, CHARS.LEFT); + } + await checkElement(editor, 4, "", "New text"); + + info("delete word left"); + if (IS_MAC) { + await synthesizeKey(VK.BACKSPACE, { altKey: true }, CHARS.BACKSPACE); + } else { + await synthesizeKey(VK.BACKSPACE, { ctrlKey: true }, CHARS.BACKSPACE); + } + await checkElement(editor, 0, "", "text"); + + info("undo"); + await synthesizeKey(VK.Z, { accelKey: true }, "z"); + await checkElement(editor, 4, "", "New text"); + + info("redo"); + if (IS_MAC) { + await synthesizeKey(VK.Z, { accelKey: true, shiftKey: true }, "z"); + } else { + await synthesizeKey(VK.Y, { accelKey: true }, "y"); + } + await checkElement(editor, 0, "", "text"); + + info("typing"); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await synthesizeKey(VK.SPACE, {}, " "); + await synthesizeKey(VK.F, {}, "f"); + await synthesizeKey(VK.O, {}, "o"); + await synthesizeKey(VK.O, {}, "o"); + await checkElement(editor, 8, "", "text foo"); + + SimpleTest.finish(); + } + ]]> + </script> + + <body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display:none;"></div> + <pre id="test"></pre> + </body> + <editor id="editor" editortype="text" src="data:text/plain,Test text" style="height: 500px"/> +</window> diff --git a/dom/tests/mochitest/keyhandling/test_input.html b/dom/tests/mochitest/keyhandling/test_input.html new file mode 100644 index 0000000000..e9c5a86978 --- /dev/null +++ b/dom/tests/mochitest/keyhandling/test_input.html @@ -0,0 +1,226 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>input key handling</title> + +<script type="text/javascript" src="http://mochi.test:8888/tests/SimpleTest/SimpleTest.js"></script> +<script type="text/javascript" src="http://mochi.test:8888/tests/SimpleTest/EventUtils.js"></script> +<script type="text/javascript" src="http://mochi.test:8888/tests/SimpleTest/NativeKeyCodes.js"></script> +<link rel="stylesheet" type="text/css" href="http://mochi.test:8888/tests/SimpleTest/test.css" /> + +<script type="text/javascript"> +const IS_MAC = navigator.platform.indexOf("Mac") == 0; +const VK = {}; +const CHARS = {}; + +if (IS_MAC) { + VK.LEFT = MAC_VK_LeftArrow; + CHARS.LEFT = "\uF702"; + VK.RIGHT = MAC_VK_RightArrow; + CHARS.RIGHT = "\uF703"; + VK.UP = MAC_VK_UpArrow; + CHARS.UP = "\uF700"; + VK.DOWN = MAC_VK_DownArrow; + CHARS.DOWN = "\uF701"; + VK.X = MAC_VK_ANSI_X; + VK.V = MAC_VK_ANSI_V; + VK.A = MAC_VK_ANSI_A; + VK.F = MAC_VK_ANSI_F; + VK.O = MAC_VK_ANSI_O; + VK.BACKSPACE = MAC_VK_PC_Backspace; + CHARS.BACKSPACE = "\u007F"; + VK.Z = MAC_VK_ANSI_Z; + VK.SPACE = MAC_VK_Space; +} else { + VK.LEFT = WIN_VK_LEFT; + CHARS.LEFT = ""; + VK.RIGHT = WIN_VK_RIGHT; + CHARS.RIGHT = ""; + VK.UP = WIN_VK_UP; + CHARS.UP = ""; + VK.DOWN = WIN_VK_DOWN; + CHARS.DOWN = ""; + VK.X = WIN_VK_X; + VK.V = WIN_VK_V; + VK.A = WIN_VK_A; + VK.F = WIN_VK_F; + VK.O = WIN_VK_O; + VK.END = WIN_VK_END; + CHARS.END = ""; + VK.HOME = WIN_VK_HOME; + CHARS.HOME = ""; + VK.BACKSPACE = WIN_VK_BACK; + CHARS.BACKSPACE = ""; + VK.Z = WIN_VK_Z; + VK.SPACE = WIN_VK_SPACE; +} + +if (window.arguments && window.arguments[0]) { + ok = window.arguments[0].ok; + is = window.arguments[0].is; +} + +function synthesizeKey(keyCode, modifiers, chars, event = "keyup") { + return new Promise((resolve, reject) => { + window.addEventListener(event, resolve, { once: true }); + + if (!synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, keyCode, modifiers, chars, chars)) { + reject(); + } + }); +} + +async function checkElement(element, start, end, content = "Test text") { + isReady = () => { + if (start != element.selectionStart) { + return false; + } + if (end != element.selectionEnd) { + return false; + } + if (content != element.value) { + return false; + } + return true; + }; + + for (let i = 0; i < 10; i++) { + if (isReady()) { + return; + } + + SimpleTest.requestFlakyTimeout("Polling for changes to apply"); + await new Promise(resolve => setTimeout(resolve, 50)); + } + ok(false, "Timed out waiting for state"); + is(element.selectionStart, start, "Should have the right selectionStart"); + is(element.selectionEnd, end, "Should have the right selectionEnd"); + is(element.value, content, "Should have the right value"); +} + +async function startTest() { + let input = document.getElementById("input"); + input.focus(); + await checkElement(input, 0, 0); + + info("right"); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await checkElement(input, 1, 1); + + info("shift+right"); + await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); + await checkElement(input, 1, 2); + + info("shift+right"); + await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); + await checkElement(input, 1, 3); + + info("shift+left"); + await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); + await checkElement(input, 1, 2); + + info("shift+left"); + await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); + await checkElement(input, 1, 1); + + info("shift+left"); + await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); + await checkElement(input, 0, 1); + + info("shift+right"); + await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); + await checkElement(input, 1, 1); + + info("left"); + await synthesizeKey(VK.LEFT, {}, CHARS.LEFT); + await checkElement(input, 0, 0); + + if (IS_MAC) { + info("down"); + await synthesizeKey(VK.DOWN, { shiftKey: true }, CHARS.DOWN); + } else { + info("end"); + await synthesizeKey(VK.END, { shiftKey: true }, CHARS.END); + } + await checkElement(input, 0, 9); + + info("cut"); + await synthesizeKey(VK.X, { accelKey: true }, "x", "input"); + await checkElement(input, 0, 0, ""); + let text = SpecialPowers.getClipboardData("text/unicode"); + is(text, "Test text", "Should have cut to the clipboard"); + SpecialPowers.clipboardCopyString("New text"); + + info("paste"); + await synthesizeKey(VK.V, { accelKey: true }, "v", "input"); + await checkElement(input, 8, 8, "New text"); + + if (IS_MAC) { + info("up"); + await synthesizeKey(VK.UP, {}, CHARS.UP); + } else { + info("home"); + await synthesizeKey(VK.HOME, {}, CHARS.HOME); + } + await checkElement(input, 0, 0, "New text"); + + info("select all"); + await synthesizeKey(VK.A, { accelKey: true}, "a", "select"); + await checkElement(input, 0, 8, "New text"); + + info("right"); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await checkElement(input, 8, 8, "New text"); + + info("word left"); + if (IS_MAC) { + await synthesizeKey(VK.LEFT, { altKey: true }, CHARS.LEFT); + } else { + await synthesizeKey(VK.LEFT, { ctrlKey: true }, CHARS.LEFT); + } + await checkElement(input, 4, 4, "New text"); + + info("delete word left"); + if (IS_MAC) { + await synthesizeKey(VK.BACKSPACE, { altKey: true }, CHARS.BACKSPACE); + } else { + await synthesizeKey(VK.BACKSPACE, { ctrlKey: true }, CHARS.BACKSPACE); + } + await checkElement(input, 0, 0, "text"); + + info("undo"); + await synthesizeKey(VK.Z, { accelKey: true }, "", "input"); + await checkElement(input, 4, 4, "New text"); + + info("redo"); + await synthesizeKey(VK.Z, { accelKey: true, shiftKey: true }, "", "input"); + await checkElement(input, 0, 0, "text"); + + info("typing"); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await synthesizeKey(VK.SPACE, {}, " "); + await synthesizeKey(VK.F, {}, "f"); + await synthesizeKey(VK.O, {}, "o"); + await synthesizeKey(VK.O, {}, "o"); + await checkElement(input, 8, 8, "text foo"); +} + +async function runTest() { + // When running in windowed mode the caller will start the test once we have + // focus. + if (window.arguments && window.arguments[0]) { + return; + } + + SimpleTest.waitForExplicitFinish(); + await startTest(); + SimpleTest.finish(); +} +</script> +</head> +<body onload="runTest();"> +<input id=input value="Test text"/> +</body> +</html> diff --git a/dom/tests/mochitest/keyhandling/test_textarea.html b/dom/tests/mochitest/keyhandling/test_textarea.html new file mode 100644 index 0000000000..57506790fc --- /dev/null +++ b/dom/tests/mochitest/keyhandling/test_textarea.html @@ -0,0 +1,226 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>input key handling</title> + +<script type="text/javascript" src="http://mochi.test:8888/tests/SimpleTest/SimpleTest.js"></script> +<script type="text/javascript" src="http://mochi.test:8888/tests/SimpleTest/EventUtils.js"></script> +<script type="text/javascript" src="http://mochi.test:8888/tests/SimpleTest/NativeKeyCodes.js"></script> +<link rel="stylesheet" type="text/css" href="http://mochi.test:8888/tests/SimpleTest/test.css" /> + +<script type="text/javascript"> +const IS_MAC = navigator.platform.indexOf("Mac") == 0; +const VK = {}; +const CHARS = {}; + +if (IS_MAC) { + VK.LEFT = MAC_VK_LeftArrow; + CHARS.LEFT = "\uF702"; + VK.RIGHT = MAC_VK_RightArrow; + CHARS.RIGHT = "\uF703"; + VK.UP = MAC_VK_UpArrow; + CHARS.UP = "\uF700"; + VK.DOWN = MAC_VK_DownArrow; + CHARS.DOWN = "\uF701"; + VK.X = MAC_VK_ANSI_X; + VK.V = MAC_VK_ANSI_V; + VK.A = MAC_VK_ANSI_A; + VK.F = MAC_VK_ANSI_F; + VK.O = MAC_VK_ANSI_O; + VK.BACKSPACE = MAC_VK_PC_Backspace; + CHARS.BACKSPACE = "\u007F"; + VK.Z = MAC_VK_ANSI_Z; + VK.SPACE = MAC_VK_Space; +} else { + VK.LEFT = WIN_VK_LEFT; + CHARS.LEFT = ""; + VK.RIGHT = WIN_VK_RIGHT; + CHARS.RIGHT = ""; + VK.UP = WIN_VK_UP; + CHARS.UP = ""; + VK.DOWN = WIN_VK_DOWN; + CHARS.DOWN = ""; + VK.X = WIN_VK_X; + VK.V = WIN_VK_V; + VK.A = WIN_VK_A; + VK.F = WIN_VK_F; + VK.O = WIN_VK_O; + VK.END = WIN_VK_END; + CHARS.END = ""; + VK.HOME = WIN_VK_HOME; + CHARS.HOME = ""; + VK.BACKSPACE = WIN_VK_BACK; + CHARS.BACKSPACE = ""; + VK.Z = WIN_VK_Z; + VK.SPACE = WIN_VK_SPACE; +} + +if (window.arguments && window.arguments[0]) { + ok = window.arguments[0].ok; + is = window.arguments[0].is; +} + +function synthesizeKey(keyCode, modifiers, chars, event = "keyup") { + return new Promise((resolve, reject) => { + window.addEventListener(event, resolve, { once: true }); + + if (!synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, keyCode, modifiers, chars, chars)) { + reject(); + } + }); +} + +async function checkElement(element, start, end, content = "Test text") { + isReady = () => { + if (start != element.selectionStart) { + return false; + } + if (end != element.selectionEnd) { + return false; + } + if (content != element.value) { + return false; + } + return true; + }; + + for (let i = 0; i < 10; i++) { + if (isReady()) { + return; + } + + SimpleTest.requestFlakyTimeout("Polling for changes to apply"); + await new Promise(resolve => setTimeout(resolve, 50)); + } + ok(false, "Timed out waiting for state"); + is(element.selectionStart, start, "Should have the right selectionStart"); + is(element.selectionEnd, end, "Should have the right selectionEnd"); + is(element.value, content, "Should have the right value"); +} + +async function startTest() { + let input = document.getElementById("input"); + input.focus(); + await checkElement(input, 0, 0); + + info("right"); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await checkElement(input, 1, 1); + + info("shift+right"); + await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); + await checkElement(input, 1, 2); + + info("shift+right"); + await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); + await checkElement(input, 1, 3); + + info("shift+left"); + await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); + await checkElement(input, 1, 2); + + info("shift+left"); + await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); + await checkElement(input, 1, 1); + + info("shift+left"); + await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); + await checkElement(input, 0, 1); + + info("shift+right"); + await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); + await checkElement(input, 1, 1); + + info("left"); + await synthesizeKey(VK.LEFT, {}, CHARS.LEFT); + await checkElement(input, 0, 0); + + if (IS_MAC) { + info("down"); + await synthesizeKey(VK.DOWN, { shiftKey: true }, CHARS.DOWN); + } else { + info("end"); + await synthesizeKey(VK.END, { shiftKey: true }, CHARS.END); + } + await checkElement(input, 0, 9); + + info("cut"); + await synthesizeKey(VK.X, { accelKey: true }, "x", "input"); + await checkElement(input, 0, 0, ""); + let text = SpecialPowers.getClipboardData("text/unicode"); + is(text, "Test text", "Should have cut to the clipboard"); + SpecialPowers.clipboardCopyString("New text"); + + info("paste"); + await synthesizeKey(VK.V, { accelKey: true }, "v", "input"); + await checkElement(input, 8, 8, "New text"); + + if (IS_MAC) { + info("up"); + await synthesizeKey(VK.UP, {}, CHARS.UP); + } else { + info("home"); + await synthesizeKey(VK.HOME, {}, CHARS.HOME); + } + await checkElement(input, 0, 0, "New text"); + + info("select all"); + await synthesizeKey(VK.A, { accelKey: true}, "a", "select"); + await checkElement(input, 0, 8, "New text"); + + info("right"); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await checkElement(input, 8, 8, "New text"); + + info("word left"); + if (IS_MAC) { + await synthesizeKey(VK.LEFT, { altKey: true }, CHARS.LEFT); + } else { + await synthesizeKey(VK.LEFT, { ctrlKey: true }, CHARS.LEFT); + } + await checkElement(input, 4, 4, "New text"); + + info("delete word left"); + if (IS_MAC) { + await synthesizeKey(VK.BACKSPACE, { altKey: true }, CHARS.BACKSPACE); + } else { + await synthesizeKey(VK.BACKSPACE, { ctrlKey: true }, CHARS.BACKSPACE); + } + await checkElement(input, 0, 0, "text"); + + info("undo"); + await synthesizeKey(VK.Z, { accelKey: true }, "", "input"); + await checkElement(input, 4, 4, "New text"); + + info("redo"); + await synthesizeKey(VK.Z, { accelKey: true, shiftKey: true }, "", "input"); + await checkElement(input, 0, 0, "text"); + + info("typing"); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); + await synthesizeKey(VK.SPACE, {}, " "); + await synthesizeKey(VK.F, {}, "f"); + await synthesizeKey(VK.O, {}, "o"); + await synthesizeKey(VK.O, {}, "o"); + await checkElement(input, 8, 8, "text foo"); +} + +async function runTest() { + // When running in windowed mode the caller will start the test once we have + // focus. + if (window.arguments && window.arguments[0]) { + return; + } + + SimpleTest.waitForExplicitFinish(); + await startTest(); + SimpleTest.finish(); +} +</script> +</head> +<body onload="runTest();"> +<textarea id=input>Test text</textarea> +</body> +</html> diff --git a/dom/tests/mochitest/keyhandling/test_windowed.xhtml b/dom/tests/mochitest/keyhandling/test_windowed.xhtml new file mode 100644 index 0000000000..c89027b5c6 --- /dev/null +++ b/dom/tests/mochitest/keyhandling/test_windowed.xhtml @@ -0,0 +1,33 @@ +<?xml version="1.0"?> + +<window title="Top-level window keyhandling tests" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="test();"> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + + <script type="application/javascript"> + <![CDATA[ + SimpleTest.waitForExplicitFinish(); + + async function run_test(path) { + let win = window.browsingContext.topChromeWindow + .openDialog(path, "_blank", "width=500,height=500", window); + await SimpleTest.promiseFocus(win); + await win.startTest(); + } + + async function test() { + await run_test("test_input.html"); + await run_test("test_textarea.html"); + SimpleTest.finish(); + } + ]]> + </script> + + <body xmlns="http://www.w3.org/1999/xhtml"> + <p id="display"></p> + <div id="content" style="display:none;"></div> + <pre id="test"></pre> + </body> +</window> |