setup-selenium-testing 0.2.0__py3-none-any.whl → 1.0.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- setup_selenium/setup_selenium.py +61 -92
- {setup_selenium_testing-0.2.0.dist-info → setup_selenium_testing-1.0.0.dist-info}/METADATA +41 -27
- setup_selenium_testing-1.0.0.dist-info/RECORD +7 -0
- {setup_selenium_testing-0.2.0.dist-info → setup_selenium_testing-1.0.0.dist-info}/WHEEL +1 -1
- setup_selenium_testing-0.2.0.dist-info/RECORD +0 -7
- {setup_selenium_testing-0.2.0.dist-info → setup_selenium_testing-1.0.0.dist-info}/LICENSE +0 -0
setup_selenium/setup_selenium.py
CHANGED
@@ -2,14 +2,12 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
import errno
|
6
5
|
import logging
|
7
6
|
import os as os
|
8
7
|
from enum import Enum
|
9
8
|
from typing import TYPE_CHECKING, Optional, Union
|
10
9
|
|
11
10
|
from selenium import __version__, webdriver
|
12
|
-
from selenium.common.exceptions import NoSuchWindowException, WebDriverException
|
13
11
|
from selenium.webdriver.chrome.service import Service as ChromeService
|
14
12
|
from selenium.webdriver.common.selenium_manager import SeleniumManager
|
15
13
|
from selenium.webdriver.edge.service import Service as EdgeService
|
@@ -18,7 +16,6 @@ from semantic_version import Version # type: ignore[import-untyped]
|
|
18
16
|
from typing_extensions import TypeAlias
|
19
17
|
|
20
18
|
if TYPE_CHECKING:
|
21
|
-
from collections.abc import Mapping
|
22
19
|
|
23
20
|
from selenium.webdriver import Chrome, Edge, Firefox
|
24
21
|
from selenium.webdriver.common.options import ArgOptions
|
@@ -68,27 +65,10 @@ class Browser(str, Enum):
|
|
68
65
|
################################################################################
|
69
66
|
################################################################################
|
70
67
|
class SetupSelenium:
|
71
|
-
DIMENSIONS: Mapping[str, tuple[int, int]] = {
|
72
|
-
# ratio 4:3
|
73
|
-
"1024": (1024, 768),
|
74
|
-
"1280": (1280, 960),
|
75
|
-
"1600": (1600, 1200),
|
76
|
-
"1920": (1920, 1440),
|
77
|
-
# ratio 16:9
|
78
|
-
"720": (1280, 720),
|
79
|
-
"1080": (1920, 1080),
|
80
|
-
"1440": (2560, 1440),
|
81
|
-
"2160": (3840, 2160), # 4k
|
82
|
-
"4320": (7680, 4320), # 8k
|
83
|
-
}
|
84
|
-
|
85
68
|
def __init__(
|
86
69
|
self,
|
87
70
|
browser: Browser = Browser.CHROME,
|
88
|
-
baseurl: str = "",
|
89
|
-
timeout: int = 15,
|
90
71
|
headless: bool = False,
|
91
|
-
window_size: str = "720",
|
92
72
|
enable_log_performance: bool = False,
|
93
73
|
enable_log_console: bool = False,
|
94
74
|
enable_log_driver: bool = False,
|
@@ -99,11 +79,6 @@ class SetupSelenium:
|
|
99
79
|
browser_path: str | None = None,
|
100
80
|
) -> None:
|
101
81
|
log_path = os.path.abspath(os.path.expanduser(log_path))
|
102
|
-
self.main_window_handle: str = ""
|
103
|
-
self.screenshot_path: str = self.make_screenshot_path(log_path)
|
104
|
-
self.log_path: str = log_path
|
105
|
-
self.timeout: int = timeout
|
106
|
-
self.baseurl: str = baseurl
|
107
82
|
|
108
83
|
if driver_path:
|
109
84
|
driver_path = os.path.abspath(os.path.expanduser(driver_path))
|
@@ -131,35 +106,11 @@ class SetupSelenium:
|
|
131
106
|
driver_path=driver_path,
|
132
107
|
)
|
133
108
|
|
134
|
-
# driver must be setup before the following
|
135
|
-
self.driver.set_window_position(0, 0)
|
136
|
-
self.set_window_size(window_size)
|
137
|
-
self.set_main_window_handle()
|
138
|
-
|
139
|
-
############################################################################
|
140
|
-
@staticmethod
|
141
|
-
def make_screenshot_path(
|
142
|
-
output_dir: str = "./logs", screenshots: str = "screenshots"
|
143
|
-
) -> str:
|
144
|
-
"""Set the output directory for where screenshots should go."""
|
145
|
-
output_dir = os.path.abspath(os.path.expanduser(output_dir))
|
146
|
-
if os.path.split(output_dir)[-1].lower() != screenshots:
|
147
|
-
output_dir = os.path.join(output_dir, screenshots)
|
148
|
-
|
149
|
-
try:
|
150
|
-
os.makedirs(output_dir)
|
151
|
-
except OSError as e:
|
152
|
-
if e.errno == errno.EEXIST and os.path.isdir(output_dir):
|
153
|
-
pass
|
154
|
-
else:
|
155
|
-
raise
|
156
|
-
|
157
|
-
return output_dir
|
158
|
-
|
159
109
|
############################################################################
|
160
110
|
@staticmethod
|
161
111
|
def log_options(options: ArgOptions) -> None:
|
162
112
|
"""Logs the browser option in clean format"""
|
113
|
+
# logger.debug(f"{json.dumps(options.capabilities, indent=2)}") # noqa: ERA001
|
163
114
|
opts = "\n".join(options.arguments)
|
164
115
|
logger.debug(f"{opts}")
|
165
116
|
|
@@ -282,6 +233,24 @@ class SetupSelenium:
|
|
282
233
|
options.set_preference(
|
283
234
|
"extensions.formautofill.addresses.capture.enabled", False
|
284
235
|
)
|
236
|
+
# By default, headless Firefox runs as though no pointers capabilities
|
237
|
+
# are available.
|
238
|
+
# https://github.com/microsoft/playwright/issues/7769#issuecomment-966098074
|
239
|
+
#
|
240
|
+
# This impacts React Spectrum which uses an '(any-pointer: fine)'
|
241
|
+
# media query to determine font size. It also causes certain chart
|
242
|
+
# elements to always be visible that should only be visible on
|
243
|
+
# hover.
|
244
|
+
#
|
245
|
+
# Available values for pointer capabilities:
|
246
|
+
# NO_POINTER 0x00
|
247
|
+
# COARSE_POINTER 0x01
|
248
|
+
# FINE_POINTER 0x02
|
249
|
+
# HOVER_CAPABLE_POINTER 0x04
|
250
|
+
#
|
251
|
+
# Setting to 0x02 | 0x04 says the system supports a mouse
|
252
|
+
options.set_preference("ui.primaryPointerCapabilities", 0x02 | 0x04)
|
253
|
+
options.set_preference("ui.allPointerCapabilities", 0x02 | 0x04)
|
285
254
|
return options
|
286
255
|
|
287
256
|
@staticmethod
|
@@ -338,9 +307,29 @@ class SetupSelenium:
|
|
338
307
|
def chrome_options() -> webdriver.ChromeOptions:
|
339
308
|
"""Default options for chrome"""
|
340
309
|
logger.debug("Setting up chrome options")
|
310
|
+
# the ultimate list of flags (created by the chromium dev group)
|
311
|
+
# https://peter.sh/experiments/chromium-command-line-switches/
|
312
|
+
|
341
313
|
# The list of options set below mostly came from this StackOverflow post
|
342
314
|
# https://stackoverflow.com/q/48450594/2532408
|
343
315
|
opts = (
|
316
|
+
# "--disable-features=ImprovedCookieControls,LazyFrameLoading,GlobalMediaControls,DestroyProfileOnBrowserClose,MediaRouter,DialMediaRouteProvider,AcceptCHFrame,AutoExpandDetailsElement,CertificateTransparencyComponentUpdater,AvoidUnnecessaryBeforeUnloadCheckSync", # noqa: ERA001
|
317
|
+
"--disable-back-forward-cache",
|
318
|
+
"--disable-background-timer-throttling",
|
319
|
+
"--disable-breakpad",
|
320
|
+
"--disable-component-extensions-with-background-pages",
|
321
|
+
"--disable-ipc-flooding-protection",
|
322
|
+
"--enable-features=NetworkService,NetworkServiceInProcess",
|
323
|
+
"--enable-logging",
|
324
|
+
"--export-tagged-pdf",
|
325
|
+
"--force-color-profile=srgb",
|
326
|
+
"--metrics-recording-only",
|
327
|
+
"--mute-audio",
|
328
|
+
"--remote-debugging-pipe",
|
329
|
+
# fixes MUI fade issue
|
330
|
+
"--disable-renderer-backgrounding",
|
331
|
+
# fixes actionchains in headless
|
332
|
+
"--disable-backgrounding-occluded-windows",
|
344
333
|
"--disable-extensions",
|
345
334
|
"--allow-running-insecure-content",
|
346
335
|
"--ignore-certificate-errors",
|
@@ -378,7 +367,7 @@ class SetupSelenium:
|
|
378
367
|
options.binary_location = binary
|
379
368
|
|
380
369
|
if headless:
|
381
|
-
options.add_argument("--headless")
|
370
|
+
options.add_argument("--headless=new")
|
382
371
|
|
383
372
|
logging_prefs = {"browser": "OFF", "performance": "OFF", "driver": "OFF"}
|
384
373
|
|
@@ -475,9 +464,29 @@ class SetupSelenium:
|
|
475
464
|
def edge_options() -> webdriver.EdgeOptions:
|
476
465
|
"""Default options for edgedriver"""
|
477
466
|
logger.debug("Setting up edge options")
|
467
|
+
# the ultimate list of flags (created by the chromium dev group)
|
468
|
+
# https://peter.sh/experiments/chromium-command-line-switches/
|
469
|
+
|
478
470
|
# The list of options set below mostly came from this StackOverflow post
|
479
471
|
# https://stackoverflow.com/q/48450594/2532408
|
480
472
|
opts = (
|
473
|
+
# "--disable-features=ImprovedCookieControls,LazyFrameLoading,GlobalMediaControls,DestroyProfileOnBrowserClose,MediaRouter,DialMediaRouteProvider,AcceptCHFrame,AutoExpandDetailsElement,CertificateTransparencyComponentUpdater,AvoidUnnecessaryBeforeUnloadCheckSync", # noqa: ERA001
|
474
|
+
"--disable-back-forward-cache",
|
475
|
+
"--disable-background-timer-throttling",
|
476
|
+
"--disable-breakpad",
|
477
|
+
"--disable-component-extensions-with-background-pages",
|
478
|
+
"--disable-ipc-flooding-protection",
|
479
|
+
"--enable-features=NetworkService,NetworkServiceInProcess",
|
480
|
+
"--enable-logging",
|
481
|
+
"--export-tagged-pdf",
|
482
|
+
"--force-color-profile=srgb",
|
483
|
+
"--metrics-recording-only",
|
484
|
+
"--mute-audio",
|
485
|
+
"--remote-debugging-pipe",
|
486
|
+
# fixes MUI fade issue
|
487
|
+
"--disable-renderer-backgrounding",
|
488
|
+
# fixes actionchains in headless
|
489
|
+
"--disable-backgrounding-occluded-windows",
|
481
490
|
"--disable-extensions",
|
482
491
|
"--allow-running-insecure-content",
|
483
492
|
"--ignore-certificate-errors",
|
@@ -523,12 +532,11 @@ class SetupSelenium:
|
|
523
532
|
# by default performance is disabled.
|
524
533
|
if enable_log_performance:
|
525
534
|
logging_prefs["performance"] = "ALL"
|
526
|
-
options.
|
535
|
+
options.add_experimental_option(
|
527
536
|
"perfLoggingPrefs",
|
528
537
|
{
|
529
538
|
"enableNetwork": True,
|
530
539
|
"enablePage": False,
|
531
|
-
"enableTimeline": False,
|
532
540
|
},
|
533
541
|
)
|
534
542
|
|
@@ -579,42 +587,3 @@ class SetupSelenium:
|
|
579
587
|
logger.info(bsrmsg)
|
580
588
|
SetupSelenium.log_options(options)
|
581
589
|
return driver
|
582
|
-
|
583
|
-
############################################################################
|
584
|
-
def set_window_size(self, size: str = "720") -> None:
|
585
|
-
"""Helper to set the window size after driver has been instantiated."""
|
586
|
-
if size == "max":
|
587
|
-
self.driver.maximize_window()
|
588
|
-
return
|
589
|
-
|
590
|
-
width, height = SetupSelenium.DIMENSIONS.get(
|
591
|
-
size, SetupSelenium.DIMENSIONS.get(size, (1280, 720))
|
592
|
-
)
|
593
|
-
self.driver.set_window_size(width, height)
|
594
|
-
|
595
|
-
def set_main_window_handle(self, window: str | None = None) -> str:
|
596
|
-
"""
|
597
|
-
Maintains the initial window handle as an attribute
|
598
|
-
|
599
|
-
Most users will never utilize this. It's part of a legacy requirement for
|
600
|
-
an old test suite
|
601
|
-
"""
|
602
|
-
# does the main_window_handle exist and point to an available window?
|
603
|
-
if not window and not self.main_window_handle:
|
604
|
-
try:
|
605
|
-
window = self.driver.current_window_handle
|
606
|
-
except NoSuchWindowException:
|
607
|
-
try:
|
608
|
-
window = self.driver.window_handles[0]
|
609
|
-
except WebDriverException: # noqa: TRY203
|
610
|
-
# Have we closed all the windows?
|
611
|
-
raise
|
612
|
-
if window:
|
613
|
-
self.main_window_handle = window
|
614
|
-
return self.main_window_handle
|
615
|
-
|
616
|
-
############################################################################
|
617
|
-
def __repr__(self) -> str:
|
618
|
-
browser = self.driver.name if self.driver is not None else "NoBrowserSet"
|
619
|
-
url = self.baseurl
|
620
|
-
return f"{self.__class__.__name__} :: {browser} -> {url}"
|
@@ -1,18 +1,16 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: setup-selenium-testing
|
3
|
-
Version: 0.
|
3
|
+
Version: 1.0.0
|
4
4
|
Summary: Setup Selenium for automation testing
|
5
|
-
Home-page: https://github.com/bandophahita/setup_selenium
|
6
5
|
License: MIT
|
7
6
|
Author: Marcel Wilson
|
8
7
|
Author-email: trenchrats+pypi@gmail.com
|
9
|
-
Requires-Python: >=3.
|
8
|
+
Requires-Python: >=3.9,<4.0
|
10
9
|
Classifier: Intended Audience :: Developers
|
11
10
|
Classifier: License :: OSI Approved :: MIT License
|
12
11
|
Classifier: Natural Language :: English
|
13
12
|
Classifier: Operating System :: OS Independent
|
14
13
|
Classifier: Programming Language :: Python :: 3
|
15
|
-
Classifier: Programming Language :: Python :: 3.8
|
16
14
|
Classifier: Programming Language :: Python :: 3.9
|
17
15
|
Classifier: Programming Language :: Python :: 3.10
|
18
16
|
Classifier: Programming Language :: Python :: 3.11
|
@@ -52,7 +50,42 @@ in every project. Time to consolidate.
|
|
52
50
|
[](https://github.com/bandophahita/setup_selenium/actions/workflows/lint.yml)
|
53
51
|
|
54
52
|
|
55
|
-
#
|
53
|
+
# Instantiating SetupSelenium
|
54
|
+
|
55
|
+
This will automatically handle any downloading of drivers or browsers via `SeleniumManager`
|
56
|
+
|
57
|
+
```python
|
58
|
+
from setup_selenium import SetupSelenium
|
59
|
+
|
60
|
+
s = SetupSelenium(headless=True)
|
61
|
+
assert s.driver.service.is_connectable()
|
62
|
+
```
|
63
|
+
|
64
|
+
Advanced usage:
|
65
|
+
|
66
|
+
```python
|
67
|
+
from setup_selenium import Browser, SetupSelenium
|
68
|
+
|
69
|
+
s = SetupSelenium(Browser.FIREFOX, headless=True, driver_version="118.0.5993.70")
|
70
|
+
s = SetupSelenium(Browser.CHROME, headless=True, driver_version="118.0.5993.70",
|
71
|
+
driver_path="/path/to/webdriver"
|
72
|
+
)
|
73
|
+
```
|
74
|
+
|
75
|
+
> [!NOTE]
|
76
|
+
> Version and path arguments follow the logic of
|
77
|
+
> [SeleniumManager](https://www.selenium.dev/documentation/selenium_manager/).
|
78
|
+
> Caution is advised in cases where version and path do not match.
|
79
|
+
> See their documentation.
|
80
|
+
|
81
|
+
# Install Driver only
|
82
|
+
```python
|
83
|
+
from setup_selenium import Browser, SetupSelenium
|
84
|
+
|
85
|
+
driver_path, browser_path = SetupSelenium.install_driver(Browser.CHROME, driver_version="118.0.5993.70")
|
86
|
+
```
|
87
|
+
|
88
|
+
# Create driver only
|
56
89
|
|
57
90
|
```python
|
58
91
|
from setup_selenium import Browser, SetupSelenium
|
@@ -60,7 +93,8 @@ from setup_selenium import Browser, SetupSelenium
|
|
60
93
|
driver = SetupSelenium.create_driver(browser=Browser.CHROME, headless=True)
|
61
94
|
```
|
62
95
|
|
63
|
-
|
96
|
+
Advanced usage:
|
97
|
+
|
64
98
|
```python
|
65
99
|
from setup_selenium import Browser, SetupSelenium
|
66
100
|
|
@@ -77,19 +111,11 @@ driver = SetupSelenium.create_driver(
|
|
77
111
|
```
|
78
112
|
|
79
113
|
> [!NOTE]
|
80
|
-
> It is possible to enable the performance and console logging
|
114
|
+
> It is possible to enable the performance and console logging
|
81
115
|
> but only for chrome based browsers. This only enables the browser ability.
|
82
116
|
> It is up to the tester to handle logging the messages.
|
83
117
|
|
84
118
|
|
85
|
-
|
86
|
-
# Driver installation
|
87
|
-
```python
|
88
|
-
from setup_selenium import Browser, SetupSelenium
|
89
|
-
|
90
|
-
driver_path, browser_path = SetupSelenium.install_driver(Browser.CHROME, "118.0.5993.70")
|
91
|
-
```
|
92
|
-
|
93
119
|
# Custom logger
|
94
120
|
```python
|
95
121
|
import logging
|
@@ -99,18 +125,6 @@ set_logger(logging.getLogger("your_custom_logger"))
|
|
99
125
|
driver = SetupSelenium.create_driver(browser=Browser.CHROME, headless=True)
|
100
126
|
```
|
101
127
|
|
102
|
-
# Instantiating SetupSelenium
|
103
|
-
While it is possible to use the class directly caution is advised; as the class
|
104
|
-
will create the driver upon instantiation.
|
105
|
-
|
106
|
-
```python
|
107
|
-
from setup_selenium import SetupSelenium
|
108
|
-
|
109
|
-
s = SetupSelenium(headless=True)
|
110
|
-
assert s.driver.service.is_connectable()
|
111
|
-
```
|
112
|
-
|
113
|
-
|
114
128
|
# Automatic driver and browser installation
|
115
129
|
This package not only handles setup of the webdriver but also will
|
116
130
|
automatically install the webdriver and/or browser depending on your
|
@@ -0,0 +1,7 @@
|
|
1
|
+
setup_selenium/__init__.py,sha256=-w9Vvo72ZLaEyIEfc_Nh0bDDJz9W0pOy4rkRXurIJHI,63
|
2
|
+
setup_selenium/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
+
setup_selenium/setup_selenium.py,sha256=6IijZ0maMo7t3_W1vUyn0l2SnEi8vsZoVZRUeQmu5kA,21834
|
4
|
+
setup_selenium_testing-1.0.0.dist-info/LICENSE,sha256=KGdE-1D1chm3UNFtfE8x-EpVxhmv2zFx8oltbO8M1qE,1070
|
5
|
+
setup_selenium_testing-1.0.0.dist-info/METADATA,sha256=N0t4a2Zf4wGPcc6lVTtdpFDlSDQ2QsgCUF1lhsP6Kjs,5847
|
6
|
+
setup_selenium_testing-1.0.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
7
|
+
setup_selenium_testing-1.0.0.dist-info/RECORD,,
|
@@ -1,7 +0,0 @@
|
|
1
|
-
setup_selenium/__init__.py,sha256=-w9Vvo72ZLaEyIEfc_Nh0bDDJz9W0pOy4rkRXurIJHI,63
|
2
|
-
setup_selenium/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
setup_selenium/setup_selenium.py,sha256=asqQhE6fXcivb2MK3PL90TcQcCBVr_2Mgx-_CULxfUk,21921
|
4
|
-
setup_selenium_testing-0.2.0.dist-info/LICENSE,sha256=KGdE-1D1chm3UNFtfE8x-EpVxhmv2zFx8oltbO8M1qE,1070
|
5
|
-
setup_selenium_testing-0.2.0.dist-info/METADATA,sha256=0asqR9fuACtsQwpq_LcFCI38lB6ALuCtS7LcCFn_l8M,5413
|
6
|
-
setup_selenium_testing-0.2.0.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
|
7
|
-
setup_selenium_testing-0.2.0.dist-info/RECORD,,
|
File without changes
|