mirror of
https://forge.fsky.io/oneflux/omegafox.git
synced 2026-02-10 14:22:05 -08:00
525 lines
20 KiB
Python
525 lines
20 KiB
Python
# Copyright (c) Microsoft Corporation.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
import pytest
|
|
from playwright.async_api import Error, JSHandle, Page
|
|
|
|
from tests.server import Server
|
|
|
|
from .utils import Utils
|
|
|
|
|
|
async def captureLastKeydown(page: Page) -> JSHandle:
|
|
lastEvent = await page.evaluate_handle(
|
|
"""() => {
|
|
const lastEvent = {
|
|
repeat: false,
|
|
location: -1,
|
|
code: '',
|
|
key: '',
|
|
metaKey: false,
|
|
keyIdentifier: 'unsupported'
|
|
};
|
|
document.addEventListener('keydown', e => {
|
|
lastEvent.repeat = e.repeat;
|
|
lastEvent.location = e.location;
|
|
lastEvent.key = e.key;
|
|
lastEvent.code = e.code;
|
|
lastEvent.metaKey = e.metaKey;
|
|
// keyIdentifier only exists in WebKit, and isn't in TypeScript's lib.
|
|
lastEvent.keyIdentifier = 'keyIdentifier' in e && e.keyIdentifier;
|
|
}, true);
|
|
return lastEvent;
|
|
}"""
|
|
)
|
|
return lastEvent
|
|
|
|
|
|
async def test_keyboard_type_into_a_textarea(page: Page) -> None:
|
|
await page.evaluate(
|
|
"""
|
|
const textarea = document.createElement('textarea');
|
|
document.body.appendChild(textarea);
|
|
textarea.focus();
|
|
"""
|
|
)
|
|
text = "Hello world. I am the text that was typed!"
|
|
await page.keyboard.type(text)
|
|
assert await page.evaluate('document.querySelector("textarea").value') == text
|
|
|
|
|
|
async def test_keyboard_move_with_the_arrow_keys(page: Page, server: Server) -> None:
|
|
await page.goto(f"{server.PREFIX}/input/textarea.html")
|
|
await page.type("textarea", "Hello World!")
|
|
assert await page.evaluate("document.querySelector('textarea').value") == "Hello World!"
|
|
for _ in "World!":
|
|
await page.keyboard.press("ArrowLeft")
|
|
await page.keyboard.type("inserted ")
|
|
assert (
|
|
await page.evaluate("document.querySelector('textarea').value") == "Hello inserted World!"
|
|
)
|
|
await page.keyboard.down("Shift")
|
|
for _ in "inserted ":
|
|
await page.keyboard.press("ArrowLeft")
|
|
await page.keyboard.up("Shift")
|
|
await page.keyboard.press("Backspace")
|
|
assert await page.evaluate("document.querySelector('textarea').value") == "Hello World!"
|
|
|
|
|
|
async def test_keyboard_send_a_character_with_elementhandle_press(
|
|
page: Page, server: Server
|
|
) -> None:
|
|
await page.goto(f"{server.PREFIX}/input/textarea.html")
|
|
textarea = await page.query_selector("textarea")
|
|
assert textarea
|
|
await textarea.press("a")
|
|
assert await page.evaluate("document.querySelector('textarea').value") == "a"
|
|
await page.evaluate("() => window.addEventListener('keydown', e => e.preventDefault(), true)")
|
|
await textarea.press("b")
|
|
assert await page.evaluate("document.querySelector('textarea').value") == "a"
|
|
|
|
|
|
async def test_should_send_a_character_with_send_character(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/textarea.html")
|
|
await page.focus("textarea")
|
|
await page.keyboard.insert_text("嗨")
|
|
assert await page.evaluate('() => document.querySelector("textarea").value') == "嗨"
|
|
await page.evaluate('() => window.addEventListener("keydown", e => e.preventDefault(), true)')
|
|
await page.keyboard.insert_text("a")
|
|
assert await page.evaluate('() => document.querySelector("textarea").value') == "嗨a"
|
|
|
|
|
|
async def test_should_only_emit_input_event(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/textarea.html")
|
|
await page.focus("textarea")
|
|
events = await page.evaluate_handle(
|
|
"""() => {
|
|
const events = [];
|
|
document.addEventListener('keydown', e => events.push(e.type));
|
|
document.addEventListener('keyup', e => events.push(e.type));
|
|
document.addEventListener('keypress', e => events.push(e.type));
|
|
document.addEventListener('input', e => events.push(e.type));
|
|
return events;
|
|
}"""
|
|
)
|
|
|
|
await page.keyboard.insert_text("hello world")
|
|
assert await events.json_value() == ["input"]
|
|
|
|
|
|
@pytest.mark.skip(reason="Not supported by Camoufox")
|
|
async def test_should_report_shiftkey(
|
|
page: Page, server: Server, is_mac: bool, is_firefox: bool
|
|
) -> None:
|
|
if is_firefox and is_mac:
|
|
pytest.skip()
|
|
await page.goto(server.PREFIX + "/input/keyboard.html")
|
|
keyboard = page.keyboard
|
|
codeForKey = {"Shift": 16, "Alt": 18, "Control": 17}
|
|
for modifierKey in codeForKey.keys():
|
|
await keyboard.down(modifierKey)
|
|
assert (
|
|
await page.evaluate("() => getResult()")
|
|
== "Keydown: "
|
|
+ modifierKey
|
|
+ " "
|
|
+ modifierKey
|
|
+ "Left "
|
|
+ str(codeForKey[modifierKey])
|
|
+ " ["
|
|
+ modifierKey
|
|
+ "]"
|
|
)
|
|
await keyboard.down("!")
|
|
# Shift+! will generate a keypress
|
|
if modifierKey == "Shift":
|
|
assert (
|
|
await page.evaluate("() => getResult()")
|
|
== "Keydown: ! Digit1 49 ["
|
|
+ modifierKey
|
|
+ "]\nKeypress: ! Digit1 33 33 ["
|
|
+ modifierKey
|
|
+ "]"
|
|
)
|
|
else:
|
|
assert (
|
|
await page.evaluate("() => getResult()")
|
|
== "Keydown: ! Digit1 49 [" + modifierKey + "]"
|
|
)
|
|
|
|
await keyboard.up("!")
|
|
assert (
|
|
await page.evaluate("() => getResult()") == "Keyup: ! Digit1 49 [" + modifierKey + "]"
|
|
)
|
|
await keyboard.up(modifierKey)
|
|
assert (
|
|
await page.evaluate("() => getResult()")
|
|
== "Keyup: "
|
|
+ modifierKey
|
|
+ " "
|
|
+ modifierKey
|
|
+ "Left "
|
|
+ str(codeForKey[modifierKey])
|
|
+ " []"
|
|
)
|
|
|
|
|
|
@pytest.mark.skip(reason="Not supported by Camoufox")
|
|
async def test_should_report_multiple_modifiers(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/keyboard.html")
|
|
keyboard = page.keyboard
|
|
await keyboard.down("Control")
|
|
assert await page.evaluate("() => getResult()") == "Keydown: Control ControlLeft 17 [Control]"
|
|
await keyboard.down("Alt")
|
|
assert await page.evaluate("() => getResult()") == "Keydown: Alt AltLeft 18 [Alt Control]"
|
|
await keyboard.down(";")
|
|
assert await page.evaluate("() => getResult()") == "Keydown: ; Semicolon 186 [Alt Control]"
|
|
await keyboard.up(";")
|
|
assert await page.evaluate("() => getResult()") == "Keyup: ; Semicolon 186 [Alt Control]"
|
|
await keyboard.up("Control")
|
|
assert await page.evaluate("() => getResult()") == "Keyup: Control ControlLeft 17 [Alt]"
|
|
await keyboard.up("Alt")
|
|
assert await page.evaluate("() => getResult()") == "Keyup: Alt AltLeft 18 []"
|
|
|
|
|
|
@pytest.mark.skip(reason="Not supported by Camoufox")
|
|
async def test_should_send_proper_codes_while_typing(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/keyboard.html")
|
|
await page.keyboard.type("!")
|
|
assert await page.evaluate("() => getResult()") == "\n".join(
|
|
[
|
|
"Keydown: ! Digit1 49 []",
|
|
"Keypress: ! Digit1 33 33 []",
|
|
"Keyup: ! Digit1 49 []",
|
|
]
|
|
)
|
|
await page.keyboard.type("^")
|
|
assert await page.evaluate("() => getResult()") == "\n".join(
|
|
[
|
|
"Keydown: ^ Digit6 54 []",
|
|
"Keypress: ^ Digit6 94 94 []",
|
|
"Keyup: ^ Digit6 54 []",
|
|
]
|
|
)
|
|
|
|
|
|
@pytest.mark.skip(reason="Not supported by Camoufox")
|
|
async def test_should_send_proper_codes_while_typing_with_shift(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/keyboard.html")
|
|
keyboard = page.keyboard
|
|
await keyboard.down("Shift")
|
|
await page.keyboard.type("~")
|
|
assert await page.evaluate("() => getResult()") == "\n".join(
|
|
[
|
|
"Keydown: Shift ShiftLeft 16 [Shift]",
|
|
"Keydown: ~ Backquote 192 [Shift]", # 192 is ` keyCode
|
|
"Keypress: ~ Backquote 126 126 [Shift]", # 126 is ~ charCode
|
|
"Keyup: ~ Backquote 192 [Shift]",
|
|
]
|
|
)
|
|
await keyboard.up("Shift")
|
|
|
|
|
|
async def test_should_not_type_canceled_events(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/textarea.html")
|
|
await page.focus("textarea")
|
|
await page.evaluate(
|
|
"""() => {
|
|
window.addEventListener('keydown', event => {
|
|
event.stopPropagation();
|
|
event.stopImmediatePropagation();
|
|
if (event.key === 'l')
|
|
event.preventDefault();
|
|
if (event.key === 'o')
|
|
event.preventDefault();
|
|
}, false);
|
|
}"""
|
|
)
|
|
|
|
await page.keyboard.type("Hello World!")
|
|
assert await page.eval_on_selector("textarea", "textarea => textarea.value") == "He Wrd!"
|
|
|
|
|
|
@pytest.mark.skip(reason="Not supported by Camoufox")
|
|
async def test_should_press_plus(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/keyboard.html")
|
|
await page.keyboard.press("+")
|
|
assert await page.evaluate("() => getResult()") == "\n".join(
|
|
[
|
|
"Keydown: + Equal 187 []", # 192 is ` keyCode
|
|
"Keypress: + Equal 43 43 []", # 126 is ~ charCode
|
|
"Keyup: + Equal 187 []",
|
|
]
|
|
)
|
|
|
|
|
|
@pytest.mark.skip(reason="Not supported by Camoufox")
|
|
async def test_should_press_shift_plus(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/keyboard.html")
|
|
await page.keyboard.press("Shift++")
|
|
assert await page.evaluate("() => getResult()") == "\n".join(
|
|
[
|
|
"Keydown: Shift ShiftLeft 16 [Shift]",
|
|
"Keydown: + Equal 187 [Shift]", # 192 is ` keyCode
|
|
"Keypress: + Equal 43 43 [Shift]", # 126 is ~ charCode
|
|
"Keyup: + Equal 187 [Shift]",
|
|
"Keyup: Shift ShiftLeft 16 []",
|
|
]
|
|
)
|
|
|
|
|
|
@pytest.mark.skip(reason="Not supported by Camoufox")
|
|
async def test_should_support_plus_separated_modifiers(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/keyboard.html")
|
|
await page.keyboard.press("Shift+~")
|
|
assert await page.evaluate("() => getResult()") == "\n".join(
|
|
[
|
|
"Keydown: Shift ShiftLeft 16 [Shift]",
|
|
"Keydown: ~ Backquote 192 [Shift]", # 192 is ` keyCode
|
|
"Keypress: ~ Backquote 126 126 [Shift]", # 126 is ~ charCode
|
|
"Keyup: ~ Backquote 192 [Shift]",
|
|
"Keyup: Shift ShiftLeft 16 []",
|
|
]
|
|
)
|
|
|
|
|
|
@pytest.mark.skip(reason="Not supported by Camoufox")
|
|
async def test_should_suport_multiple_plus_separated_modifiers(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/keyboard.html")
|
|
await page.keyboard.press("Control+Shift+~")
|
|
assert await page.evaluate("() => getResult()") == "\n".join(
|
|
[
|
|
"Keydown: Control ControlLeft 17 [Control]",
|
|
"Keydown: Shift ShiftLeft 16 [Control Shift]",
|
|
"Keydown: ~ Backquote 192 [Control Shift]", # 192 is ` keyCode
|
|
"Keyup: ~ Backquote 192 [Control Shift]",
|
|
"Keyup: Shift ShiftLeft 16 [Control]",
|
|
"Keyup: Control ControlLeft 17 []",
|
|
]
|
|
)
|
|
|
|
|
|
@pytest.mark.skip(reason="Not supported by Camoufox")
|
|
async def test_should_shift_raw_codes(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/keyboard.html")
|
|
await page.keyboard.press("Shift+Digit3")
|
|
assert await page.evaluate("() => getResult()") == "\n".join(
|
|
[
|
|
"Keydown: Shift ShiftLeft 16 [Shift]",
|
|
"Keydown: # Digit3 51 [Shift]", # 51 is # keyCode
|
|
"Keypress: # Digit3 35 35 [Shift]", # 35 is # charCode
|
|
"Keyup: # Digit3 51 [Shift]",
|
|
"Keyup: Shift ShiftLeft 16 []",
|
|
]
|
|
)
|
|
|
|
|
|
async def test_should_specify_repeat_property(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/textarea.html")
|
|
await page.focus("textarea")
|
|
lastEvent = await captureLastKeydown(page)
|
|
await page.keyboard.down("a")
|
|
assert await lastEvent.evaluate("e => e.repeat") is False
|
|
await page.keyboard.press("a")
|
|
assert await lastEvent.evaluate("e => e.repeat")
|
|
|
|
await page.keyboard.down("b")
|
|
assert await lastEvent.evaluate("e => e.repeat") is False
|
|
await page.keyboard.down("b")
|
|
assert await lastEvent.evaluate("e => e.repeat")
|
|
|
|
await page.keyboard.up("a")
|
|
await page.keyboard.down("a")
|
|
assert await lastEvent.evaluate("e => e.repeat") is False
|
|
|
|
|
|
async def test_should_type_all_kinds_of_characters(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/textarea.html")
|
|
await page.focus("textarea")
|
|
text = "This text goes onto two lines.\nThis character is 嗨."
|
|
await page.keyboard.type(text)
|
|
assert await page.eval_on_selector("textarea", "t => t.value") == text
|
|
|
|
|
|
async def test_should_specify_location(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/textarea.html")
|
|
lastEvent = await captureLastKeydown(page)
|
|
textarea = await page.query_selector("textarea")
|
|
assert textarea
|
|
|
|
await textarea.press("Digit5")
|
|
assert await lastEvent.evaluate("e => e.location") == 0
|
|
|
|
await textarea.press("ControlLeft")
|
|
assert await lastEvent.evaluate("e => e.location") == 1
|
|
|
|
await textarea.press("ControlRight")
|
|
assert await lastEvent.evaluate("e => e.location") == 2
|
|
|
|
await textarea.press("NumpadSubtract")
|
|
assert await lastEvent.evaluate("e => e.location") == 3
|
|
|
|
|
|
async def test_should_press_enter(page: Page) -> None:
|
|
await page.set_content("<textarea></textarea>")
|
|
await page.focus("textarea")
|
|
lastEventHandle = await captureLastKeydown(page)
|
|
|
|
async def testEnterKey(key: str, expectedKey: str, expectedCode: str) -> None:
|
|
await page.keyboard.press(key)
|
|
lastEvent = await lastEventHandle.json_value()
|
|
assert lastEvent["key"] == expectedKey
|
|
assert lastEvent["code"] == expectedCode
|
|
value = await page.eval_on_selector("textarea", "t => t.value")
|
|
assert value == "\n"
|
|
await page.eval_on_selector("textarea", "t => t.value = ''")
|
|
|
|
await testEnterKey("Enter", "Enter", "Enter")
|
|
await testEnterKey("NumpadEnter", "Enter", "NumpadEnter")
|
|
await testEnterKey("\n", "Enter", "Enter")
|
|
await testEnterKey("\r", "Enter", "Enter")
|
|
|
|
|
|
async def test_should_throw_unknown_keys(page: Page, server: Server) -> None:
|
|
with pytest.raises(Error) as exc:
|
|
await page.keyboard.press("NotARealKey")
|
|
assert exc.value.message == 'Keyboard.press: Unknown key: "NotARealKey"'
|
|
|
|
with pytest.raises(Error) as exc:
|
|
await page.keyboard.press("ё")
|
|
assert exc.value.message == 'Keyboard.press: Unknown key: "ё"'
|
|
|
|
with pytest.raises(Error) as exc:
|
|
await page.keyboard.press("😊")
|
|
assert exc.value.message == 'Keyboard.press: Unknown key: "😊"'
|
|
|
|
|
|
async def test_should_type_emoji(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/textarea.html")
|
|
await page.type("textarea", "👹 Tokyo street Japan 🇯🇵")
|
|
assert (
|
|
await page.eval_on_selector("textarea", "textarea => textarea.value")
|
|
== "👹 Tokyo street Japan 🇯🇵"
|
|
)
|
|
|
|
|
|
async def test_should_type_emoji_into_an_iframe(page: Page, server: Server, utils: Utils) -> None:
|
|
await page.goto(server.EMPTY_PAGE)
|
|
await utils.attach_frame(page, "emoji-test", server.PREFIX + "/input/textarea.html")
|
|
frame = page.frames[1]
|
|
textarea = await frame.query_selector("textarea")
|
|
assert textarea
|
|
await textarea.type("👹 Tokyo street Japan 🇯🇵")
|
|
assert (
|
|
await frame.eval_on_selector("textarea", "textarea => textarea.value")
|
|
== "👹 Tokyo street Japan 🇯🇵"
|
|
)
|
|
|
|
|
|
async def test_should_handle_select_all(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/textarea.html")
|
|
textarea = await page.query_selector("textarea")
|
|
assert textarea
|
|
await textarea.type("some text")
|
|
await page.keyboard.down("ControlOrMeta")
|
|
await page.keyboard.press("a")
|
|
await page.keyboard.up("ControlOrMeta")
|
|
await page.keyboard.press("Backspace")
|
|
assert await page.eval_on_selector("textarea", "textarea => textarea.value") == ""
|
|
|
|
|
|
async def test_should_be_able_to_prevent_select_all(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/textarea.html")
|
|
textarea = await page.query_selector("textarea")
|
|
assert textarea
|
|
await textarea.type("some text")
|
|
await page.eval_on_selector(
|
|
"textarea",
|
|
"""textarea => {
|
|
textarea.addEventListener('keydown', event => {
|
|
if (event.key === 'a' && (event.metaKey || event.ctrlKey))
|
|
event.preventDefault();
|
|
}, false);
|
|
}""",
|
|
)
|
|
|
|
await page.keyboard.down("ControlOrMeta")
|
|
await page.keyboard.press("a")
|
|
await page.keyboard.up("ControlOrMeta")
|
|
await page.keyboard.press("Backspace")
|
|
assert await page.eval_on_selector("textarea", "textarea => textarea.value") == "some tex"
|
|
|
|
|
|
@pytest.mark.only_platform("darwin")
|
|
@pytest.mark.skip_browser("firefox") # Upstream issue
|
|
async def test_should_support_macos_shortcuts(
|
|
page: Page, server: Server, is_firefox: bool, is_mac: bool
|
|
) -> None:
|
|
await page.goto(server.PREFIX + "/input/textarea.html")
|
|
textarea = await page.query_selector("textarea")
|
|
assert textarea
|
|
await textarea.type("some text")
|
|
# select one word backwards
|
|
await page.keyboard.press("Shift+Control+Alt+KeyB")
|
|
await page.keyboard.press("Backspace")
|
|
assert await page.eval_on_selector("textarea", "textarea => textarea.value") == "some "
|
|
|
|
|
|
async def test_should_press_the_meta_key(page: Page) -> None:
|
|
lastEvent = await captureLastKeydown(page)
|
|
await page.keyboard.press("Meta")
|
|
v = await lastEvent.json_value()
|
|
metaKey = v["metaKey"]
|
|
key = v["key"]
|
|
code = v["code"]
|
|
assert key == "Meta"
|
|
assert code == "MetaLeft"
|
|
assert metaKey
|
|
|
|
|
|
async def test_should_work_after_a_cross_origin_navigation(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/empty.html")
|
|
await page.goto(server.CROSS_PROCESS_PREFIX + "/empty.html")
|
|
lastEvent = await captureLastKeydown(page)
|
|
await page.keyboard.press("a")
|
|
assert await lastEvent.evaluate("l => l.key") == "a"
|
|
|
|
|
|
# event.keyIdentifier has been removed from all browsers except WebKit
|
|
@pytest.mark.only_browser("webkit")
|
|
async def test_should_expose_keyIdentifier_in_webkit(page: Page, server: Server) -> None:
|
|
lastEvent = await captureLastKeydown(page)
|
|
keyMap = {
|
|
"ArrowUp": "Up",
|
|
"ArrowDown": "Down",
|
|
"ArrowLeft": "Left",
|
|
"ArrowRight": "Right",
|
|
"Backspace": "U+0008",
|
|
"Tab": "U+0009",
|
|
"Delete": "U+007F",
|
|
"a": "U+0041",
|
|
"b": "U+0042",
|
|
"F12": "F12",
|
|
}
|
|
for key, keyIdentifier in keyMap.items():
|
|
await page.keyboard.press(key)
|
|
assert await lastEvent.evaluate("e => e.keyIdentifier") == keyIdentifier
|
|
|
|
|
|
async def test_should_scroll_with_pagedown(page: Page, server: Server) -> None:
|
|
await page.goto(server.PREFIX + "/input/scrollable.html")
|
|
# A click is required for WebKit to send the event into the body.
|
|
await page.click("body")
|
|
await page.keyboard.press("PageDown")
|
|
# We can't wait for the scroll to finish, so just wait for it to start.
|
|
await page.wait_for_function("() => scrollY > 0")
|