From 9e47defb845aa3939c1bb5106ec8f9e04610f959 Mon Sep 17 00:00:00 2001 From: Joshua Fehler Date: Fri, 28 Jun 2024 08:45:24 -0400 Subject: [PATCH] Add pressed() method --- docs/keyboard.rst | 25 +++++++++++++++-- splinter/driver/webdriver/keyboard.py | 18 ++++++++++++ tests/tests_webdriver/test_keyboard.py | 38 ++++++++++++++------------ 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/docs/keyboard.rst b/docs/keyboard.rst index d699fdbae..26c75c642 100644 --- a/docs/keyboard.rst +++ b/docs/keyboard.rst @@ -16,9 +16,13 @@ keyboard events inside the current browser window. .. note:: Input detection is limited to the page. You cannot control the browser or your operating system directly using the keyboard. +The keyboard interface is generally used to trigger modifier keys. +For text input, using the keyboard is not recommended. Instead, use the +:func:`element.fill() ` method. + .. note:: The control modifier key is different across operating systems. - e.g.: macOS uses `Command` and Windows & Linux use `Control`. - If you need a cross-platform solution, `CTRL` can be used and will be resolved + e.g.: macOS uses `COMMAND` and Windows & Linux use `CONTROL`. + For a cross-platform solution, `CTRL` can be used and will be resolved for you. Actions @@ -86,6 +90,23 @@ This allows multiple presses to be chained together: the press method is designed for single keys. There may be unintended side effects to using it in place of Element.fill() or Element.type(). +Press Using a Context Manager +----------------------------- + +Using the `pressed()` method, a context manager will be invoked. +The specified key will be held down, then released when the block is exited. + +.. code-block:: python + + from splinter import Browser + + + browser = Browser() + browser.visit("https://duckduckgo.com/") + with browser.keyboard.pressed("SHIFT"): + browser.find_by_css("[@name='q']").fill('splinter') + + Element.press() --------------- diff --git a/splinter/driver/webdriver/keyboard.py b/splinter/driver/webdriver/keyboard.py index 967f6c1d4..19c680ad3 100644 --- a/splinter/driver/webdriver/keyboard.py +++ b/splinter/driver/webdriver/keyboard.py @@ -1,4 +1,6 @@ +import contextlib import platform +from collections.abc import Iterator from typing import Union from selenium.webdriver.common.action_chains import ActionChains @@ -136,3 +138,19 @@ def press(self, key_pattern: str, delay: int = 0) -> "Keyboard": chain.perform() return self + + @contextlib.contextmanager + def pressed(self, key_pattern: str) -> Iterator[None]: + """Hold a key pattern inside a `with` block and releas it upon exit. + + Arguments: + key_pattern: Pattern of keys to hold and release. + + Example: + >>> b = Browser() + >>> with b.keyboard.pressed('CONTROL'): + >>> ... + """ + self.down(key_pattern) + yield + self.up(key_pattern) diff --git a/tests/tests_webdriver/test_keyboard.py b/tests/tests_webdriver/test_keyboard.py index c1cfadae5..3ba62bc4e 100644 --- a/tests/tests_webdriver/test_keyboard.py +++ b/tests/tests_webdriver/test_keyboard.py @@ -1,13 +1,8 @@ -from splinter.driver.webdriver import Keyboard - - def test_keyboard_down_modifier(browser, app_url): """Scenario: Keys can be held down""" browser.visit(app_url) - keyboard = Keyboard(browser.driver) - - keyboard.down("CONTROL") + browser.keyboard.down("CONTROL") elem = browser.find_by_css("#keypress_detect") assert elem.first @@ -17,22 +12,18 @@ def test_keyboard_up_modifier(browser, app_url): """Scenario: Keys can be held up""" browser.visit(app_url) - keyboard = Keyboard(browser.driver) - - keyboard.down("CONTROL") - keyboard.up("CONTROL") + browser.keyboard.down("CONTROL") + browser.keyboard.up("CONTROL") elem = browser.find_by_css("#keyup_detect") assert elem.first def test_keyboard_press_modifier(browser, app_url): - """Keys can be pressed""" + """Scenario: Keys can be pressed""" browser.visit(app_url) - keyboard = Keyboard(browser.driver) - - keyboard.press("CONTROL") + browser.keyboard.press("CONTROL") elem = browser.find_by_css("#keyup_detect") assert elem.first @@ -42,14 +33,27 @@ def test_element_press_combo(browser, app_url): """Scenario: Key presses can be used in a combo""" browser.visit(app_url) - keyboard = Keyboard(browser.driver) - - keyboard.press("CONTROL+a") + browser.keyboard.press("CONTROL+a") elem = browser.find_by_css("#keypress_detect_a") assert elem.first +def test_keyboard_pressed_modifier(browser, app_url): + """Scenario: Keys can be pressed by a context manager.""" + browser.visit(app_url) + + with browser.keyboard.pressed("CONTROL"): + down_elem = browser.find_by_css("#keypress_detect") + assert down_elem.first + + up_elem = browser.find_by_css("#keyup_detect") + assert up_elem.is_empty() + + up_elem = browser.find_by_css("#keyup_detect") + assert up_elem.first + + def test_keyboard_ctrl(browser, app_url): """Scenario: The CTRL value is correct across platforms""" browser.visit(app_url)