From 7a4563cdd0f9c6fca31904e8804d7b927a1eecf7 Mon Sep 17 00:00:00 2001 From: Mike Reiche Date: Tue, 11 Mar 2025 14:43:41 +0100 Subject: [PATCH 1/8] Implement WebDriverManagerListener --- paf/assertion.py | 10 ++-- paf/common.py | 5 ++ paf/config.py | 6 +-- paf/listener.py | 107 ++++++++++++++++++++++++++--------------- paf/manager.py | 19 ++++++++ paf/uielement.py | 10 ++-- test/__init__.py | 1 + test/test_demo_mode.py | 43 +++++++++++------ test/test_manager.py | 64 +++++++++++++++++++++++- 9 files changed, 196 insertions(+), 69 deletions(-) diff --git a/paf/assertion.py b/paf/assertion.py index d4286c5..da3067a 100644 --- a/paf/assertion.py +++ b/paf/assertion.py @@ -72,15 +72,15 @@ def _test_sequence( test: Predicate[ACTUAL_TYPE], additional_subject: Supplier = None, ) -> bool: - from paf.listener import Listener - listener = inject.instance(Listener) + from paf.listener import AssertionListener + assertion_listener = inject.instance(AssertionListener) try: def perform_test(): assert test(self.actual), "Expected" - retry(perform_test, lambda e: listener.assertion_failed(self, self._find_closest_ui_element(), e)) - listener.assertion_passed(self, self._find_closest_ui_element()) + retry(perform_test, lambda e: assertion_listener.assertion_failed(self, self._find_closest_ui_element(), e)) + assertion_listener.assertion_passed(self, self._find_closest_ui_element()) return True except RetryException as exception: @@ -88,7 +88,7 @@ def perform_test(): if additional_subject: exception.add_subject(additional_subject()) #exception.update_sequence(sequence) - listener.assertion_failed_finally(self, self._find_closest_ui_element(), exception) + assertion_listener.assertion_failed_finally(self, self._find_closest_ui_element(), exception) if self._raise: raise AssertionErrorWrapper(exception) diff --git a/paf/common.py b/paf/common.py index 65370b2..044014b 100644 --- a/paf/common.py +++ b/paf/common.py @@ -211,6 +211,11 @@ class Property(Enum): def env(prop: "Property") -> any: return os.getenv(prop.name, prop.value) + @staticmethod + def is_true(prop: "Property") -> bool: + val = Property.env(prop) + return val and str.lower(val) in ("1", "on", "true", "enabled") + class Formatter: def datetime(self, date: datetime): diff --git a/paf/config.py b/paf/config.py index 9d88797..4c705b4 100644 --- a/paf/config.py +++ b/paf/config.py @@ -4,13 +4,11 @@ import paf.control import paf.manager import paf.page -from paf.common import Property -from paf.listener import Listener, HighlightListener +import paf.listener def inject(binder: Binder): binder.install(paf.manager.inject_config) binder.install(paf.page.inject_config) binder.install(paf.common.inject_config) - if Property.env(Property.PAF_DEMO_MODE) == "1": - binder.bind(Listener, HighlightListener()) + binder.install(paf.listener.inject_config) diff --git a/paf/listener.py b/paf/listener.py index 19d60dc..4901b2f 100644 --- a/paf/listener.py +++ b/paf/listener.py @@ -1,61 +1,83 @@ import logging +from warnings import deprecated +import inject +from selenium.webdriver.remote.webdriver import WebDriver from selenium.webdriver.support.color import Color from paf import javascript from paf.assertion import AbstractAssertion -from paf.common import NotFoundException +from paf.common import NotFoundException, Property +from paf.request import WebDriverRequest -class Listener: +class ActionListener: def action_passed( - self, - action_name: str, - ui_element: "UiElement" + self, + action_name: str, + ui_element: "UiElement" ): # pragma: no cover pass def action_failed( - self, - action_name: str, - ui_element: "UiElement", - exception: Exception + self, + action_name: str, + ui_element: "UiElement", + exception: Exception ): # pragma: no cover pass def action_failed_finally( - self, - action_name: str, - ui_element: "UiElement", - exception: Exception + self, + action_name: str, + ui_element: "UiElement", + exception: Exception ): # pragma: no cover pass +class AssertionListener: def assertion_passed( - self, - assertion: AbstractAssertion, - ui_element: "UiElement" + self, + assertion: AbstractAssertion, + ui_element: "UiElement" ): # pragma: no cover pass def assertion_failed( - self, - assertion: AbstractAssertion, - ui_element: "UiElement", - exception: Exception + self, + assertion: AbstractAssertion, + ui_element: "UiElement", + exception: Exception ): # pragma: no cover pass def assertion_failed_finally( - self, - assertion: AbstractAssertion, - ui_element: "UiElement", - exception: Exception + self, + assertion: AbstractAssertion, + ui_element: "UiElement", + exception: Exception ): # pragma: no cover pass +@deprecated("Use specific listener interface") +class Listener(ActionListener, AssertionListener): + pass -class HighlightListener(Listener): + +class WebDriverManagerListener: + def webdriver_create(self, request: WebDriverRequest): # pragma: no cover + pass + def webdriver_introduce(self, webdriver: WebDriver): + pass + def webdriver_introduced(self, webdriver: WebDriver): # pragma: no cover + pass + def webdriver_close(self, webdriver: WebDriver): # pragma: no cover + pass + def webdriver_closed(self, webdriver: WebDriver): # pragma: no cover + pass + + +class HighlightListener(ActionListener, AssertionListener): def _highlight_with_color(self, ui_element: "UiElement", color: str): try: @@ -66,9 +88,9 @@ def _highlight_with_color(self, ui_element: "UiElement", color: str): logging.warning(f"Cannot highlight {ui_element.name_path}: {e}") def action_passed( - self, - action_name: str, - ui_element: "UiElement" + self, + action_name: str, + ui_element: "UiElement" ): if action_name == "highlight": return @@ -76,10 +98,10 @@ def action_passed( self._highlight_with_color(ui_element, "#ff0") def action_failed_finally( - self, - action_name: str, - ui_element: "UiElement", - exception: Exception + self, + action_name: str, + ui_element: "UiElement", + exception: Exception ): if action_name == "highlight": return @@ -88,18 +110,25 @@ def action_failed_finally( self._highlight_with_color(ui_element, "#f00") def assertion_passed( - self, - assertion: AbstractAssertion, - ui_element: "UiElement" + self, + assertion: AbstractAssertion, + ui_element: "UiElement" ): if assertion.raise_exception: self._highlight_with_color(ui_element, "#0f0") def assertion_failed_finally( - self, - assertion: AbstractAssertion, - ui_element: "UiElement", - exception: Exception + self, + assertion: AbstractAssertion, + ui_element: "UiElement", + exception: Exception ): if not isinstance(exception, NotFoundException) and assertion.raise_exception: self._highlight_with_color(ui_element, "#f00") + + +def inject_config(binder: inject.Binder): + if Property.is_true(Property.PAF_DEMO_MODE): + highlight_listener = HighlightListener() + binder.bind(ActionListener, highlight_listener) + binder.bind(AssertionListener, highlight_listener) diff --git a/paf/manager.py b/paf/manager.py index 406e663..4da63d8 100644 --- a/paf/manager.py +++ b/paf/manager.py @@ -10,6 +10,7 @@ from selenium.webdriver.remote.webdriver import WebDriver, BaseWebDriver from paf.common import Property, Formatter +from paf.listener import WebDriverManagerListener from paf.request import WebDriverRequest OPTION = TypeVar("OPTION") @@ -61,6 +62,10 @@ def get_webdriver(self, request: WebDriverRequest) -> WebDriver: if request.browser_version: options.set_capability("browserVersion", request.browser_version) + listener = inject.instance(WebDriverManagerListener) + if listener: + listener.webdriver_create(request) + if request.server_url: driver = webdriver.Remote(command_executor=request.server_url.geturl(), options=options) elif driver_class: @@ -79,6 +84,10 @@ def get_webdriver(self, request: WebDriverRequest) -> WebDriver: return driver def introduce_webdriver(self, webdriver: WebDriver, request: WebDriverRequest): + listener = inject.instance(WebDriverManagerListener) + if listener: + listener.webdriver_introduce(webdriver) + self._session_driver_map[request.session_name] = webdriver if request.window_position: @@ -90,6 +99,9 @@ def introduce_webdriver(self, webdriver: WebDriver, request: WebDriverRequest): elif request.window_size: webdriver.set_window_size(request.window_size.width, request.window_size.height) + if listener: + listener.webdriver_introduced(webdriver) + def __map_session_name(self, session_name_or_request: str | WebDriverRequest) -> str: if isinstance(session_name_or_request, WebDriverRequest): session_name_or_request = session_name_or_request.session_name @@ -107,6 +119,10 @@ def shutdown_session(self, session_name_or_request: str | WebDriverRequest): raise Exception(f"Unknown session: {session_name}") def shutdown(self, webdriver: WebDriver): + listener = inject.instance(WebDriverManagerListener) + if listener: + listener.webdriver_close(webdriver) + webdriver.quit() webdrivers = list(self._session_driver_map.values()) index = webdrivers.index(webdriver) @@ -115,6 +131,9 @@ def shutdown(self, webdriver: WebDriver): key = session_keys[index] self._session_driver_map.pop(key) + if listener: + listener.webdriver_closed(webdriver) + def shutdown_all(self): for webdriver in list(self._session_driver_map.values()): self.shutdown(webdriver) diff --git a/paf/uielement.py b/paf/uielement.py index 696edea..f052c66 100644 --- a/paf/uielement.py +++ b/paf/uielement.py @@ -20,7 +20,7 @@ WebdriverRetainer, SubjectException from paf.control import retry from paf.dom import Attribute -from paf.listener import Listener +from paf.listener import Listener, ActionListener from paf.locator import By from paf.types import Mapper, Consumer from paf.xpath import XPath @@ -379,18 +379,18 @@ def _find_web_elements(self) -> ContextManager[List[WebElement]]: # raise NotFoundException() def _web_element_action_sequence(self, action: Consumer[WebElement], action_name: str): - listener = inject.instance(Listener) + action_listener = inject.instance(ActionListener) def _sequence(): with self.find_web_element() as web_element: action(web_element) try: - retry(_sequence, lambda e: listener.action_failed(action_name, self, e)) - listener.action_passed(action_name, self) + retry(_sequence, lambda e: action_listener.action_failed(action_name, self, e)) + action_listener.action_passed(action_name, self) except SubjectException as exception: exception.add_subject(self.name_path) - listener.action_failed_finally(action_name, self, exception) + action_listener.action_failed_finally(action_name, self, exception) raise exception def click(self): diff --git a/test/__init__.py b/test/__init__.py index e11fa16..fb4ff63 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -9,6 +9,7 @@ from paf.page import PageFactory, FinderPage from paf.request import WebDriverRequest + @pytest.fixture() def page_factory(): yield inject.instance(PageFactory) diff --git a/test/test_demo_mode.py b/test/test_demo_mode.py index ad21099..a8ef2e9 100644 --- a/test/test_demo_mode.py +++ b/test/test_demo_mode.py @@ -4,7 +4,7 @@ import paf.config from paf.common import Property -from paf.listener import Listener, HighlightListener +from paf.listener import HighlightListener, ActionListener, AssertionListener from paf.manager import WebDriverManager from paf.page import PageFactory, FinderPage from test import create_webdriver @@ -18,11 +18,11 @@ def finder(): @pytest.fixture(scope="function") -def listener(monkeypatch): +def action_listener(monkeypatch): assert Property.env(Property.PAF_DEMO_MODE) == "0" monkeypatch.setenv(Property.PAF_DEMO_MODE.name, "1") inject.clear_and_configure(paf.config.inject) - listener = inject.instance(Listener) + listener = inject.instance(ActionListener) assert isinstance(listener, HighlightListener) yield listener @@ -31,13 +31,34 @@ def listener(monkeypatch): inject.clear_and_configure(paf.config.inject) -def test_highlight_action(finder: FinderPage, listener: Listener): +@pytest.fixture(scope="function") +def assertion_listener(monkeypatch): + assert Property.env(Property.PAF_DEMO_MODE) == "0" + monkeypatch.setenv(Property.PAF_DEMO_MODE.name, "1") + inject.clear_and_configure(paf.config.inject) + listener = inject.instance(AssertionListener) + assert isinstance(listener, HighlightListener) + + yield listener + + monkeypatch.setenv(Property.PAF_DEMO_MODE.name, "0") + inject.clear_and_configure(paf.config.inject) + + +def test_highlight_action(finder: FinderPage, action_listener: ActionListener): btn = finder.find("#button") btn.click() btn.expect.css("outline").be("rgb(255, 255, 0) solid 5px") -def test_highlight_failed_assertion(finder: FinderPage, listener: Listener): +def test_highlight_action_success_skips_highlighting(finder: FinderPage, action_listener: ActionListener): + btn = finder.find("#button") + btn.highlight(Color.from_string("#888888")) + with btn.find_web_element() as web_element: + assert web_element.value_of_css_property("outline") == "rgb(136, 136, 136) solid 5px" + + +def test_highlight_failed_assertion(finder: FinderPage, assertion_listener: AssertionListener): btn = finder.find("#button") with pytest.raises(Exception): @@ -47,13 +68,13 @@ def test_highlight_failed_assertion(finder: FinderPage, listener: Listener): assert not btn.wait_for.text.raise_exception -def test_highlight_passed_assertion(finder: FinderPage, listener: Listener): +def test_highlight_passed_assertion(finder: FinderPage, assertion_listener: AssertionListener): btn = finder.find("#button") btn.expect.value.be("click me") btn.expect.css("outline").be("rgb(0, 255, 0) solid 5px") -def test_highlight_not_found_log(finder: FinderPage, listener: Listener, caplog): +def test_highlight_not_found_log(finder: FinderPage, assertion_listener: AssertionListener, caplog): inexistent = finder.find("#inexistent") with pytest.raises(Exception): @@ -63,13 +84,5 @@ def test_highlight_not_found_log(finder: FinderPage, listener: Listener, caplog) for record in caplog.records: assert "Cannot highlight UiElement(By.css selector(#inexistent))[0]: Not found" in record.message - -def test_highlight_action_success_skips_highlighting(finder: FinderPage, listener: Listener): - btn = finder.find("#button") - btn.highlight(Color.from_string("#888888")) - with btn.find_web_element() as web_element: - assert web_element.value_of_css_property("outline") == "rgb(136, 136, 136) solid 5px" - - def teardown_module(): inject.instance(WebDriverManager).shutdown_all() diff --git a/test/test_manager.py b/test/test_manager.py index 268b39f..582855c 100644 --- a/test/test_manager.py +++ b/test/test_manager.py @@ -10,11 +10,12 @@ from selenium.webdriver.remote.webdriver import WebDriver from paf.common import Property, Size, Rect, Point +from paf.listener import WebDriverManagerListener from paf.manager import WebDriverManager from paf.page import PageFactory, FinderPage from paf.request import WebDriverRequest from test import create_webdriver, finder - +import paf.config @pytest.fixture def manager(): @@ -168,5 +169,66 @@ async def test_thread_singleton(): assert managers[0] == managers[1] + +def test_listener(): + + class WebDriverManagerTestListener(WebDriverManagerListener): + def __init__(self): + self.close_called = False + self.create_called = False + self.closed_called = False + self.introduce_called = False + self.introduced_called = False + + def webdriver_close(self, webdriver: WebDriver): + self.close_called = True + def webdriver_create(self, webdriver: WebDriver): + self.create_called = True + def webdriver_introduce(self, webdriver: WebDriver): + self.introduce_called = True + def webdriver_introduced(self, webdriver: WebDriver): + self.introduced_called = True + def webdriver_closed(self, webdriver: WebDriver): + self.closed_called = True + + + def _inject(binder: inject.Binder): + paf.config.inject(binder) + binder.bind(WebDriverManagerListener, WebDriverManagerTestListener()) + + inject.clear_and_configure(_inject) + listener: WebDriverManagerTestListener = inject.instance(WebDriverManagerListener) + assert isinstance(listener, WebDriverManagerListener) + + request = WebDriverRequest("listener") + + manager = inject.instance(WebDriverManager) + assert listener.create_called == False + assert listener.introduce_called == False + assert listener.introduced_called == False + manager.get_webdriver(request) + assert listener.create_called == True + assert listener.introduce_called == True + assert listener.introduced_called == True + + listener.create_called = False + listener.introduce_called = False + listener.introduced_called = False + manager.get_webdriver(request) + assert listener.create_called == False + assert listener.introduce_called == False + assert listener.introduced_called == False + + assert listener.close_called == False + assert listener.closed_called == False + manager.shutdown_session(request) + assert listener.close_called == True + assert listener.closed_called == True + + listener.closed_called = False + with pytest.raises(Exception, match="Unknown session: listener"): + manager.shutdown_session(request) + assert listener.closed_called == False + def teardown_module(): inject.instance(WebDriverManager).shutdown_all() From 0fe1f6d9fc9c8f4405098618a3d06f4359e8ea77 Mon Sep 17 00:00:00 2001 From: Mike Reiche Date: Tue, 11 Mar 2025 14:52:11 +0100 Subject: [PATCH 2/8] Improve listener documentation --- README.md | 2 +- doc/listener.md | 32 -------------------------------- doc/listeners.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 33 deletions(-) delete mode 100644 doc/listener.md create mode 100644 doc/listeners.md diff --git a/README.md b/README.md index 1e6c1f9..91a564f 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ element.expect.text.be("Search") - [Components](doc/components.md) - [Managing WebDrivers](doc/manager.md) - [Execution controlling](doc/control.md) -- [Inject listener](doc/listener.md) +- [Inject listener](doc/listeners.md) ### Missing features (tdb) diff --git a/doc/listener.md b/doc/listener.md deleted file mode 100644 index 48ed252..0000000 --- a/doc/listener.md +++ /dev/null @@ -1,32 +0,0 @@ -# Listener - -The *Listener* interface provides methods that are called, when an action or assertion is performed. - -Implement your custom listener the following way - -```python -from paf.listener import Listener -from paf.uielement import UiElement - -class MyListener(Listener): - def action_passed( - self, - action_name: str, - ui_element: UiElement - ): - pass -``` -You need to inject your listener at configuration level like: -```python -import inject -from inject import Binder -import paf.config -from paf.listener import Listener - -def _inject(binder: Binder): - binder.install(paf.config.inject) - binder.bind(Listener, MyListener()) - -inject.configure(_inject) -``` -Make sure, that the environment variable is `PAF_DEMO_MODE=0`, to prevent a duplicate injection of *HighlightListener*. diff --git a/doc/listeners.md b/doc/listeners.md new file mode 100644 index 0000000..78240c8 --- /dev/null +++ b/doc/listeners.md @@ -0,0 +1,42 @@ +# Listeners + +*PAF* provides some listener interfaces to intercept internals. + +* `ActionListener`: Listens to element actions +* `AssertionListener`: Listens to element assertions +* `WebDriverManagerListener`: Listen to the lifecycle of a *WebDriver* + +## HighlightListener + +Highlights actions and assertions on the element. Gets automatically injected when `PAF_DEMO_MODE` is enabled. + +## Custom listeners + +Implement your custom listener the following way + +```python +from paf.listener import ActionListener, WebDriverManagerListener +from paf.uielement import UiElement + +class MyListener(ActionListener, WebDriverManagerListener): + def action_passed(self, action_name: str, ui_element: UiElement): + pass + def webdriver_closed(self, webdriver: WebDriver): + pass +``` +You need to inject your listener at configuration level like: +```python +import inject +from inject import Binder +import paf.config +from paf.listener import ActionListener, WebDriverManagerListener + +def _inject(binder: Binder): + binder.install(paf.config.inject) + my_listener = MyListener() + binder.bind(ActionListener, my_listener) + binder.bind(WebDriverManagerListener, my_listener) + +inject.configure(_inject) +``` +Make sure, that the environment variable is `PAF_DEMO_MODE=0`, to prevent a duplicate injection of *HighlightListener*. From c859a7872390fefb9b9be2ab2171cb67a7345ef2 Mon Sep 17 00:00:00 2001 From: Mike Reiche Date: Tue, 11 Mar 2025 14:56:22 +0100 Subject: [PATCH 3/8] Upgrade Python version to 3.13 --- .github/workflows/integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 20e9cac..810ae5b 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -40,7 +40,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: "3.11" + python-version: "3.13" - name: Install dependencies of all modules run: pip install -r requirements.txt - name: Test with pytest From 3dc579b7b5e64a36efd065736d5d077189bfcc1c Mon Sep 17 00:00:00 2001 From: Mike Reiche Date: Tue, 11 Mar 2025 14:59:11 +0100 Subject: [PATCH 4/8] Update requirements --- requirements.txt | 1 + setup.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 26267b1..a1f5f13 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ inject==4.3.1 pytest-xdist==3.2.1 pytest-cov==4.0.0 pytest-asyncio==0.21.1 +setuptools==76.0.0 diff --git a/setup.py b/setup.py index 2dbb613..8686918 100644 --- a/setup.py +++ b/setup.py @@ -14,5 +14,6 @@ url="https://github.com/mreiche/python-automation-framework", author="Mike Reiche", packages=["paf"], - install_requires=["inject>=4.3.1", "selenium>=4.8.3", "is-empty>=1.0.1"], + install_requires=["inject>=4.3.1", "selenium>=4.23.1", "is-empty>=1.0.1"], + python_requires=">=3.13", ) From 1d17f2032754615fc600715a02b41029cb912bbe Mon Sep 17 00:00:00 2001 From: Mike Reiche Date: Tue, 11 Mar 2025 15:01:31 +0100 Subject: [PATCH 5/8] Disable build-image job --- .github/workflows/build-paf-test-base.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-paf-test-base.yml b/.github/workflows/build-paf-test-base.yml index 3e48247..72ca909 100644 --- a/.github/workflows/build-paf-test-base.yml +++ b/.github/workflows/build-paf-test-base.yml @@ -25,6 +25,7 @@ permissions: # https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#publishing-images-to-github-packages jobs: build-image: + if: false # Disabled runs-on: ubuntu-latest steps: - name: Set up QEMU From 0630b948f89110e56281456585f0164d21042aea Mon Sep 17 00:00:00 2001 From: Mike Reiche Date: Tue, 11 Mar 2025 15:04:30 +0100 Subject: [PATCH 6/8] Use separated user-data-dir --- test/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/__init__.py b/test/__init__.py index fb4ff63..ad28e39 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -37,7 +37,7 @@ def create_webdriver(request: WebDriverRequest = None): if not request.window_size: request.window_size = Size(1920, 1080) - #options.add_argument(f"--user-data-dir=/tmp/chromedriver-{request.session_name}") + options.add_argument(f"--user-data-dir=/tmp/chromedriver-{request.session_name}") options.add_argument("--disable-search-engine-choice-screen") options.add_argument("--disable-extensions") From 3aecba8639681dc3754cb4fd2fc6e13234b9cf9f Mon Sep 17 00:00:00 2001 From: Mike Reiche Date: Tue, 11 Mar 2025 15:09:08 +0100 Subject: [PATCH 7/8] Revert "Use separated user-data-dir" This reverts commit 0630b948f89110e56281456585f0164d21042aea. --- test/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/__init__.py b/test/__init__.py index ad28e39..fb4ff63 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -37,7 +37,7 @@ def create_webdriver(request: WebDriverRequest = None): if not request.window_size: request.window_size = Size(1920, 1080) - options.add_argument(f"--user-data-dir=/tmp/chromedriver-{request.session_name}") + #options.add_argument(f"--user-data-dir=/tmp/chromedriver-{request.session_name}") options.add_argument("--disable-search-engine-choice-screen") options.add_argument("--disable-extensions") From b0dae271885510eb4c921e6b339635171569f9b9 Mon Sep 17 00:00:00 2001 From: Mike Reiche Date: Tue, 11 Mar 2025 15:13:07 +0100 Subject: [PATCH 8/8] Use correct test related webdriver getter --- examples/test_asyncio.py | 4 ++-- examples/test_cloudflare_challenge.py | 4 ++-- examples/test_monkeytype.py | 4 ++-- test/__init__.py | 6 +++--- test/test_component.py | 4 ++-- test/test_demo_mode.py | 4 ++-- test/test_detect_webdriver.py | 6 +++--- test/test_javascript.py | 4 ++-- test/test_manager.py | 26 +++++++++++++------------- test/test_page.py | 8 ++++---- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/examples/test_asyncio.py b/examples/test_asyncio.py index 1ddd04c..767956c 100644 --- a/examples/test_asyncio.py +++ b/examples/test_asyncio.py @@ -7,7 +7,7 @@ from paf.manager import WebDriverManager from paf.page import PageFactory from paf.request import WebDriverRequest -from test import create_webdriver +from test import get_webdriver @pytest.mark.asyncio @@ -26,7 +26,7 @@ async def test_run_in_tasks(): def run_google_search(i: int): request = WebDriverRequest(f"asyncio{i}") - webdriver = create_webdriver(request) + webdriver = get_webdriver(request) page_factory = inject.instance(PageFactory) webdriver_manager = inject.instance(WebDriverManager) diff --git a/examples/test_cloudflare_challenge.py b/examples/test_cloudflare_challenge.py index bb7c9a0..a29def7 100644 --- a/examples/test_cloudflare_challenge.py +++ b/examples/test_cloudflare_challenge.py @@ -15,7 +15,7 @@ from paf.request import WebDriverRequest from paf.uielement import UiElement from paf.xpath import XPath -from test import create_webdriver +from test import get_webdriver @pytest.fixture @@ -24,7 +24,7 @@ def cloudflare(): request = WebDriverRequest("cloudflare") request.window_position = Point(-1024,0) request.window_maximize = True - page = page_factory.create_page(CloudflarePage, create_webdriver(request)) + page = page_factory.create_page(CloudflarePage, get_webdriver(request)) yield page diff --git a/examples/test_monkeytype.py b/examples/test_monkeytype.py index 133241c..202d62e 100644 --- a/examples/test_monkeytype.py +++ b/examples/test_monkeytype.py @@ -4,13 +4,13 @@ from paf.control import change from paf.manager import WebDriverManager from paf.page import PageFactory, FinderPage -from test import create_webdriver +from test import get_webdriver @pytest.fixture def finder(): page_factory = inject.instance(PageFactory) - finder = page_factory.create_page(FinderPage, create_webdriver()) + finder = page_factory.create_page(FinderPage, get_webdriver()) yield finder diff --git a/test/__init__.py b/test/__init__.py index fb4ff63..84f2a75 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -17,11 +17,11 @@ def page_factory(): @pytest.fixture def finder(): page_factory = inject.instance(PageFactory) - finder = page_factory.create_page(FinderPage, create_webdriver()) + finder = page_factory.create_page(FinderPage, get_webdriver()) yield finder -def create_webdriver(request: WebDriverRequest = None): +def get_webdriver(request: WebDriverRequest = None): manager = inject.instance(WebDriverManager) if not request: @@ -37,7 +37,7 @@ def create_webdriver(request: WebDriverRequest = None): if not request.window_size: request.window_size = Size(1920, 1080) - #options.add_argument(f"--user-data-dir=/tmp/chromedriver-{request.session_name}") + #options.add_argument(f"--user-data-dir=/tmp/chromedriver-{request.session_name}") # Strange behaviour in xdist options.add_argument("--disable-search-engine-choice-screen") options.add_argument("--disable-extensions") diff --git a/test/test_component.py b/test/test_component.py index 677a988..e64dfeb 100644 --- a/test/test_component.py +++ b/test/test_component.py @@ -9,12 +9,12 @@ from paf.manager import WebDriverManager from paf.page import Page, PageFactory from paf.xpath import XPath -from test import create_webdriver +from test import get_webdriver @pytest.fixture def components_page(): - yield inject.instance(PageFactory).create_page(ComponentsPage, create_webdriver()) + yield inject.instance(PageFactory).create_page(ComponentsPage, get_webdriver()) class ComponentsPage(Page): diff --git a/test/test_demo_mode.py b/test/test_demo_mode.py index a8ef2e9..f11056c 100644 --- a/test/test_demo_mode.py +++ b/test/test_demo_mode.py @@ -7,12 +7,12 @@ from paf.listener import HighlightListener, ActionListener, AssertionListener from paf.manager import WebDriverManager from paf.page import PageFactory, FinderPage -from test import create_webdriver +from test import get_webdriver @pytest.fixture def finder(): - finder = inject.instance(PageFactory).create_page(FinderPage, create_webdriver()) + finder = inject.instance(PageFactory).create_page(FinderPage, get_webdriver()) finder.open("https://testpages.herokuapp.com/styled/key-click-display-test.html") yield finder diff --git a/test/test_detect_webdriver.py b/test/test_detect_webdriver.py index 7a274f1..29c346c 100644 --- a/test/test_detect_webdriver.py +++ b/test/test_detect_webdriver.py @@ -3,14 +3,14 @@ from paf.manager import WebDriverManager from paf.request import WebDriverRequest -from test import create_webdriver +from test import get_webdriver import logging def test_detect_webdriver(): request = WebDriverRequest("automated") request.browser = "chrome" - webdriver = create_webdriver(request) + webdriver = get_webdriver(request) result = webdriver.execute_script("return navigator.webdriver") assert result is True @@ -32,7 +32,7 @@ def test_hide_webdriver(): options.add_experimental_option('useAutomationExtension', False) request.options = options - webdriver = create_webdriver(request) + webdriver = get_webdriver(request) logging.info(f"Request {request}") webdriver.execute_cdp_cmd('Network.setUserAgentOverride', {"userAgent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.53 Safari/537.36'}) webdriver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => false})") diff --git a/test/test_javascript.py b/test/test_javascript.py index 4ea764f..9f37bd6 100644 --- a/test/test_javascript.py +++ b/test/test_javascript.py @@ -5,7 +5,7 @@ from paf.manager import WebDriverManager from paf.page import FinderPage from paf.request import WebDriverRequest -from test import create_webdriver +from test import get_webdriver from test import finder @@ -13,7 +13,7 @@ def test_viewport(): request = WebDriverRequest() request.browser = "chrome" request.window_size = Size(1024, 768) - webdriver = create_webdriver(request) + webdriver = get_webdriver(request) viewport = javascript.get_viewport(webdriver) assert isinstance(viewport, Rect) assert viewport.top == 0 diff --git a/test/test_manager.py b/test/test_manager.py index 582855c..90179eb 100644 --- a/test/test_manager.py +++ b/test/test_manager.py @@ -14,7 +14,7 @@ from paf.manager import WebDriverManager from paf.page import PageFactory, FinderPage from paf.request import WebDriverRequest -from test import create_webdriver, finder +from test import get_webdriver, finder import paf.config @pytest.fixture @@ -28,7 +28,7 @@ def test_manager_singleton(manager: WebDriverManager): def test_take_screenshot(manager: WebDriverManager): - create_webdriver() + get_webdriver() webdrivers = manager.webdrivers assert isinstance(webdrivers, list) @@ -45,7 +45,7 @@ def test_take_screenshot(manager: WebDriverManager): def test_shutdown_by_session_key(manager: WebDriverManager): request = WebDriverRequest("test") - create_webdriver(request) + get_webdriver(request) assert manager.has_webdriver(request) manager.shutdown_session(request) assert manager.has_webdriver(request.session_name) is False @@ -67,7 +67,7 @@ def test_take_screenshot_fails_read_only(monkeypatch, manager: WebDriverManager) dir = Path(Property.env(Property.PAF_SCREENSHOTS_DIR)) dir.mkdir(parents=True, exist_ok=True) os.chmod(dir, 555) - webdriver = create_webdriver() + webdriver = get_webdriver() path = manager.take_screenshot(webdriver) assert path is None os.chmod(dir, 775) @@ -75,14 +75,14 @@ def test_take_screenshot_fails_read_only(monkeypatch, manager: WebDriverManager) def test_take_screenshot_fails_invalid_session(manager: WebDriverManager): - webdriver = create_webdriver() + webdriver = get_webdriver() manager.shutdown(webdriver) with pytest.raises(Exception): manager.take_screenshot(webdriver) def test_empty_request(manager: WebDriverManager): - webdriver = create_webdriver() + webdriver = get_webdriver() assert isinstance(webdriver, WebDriver) assert manager.has_webdriver("test") @@ -91,14 +91,14 @@ def test_given_chrome_options(manager: WebDriverManager): request = WebDriverRequest("chrome-with-options") request.browser = "chrome" request.options = ChromeOptions() - webdriver = create_webdriver(request) + webdriver = get_webdriver(request) assert request.browser in webdriver.name def test_not_given_chrome_options(manager: WebDriverManager): request = WebDriverRequest("chrome-no-options") request.browser = "chrome" - webdriver = create_webdriver(request) + webdriver = get_webdriver(request) assert request.browser in webdriver.name @@ -112,7 +112,7 @@ def test_remote_webdriver(monkeypatch): request.browser = "chrome" request.options = ChromeOptions() assert isinstance(request.server_url, ParseResult) - webdriver = create_webdriver(request) + webdriver = get_webdriver(request) assert webdriver.name == request.browser @@ -130,7 +130,7 @@ def test_window_size_and_position(finder: FinderPage): request = WebDriverRequest("position") request.window_position = Point(30, 40) request.window_size = Size(1024, 768) - webdriver = create_webdriver(request) + webdriver = get_webdriver(request) window_rect = Rect.from_rect_dict(webdriver.get_window_rect()) assert window_rect.origin.x == 30 @@ -142,7 +142,7 @@ def test_window_size_and_position(finder: FinderPage): def test_window_maximize(): request = WebDriverRequest("maximize") request.window_maximize = True - webdriver = create_webdriver(request) + webdriver = get_webdriver(request) window_rect = Rect.from_rect_dict(webdriver.get_window_rect()) assert window_rect.origin.x >= 0 assert window_rect.origin.y >= 0 @@ -206,7 +206,7 @@ def _inject(binder: inject.Binder): assert listener.create_called == False assert listener.introduce_called == False assert listener.introduced_called == False - manager.get_webdriver(request) + get_webdriver(request) assert listener.create_called == True assert listener.introduce_called == True assert listener.introduced_called == True @@ -214,7 +214,7 @@ def _inject(binder: inject.Binder): listener.create_called = False listener.introduce_called = False listener.introduced_called = False - manager.get_webdriver(request) + get_webdriver(request) assert listener.create_called == False assert listener.introduce_called == False assert listener.introduced_called == False diff --git a/test/test_page.py b/test/test_page.py index c49b139..092f23e 100644 --- a/test/test_page.py +++ b/test/test_page.py @@ -9,7 +9,7 @@ from paf.manager import WebDriverManager from paf.page import PageFactory, Page, FinderPage from paf.request import WebDriverRequest -from test import create_webdriver +from test import get_webdriver from test import finder, page_factory @@ -30,7 +30,7 @@ def test_assertions(finder: FinderPage): def test_create_page_from_page(page_factory: PageFactory): - webdriver = create_webdriver(WebDriverRequest()) + webdriver = get_webdriver(WebDriverRequest()) page = page_factory.create_page(Page) other_page = page._create_page(Page) assert isinstance(other_page, Page) @@ -39,7 +39,7 @@ def test_create_page_from_page(page_factory: PageFactory): def test_create_page_without_webdriver(page_factory: PageFactory): - webdriver = create_webdriver(WebDriverRequest()) + webdriver = get_webdriver(WebDriverRequest()) page = page_factory.create_page(Page) assert page.webdriver == webdriver assert isinstance(page, Page) @@ -60,7 +60,7 @@ def test_absolute_viewport(page_factory: PageFactory): request = WebDriverRequest("viewport") request.window_position = Point(10, 20) request.window_size = Size(1024, 768) - webdriver = create_webdriver(request) + webdriver = get_webdriver(request) finder = page_factory.create_page(FinderPage, webdriver) viewport = finder.get_absolute_viewport()