diff --git a/tests/addon.py b/tests/addon.py index b5d65e4c..33a5bc3c 100644 --- a/tests/addon.py +++ b/tests/addon.py @@ -320,7 +320,7 @@ def open_context_menu(self) -> None: else: offset = 0 - self.helper.gui_typewrite(['up'] + ['up'] * offset + ['enter'], interval=0.5) + self.helper.gui_write(['up'] + ['up'] * offset + ['enter'], interval=0.5) # TODO this doesn't belong to this class really, think about it def move_to(self, element) -> None: diff --git a/tests/addon_helper.py b/tests/addon_helper.py index 1cd280fa..9dd97293 100644 --- a/tests/addon_helper.py +++ b/tests/addon_helper.py @@ -4,13 +4,12 @@ from pathlib import Path import re import subprocess -from typing import Any, List +from typing import Any from loguru import logger -import psutil from selenium import webdriver -from webdriver_utils import is_headless +from webdriver_utils import is_headless, get_browser_process @dataclass @@ -27,6 +26,10 @@ def manifest(self) -> Any: # ugh. sadly (at least in Firefox) there doesn't seem a way to read actual manifest loaded in browser? return json.loads((self.addon_source / 'manifest.json').read_text()) + @cached_property + def manifest_version(self) -> int: + return self.manifest['manifest_version'] + @property def extension_prefix(self) -> str: protocol = { @@ -63,9 +66,9 @@ def trigger_command(self, command: str) -> None: ) else: hotkey = commands[command]['suggested_key']['default'] - self.trigger_hotkey(hotkey) + self.gui_hotkey(hotkey) - def trigger_hotkey(self, key: str) -> None: + def gui_hotkey(self, key: str) -> None: assert not self.headless # just in case lkey = key.lower().split('+') logger.debug(f'sending hotkey {lkey}') @@ -75,13 +78,13 @@ def trigger_hotkey(self, key: str) -> None: focus_browser_window(self.driver) pyautogui.hotkey(*lkey) - def gui_typewrite(self, *args, **kwargs) -> None: + def gui_write(self, *args, **kwargs) -> None: assert not self.headless import pyautogui focus_browser_window(self.driver) - pyautogui.typewrite(*args, **kwargs) # select first item + pyautogui.write(*args, **kwargs) # NOTE looks like it used to be posssible in webdriver api? @@ -142,11 +145,7 @@ def get_window_id(driver: webdriver.Remote) -> str: pid = str(driver.capabilities['moz:processID']) elif driver.name == 'chrome': # ugh no pid in capabilities... - driver_pid = driver.service.process.pid # type: ignore[attr-defined] - process = psutil.Process(driver_pid) - [chrome_process] = process.children() - cmdline = chrome_process.cmdline() - assert '--enable-automation' in cmdline, cmdline + chrome_process = get_browser_process(driver) pid = str(chrome_process.pid) else: raise RuntimeError(driver.name) diff --git a/tests/end2end_test.py b/tests/end2end_test.py index a854c600..9f002e51 100755 --- a/tests/end2end_test.py +++ b/tests/end2end_test.py @@ -291,7 +291,7 @@ def test_add_to_blacklist_context_menu(addon: Addon, driver: Driver) -> None: driver.get('https://example.com') addon.open_context_menu() - addon.helper.gui_typewrite(['enter']) # select first item + addon.helper.gui_write(['enter']) # select first item confirm('shows prompt with alert to enter pattern to block?') wait_for_alert(driver).accept() @@ -682,7 +682,7 @@ def test_fuzz(addon: Addon, driver: Driver, backend: Backend) -> None: pytest.skip("Rest of this test uses send_key to restore tab and it's not working under headless webdriver :(") for _ in range(10): - addon.helper.trigger_hotkey('Ctrl+Shift+t') # restore tabs + addon.helper.gui_hotkey('Ctrl+Shift+t') # restore tabs sleep(0.1) confirm("shouldn't result in 'unexpected error occured'; show only show single notification per page") diff --git a/tests/webdriver_utils.py b/tests/webdriver_utils.py index 51d99818..08af3040 100644 --- a/tests/webdriver_utils.py +++ b/tests/webdriver_utils.py @@ -3,6 +3,7 @@ from time import sleep from typing import Dict, Iterator, Optional +import psutil from selenium import webdriver from selenium.common.exceptions import NoAlertPresentException from selenium.webdriver import Remote as Driver @@ -53,8 +54,10 @@ def is_headless(driver: Driver) -> bool: if driver.name == 'firefox': return driver.capabilities.get('moz:headless', False) elif driver.name == 'chrome': + return any('--headless' in c for c in get_browser_process(driver).cmdline()) + # ugh.. looks like this stopped working? # https://antoinevastel.com/bot%20detection/2018/01/17/detect-chrome-headless-v2.html - return driver.execute_script("return navigator.webdriver") is True + # return driver.execute_script("return navigator.webdriver") is True else: raise RuntimeError(driver.name) @@ -157,3 +160,17 @@ def get_webdriver( version_string = ' '.join(f'{k}={v}' for k, v in version_data.items()) logger.info(f'webdriver version: {version_string}') return driver + + +def get_browser_process(driver: webdriver.Remote) -> psutil.Process: + driver_pid = driver.service.process.pid # type: ignore[attr-defined] + dprocess = psutil.Process(driver_pid) + [process] = dprocess.children() + cmdline = process.cmdline() + if driver.name == 'firefox': + assert '--marionette' in cmdline, cmdline + elif driver.name == 'chrome': + assert '--enable-automation' in cmdline, cmdline + else: + raise AssertionError + return process