Skip to content

Commit 95307f2

Browse files
Version 2.3.3 (#72)
1 parent 1443afa commit 95307f2

14 files changed

Lines changed: 122 additions & 72 deletions

File tree

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22

33
<br>
44

5+
## v2.3.3
6+
*Release date: 2025-01-09*
7+
8+
### Added
9+
- `dyatel.mixins/objects.driver.Driver` object
10+
11+
### Changed
12+
- **Breaking:** `DriverWrapper` initialization now requires a `Driver` object
13+
- **Breaking:** Playwright's `context` and `page` creation have been moved out of `dyatel-wrapper`
14+
15+
**Note:** Examples of the new logic can be found in the [ReadTheDocs documentation](https://dyatel-wrapper.readthedocs.io/getting_started.html#selenium-driver-setup)
16+
17+
---
18+
519
## v2.3.2
620
*Release date: 2024-12-19*
721

docs/source/getting_started.md

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,13 @@ class MainPage(Page):
7171
```python
7272
import pytest # noqa
7373
from selenium.webdriver.chrome.webdriver import WebDriver as ChromeWebDriver
74+
7475
from dyatel.base.driver_wrapper import DriverWrapper
76+
from dyatel.mixins.objects.driver import Driver
7577

7678
@pytest.fixture
7779
def driver_wrapper():
78-
selenium_driver = ChromeWebDriver()
80+
selenium_driver = Driver(driver=ChromeWebDriver())
7981
return DriverWrapper(selenium_driver)
8082
```
8183

@@ -87,17 +89,24 @@ def driver_wrapper():
8789
```python
8890
import pytest # noqa
8991
from appium.webdriver.webdriver import WebDriver as SourceAppiumDriver
92+
from appium.options.common.base import AppiumOptions
93+
9094
from dyatel.base.driver_wrapper import DriverWrapper
95+
from dyatel.mixins.objects.driver import Driver
96+
9197

9298
@pytest.fixture
9399
def driver_wrapper():
94100
caps = {} # Your device capabilities
95101
appium_ip, appium_port = None, None # Your appium ip and port
102+
options = AppiumOptions().load_capabilities(caps)
103+
96104
appium_driver = SourceAppiumDriver(
97105
command_executor=f'http://{appium_ip}:{appium_port}/wd/hub',
98-
desired_capabilities=caps
106+
options=options
99107
)
100-
return DriverWrapper(appium_driver)
108+
109+
return DriverWrapper(Driver(driver=appium_driver))
101110
```
102111

103112
---
@@ -112,13 +121,18 @@ Dyatel Wrapper supports only sync API of playwright
112121
```python
113122
import pytest # noqa
114123
from playwright.sync_api import sync_playwright
124+
from dyatel.mixins.objects.driver import Driver
125+
115126
from dyatel.base.driver_wrapper import DriverWrapper
116127

117128

118129
@pytest.fixture
119130
def driver_wrapper():
120-
playwright_driver = sync_playwright().start().chromium.launch()
121-
return DriverWrapper(playwright_driver)
131+
instance = sync_playwright().start().chromium.launch()
132+
context = instance.new_context()
133+
page = context.new_page()
134+
135+
return DriverWrapper(Driver(driver=page, context=context, instance=instance))
122136
```
123137

124138
---

dyatel/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
dyatel_version = '2.3.2'
1+
dyatel_version = '2.3.3'

dyatel/base/driver_wrapper.py

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
from __future__ import annotations
22

3-
from typing import Union, Type, List, Tuple, Any, Optional
3+
from typing import Union, Type, List, Tuple, Any
44

55
from PIL import Image
66
from appium.webdriver.webdriver import WebDriver as AppiumDriver
77
from selenium.webdriver.remote.webdriver import WebDriver as SeleniumDriver
8-
from playwright.sync_api import (
9-
Browser as PlaywrightBrowser,
10-
BrowserContext as PlaywrightContext,
11-
Page as PlaywrightDriver,
12-
)
8+
from playwright.sync_api import Page as PlaywrightDriver
139

1410
from dyatel.mixins.objects.cut_box import CutBox
11+
from dyatel.mixins.objects.driver import Driver
1512
from dyatel.visual_comparison import VisualComparison
1613
from dyatel.abstraction.driver_wrapper_abc import DriverWrapperABC
1714
from dyatel.dyatel_play.play_driver import PlayDriver
@@ -81,6 +78,7 @@ class DriverWrapper(InternalMixin, Logging, DriverWrapperABC):
8178
_object = 'driver_wrapper'
8279
_base_cls: Type[PlayDriver, MobileDriver, WebDriver] = None
8380

81+
driver: Union[SeleniumDriver, AppiumDriver, PlaywrightDriver]
8482
session: DriverWrapperSessions = DriverWrapperSessions
8583

8684
anchor = None
@@ -107,10 +105,6 @@ class DriverWrapper(InternalMixin, Logging, DriverWrapperABC):
107105

108106
browser_name = None
109107

110-
driver: Union[SeleniumDriver, AppiumDriver, PlaywrightDriver]
111-
instance: PlaywrightBrowser # Only for playwright instance
112-
context: PlaywrightContext # Only for playwright instance
113-
114108
def __new__(cls, *args, **kwargs):
115109
if cls.session.sessions_count() == 0:
116110
cls = super().__new__(cls)
@@ -133,23 +127,17 @@ def __repr__(self):
133127

134128
return f'{cls.__name__}({self.label}={self.driver}) at {hex(id(self))}, platform={label}'
135129

136-
def __init__(
137-
self,
138-
driver: Union[PlaywrightBrowser, AppiumDriver, SeleniumDriver],
139-
mobile_resolution: Optional[bool] = False,
140-
*args,
141-
**kwargs
142-
):
130+
def __init__(self, driver: Driver):
143131
"""
144132
Initializing of driver wrapper based on given driver source
145133
146134
:param driver: appium or selenium or playwright driver to initialize
147135
"""
148-
self.driver = driver
136+
self.__driver_container = driver
149137
self.session.add_session(self)
150138
self.label = f'{self.session.all_sessions.index(self) + 1}_driver'
151-
self.__init_base_class__(*args, **kwargs)
152-
if mobile_resolution:
139+
self.__init_base_class__()
140+
if driver.is_mobile_resolution:
153141
self.is_mobile_resolution = True
154142
self.is_desktop = False
155143
self.is_mobile = True
@@ -277,26 +265,28 @@ def soft_assert_screenshot(
277265

278266
return True, f'No visual mismatch found for entire screen'
279267

280-
def __init_base_class__(self, *args, **kwargs) -> None:
268+
def __init_base_class__(self) -> None:
281269
"""
282270
Get driver wrapper class in according to given driver source, and set him as base class
283271
284272
:return: None
285273
"""
286-
if isinstance(self.driver, PlaywrightBrowser):
274+
source_driver = self.__driver_container.driver
275+
276+
if isinstance(source_driver, PlaywrightDriver):
287277
self.is_playwright = True
288278
self._base_cls = PlayDriver
289-
elif isinstance(self.driver, AppiumDriver):
279+
elif isinstance(source_driver, AppiumDriver):
290280
self.is_appium = True
291281
self._base_cls = MobileDriver
292-
elif isinstance(self.driver, SeleniumDriver):
282+
elif isinstance(source_driver, SeleniumDriver):
293283
self.is_selenium = True
294284
self._base_cls = WebDriver
295285
else:
296286
raise DriverWrapperException(f'Cant specify {self.__class__.__name__}')
297287

298288
self._set_static(self._base_cls)
299-
self._base_cls.__init__(self, driver=self.driver, *args, **kwargs)
289+
self._base_cls.__init__(self, driver_container=self.__driver_container)
300290

301291
for name, value in self.__dict__.items():
302292
setattr(self.__class__, name, value)

dyatel/dyatel_play/play_driver.py

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,32 @@
22

33
from typing import List, Union, Any
44

5+
from playwright._impl._errors import Error as PlaywrightError # noqa
6+
57
from PIL import Image
68
from playwright.sync_api import Locator, Page, Browser, BrowserContext
7-
from dyatel.dyatel_play.helpers.Trace import Trace
89

910
from dyatel.abstraction.driver_wrapper_abc import DriverWrapperABC
11+
from dyatel.mixins.objects.driver import Driver
1012
from dyatel.shared_utils import get_image
1113
from dyatel.utils.internal_utils import get_timeout_in_ms, WAIT_UNIT
1214
from dyatel.utils.logs import Logging
1315

1416

1517
class PlayDriver(Logging, DriverWrapperABC):
1618

17-
instance: Browser
18-
context: BrowserContext
19-
driver: Page
20-
21-
def __init__(self, driver: Browser, trace: Trace = None, *args, **kwargs):
19+
def __init__(self, driver_container: Driver):
2220
"""
2321
Initializing of desktop web driver with playwright
2422
25-
:param driver: playwright driver to initialize
23+
:param driver_container: Driver that contains playwright instance, context and driver objects
2624
"""
2725
self.is_desktop = True
28-
self.trace = trace
29-
self.instance = driver
30-
self.context = driver.new_context(*args, **kwargs)
3126

32-
if trace:
33-
self.context.tracing.start(**trace.__dict__)
27+
self.instance: Browser = driver_container.instance
28+
self.context: BrowserContext = driver_container.context
29+
self.driver: Page = driver_container.driver
3430

35-
self.driver = self.context.new_page()
3631
self.original_tab = self.driver
3732
self.browser_name = self.instance.browser_type.name
3833

@@ -124,8 +119,11 @@ def quit(self, silent: bool = False, trace_path: str = 'trace.zip'):
124119
:param trace_path: Playwright only: path for the trace
125120
:return: None
126121
"""
127-
if self.trace and trace_path:
128-
self.context.tracing.stop(path=trace_path)
122+
if trace_path:
123+
try:
124+
self.context.tracing.stop(path=trace_path)
125+
except PlaywrightError:
126+
pass
129127

130128
self.driver.close()
131129
self.context.close()

dyatel/dyatel_sel/driver/mobile_driver.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ class MobileDriver(CoreDriver):
1313

1414
bundle_id: Optional[str]
1515

16-
def __init__(self, driver: AppiumDriver, *args, **kwargs): # noqa
16+
def __init__(self, driver_container: Driver, *args, **kwargs): # noqa
1717
"""
1818
Initializing of mobile driver with appium
1919
20-
:param driver: appium driver to initialize
20+
:param driver_container: Driver that contains appium driver object
2121
"""
22-
self.caps = driver.capabilities
22+
self.driver: AppiumDriver = driver_container.driver
23+
self.caps = self.driver.capabilities
2324
self.browser_name = self.caps.get('browserName', None)
2425
self.is_web = bool(self.browser_name) or False
2526
self.is_app = self.caps.get('app', False)
@@ -39,7 +40,7 @@ def __init__(self, driver: AppiumDriver, *args, **kwargs): # noqa
3940

4041
self.native_safari = NativeSafari(self)
4142

42-
CoreDriver.__init__(self, driver=driver)
43+
CoreDriver.__init__(self, driver=self.driver)
4344

4445
def is_app_installed(self) -> bool:
4546
"""

dyatel/dyatel_sel/driver/web_driver.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,23 @@
33
from selenium.webdriver.remote.webdriver import WebDriver as SeleniumWebDriver
44

55
from dyatel.dyatel_sel.core.core_driver import CoreDriver
6+
from dyatel.mixins.objects.driver import Driver
67

78

89
class WebDriver(CoreDriver):
910

10-
def __init__(self, driver: SeleniumWebDriver, *args, **kwargs): # noqa
11+
def __init__(self, driver_container: Driver, *args, **kwargs): # noqa
1112
"""
1213
Initializing of desktop web driver with selenium
1314
14-
:param driver: selenium driver to initialize
15+
:param driver_container: Driver that contains selenium driver object
1516
"""
17+
self.driver : SeleniumWebDriver = driver_container.driver
1618
self.is_desktop = True
17-
self.original_tab = driver.current_window_handle
18-
self.browser_name = driver.caps.get('browserName', None)
19+
self.original_tab = self.driver.current_window_handle
20+
self.browser_name = self.driver.caps.get('browserName', None)
1921

20-
CoreDriver.__init__(self, driver=driver)
22+
CoreDriver.__init__(self, driver=self.driver)
2123

2224
def set_window_size(self, width: int, height: int) -> CoreDriver:
2325
"""

dyatel/mixins/objects/driver.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from dataclasses import dataclass
2+
from typing import Union
3+
4+
from appium.webdriver.webdriver import WebDriver as AppiumDriver
5+
from selenium.webdriver.remote.webdriver import WebDriver as SeleniumWebDriver
6+
from playwright.sync_api import (
7+
Browser as PlaywrightBrowser,
8+
BrowserContext as PlaywrightContext,
9+
Page as PlaywrightDriver,
10+
)
11+
12+
13+
@dataclass
14+
class Driver:
15+
driver: Union[AppiumDriver, SeleniumWebDriver, PlaywrightDriver]
16+
context: Union[PlaywrightContext, None] = None
17+
instance: Union[PlaywrightBrowser, None] = None
18+
is_mobile_resolution: bool = False

tests/adata/drivers/appium_driver.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from appium.webdriver.webdriver import WebDriver as SourceAppiumDriver
22

33
from dyatel.base.driver_wrapper import DriverWrapperSessions
4+
from dyatel.mixins.objects.driver import Driver
45
from tests.adata.drivers.driver_entities import DriverEntities
56
from tests.adata.drivers.selenium_driver import SeleniumDriver
67
from tests.settings import android_desired_caps, ios_desired_caps
@@ -9,7 +10,7 @@
910
class AppiumDriver:
1011

1112
@staticmethod
12-
def create_appium_driver(entities: DriverEntities):
13+
def create_appium_driver(entities: DriverEntities) -> Driver:
1314
appium_ip = entities.config.getoption('--appium-ip')
1415
appium_port = entities.config.getoption('--appium-port')
1516
command_exc = f'http://{appium_ip}:{appium_port}/wd/hub'
@@ -24,4 +25,4 @@ def create_appium_driver(entities: DriverEntities):
2425
if DriverWrapperSessions.is_connected():
2526
return SeleniumDriver.create_selenium_driver(entities)
2627

27-
return SourceAppiumDriver(command_executor=command_exc, desired_capabilities=caps)
28+
return Driver(driver=SourceAppiumDriver(command_executor=command_exc, desired_capabilities=caps))

tests/adata/drivers/driver_factory.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from dyatel.mixins.objects.driver import Driver
12
from tests.adata.drivers.playwright_driver import PlaywrightDriver
23
from tests.adata.drivers.appium_driver import AppiumDriver
34
from tests.adata.drivers.driver_entities import DriverEntities
@@ -7,7 +8,7 @@
78
class DriverFactory:
89

910
@staticmethod
10-
def create_driver(entities: DriverEntities):
11+
def create_driver(entities: DriverEntities) -> Driver:
1112

1213
is_mobile = entities.platform in ('ios', 'android')
1314

0 commit comments

Comments
 (0)