From d1425a25cfad98c193c6af3048d74ed2ffe10e6e Mon Sep 17 00:00:00 2001
From: Douglas Cardoso <29078346+douglasdcm@users.noreply.github.com>
Date: Fri, 28 Nov 2025 01:40:12 -0300
Subject: [PATCH 01/40] Add type hinting Add 'delay' paramter to server.dispose
---
README.md | 9 +++------
caqui/asynchronous.py | 23 +++++++++++++++++------
caqui/easy/action_chains.py | 6 +++---
caqui/easy/capabilities.py | 27 +++++++++++++++++++--------
caqui/easy/page.py | 4 ++--
caqui/easy/server.py | 17 ++++++++++++-----
caqui/synchronous.py | 3 ++-
dev-requirements.txt | 3 ++-
test-requirements.txt | 1 +
tests/conftest.py | 13 +++++--------
tests/constants.py | 2 +-
11 files changed, 67 insertions(+), 41 deletions(-)
diff --git a/README.md b/README.md
index 3bfee0d..8e4fe04 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# Caqui
-
+[](https://github.com/douglasdcm/caqui/actions/workflows/python-app.yml)
[](https://pepy.tech/projects/caqui)
**Caqui** executes commands against Drivers synchronously and asynchronously. The intention is that the user does not worry about which Driver they're using. It can be **Web**Drivers like [Selenium](https://www.selenium.dev/), **Mobile**Drivers like [Appium](http://appium.io/docs/en/2.0/), or **Desktop**Drivers like [Winium](https://github.com/2gis/Winium.Desktop). It can also be used in remote calls. The user can start the Driver as a server in any host and provide the URL to **Caqui** clients.
@@ -35,10 +35,8 @@ from tests.constants import PAGE_URL
from caqui.easy import AsyncPage
from caqui.by import By
from caqui import synchronous
-from caqui.easy.capabilities import ChromeOptionsBuilder
from caqui.easy.options import ChromeOptionsBuilder
from caqui.easy.server import Server
-from time import sleep
SERVER_PORT = 9999
SERVER_URL = f"http://localhost:{SERVER_PORT}"
@@ -49,13 +47,12 @@ def setup_server():
server = Server.get_instance(port=SERVER_PORT)
server.start()
yield
- sleep(3)
- server.dispose()
+ server.dispose(delay=3)
@fixture
def setup_environment():
server_url = SERVER_URL
- options = ChromeOptionsBuilder().args(["headless"]).to_dict()
+ options = ChromeOptionsBuilder().args(["headless"])
capabilities = ChromeCapabilitiesBuilder().accept_insecure_certs(True).add_options(options).to_dict()
page = AsyncPage(server_url, capabilities, PAGE_URL)
yield page
diff --git a/caqui/asynchronous.py b/caqui/asynchronous.py
index 7a13124..059c422 100644
--- a/caqui/asynchronous.py
+++ b/caqui/asynchronous.py
@@ -3,6 +3,7 @@
from caqui.constants import HEADERS as __HEADERS
from caqui.exceptions import WebDriverError as WebDriverError
from caqui import helper as __helper
+from typing import Optional
async def __handle_response(resp):
@@ -32,7 +33,9 @@ async def __delete(url):
async def __post(url, payload):
try:
async with __aiohttp.ClientSession() as session:
- async with session.post(url, data=__json.dumps(payload), headers=__HEADERS) as resp:
+ async with session.post(
+ url, data=__json.dumps(payload), headers=__HEADERS
+ ) as resp:
return await __handle_response(resp)
except Exception as error:
raise WebDriverError("'POST' request failed.") from error
@@ -228,7 +231,9 @@ async def dismiss_alert(server_url, session):
raise WebDriverError("Failed to dismiss alert.") from error
-async def take_screenshot_element(server_url, session, element, path="/tmp", file_name="caqui"):
+async def take_screenshot_element(
+ server_url, session, element, path="/tmp", file_name="caqui"
+):
"""Take screenshot of element"""
try:
url = f"{server_url}/session/{session}/element/{element}/screenshot"
@@ -444,7 +449,9 @@ async def set_timeouts(server_url, session, timeouts):
raise WebDriverError("Failed to set timeouts.") from error
-async def find_children_elements(server_url, session, parent_element, locator_type, locator_value):
+async def find_children_elements(
+ server_url, session, parent_element, locator_type, locator_value
+):
"""Find the children elements by 'locator_type'
If the 'parent_element' is a shadow element, set the 'locator_type' as 'id' or
@@ -461,7 +468,9 @@ async def find_children_elements(server_url, session, parent_element, locator_ty
) from error
-async def find_child_element(server_url, session, parent_element, locator_type, locator_value):
+async def find_child_element(
+ server_url, session, parent_element, locator_type, locator_value
+):
"""Find the child element by 'locator_type'"""
try:
url = f"{server_url}/session/{session}/element/{parent_element}/element"
@@ -773,7 +782,7 @@ async def find_element(server_url, session, locator_type, locator_value) -> dict
) from error
-async def get_session(server_url: str, capabilities: dict = None) -> str:
+async def get_session(server_url: str, capabilities: Optional[dict] = None) -> str:
"""
Opens a browser and a session.
This session is used for all functions to perform events in the page
@@ -785,4 +794,6 @@ async def get_session(server_url: str, capabilities: dict = None) -> str:
response = await __post(url, capabilities)
return response.get("sessionId")
except Exception as error:
- raise WebDriverError("Failed to open session. Check the browser capabilities.") from error
+ raise WebDriverError(
+ "Failed to open session. Check the browser capabilities."
+ ) from error
diff --git a/caqui/easy/action_chains.py b/caqui/easy/action_chains.py
index c9aa651..7a5a33f 100644
--- a/caqui/easy/action_chains.py
+++ b/caqui/easy/action_chains.py
@@ -1,12 +1,13 @@
from caqui import asynchronous
from caqui.easy.element import Element
+from typing import Coroutine
class ActionChains:
def __init__(self, driver) -> None:
self.__remote = driver.remote
self.__session = driver.session
- self.__coroutines = []
+ self.__coroutines: list[Coroutine] = []
def click(self, element: Element):
"""
@@ -37,6 +38,5 @@ def scroll_to_element(self, element: Element):
async def perform(self):
"""Executes the chain of Coroutines"""
- for coroutine in self.__coroutines:
- await coroutine
+ [await coroutine for coroutine in self.__coroutines]
return True
diff --git a/caqui/easy/capabilities.py b/caqui/easy/capabilities.py
index 3cdae8f..72ba3af 100644
--- a/caqui/easy/capabilities.py
+++ b/caqui/easy/capabilities.py
@@ -1,5 +1,7 @@
from math import ceil
+from caqui.easy.options import BaseOptions
+
class Browser:
"""
@@ -19,7 +21,7 @@ class ProxyConfigurationBuilder:
"""
def __init__(self) -> None:
- self.__proxy = {}
+ self.__proxy: dict = {}
def proxy_type(self, proxy: str):
"""
@@ -127,7 +129,7 @@ class TimeoutsBuilder:
"""
def __init__(self) -> None:
- self.__timeouts = {}
+ self.__timeouts: dict = {}
def implicit(self, timeout: int):
"""Notice: if the number is a float, converts it to an integer"""
@@ -164,8 +166,8 @@ class BaseCapabilities:
"""Reference: https://www.w3.org/TR/webdriver/#capabilities"""
def __init__(self) -> None:
- self.desired_capabilities = {}
- self.options = {}
+ self.desired_capabilities: dict = {}
+ self.options: dict = {}
def to_dict(self):
raise NotImplementedError
@@ -217,11 +219,13 @@ def page_load_strategy(self, strategy: str):
}
return self
- def proxy(self, proxy_configuration: dict):
+ def proxy(self, proxy_configuration: dict | ProxyConfigurationBuilder):
"""
Defines the current session’s proxy configuration.
Use the ProxyConfigurationBuilder class for simplicity.
"""
+ if isinstance(proxy_configuration, ProxyConfigurationBuilder):
+ proxy_configuration = proxy_configuration.to_dict()
self.desired_capabilities = {
**self.desired_capabilities,
**proxy_configuration,
@@ -238,11 +242,13 @@ def set_window_rect(self, decison: bool):
}
return self
- def timeouts(self, session_timeouts: dict):
+ def timeouts(self, session_timeouts: dict | TimeoutsBuilder):
"""
Describes the timeouts imposed on certain session operations.
Use the TimeoutsBuilder class for simplicity.
"""
+ if isinstance(session_timeouts, TimeoutsBuilder):
+ session_timeouts = session_timeouts.to_dict()
self.desired_capabilities = {
**self.desired_capabilities,
**session_timeouts,
@@ -293,11 +299,13 @@ def user_agent(self, agent: str):
}
return self
- def add_options(self, options: dict):
+ def add_options(self, options: dict | BaseOptions):
"""Add vendor options, for example
{"goog:chromeOptions": {"extensions": [], "args": ["--headless"]}} or
{"moz:experimental-webdriver": true}
"""
+ if isinstance(options, BaseOptions):
+ options = options.to_dict()
self.options = options
return self
@@ -329,5 +337,8 @@ def to_dict(self):
"""
result = {"capabilities": self.desired_capabilities}
if self.options:
- result["capabilities"] = {**result["capabilities"], **{"firstMatch": self.options}}
+ result["capabilities"] = {
+ **result["capabilities"],
+ **{"firstMatch": self.options},
+ }
return result
diff --git a/caqui/easy/page.py b/caqui/easy/page.py
index 8137f7d..bfaadc6 100644
--- a/caqui/easy/page.py
+++ b/caqui/easy/page.py
@@ -1,5 +1,5 @@
import os
-from typing import Union
+from typing import Optional, Union
from caqui import asynchronous, synchronous
from caqui.easy.action_chains import ActionChains
from caqui.easy.window import Window
@@ -11,7 +11,7 @@
class AsyncPage:
def __init__(
- self, server_url: str, capabilities: dict = None, url: Union[str, None] = None
+ self, server_url: str, capabilities: Optional[dict] = None, url: Union[str, None] = None
) -> None:
"""Mimics Selenium methods"""
if not capabilities:
diff --git a/caqui/easy/server.py b/caqui/easy/server.py
index 2d4bdc1..b00bc64 100644
--- a/caqui/easy/server.py
+++ b/caqui/easy/server.py
@@ -1,14 +1,15 @@
+import requests
+import subprocess
from time import sleep
from typing import Union
from requests import head
from requests.exceptions import ConnectionError
-import requests
-import subprocess
from webdriver_manager.core.manager import DriverManager
from webdriver_manager.chrome import ChromeDriverManager
from caqui.exceptions import ServerError
-TIMEOUT = 120 # seconds
+TIMEOUT = 120 # seconds
+
class Server:
"""
@@ -42,7 +43,7 @@ def __wait_server(self):
requests.get(self.url, timeout=TIMEOUT)
break
except ConnectionError:
- sleep(1)
+ sleep(0.5)
if i == (MAX_RETIES - 1):
self.__process.kill()
self.__process.wait()
@@ -88,10 +89,16 @@ def process(self):
"""Returns the process (PID)"""
return self.__process
- def dispose(self):
+ def dispose(self, delay: float = 0):
"""
Disposes the driver process.
+
+ Args:
+ delay: Delay execution for a given number of seconds.
+ The argument may be a floating point number for subsecond precision.
"""
+ if delay:
+ sleep(delay)
if self.__process:
self.__process.kill()
self.__process.wait()
diff --git a/caqui/synchronous.py b/caqui/synchronous.py
index f3bc5fa..c5ee515 100644
--- a/caqui/synchronous.py
+++ b/caqui/synchronous.py
@@ -3,6 +3,7 @@
from caqui.exceptions import WebDriverError as WebDriverError
from caqui import helper as __helper
from caqui.constants import HEADERS as __HEADERS
+from typing import Optional
def __handle_response(response):
@@ -740,7 +741,7 @@ def __get_session(response) -> str:
return response.get("sessionId")
-def get_session(server_url: str, capabilities: dict = None):
+def get_session(server_url: str, capabilities: Optional[dict] = None):
"""
Opens a browser and a session.
This session is used for all functions to perform events in the page
diff --git a/dev-requirements.txt b/dev-requirements.txt
index 91f6e12..0267580 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -1,3 +1,4 @@
requests
aiohttp
-webdriver_manager
\ No newline at end of file
+webdriver_manager
+types-requests
\ No newline at end of file
diff --git a/test-requirements.txt b/test-requirements.txt
index ad1abef..ec3406d 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -5,3 +5,4 @@ coverage
tox
pytest-asyncio
build
+mypy
diff --git a/tests/conftest.py b/tests/conftest.py
index aad06bb..61e1444 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,4 +1,3 @@
-from time import sleep
from pytest import fixture
from tests.constants import PAGE_URL
from caqui.easy import AsyncPage
@@ -13,7 +12,7 @@
def __build_capabilities():
- options = ChromeOptionsBuilder().args(["headless"]).to_dict()
+ options = ChromeOptionsBuilder().args(["headless"])
capabilities = (
ChromeCapabilitiesBuilder()
.accept_insecure_certs(True)
@@ -28,8 +27,7 @@ def setup_server():
server = Server.get_instance(port=SERVER_PORT)
server.start()
yield
- sleep(3)
- server.dispose()
+ server.dispose(delay=3)
@fixture
@@ -47,10 +45,8 @@ def setup_functional_environment():
synchronous.dismiss_alert(server_url, session)
except Exception:
pass
- try:
+ finally:
synchronous.close_session(server_url, session)
- except Exception:
- pass
@fixture
@@ -63,4 +59,5 @@ def setup_environment():
synchronous.dismiss_alert(server_url, page.session)
except Exception:
pass
- page.quit()
+ finally:
+ page.quit()
diff --git a/tests/constants.py b/tests/constants.py
index 01d3430..dfbc00c 100644
--- a/tests/constants.py
+++ b/tests/constants.py
@@ -13,4 +13,4 @@
"sameSite": "Lax",
"secure": True,
"value": "523=Sc0_gsThISC9jkAfuOsEdaX51SxT6FWqrG3UWhn7eaw5JZooxNWC2jbQZVadDFgM4OYLjDSTAYPb3rQdKt23GQgDcTa_iuLSOyJ7Tlpo3PKa_ijrjrcoMeIWT6O6DnvvG1q8tSfeahhzv44f9cgkJrjZ5VPC4wg1ZKocrQFiJOZEIS6XZpsK73d2hnw0HZkTymQsYt3UVoWrsqPujsTzw542M45aSRl3U406lNMU9zailbJurvW6ZRVL2TIaaUMhkQ", # noqa E501
-}
\ No newline at end of file
+}
From d49b40a0e4b6714a096bdac9994cc7988bd6a377 Mon Sep 17 00:00:00 2001
From: Douglas Cardoso <29078346+douglasdcm@users.noreply.github.com>
Date: Fri, 28 Nov 2025 13:55:17 -0300
Subject: [PATCH 02/40] add single async session option
---
caqui/asynchronous.py | 684 +++++----
caqui/easy/action_chains.py | 28 +-
caqui/easy/alert.py | 13 +-
caqui/easy/element.py | 61 +-
caqui/easy/page.py | 79 +-
caqui/easy/switch_to.py | 35 +-
tests/conftest.py | 24 +-
tests/feature/test_async_with_http_session.py | 1245 +++++++++++++++++
tests/feature/test_sync_and_async.py | 160 ++-
tests/integration/test_async_scenarios.py | 10 +-
tests/unit/test_async_unit.py | 62 +-
11 files changed, 1938 insertions(+), 463 deletions(-)
create mode 100644 tests/feature/test_async_with_http_session.py
diff --git a/caqui/asynchronous.py b/caqui/asynchronous.py
index 059c422..05f29f0 100644
--- a/caqui/asynchronous.py
+++ b/caqui/asynchronous.py
@@ -1,12 +1,12 @@
-import aiohttp as __aiohttp
-import json as __json
+from aiohttp import ClientSession
+from json import dumps
from caqui.constants import HEADERS as __HEADERS
from caqui.exceptions import WebDriverError as WebDriverError
-from caqui import helper as __helper
+from caqui.helper import save_picture, get_elements, get_element
from typing import Optional
-async def __handle_response(resp):
+async def _handle_response(resp):
result = None
if resp.status in range(200, 399):
result = await resp.json()
@@ -21,141 +21,179 @@ async def __handle_response(resp):
return result
-async def __delete(url):
- try:
- async with __aiohttp.ClientSession() as session:
- async with session.delete(url, headers=__HEADERS) as resp:
- return await __handle_response(resp)
- except Exception as error:
- raise WebDriverError("'DELETE' request failed.") from error
-
+async def _delete(url, session_http: ClientSession = None):
+ if session_http:
+ try:
+ async with session_http.delete(url, headers=__HEADERS) as resp:
+ return await _handle_response(resp)
+ except Exception as e:
+ raise WebDriverError("'DELETE' request failed.") from e
-async def __post(url, payload):
- try:
- async with __aiohttp.ClientSession() as session:
- async with session.post(
- url, data=__json.dumps(payload), headers=__HEADERS
+ else:
+ try:
+ async with ClientSession() as session_http:
+ async with session_http.delete(url, headers=__HEADERS) as resp:
+ return await _handle_response(resp)
+ except Exception as e:
+ raise WebDriverError("'DELETE' request failed.") from e
+
+
+async def _post(url, payload, session_http: ClientSession = None):
+ if session_http:
+ try:
+ async with session_http.post(
+ url, data=dumps(payload), headers=__HEADERS
) as resp:
- return await __handle_response(resp)
- except Exception as error:
- raise WebDriverError("'POST' request failed.") from error
-
-
-async def __get(url):
- try:
- async with __aiohttp.ClientSession() as session:
- async with session.get(url, headers=__HEADERS) as resp:
- return await __handle_response(resp)
- except Exception as error:
- raise WebDriverError("'GET' request failed.") from error
+ return await _handle_response(resp)
+ except Exception as e:
+ raise WebDriverError("'POST' request failed.") from e
+ else:
+ try:
+ async with ClientSession() as session_http:
+ async with session_http.post(
+ url, data=dumps(payload), headers=__HEADERS
+ ) as resp:
+ return await _handle_response(resp)
+ except Exception as e:
+ raise WebDriverError("'POST' request failed.") from e
+
+
+async def _get(url, session_http: ClientSession = None):
+ if session_http:
+ try:
+ async with session_http.get(url, headers=__HEADERS) as resp:
+ return await _handle_response(resp)
+ except Exception as e:
+ raise WebDriverError("'GET' request failed.") from e
+ else:
+ try:
+ async with ClientSession() as session_http:
+ async with session_http.get(url, headers=__HEADERS) as resp:
+ return await _handle_response(resp)
+ except Exception as e:
+ raise WebDriverError("'GET' request failed.") from e
-async def __handle_alert(server_url, session, command) -> bool:
+async def _handle_alert(server_url, session, command, session_http) -> bool:
url = f"{server_url}/session/{session}/alert/{command}"
payload = {
"value": command,
}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
-async def __handle_window(server_url, session, command):
+async def _handle_window(
+ server_url, session, command, session_http: ClientSession = None
+):
url = f"{server_url}/session/{session}/window/{command}"
payload = {}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
-async def add_cookie(server_url, session, cookie):
+async def add_cookie(server_url, session, cookie, session_http: ClientSession = None):
"""Add cookie"""
try:
url = f"{server_url}/session/{session}/cookie"
payload = {"cookie": cookie}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to add cookie.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to add cookie.") from e
-async def delete_cookie(server_url, session, name):
+async def delete_cookie(server_url, session, name, session_http: ClientSession = None):
"""Delete cookie by name"""
try:
url = f"{server_url}/session/{session}/cookie/{name}"
- await __delete(url)
+ await _delete(url, session_http)
return True
- except Exception as error:
- raise WebDriverError(f"Failed to delete cookie '{name}'.") from error
+ except Exception as e:
+ raise WebDriverError(f"Failed to delete cookie '{name}'.") from e
-async def refresh_page(server_url, session):
+async def refresh_page(server_url, session, session_http: ClientSession = None):
"""Refresh page"""
try:
url = f"{server_url}/session/{session}/refresh"
payload = {}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to refresh page.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to refresh page.") from e
-async def go_forward(server_url, session):
+async def go_forward(server_url, session, session_http: ClientSession = None):
"""Go to page forward"""
try:
url = f"{server_url}/session/{session}/forward"
payload = {}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to go to page forward.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to go to page forward.") from e
-async def set_window_rectangle(server_url, session, width, height, x, y):
+async def set_window_rectangle(
+ server_url, session, width, height, x, y, session_http=None
+):
"""Set window rectangle"""
try:
url = f"{server_url}/session/{session}/window/rect"
payload = {"width": width, "height": height, "x": x, "y": y}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to set window rectangle.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to set window rectangle.") from e
-async def fullscreen_window(server_url, session):
+async def fullscreen_window(server_url, session, session_http: ClientSession = None):
"""Fullscreen window"""
try:
- return await __handle_window(server_url, session, command="fullscreen")
- except Exception as error:
- raise WebDriverError("Failed to fullscreen window.") from error
+ return await _handle_window(
+ server_url, session, command="fullscreen", session_http=session_http
+ )
+ except Exception as e:
+ raise WebDriverError("Failed to fullscreen window.") from e
-async def minimize_window(server_url, session):
+async def minimize_window(server_url, session, session_http: ClientSession = None):
"""Minimize window"""
try:
- return await __handle_window(server_url, session, command="minimize")
- except Exception as error:
- raise WebDriverError("Failed to minimize window.") from error
+ return await _handle_window(
+ server_url, session, command="minimize", session_http=session_http
+ )
+ except Exception as e:
+ raise WebDriverError("Failed to minimize window.") from e
-async def maximize_window(server_url, session):
+async def maximize_window(server_url, session, session_http: ClientSession = None):
"""Maximize window"""
try:
- return await __handle_window(server_url, session, command="maximize")
- except Exception as error:
- raise WebDriverError("Failed to maximize window.") from error
+ return await _handle_window(
+ server_url, session, command="maximize", session_http=session_http
+ )
+ except Exception as e:
+ raise WebDriverError("Failed to maximize window.") from e
-async def switch_to_window(server_url, session, handle):
+async def switch_to_window(
+ server_url, session, handle, session_http: ClientSession = None
+):
"""Switch to window"""
try:
url = f"{server_url}/session/{session}/window"
payload = {"name": handle}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to switch to window.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to switch to window.") from e
-async def new_window(server_url, session, window_type="tab") -> str:
+async def new_window(
+ server_url, session, window_type="tab", session_http: ClientSession = None
+) -> str:
"""Open a new window
:param window_type (str): tab or window
@@ -164,167 +202,202 @@ async def new_window(server_url, session, window_type="tab") -> str:
try:
url = f"{server_url}/session/{session}/window/new"
payload = {"type": window_type}
- result = await __post(url, payload)
+ result = await _post(url, payload, session_http=session_http)
return result.get("value", {}).get("handle")
- except Exception as error:
- raise WebDriverError("Failed to open window.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to open window.") from e
-async def switch_to_parent_frame(server_url, session, element_frame):
+async def switch_to_parent_frame(
+ server_url, session, element_frame, session_http: ClientSession = None
+):
"""Switch to parent frame of 'element_frame'"""
try:
url = f"{server_url}/session/{session}/frame/parent"
payload = {"id": {"ELEMENT": element_frame}}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to switch to parent frame.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to switch to parent frame.") from e
-async def switch_to_frame(server_url, session, element_frame):
+async def switch_to_frame(
+ server_url, session, element_frame, session_http: ClientSession = None
+):
"""Switch to frame 'element_frame'"""
try:
url = f"{server_url}/session/{session}/frame"
payload = {"id": {"ELEMENT": element_frame}}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to switch to frame.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to switch to frame.") from e
-async def delete_all_cookies(server_url, session):
+async def delete_all_cookies(server_url, session, session_http: ClientSession = None):
"""Delete all cookies"""
try:
url = f"{server_url}/session/{session}/cookie"
- await __delete(url)
+ await _delete(url, session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to delete cookies.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to delete cookies.") from e
-async def send_alert_text(server_url, session, text):
+async def send_alert_text(
+ server_url, session, text, session_http: ClientSession = None
+):
"""Fill the alert text area and send the text"""
try:
url = f"{server_url}/session/{session}/alert/text"
payload = {
"text": text,
}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to sent text to alert.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to sent text to alert.") from e
-async def accept_alert(server_url, session):
+async def accept_alert(server_url, session, session_http: ClientSession = None):
"""Accept alert"""
try:
- return await __handle_alert(server_url, session, "accept")
- except Exception as error:
- raise WebDriverError("Failed to accept alert.") from error
+ return await _handle_alert(
+ server_url, session, "accept", session_http=session_http
+ )
+ except Exception as e:
+ raise WebDriverError("Failed to accept alert.") from e
-async def dismiss_alert(server_url, session):
+async def dismiss_alert(server_url, session, session_http: ClientSession = None):
"""Dismiss alert"""
try:
- return await __handle_alert(server_url, session, "dismiss")
- except Exception as error:
- raise WebDriverError("Failed to dismiss alert.") from error
+ return await _handle_alert(
+ server_url, session, "dismiss", session_http=session_http
+ )
+ except Exception as e:
+ raise WebDriverError("Failed to dismiss alert.") from e
async def take_screenshot_element(
- server_url, session, element, path="/tmp", file_name="caqui"
+ server_url,
+ session,
+ element,
+ path="/tmp",
+ file_name="caqui",
+ session_http: ClientSession = None,
):
"""Take screenshot of element"""
try:
url = f"{server_url}/session/{session}/element/{element}/screenshot"
- response = await __get(url)
+ response = await _get(url, session_http)
picture = response.get("value")
- __helper.save_picture(session, path, file_name, picture)
+ save_picture(session, path, file_name, picture)
return True
- except Exception as error:
- raise WebDriverError("Failed to take screenshot from element.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to take screenshot from element.") from e
-async def take_screenshot(server_url, session, path="/tmp", file_name="caqui"):
+async def take_screenshot(
+ server_url,
+ session,
+ path="/tmp",
+ file_name="caqui",
+ session_http: ClientSession = None,
+):
"""Take screenshot"""
try:
url = f"{server_url}/session/{session}/screenshot"
- response = await __get(url)
+ response = await _get(url, session_http)
picture = response.get("value")
- __helper.save_picture(session, path, file_name, picture)
+ save_picture(session, path, file_name, picture)
return True
- except Exception as error:
- raise WebDriverError("Failed to take screenshot.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to take screenshot.") from e
-async def get_named_cookie(server_url, session, name) -> str:
+async def get_named_cookie(
+ server_url, session, name, session_http: ClientSession = None
+) -> str:
"""Get cookie by name"""
try:
url = f"{server_url}/session/{session}/cookie/{name}"
- response = await __get(url)
+ response = await _get(url, session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError(f"Failed to get cookie '{name}'.") from error
+ except Exception as e:
+ raise WebDriverError(f"Failed to get cookie '{name}'.") from e
-async def get_computed_label(server_url, session, element) -> str:
+async def get_computed_label(
+ server_url, session, element, session_http: ClientSession = None
+) -> str:
"""Get the element tag computed label. Get the accessibility name"""
try:
url = f"{server_url}/session/{session}/element/{element}/computedlabel"
- response = await __get(url)
+ response = await _get(url, session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get element computed label.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get element computed label.") from e
-async def get_computed_role(server_url, session, element) -> str:
+async def get_computed_role(
+ server_url, session, element, session_http: ClientSession = None
+) -> str:
"""Get the element tag computed role (the element role)"""
try:
url = f"{server_url}/session/{session}/element/{element}/computedrole"
- response = await __get(url)
+ response = await _get(url, session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get element computed role.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get element computed role.") from e
-async def get_tag_name(server_url, session, element) -> str:
+async def get_tag_name(
+ server_url, session, element, session_http: ClientSession = None
+) -> str:
"""Get the element tag name"""
try:
url = f"{server_url}/session/{session}/element/{element}/name"
- response = await __get(url)
+ response = await _get(url, session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get element name.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get element name.") from e
-async def get_shadow_root(server_url, session, element) -> dict:
+async def get_shadow_root(
+ server_url, session, element, session_http: ClientSession = None
+) -> dict:
"""Get the shadow root element"""
try:
root_element = "shadow-6066-11e4-a52e-4f735466cecf"
url = f"{server_url}/session/{session}/element/{element}/shadow"
- response = await __get(url)
+ response = await _get(url, session_http)
return response.get("value", {}).get(root_element)
- except Exception as error:
- raise WebDriverError("Failed to get element shadow.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get element shadow.") from e
-async def get_rect(server_url, session, element) -> dict:
+async def get_rect(
+ server_url, session, element, session_http: ClientSession = None
+) -> dict:
"""Get the element rectangle"""
try:
url = f"{server_url}/session/{session}/element/{element}/rect"
- response = await __get(url)
+ response = await _get(url, session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get element rect.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get element rect.") from e
-async def actions(server_url, session, payload):
+async def actions(server_url, session, payload, session_http: ClientSession = None):
url = f"{server_url}/session/{session}/actions"
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
-async def actions_move_to_element(server_url, session, element):
+async def actions_move_to_element(
+ server_url, session, element, session_http: ClientSession = None
+):
"""Move to an element simulating a mouse movement"""
try:
payload = {
@@ -350,12 +423,14 @@ async def actions_move_to_element(server_url, session, element):
},
]
}
- return await actions(server_url, session, payload)
- except Exception as error:
- raise WebDriverError("Failed to move to element.") from error
+ return await actions(server_url, session, payload, session_http=session_http)
+ except Exception as e:
+ raise WebDriverError("Failed to move to element.") from e
-async def actions_scroll_to_element(server_url, session, element):
+async def actions_scroll_to_element(
+ server_url, session, element, session_http: ClientSession = None
+):
"""Scroll to an element simulating a mouse movement"""
try:
payload = {
@@ -377,12 +452,12 @@ async def actions_scroll_to_element(server_url, session, element):
}
]
}
- return await actions(server_url, session, payload)
- except Exception as error:
- raise WebDriverError("Failed to scroll to element.") from error
+ return await actions(server_url, session, payload, session_http=session_http)
+ except Exception as e:
+ raise WebDriverError("Failed to scroll to element.") from e
-async def submit(server_url, session, element):
+async def submit(server_url, session, element, session_http: ClientSession = None):
"""Submit a form. It is similar to 'submit' funtion in Seleniu
It is not part of W3C WebDriver. Just added for convenience
"""
@@ -393,13 +468,18 @@ async def submit(server_url, session, element):
element,
locator_type="xpath",
locator_value="*[@type='submit']",
+ session_http=session_http
+ )
+ return await click(
+ server_url, session, submit_element, session_http=session_http
)
- return await click(server_url, session, submit_element)
- except Exception as error:
- raise WebDriverError("Failed to submit form.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to submit form.") from e
-async def actions_click(server_url, session, element):
+async def actions_click(
+ server_url, session, element, session_http: ClientSession = None
+):
"""Click an element simulating a mouse movement"""
try:
payload = {
@@ -431,26 +511,33 @@ async def actions_click(server_url, session, element):
},
]
}
- return await actions(server_url, session, payload)
- except Exception as error:
- raise WebDriverError("Failed to click the element.") from error
+ return await actions(server_url, session, payload, session_http=session_http)
+ except Exception as e:
+ raise WebDriverError("Failed to click the element.") from e
-async def set_timeouts(server_url, session, timeouts):
+async def set_timeouts(
+ server_url, session, timeouts, session_http: ClientSession = None
+):
"""Set timeouts"""
try:
url = f"{server_url}/session/{session}/timeouts"
payload = {
"implicit": timeouts,
}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to set timeouts.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to set timeouts.") from e
async def find_children_elements(
- server_url, session, parent_element, locator_type, locator_value
+ server_url,
+ session,
+ parent_element,
+ locator_type,
+ locator_value,
+ session_http: ClientSession = None,
):
"""Find the children elements by 'locator_type'
@@ -460,152 +547,175 @@ async def find_children_elements(
try:
url = f"{server_url}/session/{session}/element/{parent_element}/elements"
payload = {"using": locator_type, "value": locator_value, "id": parent_element}
- response = await __post(url, payload)
- return __helper.get_elements(response)
- except Exception as error:
+ response = await _post(url, payload, session_http=session_http)
+ return get_elements(response)
+ except Exception as e:
raise WebDriverError(
f"Failed to find the children elements from '{parent_element}'."
- ) from error
+ ) from e
async def find_child_element(
- server_url, session, parent_element, locator_type, locator_value
+ server_url,
+ session,
+ parent_element,
+ locator_type,
+ locator_value,
+ session_http: ClientSession = None,
):
"""Find the child element by 'locator_type'"""
try:
url = f"{server_url}/session/{session}/element/{parent_element}/element"
payload = {"using": locator_type, "value": locator_value, "id": parent_element}
- response = await __post(url, payload)
- return __helper.get_element(response)
- except Exception as error:
+ response = await _post(url, payload, session_http=session_http)
+ return get_element(response)
+ except Exception as e:
raise WebDriverError(
f"Failed to find the child element from '{parent_element}'."
- ) from error
+ ) from e
-async def get_page_source(server_url, session) -> str:
+async def get_page_source(
+ server_url, session, session_http: ClientSession = None
+) -> str:
"""Get the page source (all content)"""
try:
url = f"{server_url}/session/{session}/source"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get the page source.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get the page source.") from e
-async def execute_script(server_url, session, script, args=[]):
+async def execute_script(
+ server_url, session, script, args=[], session_http: ClientSession = None
+):
"""Executes a script, like 'alert('something')' to open an alert window"""
try:
url = f"{server_url}/session/{session}/execute/sync"
payload = {"script": script, "args": args}
- response = await __post(url, payload)
+ response = await _post(url, payload, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to execute script.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to execute script.") from e
-async def get_alert_text(server_url, session) -> str:
+async def get_alert_text(
+ server_url, session, session_http: ClientSession = None
+) -> str:
"""Get the text from an alert"""
try:
url = f"{server_url}/session/{session}/alert/text"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get the alert text.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get the alert text.") from e
-async def get_active_element(server_url, session):
+async def get_active_element(server_url, session, session_http: ClientSession = None):
"""Get the active element"""
try:
url = f"{server_url}/session/{session}/element/active"
- response = await __get(url)
- return __helper.get_element(response)
- except Exception as error:
- raise WebDriverError("Failed to check if element is selected.") from error
+ response = await _get(url, session_http=session_http)
+ return get_element(response)
+ except Exception as e:
+ raise WebDriverError("Failed to check if element is selected.") from e
-async def clear_element(server_url, session, element):
+async def clear_element(
+ server_url, session, element, session_http: ClientSession = None
+):
"""Clear the element text"""
try:
url = f"{server_url}/session/{session}/element/{element}/clear"
payload = {"id": element}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to clear the element text.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to clear the element text.") from e
-async def is_element_enabled(server_url, session, element) -> bool:
+async def is_element_enabled(
+ server_url, session, element, session_http: ClientSession = None
+) -> bool:
"""Check if element is enabled"""
try:
url = f"{server_url}/session/{session}/element/{element}/enabled"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to check if element is enabled.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to check if element is enabled.") from e
-async def get_css_value(server_url, session, element, property_name) -> str:
+async def get_css_value(
+ server_url, session, element, property_name, session_http: ClientSession = None
+) -> str:
"""Check if element is selected"""
try:
url = f"{server_url}/session/{session}/element/{element}/css/{property_name}"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to check if element is selected.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to check if element is selected.") from e
-async def is_element_selected(server_url, session, element) -> str:
+async def is_element_selected(
+ server_url, session, element, session_http: ClientSession = None
+) -> str:
"""Check if element is selected"""
try:
url = f"{server_url}/session/{session}/element/{element}/selected"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to check if element is selected.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to check if element is selected.") from e
-async def get_window_rectangle(server_url, session) -> dict:
+async def get_window_rectangle(
+ server_url, session, session_http: ClientSession = None
+) -> dict:
"""Get window rectangle"""
try:
url = f"{server_url}/session/{session}/window/rect"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get window rectangle.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get window rectangle.") from e
-async def get_window_handles(server_url, session) -> list:
+async def get_window_handles(
+ server_url, session, session_http: ClientSession = None
+) -> list:
"""Get window handles"""
try:
url = f"{server_url}/session/{session}/window/handles"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get window handles.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get window handles.") from e
-async def close_window(server_url, session) -> list:
+async def close_window(server_url, session, session_http: ClientSession = None) -> list:
"""Close active window"""
try:
url = f"{server_url}/session/{session}/window"
- response = await __delete(url)
+ response = await _delete(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to close active window.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to close active window.") from e
-async def get_window(server_url, session) -> str:
+async def get_window(server_url, session, session_http: ClientSession = None) -> str:
"""Get window"""
try:
url = f"{server_url}/session/{session}/window"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get window.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get window.") from e
-async def go_back(server_url, session):
+async def go_back(server_url, session, session_http: ClientSession = None):
"""
This command causes the browser to traverse one step backward
in the joint session history of the
@@ -613,176 +723,192 @@ async def go_back(server_url, session):
"""
try:
url = f"{server_url}/session/{session}/back"
- await __post(url, {})
+ await _post(url, {}, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to go back to page.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to go back to page.") from e
-async def get_url(server_url, session) -> str:
+async def get_url(server_url, session, session_http: ClientSession = None) -> str:
"""Returns the URL from web page:"""
try:
url = f"{server_url}/session/{session}/url"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get page url.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get page url.") from e
-async def get_timeouts(server_url, session) -> dict:
+async def get_timeouts(server_url, session, session_http: ClientSession = None) -> dict:
"""
Returns the configured timeouts:
{"implicit": 0, "pageLoad": 300000, "script": 30000}
"""
try:
url = f"{server_url}/session/{session}/timeouts"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get timeouts.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get timeouts.") from e
-async def get_status(server_url) -> dict:
+async def get_status(server_url, session_http: ClientSession = None) -> dict:
"""Returns the status and details of the WebDriver"""
try:
url = f"{server_url}/status"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response
- except Exception as error:
- raise WebDriverError("Failed to get status.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get status.") from e
-async def get_title(server_url, session) -> str:
+async def get_title(server_url, session, session_http: ClientSession = None) -> str:
"""Get the page title"""
try:
url = f"{server_url}/session/{session}/title"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get page title.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get page title.") from e
-async def find_elements(server_url, session, locator_type, locator_value) -> str:
+async def find_elements(
+ server_url, session, locator_type, locator_value, session_http: ClientSession = None
+) -> str:
"""Search the DOM elements by 'locator', for example, 'xpath'"""
try:
payload = {"using": locator_type, "value": locator_value}
url = f"{server_url}/session/{session}/elements"
- response = await __post(url, payload)
+ response = await _post(url, payload, session_http=session_http)
return [x.get("ELEMENT") for x in response.get("value")]
- except Exception as error:
+ except Exception as e:
raise WebDriverError(
f"Failed to find element by '{locator_type}'-'{locator_value}'."
- ) from error
+ ) from e
-async def get_property(server_url, session, element, property) -> str:
+async def get_property(
+ server_url, session, element, property, session_http: ClientSession = None
+) -> str:
"""Get the given HTML property of an element, for example, 'href'"""
try:
url = f"{server_url}/session/{session}/element/{element}/property/{property}"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get value from element.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get value from element.") from e
-async def get_attribute(server_url, session, element, attribute) -> str:
+async def get_attribute(
+ server_url, session, element, attribute, session_http: ClientSession = None
+) -> str:
"""Get the given HTML attribute of an element, for example, 'aria-valuenow'"""
try:
url = f"{server_url}/session/{session}/element/{element}/attribute/{attribute}"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get value from element.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get value from element.") from e
-async def get_text(server_url, session, element) -> str:
+async def get_text(
+ server_url, session, element, session_http: ClientSession = None
+) -> str:
"""Get the text of an element"""
try:
url = f"{server_url}/session/{session}/element/{element}/text"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get text from element.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get text from element.") from e
-async def get_cookies(server_url, session) -> list:
+async def get_cookies(server_url, session, session_http: ClientSession = None) -> list:
"""Get the page cookies"""
try:
url = f"{server_url}/session/{session}/cookie"
- response = await __get(url)
+ response = await _get(url, session_http=session_http)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get page cookies.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get page cookies.") from e
-async def close_session(server_url, session):
+async def close_session(server_url, session, session_http: ClientSession = None):
"""Close an opened session and close the browser"""
try:
url = f"{server_url}/session/{session}"
- await __delete(url)
+ await _delete(url, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to close session.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to close session.") from e
-async def get(server_url, session, page_url):
+async def get(server_url, session, page_url, session_http: ClientSession = None):
"""Does the same of 'go_to_page'. Added to be compatible with selenium method name'"""
- return go_to_page(server_url, session, page_url)
+ return go_to_page(server_url, session, page_url, session_http=session_http)
-async def go_to_page(server_url, session, page_url):
+async def go_to_page(server_url, session, page_url, session_http:ClientSession=None):
"""Navigate to 'page_url'"""
try:
url = f"{server_url}/session/{session}/url"
payload = {"url": page_url}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError(f"Failed to navigate to page '{page_url}'.") from error
+ except Exception as e:
+ raise WebDriverError(f"Failed to navigate to page '{page_url}'.") from e
-async def send_keys(server_url, session, element, text):
+async def send_keys(
+ server_url, session, element, text, session_http: ClientSession = None
+):
"""Fill an editable element, for example a textarea, with a given text"""
try:
url = f"{server_url}/session/{session}/element/{element}/value"
payload = {"text": text, "value": [*text], "id": element}
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError(f"Failed to send key '{text}'.") from error
+ except Exception as e:
+ raise WebDriverError(f"Failed to send key '{text}'.") from e
-async def click(server_url, session, element):
+async def click(server_url, session, element, session_http: ClientSession = None):
"""Click on an element"""
try:
payload = {"id": element}
url = f"{server_url}/session/{session}/element/{element}/click"
- await __post(url, payload)
+ await _post(url, payload, session_http=session_http)
return True
- except Exception as error:
- raise WebDriverError("Failed to click on element.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to click on element.") from e
-async def find_element(server_url, session, locator_type, locator_value) -> dict:
+async def find_element(
+ server_url, session, locator_type, locator_value, session_http: ClientSession = None
+) -> dict:
"""Find an element by a 'locator', for example 'xpath'"""
try:
payload = {"using": locator_type, "value": locator_value}
url = f"{server_url}/session/{session}/element"
- response = await __post(url, payload)
+ response = await _post(url, payload, session_http=session_http)
# Firefox does not support id locator, so it prints the error message to the user
# It helps on debug
if response.get("value").get("error"):
raise WebDriverError(f"Failed to find element. {response}")
- return __helper.get_element(response)
- except Exception as error:
+ return get_element(response)
+ except Exception as e:
raise WebDriverError(
f"Failed to find element by '{locator_type}'-'{locator_value}'."
- ) from error
+ ) from e
-async def get_session(server_url: str, capabilities: Optional[dict] = None) -> str:
+async def get_session(
+ server_url: str,
+ capabilities: Optional[dict] = None,
+ session_http: ClientSession = None,
+) -> str:
"""
Opens a browser and a session.
This session is used for all functions to perform events in the page
@@ -791,9 +917,9 @@ async def get_session(server_url: str, capabilities: Optional[dict] = None) -> s
if not capabilities:
capabilities = {}
url = f"{server_url}/session"
- response = await __post(url, capabilities)
+ response = await _post(url, capabilities, session_http=session_http)
return response.get("sessionId")
- except Exception as error:
+ except Exception as e:
raise WebDriverError(
"Failed to open session. Check the browser capabilities."
- ) from error
+ ) from e
diff --git a/caqui/easy/action_chains.py b/caqui/easy/action_chains.py
index 7a5a33f..e278c5f 100644
--- a/caqui/easy/action_chains.py
+++ b/caqui/easy/action_chains.py
@@ -5,38 +5,40 @@
class ActionChains:
def __init__(self, driver) -> None:
- self.__remote = driver.remote
- self.__session = driver.session
- self.__coroutines: list[Coroutine] = []
+ self._remote = driver.remote
+ self._session = driver.session
+ self._session_http = driver.session_http
+ self._coroutines: list[Coroutine] = []
+ self._element = None
def click(self, element: Element):
"""
Clicks on the element `element`
"""
- self.__element = element
- coroutine = asynchronous.click(self.__remote, self.__session, str(element))
- self.__coroutines.append(coroutine)
+ self._element = element
+ coroutine = asynchronous.click(self._remote, self._session, str(element), session_http=self._session_http)
+ self._coroutines.append(coroutine)
return self
def move_to_element(self, element: Element):
"""Move the mouve to the element `element`"""
- self.__element = element
+ self._element = element
coroutine = asynchronous.actions_move_to_element(
- self.__remote, self.__session, str(element)
+ self._remote, self._session, str(element), session_http=self._session_http
)
- self.__coroutines.append(coroutine)
+ self._coroutines.append(coroutine)
return self
def scroll_to_element(self, element: Element):
"""Scrolls the screen to the element `element`"""
- self.__element = element
+ self._element = element
coroutine = asynchronous.actions_scroll_to_element(
- self.__remote, self.__session, str(element)
+ self._remote, self._session, str(element), session_http=self._session_http
)
- self.__coroutines.append(coroutine)
+ self._coroutines.append(coroutine)
return self
async def perform(self):
"""Executes the chain of Coroutines"""
- [await coroutine for coroutine in self.__coroutines]
+ [await coroutine for coroutine in self._coroutines]
return True
diff --git a/caqui/easy/alert.py b/caqui/easy/alert.py
index 9cafcb0..d1ba6f7 100644
--- a/caqui/easy/alert.py
+++ b/caqui/easy/alert.py
@@ -3,22 +3,23 @@
class Alert:
def __init__(self, driver) -> None:
- self.__remote = driver.remote
- self.__session = driver.session
+ self._remote = driver.remote
+ self._session = driver.session
+ self._session_http = driver.session_http
@property
def text(self):
"""Returns the text of the alert"""
- return synchronous.get_alert_text(self.__remote, self.__session)
+ return synchronous.get_alert_text(self._remote, self._session)
async def accept(self):
"""Accepts the alert"""
- return await asynchronous.accept_alert(self.__remote, self.__session)
+ return await asynchronous.accept_alert(self._remote, self._session, session_http=self._session_http)
async def dismiss(self):
"""Closes the alert ignoring it"""
- return await asynchronous.dismiss_alert(self.__remote, self.__session)
+ return await asynchronous.dismiss_alert(self._remote, self._session, session_http=self._session_http)
async def send_keys(self, text):
"""Send a text to a textbox in the alert"""
- return await asynchronous.send_alert_text(self.__remote, self.__session, text)
+ return await asynchronous.send_alert_text(self._remote, self._session, text, session_http=self._session_http)
diff --git a/caqui/easy/element.py b/caqui/easy/element.py
index f3056f6..6ade2fa 100644
--- a/caqui/easy/element.py
+++ b/caqui/easy/element.py
@@ -4,41 +4,42 @@
class Element:
def __init__(self, element, driver) -> None:
- self.__element = element
- self.__remote = driver.remote
- self.__session = driver.session
- self.__driver = driver
+ self._element = element
+ self._remote = driver.remote
+ self._session = driver.session
+ self._session_http = driver.session_http
+ self._driver = driver
def __str__(self) -> str:
- return self.__element
+ return self._element
@property
def rect(self):
"""Returns the rectangle that enclosed the element
For example: {"height": 23, "width": 183, "x": 10, "y": 9652.12}
"""
- return synchronous.get_rect(self.__remote, self.__session, self.__element)
+ return synchronous.get_rect(self._remote, self._session, self._element)
@property
def tag_name(self):
"""Returns the tag name of the element"""
- return synchronous.get_tag_name(self.__remote, self.__session, self.__element)
+ return synchronous.get_tag_name(self._remote, self._session, self._element)
@property
def text(self):
"""Returns the text of the element"""
- return synchronous.get_text(self.__remote, self.__session, self.__element)
+ return synchronous.get_text(self._remote, self._session, self._element)
@property
def active_element(self):
"""Returns the active element"""
- self.__element = synchronous.get_active_element(self.__driver, self.__session)
- return self.__element
+ self._element = synchronous.get_active_element(self._driver, self._session)
+ return self._element
async def value_of_css_property(self, property_name):
"""Returns the desired CSS property of the element"""
return await asynchronous.get_css_value(
- self.__remote, self.__session, self.__element, property_name
+ self._remote, self._session, self._element, property_name, session_http=self._session_http
)
async def screenshot(self, file):
@@ -48,70 +49,70 @@ async def screenshot(self, file):
path = "./"
file_name = os.path.basename(file)
return await asynchronous.take_screenshot_element(
- self.__remote, self.__session, self.__element, path, file_name
+ self._remote, self._session, self._element, path, file_name, session_http=self._session_http
)
async def is_selected(self) -> bool:
"""Returns True if the element is selected. Otherwise returns False"""
- return await asynchronous.is_element_selected(self.__remote, self.__session, self.__element)
+ return await asynchronous.is_element_selected(self._remote, self._session, self._element, session_http=self._session_http)
async def is_enabled(self):
"""Returns True if the element is enabled. Otherwise returns False"""
- return await asynchronous.is_element_enabled(self.__remote, self.__session, self.__element)
+ return await asynchronous.is_element_enabled(self._remote, self._session, self._element, session_http=self._session_http)
async def get_text(self):
"""Returns the text of the element"""
- return await asynchronous.get_text(self.__remote, self.__session, self.__element)
+ return await asynchronous.get_text(self._remote, self._session, self._element, session_http=self._session_http)
async def get_css_value(self, property_name):
"""Returns the desired CSS property of the element"""
return await asynchronous.get_css_value(
- self.__remote, self.__session, self.__element, property_name
+ self._remote, self._session, self._element, property_name, session_http=self._session_http
)
async def submit(self):
"""Submits a form"""
- return await asynchronous.submit(self.__remote, self.__session, self.__element)
+ return await asynchronous.submit(self._remote, self._session, self._element, session_http=self._session_http)
async def get_rect(self):
"""Returns the rectangle that enclosed the element"""
- return await asynchronous.get_rect(self.__remote, self.__session, self.__element)
+ return await asynchronous.get_rect(self._remote, self._session, self._element, session_http=self._session_http)
async def get_tag_name(self):
"""Returns the element tag name"""
- return await asynchronous.get_tag_name(self.__remote, self.__session, self.__element)
+ return await asynchronous.get_tag_name(self._remote, self._session, self._element, session_http=self._session_http)
async def get_computed_label(self):
"""Get the element tag computed label. Get the accessibility name"""
- return await asynchronous.get_computed_label(self.__remote, self.__session, self.__element)
+ return await asynchronous.get_computed_label(self._remote, self._session, self._element, session_http=self._session_http)
async def get_computed_role(self):
"""Get the element tag computed role (the element role)"""
- return await asynchronous.get_computed_role(self.__remote, self.__session, self.__element)
+ return await asynchronous.get_computed_role(self._remote, self._session, self._element, session_http=self._session_http)
async def get_property(self, property):
"""Get the given HTML property of an element, for example, 'href'"""
return await asynchronous.get_property(
- self.__remote, self.__session, self.__element, property
+ self._remote, self._session, self._element, property, session_http=self._session_http
)
async def get_attribute(self, attribute):
"""Get the given HTML attribute of an element, for example, 'aria-valuenow'"""
return await asynchronous.get_attribute(
- self.__remote, self.__session, self.__element, attribute
+ self._remote, self._session, self._element, attribute, session_http=self._session_http
)
async def clear(self):
"""Clear the element text"""
- return await asynchronous.clear_element(self.__remote, self.__session, self.__element)
+ return await asynchronous.clear_element(self._remote, self._session, self._element, session_http=self._session_http)
async def send_keys(self, text):
"""Fill the element with a text"""
- return await asynchronous.send_keys(self.__remote, self.__session, self.__element, text)
+ return await asynchronous.send_keys(self._remote, self._session, self._element, text, session_http=self._session_http)
async def click(self):
"""Click on the element"""
- return await asynchronous.click(self.__remote, self.__session, self.__element)
+ return await asynchronous.click(self._remote, self._session, self._element, session_http=self._session_http)
async def find_elements(self, locator, value):
"""
@@ -122,15 +123,15 @@ async def find_elements(self, locator, value):
"""
result = []
elements = await asynchronous.find_children_elements(
- self.__remote, self.__session, self.__element, locator, value
+ self._remote, self._session, self._element, locator, value, session_http=self._session_http
)
for element in elements:
- result.append(Element(element, self.__driver))
+ result.append(Element(element, self._driver))
return result
async def find_element(self, locator, value):
"""Find the element by `locator_type`"""
element = await asynchronous.find_child_element(
- self.__remote, self.__session, self.__element, locator, value
+ self._remote, self._session, self._element, locator, value, session_http=self._session_http
)
- return Element(element, self.__driver)
+ return Element(element, self._driver)
diff --git a/caqui/easy/page.py b/caqui/easy/page.py
index bfaadc6..6a877cb 100644
--- a/caqui/easy/page.py
+++ b/caqui/easy/page.py
@@ -1,5 +1,7 @@
import os
from typing import Optional, Union
+
+from aiohttp import ClientSession
from caqui import asynchronous, synchronous
from caqui.easy.action_chains import ActionChains
from caqui.easy.window import Window
@@ -11,41 +13,42 @@
class AsyncPage:
def __init__(
- self, server_url: str, capabilities: Optional[dict] = None, url: Union[str, None] = None
+ self, server_url: str, capabilities: Optional[dict] = None, url: Union[str, None] = None, session_http: ClientSession=None
) -> None:
"""Mimics Selenium methods"""
+ self.session_http = session_http
if not capabilities:
capabilities = {}
if not isinstance(capabilities, dict):
raise CapabilityNotSupported("Expected dictionary")
- self.__server_url = server_url
- self.__session = synchronous.get_session(server_url, capabilities)
+ self._server_url = server_url
+ self._session = synchronous.get_session(server_url, capabilities)
if url:
synchronous.get(
- self.__server_url,
- self.__session,
+ self._server_url,
+ self._session,
url,
)
@property
def remote(self) -> str:
"""Returns the Driver Server URL"""
- return self.__server_url
+ return self._server_url
@property
def session(self) -> str:
"""Returns tne session id"""
- return self.__session
+ return self._session
@property
def title(self):
"""Returns the title of the page"""
- return synchronous.get_title(self.__server_url, self.__session)
+ return synchronous.get_title(self._server_url, self._session)
@property
def current_url(self):
"""Returns the current URL of the page"""
- return synchronous.get_url(self.__server_url, self.__session)
+ return synchronous.get_url(self._server_url, self._session)
@property
def window(self):
@@ -70,45 +73,45 @@ def switch_to(self):
@property
def window_handles(self):
"""Returns the window handles"""
- return synchronous.get_window_handles(self.__server_url, self.__session)
+ return synchronous.get_window_handles(self._server_url, self._session)
@property
def current_window_handle(self):
"""Returns the current window handle"""
- return synchronous.get_window(self.__server_url, self.__session)
+ return synchronous.get_window(self._server_url, self._session)
def quit(self):
"""Closes the session"""
- synchronous.close_session(self.__server_url, self.__session)
+ synchronous.close_session(self._server_url, self._session)
async def close(self):
"""Closes the window"""
- return await asynchronous.close_window(self.__server_url, self.__session)
+ return await asynchronous.close_window(self._server_url, self._session, session_http=self.session_http)
async def execute_script(self, script, args=[]):
- return await asynchronous.execute_script(self.__server_url, self.__session, script, args)
+ return await asynchronous.execute_script(self._server_url, self._session, script, args, session_http=self.session_http)
async def set_window_position(self, x, y):
"""Repositions the page"""
- rect = await asynchronous.get_window_rectangle(self.__server_url, self.__session)
+ rect = await asynchronous.get_window_rectangle(self._server_url, self._session, session_http=self.session_http)
return await asynchronous.set_window_rectangle(
- self.__server_url, self.__session, rect.get("width"), rect.get("height"), x, y
+ self._server_url, self._session, rect.get("width"), rect.get("height"), x, y, session_http=self.session_http
)
async def set_window_size(self, width, height):
"""Resizes the page"""
- rect = await asynchronous.get_window_rectangle(self.__server_url, self.__session)
+ rect = await asynchronous.get_window_rectangle(self._server_url, self._session, session_http=self.session_http)
return await asynchronous.set_window_rectangle(
- self.__server_url, self.__session, width, height, rect.get("x"), rect.get("y")
+ self._server_url, self._session, width, height, rect.get("x"), rect.get("y"), session_http=self.session_http
)
async def get_window_position(self):
"""Returns the window rectangle"""
- return await asynchronous.get_window_rectangle(self.__server_url, self.__session)
+ return await asynchronous.get_window_rectangle(self._server_url, self._session, session_http=self.session_http)
async def get_window_size(self):
"""Returns the window rectangle"""
- return await asynchronous.get_window_rectangle(self.__server_url, self.__session)
+ return await asynchronous.get_window_rectangle(self._server_url, self._session, session_http=self.session_http)
async def save_screenshot(self, file):
"""Takes a scheenshot of the page"""
@@ -117,71 +120,71 @@ async def save_screenshot(self, file):
path = "./"
file_name = os.path.basename(file)
return await asynchronous.take_screenshot(
- self.__server_url, self.__session, path, file_name
+ self._server_url, self._session, path, file_name, session_http=self.session_http
)
async def delete_all_cookies(self):
"""Deletes all storaged cookies"""
- return await asynchronous.delete_all_cookies(self.__server_url, self.__session)
+ return await asynchronous.delete_all_cookies(self._server_url, self._session, session_http=self.session_http)
async def delete_cookie(self, cookie_name):
"""Delete the desired cookie"""
- return await asynchronous.delete_cookie(self.__server_url, self.__session, cookie_name)
+ return await asynchronous.delete_cookie(self._server_url, self._session, cookie_name, session_http=self.session_http)
async def get_cookies(self):
"""Get all cookies"""
- return await asynchronous.get_cookies(self.__server_url, self.__session)
+ return await asynchronous.get_cookies(self._server_url, self._session, session_http=self.session_http)
async def get_cookie(self, cookie_name):
"""Get the desired cookie"""
- return await asynchronous.get_named_cookie(self.__server_url, self.__session, cookie_name)
+ return await asynchronous.get_named_cookie(self._server_url, self._session, cookie_name, session_http=self.session_http)
async def add_cookie(self, cookie):
"""Add a new cookie"""
- return await asynchronous.add_cookie(self.__server_url, self.__session, cookie)
+ return await asynchronous.add_cookie(self._server_url, self._session, cookie, session_http=self.session_http)
async def implicitly_wait(self, timeouts: int):
"""Set implicty timeouts"""
- return await asynchronous.set_timeouts(self.__server_url, self.__session, timeouts)
+ return await asynchronous.set_timeouts(self._server_url, self._session, timeouts, session_http=self.session_http)
async def back(self):
"""This command causes the browser to traverse one step backward
in the joint session history of the
current browse. This is equivalent to pressing the back button in the browser."""
- return await asynchronous.go_back(self.__server_url, self.__session)
+ return await asynchronous.go_back(self._server_url, self._session, session_http=self.session_http)
async def forward(self):
"""Go page forward"""
- return await asynchronous.go_forward(self.__server_url, self.__session)
+ return await asynchronous.go_forward(self._server_url, self._session, session_http=self.session_http)
async def refresh(self):
"""Refreshs the page"""
- return await asynchronous.refresh_page(self.__server_url, self.__session)
+ return await asynchronous.refresh_page(self._server_url, self._session, session_http=self.session_http)
async def fullscreen_window(self):
"""Sets the page in fullscreen"""
- return await asynchronous.fullscreen_window(self.__server_url, self.__session)
+ return await asynchronous.fullscreen_window(self._server_url, self._session, session_http=self.session_http)
async def minimize_window(self):
"""Minimizes the page"""
- return await asynchronous.minimize_window(self.__server_url, self.__session)
+ return await asynchronous.minimize_window(self._server_url, self._session, session_http=self.session_http)
async def maximize_window(self):
"""Maximizes the page"""
- return await asynchronous.maximize_window(self.__server_url, self.__session)
+ return await asynchronous.maximize_window(self._server_url, self._session, session_http=self.session_http)
async def get(self, url):
"""Navigates to URL `url`"""
await asynchronous.go_to_page(
- self.__server_url,
- self.__session,
- url,
+ self._server_url,
+ self._session,
+ url,session_http=self.session_http
)
async def find_elements(self, locator, value):
"""Search the DOM elements by 'locator', for example, 'xpath'"""
elements = await asynchronous.find_elements(
- self.__server_url, self.__session, locator, value
+ self._server_url, self._session, locator, value, session_http=self.session_http
)
result = []
for element in elements:
@@ -190,5 +193,5 @@ async def find_elements(self, locator, value):
async def find_element(self, locator, value):
"""Find an element by a 'locator', for example 'xpath'"""
- element = await asynchronous.find_element(self.__server_url, self.__session, locator, value)
+ element = await asynchronous.find_element(self._server_url, self._session, locator, value, session_http=self.session_http)
return Element(element, self)
diff --git a/caqui/easy/switch_to.py b/caqui/easy/switch_to.py
index 81eaa9a..afb539a 100644
--- a/caqui/easy/switch_to.py
+++ b/caqui/easy/switch_to.py
@@ -5,47 +5,48 @@
class SwitchTo:
def __init__(self, driver) -> None:
- self.__driver = driver
- self.__iframe = None
- self.__window_handle = None
+ self._driver = driver
+ self._iframe = None
+ self._window_handle = None
+ self._session_http = driver.session_http
@property
def active_element(self):
"""Returns the active element"""
- element = synchronous.get_active_element(self.__driver.remote, self.__driver.session)
- return Element(element, self.__driver)
+ element = synchronous.get_active_element(self._driver.remote, self._driver.session)
+ return Element(element, self._driver)
@property
def alert(self):
"""Returns the `Alert` object"""
- return Alert(self.__driver)
+ return Alert(self._driver)
async def new_window(self, window_type):
"""Opens a new window"""
- self.__window_handle = await asynchronous.new_window(
- self.__driver.remote, self.__driver.session, window_type
+ self._window_handle = await asynchronous.new_window(
+ self._driver.remote, self._driver.session, window_type, session_http=self._session_http
)
- self.__window_handle = await asynchronous.switch_to_window(
- self.__driver.remote, self.__driver.session, self.__window_handle
+ self._window_handle = await asynchronous.switch_to_window(
+ self._driver.remote, self._driver.session, self._window_handle, session_http=self._session_http
)
- return self.__window_handle
+ return self._window_handle
async def window(self, window_handle):
"""Switchs to window `window_handle`"""
- self.__window_handle = await asynchronous.switch_to_window(
- self.__driver.remote, self.__driver.session, window_handle
+ self._window_handle = await asynchronous.switch_to_window(
+ self._driver.remote, self._driver.session, window_handle, session_http=self._session_http
)
- return self.__window_handle
+ return self._window_handle
async def frame(self, iframe):
"""Switches to frame `iframe`"""
- self.__iframe = str(iframe)
+ self._iframe = str(iframe)
return await asynchronous.switch_to_frame(
- self.__driver.remote, self.__driver.session, self.__iframe
+ self._driver.remote, self._driver.session, self._iframe, session_http=self._session_http
)
async def default_content(self):
"""Switches to parent frame of 'element_frame'"""
return await asynchronous.switch_to_parent_frame(
- self.__driver.remote, self.__driver.session, self.__iframe
+ self._driver.remote, self._driver.session, self._iframe, session_http=self._session_http
)
diff --git a/tests/conftest.py b/tests/conftest.py
index 61e1444..f4830e8 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,3 +1,4 @@
+from aiohttp import ClientSession
from pytest import fixture
from tests.constants import PAGE_URL
from caqui.easy import AsyncPage
@@ -5,6 +6,7 @@
from caqui.easy.options import ChromeOptionsBuilder
from caqui.easy.server import Server
from caqui import synchronous
+import pytest_asyncio
SERVER_PORT = 9999
SERVER_URL = f"http://localhost:{SERVER_PORT}"
@@ -48,16 +50,16 @@ def setup_functional_environment():
finally:
synchronous.close_session(server_url, session)
-
-@fixture
-def setup_environment():
+@pytest_asyncio.fixture
+async def setup_environment():
server_url = SERVER_URL
capabilities = __build_capabilities()
- page = AsyncPage(server_url, capabilities, PAGE_URL)
- yield page
- try:
- synchronous.dismiss_alert(server_url, page.session)
- except Exception:
- pass
- finally:
- page.quit()
+ async with ClientSession() as session_http:
+ page = AsyncPage(server_url, capabilities, PAGE_URL, session_http=session_http)
+ yield page
+ try:
+ synchronous.dismiss_alert(server_url, page.session)
+ except Exception:
+ pass
+ finally:
+ page.quit()
diff --git a/tests/feature/test_async_with_http_session.py b/tests/feature/test_async_with_http_session.py
new file mode 100644
index 0000000..d35c5fc
--- /dev/null
+++ b/tests/feature/test_async_with_http_session.py
@@ -0,0 +1,1245 @@
+from aiohttp import ClientSession
+from pytest import mark, raises
+from caqui import asynchronous, synchronous
+from caqui.exceptions import WebDriverError
+from caqui.by import By
+from tests.constants import COOKIE
+from caqui.easy import AsyncPage
+from tests.constants import PAGE_URL
+from pytest import mark
+from tests.constants import COOKIE
+
+
+@mark.asyncio
+async def test_big_scenario_of_functions_with_session_http(setup_environment: AsyncPage):
+ page = setup_environment
+ await page.implicitly_wait(10)
+
+ # Need to navigate to a web page. If use 'playgound.html' the error
+ # 'Document is cookie-averse' happens
+ await page.get(
+ "https://example.org/",
+ )
+ cookies = COOKIE
+ await page.add_cookie(cookies)
+ cookie = (await page.get_cookies())[0]
+ cookie["name"] = "other"
+ await page.add_cookie(cookie)
+ await page.delete_cookie("other")
+ await page.delete_all_cookies()
+ await page.get(
+ PAGE_URL,
+ )
+
+ await page.switch_to.active_element.get_attribute("value")
+ element = await page.find_element(By.XPATH, "//a")
+ # Returns and base64 encoded string into image
+ await element.screenshot("/tmp/image.png")
+
+ await page.back()
+ await page.forward()
+ await page.refresh()
+
+ alert_element = await page.find_element(By.CSS_SELECTOR, "#alert-button-prompt")
+ await alert_element.click()
+ alert_object = page.switch_to.alert
+ await page.alert.accept()
+
+ await alert_element.click()
+ await alert_object.send_keys("Caqui")
+ await alert_object.dismiss()
+
+ iframe = await page.find_element(By.ID, "my-iframe")
+ # switch to selected iframe
+ await page.switch_to.frame(iframe)
+ await page.switch_to.default_content()
+ # switching to second iframe based on index
+ iframe = (await page.find_elements(By.ID, "my-iframe"))[0]
+
+ # switch to selected iframe
+ await page.switch_to.frame(iframe)
+ # switch back to default content
+ await page.switch_to.default_content()
+
+ window_handle = page.current_window_handle
+ assert len(page.window_handles) >= 1
+ await page.switch_to.window(window_handle)
+ # Opens a new tab and switches to new tab
+ await page.switch_to.new_window("tab")
+ # Opens a new window and switches to new window
+ await page.switch_to.new_window("window")
+
+ # Access each dimension individually
+ await page.set_window_size(1024, 768)
+ # Move the window to the top left of the primary monitor
+ await page.set_window_position(0, 0)
+ await page.maximize_window()
+ # await driver.minimize_window() # does not work on headless mode
+ await page.save_screenshot("/tmp/image.png")
+
+ # Executing JavaScript to capture innerText of header element
+ await page.execute_script('alert("any warn")')
+
+
+
+@mark.asyncio
+async def test_add_cookie(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ # Need to navigate to a web page. If use 'playgound.html' the error
+ # 'Document is cookie-averse' happens
+ synchronous.go_to_page(
+ server_url,
+ session,
+ "https://example.org/",
+ )
+ cookie = COOKIE
+ assert synchronous.add_cookie(server_url, session, cookie) is True
+ cookies_after = synchronous.get_cookies(server_url, session)
+ assert len(cookies_after) > 0
+
+ cookies_before = cookies_after
+ cookie = cookies_before[0]
+ cookie[By.NAME] = "another"
+
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.add_cookie(
+ server_url, session, cookie, session_http=session_http
+ )
+ is True
+ )
+ cookies_after = synchronous.get_cookies(server_url, session)
+ assert len(cookies_after) > len(cookies_before)
+
+
+@mark.skip(reason="works just in firefox")
+@mark.asyncio
+async def test_delete_cookie_asynchronous(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ cookies = synchronous.get_cookies(server_url, session)
+ name = cookies[0].get(By.NAME)
+ zero = 0
+
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.delete_cookie(
+ server_url, session, name, session_http=session_http
+ )
+ is True
+ )
+ cookies = synchronous.get_cookies(server_url, session)
+ assert len(cookies) == zero
+
+
+@mark.skip(reason="works just in firefox")
+@mark.asyncio
+def test_delete_cookie_synchronous(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ cookies = synchronous.get_cookies(server_url, session)
+ name = cookies[0].get(By.NAME)
+ zero = 0
+
+ assert synchronous.delete_cookie(server_url, session, name) is True
+ cookies = synchronous.get_cookies(server_url, session)
+ assert len(cookies) == zero
+
+
+@mark.asyncio
+async def test_refresh_page(setup_functional_environment):
+ server_url, session = setup_functional_environment
+
+ element_before = synchronous.find_element(server_url, session, By.XPATH, "//input")
+ assert (
+ synchronous.refresh_page(
+ server_url,
+ session,
+ )
+ is True
+ )
+
+ element_after = synchronous.find_element(server_url, session, By.XPATH, "//input")
+ assert element_before != element_after
+
+ element_before = element_after
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.refresh_page(
+ server_url, session, session_http=session_http
+ )
+ is True
+ )
+
+ element_after = synchronous.find_element(server_url, session, By.XPATH, "//input")
+ assert element_before != element_after
+
+
+@mark.asyncio
+async def test_go_forward(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ title = "Sample page"
+
+ synchronous.go_back(server_url, session)
+ assert (
+ synchronous.go_forward(
+ server_url,
+ session,
+ )
+ is True
+ )
+ assert synchronous.get_title(server_url, session) == title
+
+ synchronous.go_back(server_url, session)
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.go_forward(
+ server_url, session, session_http=session_http
+ )
+ is True
+ )
+ assert synchronous.get_title(server_url, session) == title
+
+
+@mark.asyncio
+async def test_set_window_rectangle(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ width = 500
+ height = 300
+ window_rectangle_before = synchronous.get_window_rectangle(server_url, session)
+ x = window_rectangle_before.get("x") + 1
+ y = window_rectangle_before.get("y") + 1
+
+ assert (
+ synchronous.set_window_rectangle(server_url, session, width, height, x, y)
+ is True
+ )
+
+ window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
+ assert window_rectangle_after != window_rectangle_before
+ assert window_rectangle_after.get("height") != window_rectangle_before.get("height")
+ assert window_rectangle_after.get("width") != window_rectangle_before.get("width")
+ assert window_rectangle_after.get("x") != window_rectangle_before.get("x")
+ assert window_rectangle_after.get("y") != window_rectangle_before.get("y")
+
+ synchronous.maximize_window(server_url, session)
+
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.set_window_rectangle(
+ server_url, session, width, height, x, y, session_http=session_http
+ )
+ is True
+ )
+
+ window_rectangle_after = None
+ window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
+ assert window_rectangle_after != window_rectangle_before
+ assert window_rectangle_after.get("height") != window_rectangle_before.get("height")
+ assert window_rectangle_after.get("width") != window_rectangle_before.get("width")
+ assert window_rectangle_after.get("x") != window_rectangle_before.get("x")
+ assert window_rectangle_after.get("y") != window_rectangle_before.get("y")
+
+
+@mark.skip(reason="does not work in headless mode")
+@mark.asyncio
+async def test_fullscreen_window(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ window_rectangle_before = synchronous.get_window_rectangle(server_url, session)
+
+ assert synchronous.fullscreen_window(server_url, session) is True
+
+ window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
+ assert window_rectangle_after != window_rectangle_before
+ assert window_rectangle_after.get("height") > window_rectangle_before.get("height")
+ assert window_rectangle_after.get("width") > window_rectangle_before.get("width")
+
+ synchronous.maximize_window(server_url, session)
+
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.fullscreen_window(
+ server_url, session, session_http=session_http
+ )
+ is True
+ )
+
+ window_rectangle_after = None
+ window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
+ assert window_rectangle_after != window_rectangle_before
+ assert window_rectangle_after.get("height") > window_rectangle_before.get("height")
+ assert window_rectangle_after.get("width") > window_rectangle_before.get("width")
+
+
+@mark.skip(reason="does not work in headless mode")
+@mark.asyncio
+async def test_minimize_window(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ window_rectangle_before = synchronous.get_window_rectangle(server_url, session)
+
+ assert synchronous.minimize_window(server_url, session) is True
+
+ window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
+ assert window_rectangle_after != window_rectangle_before
+ assert window_rectangle_after.get("height") < window_rectangle_before.get("height")
+ assert window_rectangle_after.get("width") < window_rectangle_before.get("width")
+
+ synchronous.maximize_window(server_url, session)
+
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.minimize_window(
+ server_url, session, session_http=session_http
+ )
+ is True
+ )
+
+ window_rectangle_after = None
+ window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
+ assert window_rectangle_after != window_rectangle_before
+ assert window_rectangle_after.get("height") < window_rectangle_before.get("height")
+ assert window_rectangle_after.get("width") < window_rectangle_before.get("width")
+
+
+@mark.skip(reason="does not work in headless mode")
+@mark.asyncio
+async def test_maximize_window_asynchronous(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ window_rectangle_before = synchronous.get_window_rectangle(server_url, session)
+
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.maximize_window(
+ server_url, session, session_http=session_http
+ )
+ is True
+ )
+
+ window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
+ assert window_rectangle_after != window_rectangle_before
+ assert window_rectangle_after.get("height") > window_rectangle_before.get("height")
+ assert window_rectangle_after.get("width") > window_rectangle_before.get("width")
+
+
+@mark.skip(reason="does not work in headless mode")
+@mark.asyncio
+def test_maximize_window_synchronous(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ window_rectangle_before = synchronous.get_window_rectangle(server_url, session)
+
+ assert synchronous.maximize_window(server_url, session) is True
+
+ window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
+ assert window_rectangle_after != window_rectangle_before
+ assert window_rectangle_after.get("height") > window_rectangle_before.get("height")
+ assert window_rectangle_after.get("width") > window_rectangle_before.get("width")
+
+
+@mark.parametrize("window_type", ("tab", "window"))
+@mark.asyncio
+async def test_switch_to_window(setup_functional_environment, window_type):
+ server_url, session = setup_functional_environment
+
+ synchronous.new_window(server_url, session, window_type)
+ handles = synchronous.get_window_handles(server_url, session)
+ sample_page = handles[0]
+ new_page = handles[1]
+
+ assert synchronous.switch_to_window(server_url, session, handle=new_page) is True
+ assert synchronous.get_title(server_url, session) == ""
+ synchronous.switch_to_window(server_url, session, handle=sample_page) is True
+
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.switch_to_window(
+ server_url, session, handle=new_page, session_http=session_http
+ )
+ is True
+ )
+ assert synchronous.get_title(server_url, session) == ""
+
+
+@mark.parametrize("window_type", ("tab", "window"))
+@mark.asyncio
+async def test_new_window(setup_functional_environment, window_type):
+ server_url, session = setup_functional_environment
+
+ assert synchronous.new_window(server_url, session, window_type) is not None
+ import time
+
+ time.sleep(3)
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.new_window(
+ server_url, session, window_type, session_http=session_http
+ )
+ is not None
+ )
+
+
+@mark.asyncio
+async def test_switch_to_parent_frame_asynchronous(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.ID
+ locator_value = "my-iframe"
+
+ element_frame = synchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.switch_to_parent_frame(
+ server_url, session, element_frame, session_http=session_http
+ )
+ is True
+ )
+
+
+def test_switch_to_parent_frame_synchronous(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.ID
+ locator_value = "my-iframe"
+
+ element_frame = synchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
+ assert (
+ synchronous.switch_to_parent_frame(server_url, session, element_frame) is True
+ )
+
+
+@mark.asyncio
+async def test_switch_to_frame_asynchronous(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.ID
+ locator_value = "my-iframe"
+
+ element_frame = synchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.switch_to_frame(server_url, session, element_frame, session_http=session_http) is True
+ )
+
+
+def test_switch_to_frame_synchronous(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.ID
+ locator_value = "my-iframe"
+
+ element_frame = synchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
+ assert synchronous.switch_to_frame(server_url, session, element_frame) is True
+
+
+@mark.asyncio
+async def test_send_alert_text(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.CSS_SELECTOR
+ locator_value = "#alert-button-prompt"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ synchronous.click(server_url, session, element)
+
+ assert synchronous.send_alert_text(server_url, session, text="any1") is True
+ synchronous.accept_alert(server_url, session) is True
+
+ synchronous.click(server_url, session, element)
+ async with ClientSession() as session_http:
+ assert await asynchronous.send_alert_text(server_url, session, "any2", session_http=session_http) is True
+ synchronous.accept_alert(server_url, session) is True
+
+
+@mark.asyncio
+async def test_accept_alert(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.CSS_SELECTOR
+ locator_value = "#alert-button"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ synchronous.click(server_url, session, element)
+
+ assert synchronous.accept_alert(server_url, session) is True
+
+ synchronous.click(server_url, session, element)
+ async with ClientSession() as session_http:
+ assert await asynchronous.accept_alert(server_url, session, session_http=session_http) is True
+
+
+@mark.asyncio
+async def test_dismiss_alert(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.CSS_SELECTOR
+ locator_value = "#alert-button"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ synchronous.click(server_url, session, element)
+
+ assert synchronous.dismiss_alert(server_url, session) is True
+
+ synchronous.click(server_url, session, element)
+ async with ClientSession() as session_http:
+ assert await asynchronous.dismiss_alert(server_url, session, session_http=session_http) is True
+
+
+@mark.asyncio
+async def test_take_screenshot_element(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.CSS_SELECTOR
+ locator_value = "#alert-button"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ assert synchronous.take_screenshot_element(server_url, session, element) is True
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.take_screenshot_element(
+ server_url, session, element, session_http=session_http
+ )
+ is True
+ )
+
+
+@mark.asyncio
+async def test_take_screenshot(setup_functional_environment):
+ server_url, session = setup_functional_environment
+
+ assert synchronous.take_screenshot(server_url, session) is True
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.take_screenshot(
+ server_url, session, session_http=session_http
+ )
+ is True
+ )
+
+
+@mark.skip(reason="works just in firefox")
+@mark.asyncio
+async def test_delete_cookies_asynchronous(setup_functional_environment):
+ server_url, session = setup_functional_environment
+
+ cookies_before = synchronous.get_cookies(server_url, session)
+
+ async with ClientSession() as session_http:
+ response = await asynchronous.delete_all_cookies(server_url, session, session_http=session_http)
+ assert response is True
+
+ cookies_after = synchronous.get_cookies(server_url, session)
+ assert len(cookies_before) != len(cookies_after)
+
+
+@mark.skip(reason="works just in firefox")
+@mark.asyncio
+async def test_delete_cookies_synchronous(setup_functional_environment):
+ server_url, session = setup_functional_environment
+
+ cookies_before = synchronous.get_cookies(server_url, session)
+
+ assert synchronous.delete_all_cookies(server_url, session) is True
+
+ cookies_after = synchronous.get_cookies(server_url, session)
+ assert len(cookies_before) != len(cookies_after)
+
+
+@mark.skip(reason="works just with Firefox")
+@mark.asyncio
+async def test_get_named_cookie(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ name = "username" # cookie created on page load
+ expected = "John Doe"
+
+ assert (
+ synchronous.get_named_cookie(server_url, session, name).get("value") == expected
+ )
+ async with ClientSession() as session_http:
+ response = await asynchronous.get_named_cookie(server_url, session, name, session_http=session_http)
+ assert response.get("value") == expected
+
+
+@mark.asyncio
+async def test_get_computed_label(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.CSS_SELECTOR
+ locator_value = "#alert-button"
+ expected = "alert"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ assert synchronous.get_computed_label(server_url, session, element) == expected
+
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.get_computed_label(server_url, session, element, session_http=session_http) == expected
+ )
+
+
+@mark.asyncio
+async def test_get_computed_role(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//input"
+ expected = "textbox"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ assert synchronous.get_computed_role(server_url, session, element) == expected
+
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.get_computed_role(server_url, session, element, session_http=session_http) == expected
+ )
+
+
+@mark.asyncio
+async def test_get_tag_name(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//input"
+ expected = "input"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ assert synchronous.get_tag_name(server_url, session, element) == expected
+ async with ClientSession() as session_http:
+ assert await asynchronous.get_tag_name(server_url, session, element, session_http=session_http) == expected
+
+
+@mark.parametrize(
+ "locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")]
+)
+@mark.asyncio
+async def test_find_element_from_shadow_root(
+ setup_functional_environment, locator, value
+):
+ server_url, session = setup_functional_environment
+ locator_type = By.ID
+ locator_value = "shadow-root"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ shadow_root = synchronous.get_shadow_root(server_url, session, element)
+
+ actual = synchronous.find_child_element(
+ server_url, session, shadow_root, locator, value
+ )
+
+ assert actual is not None
+ async with ClientSession() as session_http:
+ actual = await asynchronous.find_child_element(
+ server_url, session, shadow_root, locator, value, session_http=session_http
+ )
+
+ assert actual is not None
+
+
+@mark.parametrize(
+ "locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")]
+)
+@mark.asyncio
+async def test_find_elements_from_shadow_root(
+ setup_functional_environment, locator, value
+):
+ server_url, session = setup_functional_environment
+ locator_type = By.ID
+ locator_value = "shadow-root"
+ one = 1
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ shadow_root = synchronous.get_shadow_root(server_url, session, element)
+
+ actual = synchronous.find_children_elements(
+ server_url, session, shadow_root, locator, value
+ )
+
+ assert len(actual) == one
+
+ async with ClientSession() as session_http:
+ actual = await asynchronous.find_children_elements(
+ server_url, session, shadow_root, locator, value, session_http=session_http
+ )
+
+ assert len(actual) == one
+
+
+@mark.asyncio
+async def test_get_shadow_root(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.ID
+ locator_value = "shadow-root"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ assert synchronous.get_shadow_root(server_url, session, element) is not None
+
+ async with ClientSession() as session_http:
+ response = await asynchronous.get_shadow_root(server_url, session, element, session_http=session_http)
+ assert response is not None
+
+
+@mark.asyncio
+async def test_get_rect(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//input"
+ expected = {"height": 21, "width": 185, "x": 8, "y": 100.4375}
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ assert synchronous.get_rect(server_url, session, element) == expected
+ async with ClientSession() as session_http:
+ assert await asynchronous.get_rect(server_url, session, element, session_http=session_http) == expected
+
+
+@mark.asyncio
+async def test_move_to_element(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//button"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ assert synchronous.actions_move_to_element(server_url, session, element) is True
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.actions_move_to_element(server_url, session, element, session_http=session_http) is True
+ )
+
+
+@mark.asyncio
+async def test_actions_scroll_to_element(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//button"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ assert synchronous.actions_scroll_to_element(server_url, session, element) is True
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.actions_scroll_to_element(server_url, session, element, session_http=session_http)
+ is True
+ )
+
+
+@mark.asyncio
+async def test_submit(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.NAME
+ locator_value = "my-form"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ assert synchronous.submit(server_url, session, element) is True
+
+ synchronous.refresh_page(server_url, session)
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ async with ClientSession() as session_http:
+ assert await asynchronous.submit(server_url, session, element, session_http=session_http) is True
+
+
+@mark.asyncio
+async def test_actions_click(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//button"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ assert synchronous.actions_click(server_url, session, element) is True
+ async with ClientSession() as session_http:
+ assert await asynchronous.actions_click(server_url, session, element,session_http=session_http) is True
+
+
+@mark.asyncio
+async def test_raise_exception_when_element_not_found(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//invalid-tag"
+
+ with raises(WebDriverError):
+ synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ with raises(WebDriverError):
+ async with ClientSession() as session_http:
+ await asynchronous.find_element(
+ server_url, session, locator_type, locator_value, session_http=session_http
+ )
+
+
+@mark.asyncio
+async def test_set_timeouts(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ timeouts_1 = 5000 # milliseconds
+ timeouts_2 = 3000 # milliseconds
+
+ synchronous.set_timeouts(server_url, session, timeouts_1)
+
+ assert synchronous.get_timeouts(server_url, session).get("implicit") == timeouts_1
+ async with ClientSession() as session_http:
+ await asynchronous.set_timeouts(server_url, session, timeouts_2, session_http=session_http)
+
+ assert synchronous.get_timeouts(server_url, session).get("implicit") == timeouts_2
+
+
+@mark.asyncio
+async def test_find_children_elements(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ expected = 1 # parent inclusive
+ locator_type = By.XPATH
+ locator_value = "//div"
+
+ parent_element = synchronous.find_element(
+ server_url, session, locator_type, '//div[@class="parent"]'
+ )
+
+ children_elements = synchronous.find_children_elements(
+ server_url, session, parent_element, locator_type, locator_value
+ )
+
+ assert len(children_elements) > expected
+ async with ClientSession() as session_http:
+ children_elements = await asynchronous.find_children_elements(
+ server_url, session, parent_element, locator_type, locator_value, session_http=session_http
+ )
+
+ assert len(children_elements) > expected
+
+
+@mark.asyncio
+async def test_find_child_element(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ expected = "any4"
+ locator_type = By.XPATH
+ locator_value = '//div[@class="child4"]'
+
+ parent_element = synchronous.find_element(
+ server_url, session, locator_type, '//div[@class="parent"]'
+ )
+
+ child_element = synchronous.find_child_element(
+ server_url, session, parent_element, locator_type, locator_value
+ )
+
+ text = synchronous.get_text(server_url, session, child_element)
+
+ assert text == expected
+ async with ClientSession() as session_http:
+ child_element = await asynchronous.find_child_element(
+ server_url, session, parent_element, locator_type, locator_value, session_http=session_http
+ )
+ text = synchronous.get_text(server_url, session, child_element)
+ assert text == expected
+
+
+@mark.asyncio
+async def test_get_page_source(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ expected = "Sample page"
+
+ assert expected in synchronous.get_page_source(server_url, session)
+ async with ClientSession() as session_http:
+ assert expected in await asynchronous.get_page_source(server_url, session, session_http=session_http)
+
+
+@mark.asyncio
+async def test_execute_script_asynchronous(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ script = "alert('any warn')"
+ async with ClientSession() as session_http:
+ assert await asynchronous.execute_script(server_url, session, script, session_http=session_http) is None
+
+
+def test_execute_script_synchronous(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ script = "alert('any warn')"
+ assert synchronous.execute_script(server_url, session, script) is None
+
+
+@mark.asyncio
+async def test_get_alert_text(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.CSS_SELECTOR
+ locator_value = "#alert-button"
+ expected = "any warn"
+
+ alert_button = synchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
+ synchronous.click(server_url, session, alert_button)
+
+ assert synchronous.get_alert_text(server_url, session) == expected
+ async with ClientSession() as session_http:
+ assert await asynchronous.get_alert_text(server_url, session, session_http=session_http) == expected
+
+
+@mark.asyncio
+async def test_get_active_element(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//input"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ synchronous.send_keys(server_url, session, element, "any")
+
+ assert synchronous.get_active_element(server_url, session) == element
+ async with ClientSession() as session_http:
+ assert await asynchronous.get_active_element(server_url, session, session_http=session_http) == element
+
+
+@mark.asyncio
+async def test_clear_element_fails_when_invalid_inputs(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ element = "invalid"
+
+ with raises(WebDriverError):
+ synchronous.clear_element(server_url, session, element) is True
+
+ with raises(WebDriverError):
+ async with ClientSession() as session_http:
+ await asynchronous.clear_element(server_url, session, element, session_http=session_http)
+
+
+@mark.asyncio
+async def test_clear_element(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//input"
+ text = "any"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ synchronous.send_keys(server_url, session, element, text)
+ assert synchronous.clear_element(server_url, session, element) is True
+
+ synchronous.send_keys(server_url, session, element, text)
+ async with ClientSession() as session_http:
+ assert await asynchronous.clear_element(server_url, session, element, session_http=session_http) is True
+
+
+@mark.asyncio
+async def test_is_element_enabled(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//input"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ assert synchronous.is_element_enabled(server_url, session, element) is True
+ async with ClientSession() as session_http:
+ assert await asynchronous.is_element_enabled(server_url, session, element, session_http=session_http) is True
+
+
+@mark.asyncio
+async def test_get_css_value(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//input"
+ property_name = "color"
+ expected = "rgba(0, 0, 0, 1)"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ assert (
+ synchronous.get_css_value(server_url, session, element, property_name)
+ == expected
+ )
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.get_css_value(server_url, session, element, property_name, session_http=session_http)
+ == expected
+ )
+
+
+@mark.asyncio
+async def test_is_element_selected(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//input"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ assert synchronous.is_element_selected(server_url, session, element) is False
+ async with ClientSession() as session_http:
+ assert await asynchronous.is_element_selected(server_url, session, element, session_http=session_http) is False
+
+
+
+@mark.asyncio
+async def test_get_window_rectangle(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ expected = "height"
+
+ assert expected in synchronous.get_window_rectangle(server_url, session)
+ async with ClientSession() as session_http:
+ rectangle = await asynchronous.get_window_rectangle(server_url, session, session_http=session_http)
+ assert expected in rectangle
+
+
+@mark.asyncio
+async def test_get_window_handles(setup_functional_environment):
+ server_url, session = setup_functional_environment
+
+ assert isinstance(synchronous.get_window_handles(server_url, session), list)
+ async with ClientSession() as session_http:
+ handles = await asynchronous.get_window_handles(server_url, session, session_http=session_http)
+ assert isinstance(handles, list)
+
+
+def test_close_window_sync(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ assert isinstance(synchronous.close_window(server_url, session), list)
+
+
+@mark.asyncio
+async def test_close_window_async(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ async with ClientSession() as session_http:
+ response = await asynchronous.close_window(server_url, session, session_http=session_http)
+ assert isinstance(response, list)
+
+
+@mark.asyncio
+async def test_get_window(setup_functional_environment):
+ server_url, session = setup_functional_environment
+
+ assert synchronous.get_window(server_url, session) is not None
+ async with ClientSession() as session_http:
+ assert await asynchronous.get_window(server_url, session, session_http=session_http) is not None
+
+
+@mark.asyncio
+async def test_get_attribute_fails_when_invalid_attribute(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ attribute = "href"
+ element = "invalid"
+
+ with raises(WebDriverError):
+ synchronous.get_attribute(server_url, session, element, attribute)
+
+ with raises(WebDriverError):
+ async with ClientSession() as session_http:
+ await asynchronous.get_attribute(server_url, session, element, attribute, session_http=session_http)
+
+
+@mark.asyncio
+async def test_get_attribute(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ attribute = "href"
+ element = synchronous.find_element(server_url, session, By.XPATH, "//a[@id='a1']")
+
+ assert (
+ synchronous.get_attribute(server_url, session, element, attribute)
+ == "http://any1.com/"
+ )
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.get_attribute(server_url, session, element, attribute, session_http=session_http)
+ == "http://any1.com/"
+ )
+
+
+@mark.asyncio
+async def test_get_cookies(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ assert isinstance(synchronous.get_cookies(server_url, session), list)
+ async with ClientSession() as session_http:
+ cookies = await asynchronous.get_cookies(server_url, session, session_http=session_http)
+ assert isinstance(cookies, list)
+
+
+@mark.asyncio
+async def test_go_back(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ title = ""
+
+ assert synchronous.go_back(server_url, session) is True
+ assert synchronous.get_title(server_url, session) == title
+
+ synchronous.go_forward(server_url, session)
+ async with ClientSession() as session_http:
+ assert await asynchronous.go_back(server_url, session, session_http=session_http) is True
+ assert synchronous.get_title(server_url, session) == title
+
+
+@mark.asyncio
+async def test_get_url(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ expected = "playground.html"
+
+ assert expected in synchronous.get_url(server_url, session)
+ async with ClientSession() as session_http:
+ assert expected in await asynchronous.get_url(server_url, session, session_http=session_http)
+
+
+@mark.asyncio
+async def test_get_timeouts(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ expected = "implicit"
+
+ assert expected in synchronous.get_timeouts(server_url, session)
+ async with ClientSession() as session_http:
+ assert expected in await asynchronous.get_timeouts(server_url, session, session_http=session_http)
+
+
+@mark.asyncio
+async def test_get_status(setup_functional_environment):
+ server_url, _ = setup_functional_environment
+ expected = "ready"
+ assert expected in synchronous.get_status(server_url).get("value")
+ async with ClientSession() as session_http:
+ response = await asynchronous.get_status(server_url, session_http=session_http)
+ assert expected in response.get("value")
+
+
+@mark.asyncio
+async def test_get_title(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ expected = "Sample page"
+
+ assert synchronous.get_title(server_url, session) == expected
+ async with ClientSession() as session_http:
+ assert await asynchronous.get_title(server_url, session, session_http=session_http) == expected
+
+
+@mark.asyncio
+async def test_find_elements_fails_when_invalid_data_input(
+ setup_functional_environment,
+):
+ server_url, session = setup_functional_environment
+ locator_type = "invalid"
+ locator_value = "//input"
+
+ with raises(WebDriverError):
+ synchronous.find_elements(server_url, session, locator_type, locator_value)
+
+ with raises(WebDriverError):
+ async with ClientSession() as session_http:
+ await asynchronous.find_elements(
+ server_url, session, locator_type, locator_value, session_http=session_http
+ )
+
+
+@mark.asyncio
+async def test_find_elements(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//input"
+
+ elements = synchronous.find_elements(
+ server_url, session, locator_type, locator_value
+ )
+ async with ClientSession() as session_http:
+ async_elements = await asynchronous.find_elements(
+ server_url, session, locator_type, locator_value, session_http=session_http
+ )
+
+ assert len(elements) > 0
+ assert len(async_elements) > 0
+
+
+@mark.asyncio
+async def test_find_element_fails_when_invalid_data_input(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = "invalid"
+ locator_value = "//input"
+
+ with raises(WebDriverError):
+ synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ with raises(WebDriverError):
+ async with ClientSession() as session_http:
+ await asynchronous.find_element(
+ server_url, session, locator_type, locator_value, session_http=session_http
+ )
+
+
+@mark.asyncio
+async def test_find_element(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//input"
+
+ assert (
+ synchronous.find_element(server_url, session, locator_type, locator_value)
+ is not None
+ )
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.find_element(
+ server_url, session, locator_type, locator_value, session_http=session_http
+ )
+ is not None
+ )
+
+
+@mark.asyncio
+async def test_get_property(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ text = "any_value"
+ locator_type = By.XPATH
+ locator_value = "//input"
+ property = "value"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ synchronous.send_keys(server_url, session, element, text)
+
+ assert synchronous.get_property(server_url, session, element, property) == text
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.get_property(
+ server_url, session, element, property, session_http=session_http
+ )
+ == text
+ )
+
+
+@mark.asyncio
+async def test_get_text(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ expected = "end"
+ locator_type = By.XPATH
+ locator_value = "//p[@id='end']" #
end
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.get_text(
+ server_url, session, element, session_http=session_http
+ )
+ == expected
+ )
+ assert synchronous.get_text(server_url, session, element) == expected
+
+
+@mark.asyncio
+async def test_send_keys(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ text_async = "any_async"
+ text_sync = "any_sync"
+ locator_type = By.XPATH
+ locator_value = "//input"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.send_keys(
+ server_url, session, element, text_async, session_http=session_http
+ )
+ is True
+ )
+ assert synchronous.send_keys(server_url, session, element, text_sync) is True
+
+
+@mark.asyncio
+async def test_click(setup_functional_environment):
+ server_url, session = setup_functional_environment
+ locator_type = By.XPATH
+ locator_value = "//button"
+
+ element = synchronous.find_element(server_url, session, locator_type, locator_value)
+ async with ClientSession() as session_http:
+ assert (
+ await asynchronous.click(
+ server_url, session, element, session_http=session_http
+ )
+ is True
+ )
+ assert synchronous.click(server_url, session, element) is True
diff --git a/tests/feature/test_sync_and_async.py b/tests/feature/test_sync_and_async.py
index 8bb6cc6..b02cee9 100644
--- a/tests/feature/test_sync_and_async.py
+++ b/tests/feature/test_sync_and_async.py
@@ -1,3 +1,4 @@
+import aiohttp
from pytest import mark, raises
from caqui import asynchronous, synchronous
from caqui.exceptions import WebDriverError
@@ -107,7 +108,10 @@ async def test_set_window_rectangle(setup_functional_environment):
x = window_rectangle_before.get("x") + 1
y = window_rectangle_before.get("y") + 1
- assert synchronous.set_window_rectangle(server_url, session, width, height, x, y) is True
+ assert (
+ synchronous.set_window_rectangle(server_url, session, width, height, x, y)
+ is True
+ )
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
@@ -118,7 +122,12 @@ async def test_set_window_rectangle(setup_functional_environment):
synchronous.maximize_window(server_url, session)
- assert await asynchronous.set_window_rectangle(server_url, session, width, height, x, y) is True
+ assert (
+ await asynchronous.set_window_rectangle(
+ server_url, session, width, height, x, y
+ )
+ is True
+ )
window_rectangle_after = None
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
@@ -219,7 +228,10 @@ async def test_switch_to_window(setup_functional_environment, window_type):
assert synchronous.get_title(server_url, session) == ""
synchronous.switch_to_window(server_url, session, handle=sample_page) is True
- assert await asynchronous.switch_to_window(server_url, session, handle=new_page) is True
+ assert (
+ await asynchronous.switch_to_window(server_url, session, handle=new_page)
+ is True
+ )
assert synchronous.get_title(server_url, session) == ""
@@ -241,8 +253,13 @@ async def test_switch_to_parent_frame_asynchronous(setup_functional_environment)
locator_type = By.ID
locator_value = "my-iframe"
- element_frame = synchronous.find_element(server_url, session, locator_type, locator_value)
- assert await asynchronous.switch_to_parent_frame(server_url, session, element_frame) is True
+ element_frame = synchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
+ assert (
+ await asynchronous.switch_to_parent_frame(server_url, session, element_frame)
+ is True
+ )
def test_switch_to_parent_frame_synchronous(setup_functional_environment):
@@ -250,8 +267,12 @@ def test_switch_to_parent_frame_synchronous(setup_functional_environment):
locator_type = By.ID
locator_value = "my-iframe"
- element_frame = synchronous.find_element(server_url, session, locator_type, locator_value)
- assert synchronous.switch_to_parent_frame(server_url, session, element_frame) is True
+ element_frame = synchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
+ assert (
+ synchronous.switch_to_parent_frame(server_url, session, element_frame) is True
+ )
@mark.asyncio
@@ -260,8 +281,12 @@ async def test_switch_to_frame_asynchronous(setup_functional_environment):
locator_type = By.ID
locator_value = "my-iframe"
- element_frame = synchronous.find_element(server_url, session, locator_type, locator_value)
- assert await asynchronous.switch_to_frame(server_url, session, element_frame) is True
+ element_frame = synchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
+ assert (
+ await asynchronous.switch_to_frame(server_url, session, element_frame) is True
+ )
def test_switch_to_frame_synchronous(setup_functional_environment):
@@ -269,7 +294,9 @@ def test_switch_to_frame_synchronous(setup_functional_environment):
locator_type = By.ID
locator_value = "my-iframe"
- element_frame = synchronous.find_element(server_url, session, locator_type, locator_value)
+ element_frame = synchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
assert synchronous.switch_to_frame(server_url, session, element_frame) is True
@@ -329,7 +356,13 @@ async def test_take_screenshot_element(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
assert synchronous.take_screenshot_element(server_url, session, element) is True
- assert await asynchronous.take_screenshot_element(server_url, session, element) is True
+ async with aiohttp.ClientSession() as session_http:
+ assert (
+ await asynchronous.take_screenshot_element(
+ server_url, session, element, session_http=session_http
+ )
+ is True
+ )
@mark.asyncio
@@ -374,7 +407,9 @@ async def test_get_named_cookie(setup_functional_environment):
name = "username" # cookie created on page load
expected = "John Doe"
- assert synchronous.get_named_cookie(server_url, session, name).get("value") == expected
+ assert (
+ synchronous.get_named_cookie(server_url, session, name).get("value") == expected
+ )
response = await asynchronous.get_named_cookie(server_url, session, name)
assert response.get("value") == expected
@@ -390,7 +425,9 @@ async def test_get_computed_label(setup_functional_environment):
assert synchronous.get_computed_label(server_url, session, element) == expected
- assert await asynchronous.get_computed_label(server_url, session, element) == expected
+ assert (
+ await asynchronous.get_computed_label(server_url, session, element) == expected
+ )
@mark.asyncio
@@ -404,7 +441,9 @@ async def test_get_computed_role(setup_functional_environment):
assert synchronous.get_computed_role(server_url, session, element) == expected
- assert await asynchronous.get_computed_role(server_url, session, element) == expected
+ assert (
+ await asynchronous.get_computed_role(server_url, session, element) == expected
+ )
@mark.asyncio
@@ -421,9 +460,13 @@ async def test_get_tag_name(setup_functional_environment):
assert await asynchronous.get_tag_name(server_url, session, element) == expected
-@mark.parametrize("locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")])
+@mark.parametrize(
+ "locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")]
+)
@mark.asyncio
-async def test_find_element_from_shadow_root(setup_functional_environment, locator, value):
+async def test_find_element_from_shadow_root(
+ setup_functional_environment, locator, value
+):
server_url, session = setup_functional_environment
locator_type = By.ID
locator_value = "shadow-root"
@@ -432,18 +475,26 @@ async def test_find_element_from_shadow_root(setup_functional_environment, locat
shadow_root = synchronous.get_shadow_root(server_url, session, element)
- actual = synchronous.find_child_element(server_url, session, shadow_root, locator, value)
+ actual = synchronous.find_child_element(
+ server_url, session, shadow_root, locator, value
+ )
assert actual is not None
- actual = await asynchronous.find_child_element(server_url, session, shadow_root, locator, value)
+ actual = await asynchronous.find_child_element(
+ server_url, session, shadow_root, locator, value
+ )
assert actual is not None
-@mark.parametrize("locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")])
+@mark.parametrize(
+ "locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")]
+)
@mark.asyncio
-async def test_find_elements_from_shadow_root(setup_functional_environment, locator, value):
+async def test_find_elements_from_shadow_root(
+ setup_functional_environment, locator, value
+):
server_url, session = setup_functional_environment
locator_type = By.ID
locator_value = "shadow-root"
@@ -453,7 +504,9 @@ async def test_find_elements_from_shadow_root(setup_functional_environment, loca
shadow_root = synchronous.get_shadow_root(server_url, session, element)
- actual = synchronous.find_children_elements(server_url, session, shadow_root, locator, value)
+ actual = synchronous.find_children_elements(
+ server_url, session, shadow_root, locator, value
+ )
assert len(actual) == one
@@ -500,7 +553,9 @@ async def test_move_to_element(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
assert synchronous.actions_move_to_element(server_url, session, element) is True
- assert await asynchronous.actions_move_to_element(server_url, session, element) is True
+ assert (
+ await asynchronous.actions_move_to_element(server_url, session, element) is True
+ )
@mark.asyncio
@@ -511,7 +566,10 @@ async def test_actions_scroll_to_element(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
assert synchronous.actions_scroll_to_element(server_url, session, element) is True
- assert await asynchronous.actions_scroll_to_element(server_url, session, element) is True
+ assert (
+ await asynchronous.actions_scroll_to_element(server_url, session, element)
+ is True
+ )
@mark.asyncio
@@ -549,7 +607,9 @@ async def test_raise_exception_when_element_not_found(setup_functional_environme
synchronous.find_element(server_url, session, locator_type, locator_value)
with raises(WebDriverError):
- await asynchronous.find_element(server_url, session, locator_type, locator_value)
+ await asynchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
@mark.asyncio
@@ -647,7 +707,9 @@ async def test_get_alert_text(setup_functional_environment):
locator_value = "#alert-button"
expected = "any warn"
- alert_button = synchronous.find_element(server_url, session, locator_type, locator_value)
+ alert_button = synchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
synchronous.click(server_url, session, alert_button)
assert synchronous.get_alert_text(server_url, session) == expected
@@ -716,8 +778,14 @@ async def test_get_css_value(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
- assert synchronous.get_css_value(server_url, session, element, property_name) == expected
- assert await asynchronous.get_css_value(server_url, session, element, property_name) == expected
+ assert (
+ synchronous.get_css_value(server_url, session, element, property_name)
+ == expected
+ )
+ assert (
+ await asynchronous.get_css_value(server_url, session, element, property_name)
+ == expected
+ )
@mark.asyncio
@@ -791,7 +859,10 @@ async def test_get_attribute(setup_functional_environment):
attribute = "href"
element = synchronous.find_element(server_url, session, By.XPATH, "//a[@id='a1']")
- assert synchronous.get_attribute(server_url, session, element, attribute) == "http://any1.com/"
+ assert (
+ synchronous.get_attribute(server_url, session, element, attribute)
+ == "http://any1.com/"
+ )
assert (
await asynchronous.get_attribute(server_url, session, element, attribute)
== "http://any1.com/"
@@ -856,7 +927,9 @@ async def test_get_title(setup_functional_environment):
@mark.asyncio
-async def test_find_elements_fails_when_invalid_data_input(setup_functional_environment):
+async def test_find_elements_fails_when_invalid_data_input(
+ setup_functional_environment,
+):
server_url, session = setup_functional_environment
locator_type = "invalid"
locator_value = "//input"
@@ -865,7 +938,9 @@ async def test_find_elements_fails_when_invalid_data_input(setup_functional_envi
synchronous.find_elements(server_url, session, locator_type, locator_value)
with raises(WebDriverError):
- await asynchronous.find_elements(server_url, session, locator_type, locator_value)
+ await asynchronous.find_elements(
+ server_url, session, locator_type, locator_value
+ )
@mark.asyncio
@@ -874,7 +949,9 @@ async def test_find_elements(setup_functional_environment):
locator_type = By.XPATH
locator_value = "//input"
- elements = synchronous.find_elements(server_url, session, locator_type, locator_value)
+ elements = synchronous.find_elements(
+ server_url, session, locator_type, locator_value
+ )
async_elements = await asynchronous.find_elements(
server_url, session, locator_type, locator_value
)
@@ -893,7 +970,9 @@ async def test_find_element_fails_when_invalid_data_input(setup_functional_envir
synchronous.find_element(server_url, session, locator_type, locator_value)
with raises(WebDriverError):
- await asynchronous.find_element(server_url, session, locator_type, locator_value)
+ await asynchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
@mark.asyncio
@@ -902,9 +981,14 @@ async def test_find_element(setup_functional_environment):
locator_type = By.XPATH
locator_value = "//input"
- assert synchronous.find_element(server_url, session, locator_type, locator_value) is not None
assert (
- await asynchronous.find_element(server_url, session, locator_type, locator_value)
+ synchronous.find_element(server_url, session, locator_type, locator_value)
+ is not None
+ )
+ assert (
+ await asynchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
is not None
)
@@ -921,7 +1005,9 @@ async def test_get_property(setup_functional_environment):
synchronous.send_keys(server_url, session, element, text)
assert synchronous.get_property(server_url, session, element, property) == text
- assert await asynchronous.get_property(server_url, session, element, property) == text
+ assert (
+ await asynchronous.get_property(server_url, session, element, property) == text
+ )
@mark.asyncio
@@ -947,7 +1033,9 @@ async def test_send_keys(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
- assert await asynchronous.send_keys(server_url, session, element, text_async) is True
+ assert (
+ await asynchronous.send_keys(server_url, session, element, text_async) is True
+ )
assert synchronous.send_keys(server_url, session, element, text_sync) is True
diff --git a/tests/integration/test_async_scenarios.py b/tests/integration/test_async_scenarios.py
index f3dc302..d9ba381 100644
--- a/tests/integration/test_async_scenarios.py
+++ b/tests/integration/test_async_scenarios.py
@@ -2,6 +2,7 @@
from pytest import mark
+
@mark.asyncio
async def test_get_all_links(setup_functional_environment):
server_url, session = setup_functional_environment
@@ -11,6 +12,11 @@ async def test_get_all_links(setup_functional_environment):
for i in range(4):
i += 1
locator_value = f"//a[@id='a{i}']"
- anchor = synchronous.find_element(server_url, session, locator_type, locator_value)
+ anchor = synchronous.find_element(
+ server_url, session, locator_type, locator_value
+ )
anchors.append(anchor)
- assert await asynchronous.get_text(server_url, session, anchors[i - 1]) == f"any{i}.com"
+ assert (
+ await asynchronous.get_text(server_url, session, anchors[i - 1])
+ == f"any{i}.com"
+ )
diff --git a/tests/unit/test_async_unit.py b/tests/unit/test_async_unit.py
index 3ee71c8..daafc89 100644
--- a/tests/unit/test_async_unit.py
+++ b/tests/unit/test_async_unit.py
@@ -7,7 +7,7 @@
from unittest.mock import patch
-async def mock_request(*args):
+async def mock_request(*args, **kwargs):
pass
@@ -15,7 +15,7 @@ async def mock_request(*args):
async def test_get_rect():
expected = {"height": 23, "width": 183, "x": 10, "y": 9652.12}
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_RECT
with patch("caqui.asynchronous.__get", mock_request):
@@ -24,7 +24,7 @@ async def mock_request(*args):
@mark.asyncio
async def test_actions_scroll_to_element():
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.ACTIONS
with patch("caqui.asynchronous.__post", mock_request):
@@ -33,7 +33,7 @@ async def mock_request(*args):
@mark.asyncio
async def test_submit():
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.CLICK
with patch("caqui.asynchronous.__post", mock_request):
@@ -42,7 +42,7 @@ async def mock_request(*args):
@mark.asyncio
async def test_actions_click():
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.ACTIONS
with patch("caqui.asynchronous.__post", mock_request):
@@ -51,7 +51,7 @@ async def mock_request(*args):
@mark.asyncio
async def test_set_timeouts():
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_TIMEOUTS
with patch("caqui.asynchronous.__post", mock_request):
@@ -62,7 +62,7 @@ async def mock_request(*args):
async def test_find_children_elements():
element = "C230605181E69CB2C4C36B8E83FE1245_element_2"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.FIND_ELEMENTS
with patch("caqui.asynchronous.__post", mock_request):
@@ -73,7 +73,7 @@ async def mock_request(*args):
async def test_find_child_element():
element = "0.8851292311864847-1"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.FIND_ELEMENT
with patch("caqui.asynchronous.__post", mock_request):
@@ -84,7 +84,7 @@ async def mock_request(*args):
async def test_execute_script():
expected = "any"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.EXECUTE_SCRIPT
with patch("caqui.asynchronous.__post", mock_request):
@@ -95,7 +95,7 @@ async def mock_request(*args):
async def test_get_page_source():
expected = "Sample page"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_PAGE_SOURCE
with patch("caqui.asynchronous.__get", mock_request):
@@ -106,7 +106,7 @@ async def mock_request(*args):
async def test_get_alert_text():
expected = "any warn"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_ALERT_TEXT
with patch("caqui.asynchronous.__get", mock_request):
@@ -117,7 +117,7 @@ async def mock_request(*args):
async def test_get_active_element():
expected = "0.8851292311864847-1"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_ACTIVE_ELEMENT
with patch("caqui.asynchronous.__get", mock_request):
@@ -126,7 +126,7 @@ async def mock_request(*args):
@mark.asyncio
async def test_clear_element():
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.CLEAR_ELEMENT
with patch("caqui.asynchronous.__post", mock_request):
@@ -135,7 +135,7 @@ async def mock_request(*args):
@mark.asyncio
async def test_is_element_enabled():
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.IS_ELEMENT_ENABLED
with patch("caqui.asynchronous.__get", mock_request):
@@ -146,7 +146,7 @@ async def mock_request(*args):
async def test_get_css_value():
expected = "rgba(0, 0, 0, 1)"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_CSS_COLOR_VALUE
with patch("caqui.asynchronous.__get", mock_request):
@@ -155,7 +155,7 @@ async def mock_request(*args):
@mark.asyncio
async def test_is_element_selected():
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.IS_ELEMENT_SELECTED
with patch("caqui.asynchronous.__get", mock_request):
@@ -166,7 +166,7 @@ async def mock_request(*args):
async def test_get_window_rectangle():
expected = "height"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_WINDOW_RECTANGLE
with patch("caqui.asynchronous.__get", mock_request):
@@ -177,7 +177,7 @@ async def mock_request(*args):
async def test_get_window_handles():
expected = ["2E55CCE389196328988ED244DAA52A5D"]
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_WINDOW_HANDLES
with patch("caqui.asynchronous.__get", mock_request):
@@ -188,7 +188,7 @@ async def mock_request(*args):
async def test_close_window():
expected = []
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.CLOSE_WINDOW
with patch("caqui.asynchronous.__delete", mock_request):
@@ -199,7 +199,7 @@ async def mock_request(*args):
async def test_get_window():
expected = "845623CAE8115F2B60C9AE8596F13D94"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_WINDOW
with patch("caqui.asynchronous.__get", mock_request):
@@ -216,7 +216,7 @@ async def test_go_back():
async def test_get_property():
expected = "any_value"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_PROPERTY_VALUE
with patch("caqui.asynchronous.__get", mock_request):
@@ -227,7 +227,7 @@ async def mock_request(*args):
async def test_get_attribute():
expected = "any_value"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_ATTRIBUTE_VALUE
with patch("caqui.asynchronous.__get", mock_request):
@@ -238,7 +238,7 @@ async def mock_request(*args):
async def test_get_url():
expected = "playground.html"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_URL
with patch("caqui.asynchronous.__get", mock_request):
@@ -250,7 +250,7 @@ async def mock_request(*args):
async def test_get_timeouts():
expected = "implicit"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_TIMEOUTS
with patch("caqui.asynchronous.__get", mock_request):
@@ -260,7 +260,7 @@ async def mock_request(*args):
@mark.asyncio
async def test_get_status():
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_STATUS
with patch("caqui.asynchronous.__get", mock_request):
@@ -272,7 +272,7 @@ async def mock_request(*args):
async def test_get_title():
expected = "Sample page"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_TITLE
with patch("caqui.asynchronous.__get", mock_request):
@@ -283,7 +283,7 @@ async def mock_request(*args):
async def test_get_cookies():
expected = []
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_COOKIES
with patch("caqui.asynchronous.__get", mock_request):
@@ -294,7 +294,7 @@ async def mock_request(*args):
async def test_get_text():
expected = "any"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_TEXT
with patch("caqui.asynchronous.__get", mock_request):
@@ -329,7 +329,7 @@ async def test_click():
async def test_find_elements():
element = "C230605181E69CB2C4C36B8E83FE1245_element_2"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.FIND_ELEMENTS
with patch("caqui.asynchronous.__post", mock_request):
@@ -340,7 +340,7 @@ async def mock_request(*args):
async def test_find_element():
element = "0.8851292311864847-1"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.FIND_ELEMENT
with patch("caqui.asynchronous.__post", mock_request):
@@ -351,7 +351,7 @@ async def mock_request(*args):
async def test_get_session():
expected = "4358a5b53794586af59678fc1653dc40"
- async def mock_request(*args):
+ async def mock_request(*args, **kwargs):
return fake_responses.GET_SESSION
with patch("caqui.asynchronous.__post", mock_request):
From 1d7f417515ebd82ab7ef76d22f0230d6ff41641d Mon Sep 17 00:00:00 2001
From: Douglas Cardoso <29078346+douglasdcm@users.noreply.github.com>
Date: Sat, 29 Nov 2025 02:46:10 -0300
Subject: [PATCH 03/40] add performance tests
---
caqui/asynchronous.py | 126 +--
caqui/easy/action_chains.py | 4 +-
caqui/easy/alert.py | 12 +-
caqui/easy/element.py | 77 +-
caqui/easy/page.py | 102 ++-
caqui/easy/server.py | 41 +-
caqui/easy/switch_to.py | 10 +-
caqui/synchronous.py | 416 ++++-----
dev-requirements.txt | 3 +-
samples/sample-web-driver.py | 4 +-
tests/conftest.py | 11 +-
tests/feature/test_async_with_http_session.py | 365 ++++----
tests/feature/test_sync_and_async.py | 147 +--
tests/integration/test_async_scenarios.py | 10 +-
tests/performance/README.md | 858 ++++++++++++++++++
tests/performance/test_process_data.py | 463 ++++++++++
tests/performance/test_single_session_http.py | 278 ++++++
tests/unit/test_async_unit.py | 70 +-
tests/unit/test_sync_unit.py | 68 +-
19 files changed, 2301 insertions(+), 764 deletions(-)
create mode 100644 tests/performance/README.md
create mode 100644 tests/performance/test_process_data.py
create mode 100644 tests/performance/test_single_session_http.py
diff --git a/caqui/asynchronous.py b/caqui/asynchronous.py
index 05f29f0..7b6b4a6 100644
--- a/caqui/asynchronous.py
+++ b/caqui/asynchronous.py
@@ -1,7 +1,7 @@
from aiohttp import ClientSession
-from json import dumps
-from caqui.constants import HEADERS as __HEADERS
-from caqui.exceptions import WebDriverError as WebDriverError
+from orjson import dumps
+from caqui.constants import HEADERS
+from caqui.exceptions import WebDriverError
from caqui.helper import save_picture, get_elements, get_element
from typing import Optional
@@ -24,7 +24,7 @@ async def _handle_response(resp):
async def _delete(url, session_http: ClientSession = None):
if session_http:
try:
- async with session_http.delete(url, headers=__HEADERS) as resp:
+ async with session_http.delete(url, headers=HEADERS) as resp:
return await _handle_response(resp)
except Exception as e:
raise WebDriverError("'DELETE' request failed.") from e
@@ -32,7 +32,7 @@ async def _delete(url, session_http: ClientSession = None):
else:
try:
async with ClientSession() as session_http:
- async with session_http.delete(url, headers=__HEADERS) as resp:
+ async with session_http.delete(url, headers=HEADERS) as resp:
return await _handle_response(resp)
except Exception as e:
raise WebDriverError("'DELETE' request failed.") from e
@@ -41,18 +41,14 @@ async def _delete(url, session_http: ClientSession = None):
async def _post(url, payload, session_http: ClientSession = None):
if session_http:
try:
- async with session_http.post(
- url, data=dumps(payload), headers=__HEADERS
- ) as resp:
+ async with session_http.post(url, data=dumps(payload), headers=HEADERS) as resp:
return await _handle_response(resp)
except Exception as e:
raise WebDriverError("'POST' request failed.") from e
else:
try:
async with ClientSession() as session_http:
- async with session_http.post(
- url, data=dumps(payload), headers=__HEADERS
- ) as resp:
+ async with session_http.post(url, data=dumps(payload), headers=HEADERS) as resp:
return await _handle_response(resp)
except Exception as e:
raise WebDriverError("'POST' request failed.") from e
@@ -61,14 +57,14 @@ async def _post(url, payload, session_http: ClientSession = None):
async def _get(url, session_http: ClientSession = None):
if session_http:
try:
- async with session_http.get(url, headers=__HEADERS) as resp:
+ async with session_http.get(url, headers=HEADERS) as resp:
return await _handle_response(resp)
except Exception as e:
raise WebDriverError("'GET' request failed.") from e
else:
try:
async with ClientSession() as session_http:
- async with session_http.get(url, headers=__HEADERS) as resp:
+ async with session_http.get(url, headers=HEADERS) as resp:
return await _handle_response(resp)
except Exception as e:
raise WebDriverError("'GET' request failed.") from e
@@ -83,9 +79,7 @@ async def _handle_alert(server_url, session, command, session_http) -> bool:
return True
-async def _handle_window(
- server_url, session, command, session_http: ClientSession = None
-):
+async def _handle_window(server_url, session, command, session_http: ClientSession = None):
url = f"{server_url}/session/{session}/window/{command}"
payload = {}
await _post(url, payload, session_http=session_http)
@@ -135,9 +129,7 @@ async def go_forward(server_url, session, session_http: ClientSession = None):
raise WebDriverError("Failed to go to page forward.") from e
-async def set_window_rectangle(
- server_url, session, width, height, x, y, session_http=None
-):
+async def set_window_rectangle(server_url, session, width, height, x, y, session_http=None):
"""Set window rectangle"""
try:
url = f"{server_url}/session/{session}/window/rect"
@@ -178,9 +170,7 @@ async def maximize_window(server_url, session, session_http: ClientSession = Non
raise WebDriverError("Failed to maximize window.") from e
-async def switch_to_window(
- server_url, session, handle, session_http: ClientSession = None
-):
+async def switch_to_window(server_url, session, handle, session_http: ClientSession = None):
"""Switch to window"""
try:
url = f"{server_url}/session/{session}/window"
@@ -221,9 +211,7 @@ async def switch_to_parent_frame(
raise WebDriverError("Failed to switch to parent frame.") from e
-async def switch_to_frame(
- server_url, session, element_frame, session_http: ClientSession = None
-):
+async def switch_to_frame(server_url, session, element_frame, session_http: ClientSession = None):
"""Switch to frame 'element_frame'"""
try:
url = f"{server_url}/session/{session}/frame"
@@ -244,9 +232,7 @@ async def delete_all_cookies(server_url, session, session_http: ClientSession =
raise WebDriverError("Failed to delete cookies.") from e
-async def send_alert_text(
- server_url, session, text, session_http: ClientSession = None
-):
+async def send_alert_text(server_url, session, text, session_http: ClientSession = None):
"""Fill the alert text area and send the text"""
try:
url = f"{server_url}/session/{session}/alert/text"
@@ -262,9 +248,7 @@ async def send_alert_text(
async def accept_alert(server_url, session, session_http: ClientSession = None):
"""Accept alert"""
try:
- return await _handle_alert(
- server_url, session, "accept", session_http=session_http
- )
+ return await _handle_alert(server_url, session, "accept", session_http=session_http)
except Exception as e:
raise WebDriverError("Failed to accept alert.") from e
@@ -272,9 +256,7 @@ async def accept_alert(server_url, session, session_http: ClientSession = None):
async def dismiss_alert(server_url, session, session_http: ClientSession = None):
"""Dismiss alert"""
try:
- return await _handle_alert(
- server_url, session, "dismiss", session_http=session_http
- )
+ return await _handle_alert(server_url, session, "dismiss", session_http=session_http)
except Exception as e:
raise WebDriverError("Failed to dismiss alert.") from e
@@ -316,9 +298,7 @@ async def take_screenshot(
raise WebDriverError("Failed to take screenshot.") from e
-async def get_named_cookie(
- server_url, session, name, session_http: ClientSession = None
-) -> str:
+async def get_named_cookie(server_url, session, name, session_http: ClientSession = None) -> str:
"""Get cookie by name"""
try:
url = f"{server_url}/session/{session}/cookie/{name}"
@@ -352,9 +332,7 @@ async def get_computed_role(
raise WebDriverError("Failed to get element computed role.") from e
-async def get_tag_name(
- server_url, session, element, session_http: ClientSession = None
-) -> str:
+async def get_tag_name(server_url, session, element, session_http: ClientSession = None) -> str:
"""Get the element tag name"""
try:
url = f"{server_url}/session/{session}/element/{element}/name"
@@ -364,9 +342,7 @@ async def get_tag_name(
raise WebDriverError("Failed to get element name.") from e
-async def get_shadow_root(
- server_url, session, element, session_http: ClientSession = None
-) -> dict:
+async def get_shadow_root(server_url, session, element, session_http: ClientSession = None) -> dict:
"""Get the shadow root element"""
try:
root_element = "shadow-6066-11e4-a52e-4f735466cecf"
@@ -377,9 +353,7 @@ async def get_shadow_root(
raise WebDriverError("Failed to get element shadow.") from e
-async def get_rect(
- server_url, session, element, session_http: ClientSession = None
-) -> dict:
+async def get_rect(server_url, session, element, session_http: ClientSession = None) -> dict:
"""Get the element rectangle"""
try:
url = f"{server_url}/session/{session}/element/{element}/rect"
@@ -395,9 +369,7 @@ async def actions(server_url, session, payload, session_http: ClientSession = No
return True
-async def actions_move_to_element(
- server_url, session, element, session_http: ClientSession = None
-):
+async def actions_move_to_element(server_url, session, element, session_http: ClientSession = None):
"""Move to an element simulating a mouse movement"""
try:
payload = {
@@ -468,18 +440,14 @@ async def submit(server_url, session, element, session_http: ClientSession = Non
element,
locator_type="xpath",
locator_value="*[@type='submit']",
- session_http=session_http
- )
- return await click(
- server_url, session, submit_element, session_http=session_http
+ session_http=session_http,
)
+ return await click(server_url, session, submit_element, session_http=session_http)
except Exception as e:
raise WebDriverError("Failed to submit form.") from e
-async def actions_click(
- server_url, session, element, session_http: ClientSession = None
-):
+async def actions_click(server_url, session, element, session_http: ClientSession = None):
"""Click an element simulating a mouse movement"""
try:
payload = {
@@ -516,9 +484,7 @@ async def actions_click(
raise WebDriverError("Failed to click the element.") from e
-async def set_timeouts(
- server_url, session, timeouts, session_http: ClientSession = None
-):
+async def set_timeouts(server_url, session, timeouts, session_http: ClientSession = None):
"""Set timeouts"""
try:
url = f"{server_url}/session/{session}/timeouts"
@@ -570,14 +536,10 @@ async def find_child_element(
response = await _post(url, payload, session_http=session_http)
return get_element(response)
except Exception as e:
- raise WebDriverError(
- f"Failed to find the child element from '{parent_element}'."
- ) from e
+ raise WebDriverError(f"Failed to find the child element from '{parent_element}'.") from e
-async def get_page_source(
- server_url, session, session_http: ClientSession = None
-) -> str:
+async def get_page_source(server_url, session, session_http: ClientSession = None) -> str:
"""Get the page source (all content)"""
try:
url = f"{server_url}/session/{session}/source"
@@ -587,9 +549,7 @@ async def get_page_source(
raise WebDriverError("Failed to get the page source.") from e
-async def execute_script(
- server_url, session, script, args=[], session_http: ClientSession = None
-):
+async def execute_script(server_url, session, script, args=[], session_http: ClientSession = None):
"""Executes a script, like 'alert('something')' to open an alert window"""
try:
url = f"{server_url}/session/{session}/execute/sync"
@@ -600,9 +560,7 @@ async def execute_script(
raise WebDriverError("Failed to execute script.") from e
-async def get_alert_text(
- server_url, session, session_http: ClientSession = None
-) -> str:
+async def get_alert_text(server_url, session, session_http: ClientSession = None) -> str:
"""Get the text from an alert"""
try:
url = f"{server_url}/session/{session}/alert/text"
@@ -622,9 +580,7 @@ async def get_active_element(server_url, session, session_http: ClientSession =
raise WebDriverError("Failed to check if element is selected.") from e
-async def clear_element(
- server_url, session, element, session_http: ClientSession = None
-):
+async def clear_element(server_url, session, element, session_http: ClientSession = None):
"""Clear the element text"""
try:
url = f"{server_url}/session/{session}/element/{element}/clear"
@@ -671,9 +627,7 @@ async def is_element_selected(
raise WebDriverError("Failed to check if element is selected.") from e
-async def get_window_rectangle(
- server_url, session, session_http: ClientSession = None
-) -> dict:
+async def get_window_rectangle(server_url, session, session_http: ClientSession = None) -> dict:
"""Get window rectangle"""
try:
url = f"{server_url}/session/{session}/window/rect"
@@ -683,9 +637,7 @@ async def get_window_rectangle(
raise WebDriverError("Failed to get window rectangle.") from e
-async def get_window_handles(
- server_url, session, session_http: ClientSession = None
-) -> list:
+async def get_window_handles(server_url, session, session_http: ClientSession = None) -> list:
"""Get window handles"""
try:
url = f"{server_url}/session/{session}/window/handles"
@@ -811,9 +763,7 @@ async def get_attribute(
raise WebDriverError("Failed to get value from element.") from e
-async def get_text(
- server_url, session, element, session_http: ClientSession = None
-) -> str:
+async def get_text(server_url, session, element, session_http: ClientSession = None) -> str:
"""Get the text of an element"""
try:
url = f"{server_url}/session/{session}/element/{element}/text"
@@ -848,7 +798,7 @@ async def get(server_url, session, page_url, session_http: ClientSession = None)
return go_to_page(server_url, session, page_url, session_http=session_http)
-async def go_to_page(server_url, session, page_url, session_http:ClientSession=None):
+async def go_to_page(server_url, session, page_url, session_http: ClientSession = None):
"""Navigate to 'page_url'"""
try:
url = f"{server_url}/session/{session}/url"
@@ -859,9 +809,7 @@ async def go_to_page(server_url, session, page_url, session_http:ClientSession=N
raise WebDriverError(f"Failed to navigate to page '{page_url}'.") from e
-async def send_keys(
- server_url, session, element, text, session_http: ClientSession = None
-):
+async def send_keys(server_url, session, element, text, session_http: ClientSession = None):
"""Fill an editable element, for example a textarea, with a given text"""
try:
url = f"{server_url}/session/{session}/element/{element}/value"
@@ -920,6 +868,4 @@ async def get_session(
response = await _post(url, capabilities, session_http=session_http)
return response.get("sessionId")
except Exception as e:
- raise WebDriverError(
- "Failed to open session. Check the browser capabilities."
- ) from e
+ raise WebDriverError("Failed to open session. Check the browser capabilities.") from e
diff --git a/caqui/easy/action_chains.py b/caqui/easy/action_chains.py
index e278c5f..cc7181e 100644
--- a/caqui/easy/action_chains.py
+++ b/caqui/easy/action_chains.py
@@ -16,7 +16,9 @@ def click(self, element: Element):
Clicks on the element `element`
"""
self._element = element
- coroutine = asynchronous.click(self._remote, self._session, str(element), session_http=self._session_http)
+ coroutine = asynchronous.click(
+ self._remote, self._session, str(element), session_http=self._session_http
+ )
self._coroutines.append(coroutine)
return self
diff --git a/caqui/easy/alert.py b/caqui/easy/alert.py
index d1ba6f7..bb42291 100644
--- a/caqui/easy/alert.py
+++ b/caqui/easy/alert.py
@@ -14,12 +14,18 @@ def text(self):
async def accept(self):
"""Accepts the alert"""
- return await asynchronous.accept_alert(self._remote, self._session, session_http=self._session_http)
+ return await asynchronous.accept_alert(
+ self._remote, self._session, session_http=self._session_http
+ )
async def dismiss(self):
"""Closes the alert ignoring it"""
- return await asynchronous.dismiss_alert(self._remote, self._session, session_http=self._session_http)
+ return await asynchronous.dismiss_alert(
+ self._remote, self._session, session_http=self._session_http
+ )
async def send_keys(self, text):
"""Send a text to a textbox in the alert"""
- return await asynchronous.send_alert_text(self._remote, self._session, text, session_http=self._session_http)
+ return await asynchronous.send_alert_text(
+ self._remote, self._session, text, session_http=self._session_http
+ )
diff --git a/caqui/easy/element.py b/caqui/easy/element.py
index 6ade2fa..fd96643 100644
--- a/caqui/easy/element.py
+++ b/caqui/easy/element.py
@@ -39,7 +39,11 @@ def active_element(self):
async def value_of_css_property(self, property_name):
"""Returns the desired CSS property of the element"""
return await asynchronous.get_css_value(
- self._remote, self._session, self._element, property_name, session_http=self._session_http
+ self._remote,
+ self._session,
+ self._element,
+ property_name,
+ session_http=self._session_http,
)
async def screenshot(self, file):
@@ -49,46 +53,71 @@ async def screenshot(self, file):
path = "./"
file_name = os.path.basename(file)
return await asynchronous.take_screenshot_element(
- self._remote, self._session, self._element, path, file_name, session_http=self._session_http
+ self._remote,
+ self._session,
+ self._element,
+ path,
+ file_name,
+ session_http=self._session_http,
)
async def is_selected(self) -> bool:
"""Returns True if the element is selected. Otherwise returns False"""
- return await asynchronous.is_element_selected(self._remote, self._session, self._element, session_http=self._session_http)
+ return await asynchronous.is_element_selected(
+ self._remote, self._session, self._element, session_http=self._session_http
+ )
async def is_enabled(self):
"""Returns True if the element is enabled. Otherwise returns False"""
- return await asynchronous.is_element_enabled(self._remote, self._session, self._element, session_http=self._session_http)
+ return await asynchronous.is_element_enabled(
+ self._remote, self._session, self._element, session_http=self._session_http
+ )
async def get_text(self):
"""Returns the text of the element"""
- return await asynchronous.get_text(self._remote, self._session, self._element, session_http=self._session_http)
+ return await asynchronous.get_text(
+ self._remote, self._session, self._element, session_http=self._session_http
+ )
async def get_css_value(self, property_name):
"""Returns the desired CSS property of the element"""
return await asynchronous.get_css_value(
- self._remote, self._session, self._element, property_name, session_http=self._session_http
+ self._remote,
+ self._session,
+ self._element,
+ property_name,
+ session_http=self._session_http,
)
async def submit(self):
"""Submits a form"""
- return await asynchronous.submit(self._remote, self._session, self._element, session_http=self._session_http)
+ return await asynchronous.submit(
+ self._remote, self._session, self._element, session_http=self._session_http
+ )
async def get_rect(self):
"""Returns the rectangle that enclosed the element"""
- return await asynchronous.get_rect(self._remote, self._session, self._element, session_http=self._session_http)
+ return await asynchronous.get_rect(
+ self._remote, self._session, self._element, session_http=self._session_http
+ )
async def get_tag_name(self):
"""Returns the element tag name"""
- return await asynchronous.get_tag_name(self._remote, self._session, self._element, session_http=self._session_http)
+ return await asynchronous.get_tag_name(
+ self._remote, self._session, self._element, session_http=self._session_http
+ )
async def get_computed_label(self):
"""Get the element tag computed label. Get the accessibility name"""
- return await asynchronous.get_computed_label(self._remote, self._session, self._element, session_http=self._session_http)
+ return await asynchronous.get_computed_label(
+ self._remote, self._session, self._element, session_http=self._session_http
+ )
async def get_computed_role(self):
"""Get the element tag computed role (the element role)"""
- return await asynchronous.get_computed_role(self._remote, self._session, self._element, session_http=self._session_http)
+ return await asynchronous.get_computed_role(
+ self._remote, self._session, self._element, session_http=self._session_http
+ )
async def get_property(self, property):
"""Get the given HTML property of an element, for example, 'href'"""
@@ -104,15 +133,21 @@ async def get_attribute(self, attribute):
async def clear(self):
"""Clear the element text"""
- return await asynchronous.clear_element(self._remote, self._session, self._element, session_http=self._session_http)
+ return await asynchronous.clear_element(
+ self._remote, self._session, self._element, session_http=self._session_http
+ )
async def send_keys(self, text):
"""Fill the element with a text"""
- return await asynchronous.send_keys(self._remote, self._session, self._element, text, session_http=self._session_http)
+ return await asynchronous.send_keys(
+ self._remote, self._session, self._element, text, session_http=self._session_http
+ )
async def click(self):
"""Click on the element"""
- return await asynchronous.click(self._remote, self._session, self._element, session_http=self._session_http)
+ return await asynchronous.click(
+ self._remote, self._session, self._element, session_http=self._session_http
+ )
async def find_elements(self, locator, value):
"""
@@ -123,7 +158,12 @@ async def find_elements(self, locator, value):
"""
result = []
elements = await asynchronous.find_children_elements(
- self._remote, self._session, self._element, locator, value, session_http=self._session_http
+ self._remote,
+ self._session,
+ self._element,
+ locator,
+ value,
+ session_http=self._session_http,
)
for element in elements:
result.append(Element(element, self._driver))
@@ -132,6 +172,11 @@ async def find_elements(self, locator, value):
async def find_element(self, locator, value):
"""Find the element by `locator_type`"""
element = await asynchronous.find_child_element(
- self._remote, self._session, self._element, locator, value, session_http=self._session_http
+ self._remote,
+ self._session,
+ self._element,
+ locator,
+ value,
+ session_http=self._session_http,
)
return Element(element, self._driver)
diff --git a/caqui/easy/page.py b/caqui/easy/page.py
index 6a877cb..8bbccbf 100644
--- a/caqui/easy/page.py
+++ b/caqui/easy/page.py
@@ -13,7 +13,11 @@
class AsyncPage:
def __init__(
- self, server_url: str, capabilities: Optional[dict] = None, url: Union[str, None] = None, session_http: ClientSession=None
+ self,
+ server_url: str,
+ capabilities: Optional[dict] = None,
+ url: Union[str, None] = None,
+ session_http: ClientSession = None,
) -> None:
"""Mimics Selenium methods"""
self.session_http = session_http
@@ -86,32 +90,56 @@ def quit(self):
async def close(self):
"""Closes the window"""
- return await asynchronous.close_window(self._server_url, self._session, session_http=self.session_http)
+ return await asynchronous.close_window(
+ self._server_url, self._session, session_http=self.session_http
+ )
async def execute_script(self, script, args=[]):
- return await asynchronous.execute_script(self._server_url, self._session, script, args, session_http=self.session_http)
+ return await asynchronous.execute_script(
+ self._server_url, self._session, script, args, session_http=self.session_http
+ )
async def set_window_position(self, x, y):
"""Repositions the page"""
- rect = await asynchronous.get_window_rectangle(self._server_url, self._session, session_http=self.session_http)
+ rect = await asynchronous.get_window_rectangle(
+ self._server_url, self._session, session_http=self.session_http
+ )
return await asynchronous.set_window_rectangle(
- self._server_url, self._session, rect.get("width"), rect.get("height"), x, y, session_http=self.session_http
+ self._server_url,
+ self._session,
+ rect.get("width"),
+ rect.get("height"),
+ x,
+ y,
+ session_http=self.session_http,
)
async def set_window_size(self, width, height):
"""Resizes the page"""
- rect = await asynchronous.get_window_rectangle(self._server_url, self._session, session_http=self.session_http)
+ rect = await asynchronous.get_window_rectangle(
+ self._server_url, self._session, session_http=self.session_http
+ )
return await asynchronous.set_window_rectangle(
- self._server_url, self._session, width, height, rect.get("x"), rect.get("y"), session_http=self.session_http
+ self._server_url,
+ self._session,
+ width,
+ height,
+ rect.get("x"),
+ rect.get("y"),
+ session_http=self.session_http,
)
async def get_window_position(self):
"""Returns the window rectangle"""
- return await asynchronous.get_window_rectangle(self._server_url, self._session, session_http=self.session_http)
+ return await asynchronous.get_window_rectangle(
+ self._server_url, self._session, session_http=self.session_http
+ )
async def get_window_size(self):
"""Returns the window rectangle"""
- return await asynchronous.get_window_rectangle(self._server_url, self._session, session_http=self.session_http)
+ return await asynchronous.get_window_rectangle(
+ self._server_url, self._session, session_http=self.session_http
+ )
async def save_screenshot(self, file):
"""Takes a scheenshot of the page"""
@@ -125,60 +153,82 @@ async def save_screenshot(self, file):
async def delete_all_cookies(self):
"""Deletes all storaged cookies"""
- return await asynchronous.delete_all_cookies(self._server_url, self._session, session_http=self.session_http)
+ return await asynchronous.delete_all_cookies(
+ self._server_url, self._session, session_http=self.session_http
+ )
async def delete_cookie(self, cookie_name):
"""Delete the desired cookie"""
- return await asynchronous.delete_cookie(self._server_url, self._session, cookie_name, session_http=self.session_http)
+ return await asynchronous.delete_cookie(
+ self._server_url, self._session, cookie_name, session_http=self.session_http
+ )
async def get_cookies(self):
"""Get all cookies"""
- return await asynchronous.get_cookies(self._server_url, self._session, session_http=self.session_http)
+ return await asynchronous.get_cookies(
+ self._server_url, self._session, session_http=self.session_http
+ )
async def get_cookie(self, cookie_name):
"""Get the desired cookie"""
- return await asynchronous.get_named_cookie(self._server_url, self._session, cookie_name, session_http=self.session_http)
+ return await asynchronous.get_named_cookie(
+ self._server_url, self._session, cookie_name, session_http=self.session_http
+ )
async def add_cookie(self, cookie):
"""Add a new cookie"""
- return await asynchronous.add_cookie(self._server_url, self._session, cookie, session_http=self.session_http)
+ return await asynchronous.add_cookie(
+ self._server_url, self._session, cookie, session_http=self.session_http
+ )
async def implicitly_wait(self, timeouts: int):
"""Set implicty timeouts"""
- return await asynchronous.set_timeouts(self._server_url, self._session, timeouts, session_http=self.session_http)
+ return await asynchronous.set_timeouts(
+ self._server_url, self._session, timeouts, session_http=self.session_http
+ )
async def back(self):
"""This command causes the browser to traverse one step backward
in the joint session history of the
current browse. This is equivalent to pressing the back button in the browser."""
- return await asynchronous.go_back(self._server_url, self._session, session_http=self.session_http)
+ return await asynchronous.go_back(
+ self._server_url, self._session, session_http=self.session_http
+ )
async def forward(self):
"""Go page forward"""
- return await asynchronous.go_forward(self._server_url, self._session, session_http=self.session_http)
+ return await asynchronous.go_forward(
+ self._server_url, self._session, session_http=self.session_http
+ )
async def refresh(self):
"""Refreshs the page"""
- return await asynchronous.refresh_page(self._server_url, self._session, session_http=self.session_http)
+ return await asynchronous.refresh_page(
+ self._server_url, self._session, session_http=self.session_http
+ )
async def fullscreen_window(self):
"""Sets the page in fullscreen"""
- return await asynchronous.fullscreen_window(self._server_url, self._session, session_http=self.session_http)
+ return await asynchronous.fullscreen_window(
+ self._server_url, self._session, session_http=self.session_http
+ )
async def minimize_window(self):
"""Minimizes the page"""
- return await asynchronous.minimize_window(self._server_url, self._session, session_http=self.session_http)
+ return await asynchronous.minimize_window(
+ self._server_url, self._session, session_http=self.session_http
+ )
async def maximize_window(self):
"""Maximizes the page"""
- return await asynchronous.maximize_window(self._server_url, self._session, session_http=self.session_http)
+ return await asynchronous.maximize_window(
+ self._server_url, self._session, session_http=self.session_http
+ )
async def get(self, url):
"""Navigates to URL `url`"""
await asynchronous.go_to_page(
- self._server_url,
- self._session,
- url,session_http=self.session_http
+ self._server_url, self._session, url, session_http=self.session_http
)
async def find_elements(self, locator, value):
@@ -193,5 +243,7 @@ async def find_elements(self, locator, value):
async def find_element(self, locator, value):
"""Find an element by a 'locator', for example 'xpath'"""
- element = await asynchronous.find_element(self._server_url, self._session, locator, value, session_http=self.session_http)
+ element = await asynchronous.find_element(
+ self._server_url, self._session, locator, value, session_http=self.session_http
+ )
return Element(element, self)
diff --git a/caqui/easy/server.py b/caqui/easy/server.py
index b00bc64..89c1d00 100644
--- a/caqui/easy/server.py
+++ b/caqui/easy/server.py
@@ -8,6 +8,7 @@
from webdriver_manager.chrome import ChromeDriverManager
from caqui.exceptions import ServerError
+
TIMEOUT = 120 # seconds
@@ -25,18 +26,18 @@ class Server:
_instance = None
def __init__(self, browser: Union[DriverManager, None] = None, port=9999):
- self.__browser = browser
- self.__port = port
- self.__process = None
+ self._browser = browser
+ self._port = port
+ self._sprocess = None
- def __browser_factory(self):
- if not self.__browser:
+ def _browser_factory(self):
+ if not self._browser:
driver_manager = ChromeDriverManager().install()
else:
- driver_manager = self.__browser.install()
+ driver_manager = self._browser.install()
return driver_manager
- def __wait_server(self):
+ def _wait_server(self):
MAX_RETIES = 10
for i in range(MAX_RETIES):
try:
@@ -45,8 +46,8 @@ def __wait_server(self):
except ConnectionError:
sleep(0.5)
if i == (MAX_RETIES - 1):
- self.__process.kill()
- self.__process.wait()
+ self._process.kill()
+ self._process.wait()
raise Exception("Driver not started")
@staticmethod
@@ -65,29 +66,29 @@ def start(self):
except Exception:
raise
- driver_manager = self.__browser_factory()
- self.__process = subprocess.Popen(
- [driver_manager, f"--port={self.__port}"],
+ driver_manager = self._browser_factory()
+ self._process = subprocess.Popen(
+ [driver_manager, f"--port={self._port}"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
start_new_session=True,
)
- if self.__process is None:
+ if self._process is None:
raise ServerError("Not able to start the server.")
- self.__wait_server()
+ self._wait_server()
@property
def url(self):
"""
Returns the driver URL.
"""
- return f"http://localhost:{self.__port}"
+ return f"http://localhost:{self._port}"
@property
def process(self):
"""Returns the process (PID)"""
- return self.__process
+ return self._process
def dispose(self, delay: float = 0):
"""
@@ -99,7 +100,7 @@ def dispose(self, delay: float = 0):
"""
if delay:
sleep(delay)
- if self.__process:
- self.__process.kill()
- self.__process.wait()
- self.__process = None
+ if self._process:
+ self._process.kill()
+ self._process.wait()
+ self._process = None
diff --git a/caqui/easy/switch_to.py b/caqui/easy/switch_to.py
index afb539a..4c068d3 100644
--- a/caqui/easy/switch_to.py
+++ b/caqui/easy/switch_to.py
@@ -27,14 +27,20 @@ async def new_window(self, window_type):
self._driver.remote, self._driver.session, window_type, session_http=self._session_http
)
self._window_handle = await asynchronous.switch_to_window(
- self._driver.remote, self._driver.session, self._window_handle, session_http=self._session_http
+ self._driver.remote,
+ self._driver.session,
+ self._window_handle,
+ session_http=self._session_http,
)
return self._window_handle
async def window(self, window_handle):
"""Switchs to window `window_handle`"""
self._window_handle = await asynchronous.switch_to_window(
- self._driver.remote, self._driver.session, window_handle, session_http=self._session_http
+ self._driver.remote,
+ self._driver.session,
+ window_handle,
+ session_http=self._session_http,
)
return self._window_handle
diff --git a/caqui/synchronous.py b/caqui/synchronous.py
index c5ee515..38bb3ed 100644
--- a/caqui/synchronous.py
+++ b/caqui/synchronous.py
@@ -1,12 +1,12 @@
-import requests as __requests
-import json as __json
-from caqui.exceptions import WebDriverError as WebDriverError
-from caqui import helper as __helper
-from caqui.constants import HEADERS as __HEADERS
+from requests import request
+from orjson import dumps
+from caqui.exceptions import WebDriverError
+from caqui import helper
+from caqui.constants import HEADERS
from typing import Optional
-def __handle_response(response):
+def _handle_response(response):
result = None
if response.status_code in range(200, 399):
result = response.json()
@@ -20,43 +20,43 @@ def __handle_response(response):
return result
-def __get(url):
+def _get(url):
try:
- response = __requests.request("GET", url, headers=__HEADERS, data={})
- return __handle_response(response)
- except Exception as error:
- raise WebDriverError("'GET' request failed.") from error
+ response = request("GET", url, headers=HEADERS, data={})
+ return _handle_response(response)
+ except Exception as e:
+ raise WebDriverError("'GET' request failed.") from e
-def __post(url, payload):
+def _post(url, payload):
try:
- response = __requests.request(
- "POST", url, headers=__HEADERS, data=__json.dumps(payload), timeout=60
+ response = request(
+ "POST", url, headers=HEADERS, data= dumps(payload), timeout=60
)
- return __handle_response(response)
- except Exception as error:
- raise WebDriverError("'POST' request failed.") from error
+ return _handle_response(response)
+ except Exception as e:
+ raise WebDriverError("'POST' request failed.") from e
-def __delete(url):
+def _delete(url):
try:
- response = __requests.request("DELETE", url, headers={}, data={})
- return __handle_response(response)
- except Exception as error:
- raise WebDriverError("'DELETE' request failed.") from error
+ response = request("DELETE", url, headers={}, data={})
+ return _handle_response(response)
+ except Exception as e:
+ raise WebDriverError("'DELETE' request failed.") from e
-def __handle_alerts(server_url, session, command):
+def _handle_alerts(server_url, session, command):
url = f"{server_url}/session/{session}/alert/{command}"
payload = {"value": command}
- __post(url, payload)
+ _post(url, payload)
return True
-def __handle_window(server_url, session, command):
+def _handle_window(server_url, session, command):
url = f"{server_url}/session/{session}/window/{command}"
payload = {}
- __post(url, payload)
+ _post(url, payload)
return True
@@ -65,20 +65,20 @@ def add_cookie(server_url, session, cookie):
try:
url = f"{server_url}/session/{session}/cookie"
payload = {"cookie": cookie}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError("Failed to add cookie.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to add cookie.") from e
def delete_cookie(server_url, session, name):
"""Delete cookie by name"""
try:
url = f"{server_url}/session/{session}/cookie/{name}"
- __delete(url)
+ _delete(url)
return True
- except Exception as error:
- raise WebDriverError("Failed to delete cookie '{name}'.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to delete cookie '{name}'.") from e
def refresh_page(server_url, session):
@@ -86,10 +86,10 @@ def refresh_page(server_url, session):
try:
url = f"{server_url}/session/{session}/refresh"
payload = {}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError("Failed to refresh page.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to refresh page.") from e
def go_forward(server_url, session):
@@ -97,10 +97,10 @@ def go_forward(server_url, session):
try:
url = f"{server_url}/session/{session}/forward"
payload = {}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError("Failed to go page forward.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to go page forward.") from e
def set_window_rectangle(server_url, session, width, height, x, y):
@@ -108,34 +108,34 @@ def set_window_rectangle(server_url, session, width, height, x, y):
try:
url = f"{server_url}/session/{session}/window/rect"
payload = {"width": width, "height": height, "x": x, "y": y}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError("Failed to set window rectangle.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to set window rectangle.") from e
def fullscreen_window(server_url, session):
"""Fullscreen window"""
try:
- return __handle_window(server_url, session, command="fullscreen")
- except Exception as error:
- raise WebDriverError("Failed to fullscreen window.") from error
+ return _handle_window(server_url, session, command="fullscreen")
+ except Exception as e:
+ raise WebDriverError("Failed to fullscreen window.") from e
def minimize_window(server_url, session):
"""Minimize window"""
try:
- return __handle_window(server_url, session, command="minimize")
- except Exception as error:
- raise WebDriverError("Failed to minimize window.") from error
+ return _handle_window(server_url, session, command="minimize")
+ except Exception as e:
+ raise WebDriverError("Failed to minimize window.") from e
def maximize_window(server_url, session):
"""Maximize window"""
try:
- return __handle_window(server_url, session, command="maximize")
- except Exception as error:
- raise WebDriverError("Failed to maximize window.") from error
+ return _handle_window(server_url, session, command="maximize")
+ except Exception as e:
+ raise WebDriverError("Failed to maximize window.") from e
def switch_to_window(server_url, session, handle):
@@ -143,10 +143,10 @@ def switch_to_window(server_url, session, handle):
try:
url = f"{server_url}/session/{session}/window"
payload = {"name": handle}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError("Failed to switch to window.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to switch to window.") from e
def new_window(server_url, session, window_type="tab"):
@@ -158,9 +158,9 @@ def new_window(server_url, session, window_type="tab"):
try:
url = f"{server_url}/session/{session}/window/new"
payload = {"type": window_type}
- return __post(url, payload).get("value", {}).get("handle")
- except Exception as error:
- raise WebDriverError("Failed to open a new window.") from error
+ return _post(url, payload).get("value", {}).get("handle")
+ except Exception as e:
+ raise WebDriverError("Failed to open a new window.") from e
def switch_to_parent_frame(server_url, session, element_frame):
@@ -168,10 +168,10 @@ def switch_to_parent_frame(server_url, session, element_frame):
try:
url = f"{server_url}/session/{session}/frame/parent"
payload = {"id": {"ELEMENT": element_frame}}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError("Failed to switch to parent frame.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to switch to parent frame.") from e
def switch_to_frame(server_url, session, element_frame):
@@ -179,20 +179,20 @@ def switch_to_frame(server_url, session, element_frame):
try:
url = f"{server_url}/session/{session}/frame"
payload = {"id": {"ELEMENT": element_frame}}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError("Failed to switch to frame.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to switch to frame.") from e
def delete_all_cookies(server_url, session):
"""Delete all cookies"""
try:
url = f"{server_url}/session/{session}/cookie"
- __delete(url)
+ _delete(url)
return True
- except Exception as error:
- raise WebDriverError("Failed to delete cookies.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to delete cookies.") from e
def send_alert_text(server_url, session, text):
@@ -200,84 +200,84 @@ def send_alert_text(server_url, session, text):
try:
url = f"{server_url}/session/{session}/alert/text"
payload = {"text": text}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError("Failed to sent text to alert.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to sent text to alert.") from e
def accept_alert(server_url, session):
"""Accept an alert"""
try:
- return __handle_alerts(server_url, session, "accept")
- except Exception as error:
- raise WebDriverError("Failed to accept the alert.") from error
+ return _handle_alerts(server_url, session, "accept")
+ except Exception as e:
+ raise WebDriverError("Failed to accept the alert.") from e
def dismiss_alert(server_url, session):
"""Dismiss an alert"""
try:
- return __handle_alerts(server_url, session, "dismiss")
- except Exception as error:
- raise WebDriverError("Failed to dismiss the alert.") from error
+ return _handle_alerts(server_url, session, "dismiss")
+ except Exception as e:
+ raise WebDriverError("Failed to dismiss the alert.") from e
def take_screenshot_element(server_url, session, element, path="/tmp", file_name="caqui"):
"""Take screenshot of element."""
try:
url = f"{server_url}/session/{session}/element/{element}/screenshot"
- response = __get(url).get("value")
- __helper.save_picture(session, path, file_name, response)
+ response = _get(url).get("value")
+ helper.save_picture(session, path, file_name, response)
return True
- except Exception as error:
- raise WebDriverError("Failed to take screeshot.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to take screeshot.") from e
def take_screenshot(server_url, session, path="/tmp", file_name="caqui"):
"""Take screenshot."""
try:
url = f"{server_url}/session/{session}/screenshot"
- response = __get(url).get("value")
- __helper.save_picture(session, path, file_name, response)
+ response = _get(url).get("value")
+ helper.save_picture(session, path, file_name, response)
return True
- except Exception as error:
- raise WebDriverError("Failed to take screeshot.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to take screeshot.") from e
def get_named_cookie(server_url, session, name) -> str:
"""Get cookie by name."""
try:
url = f"{server_url}/session/{session}/cookie/{name}"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError(f"Failed to get the cookie '{name}'.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError(f"Failed to get the cookie '{name}'.") from e
def get_computed_label(server_url, session, element) -> str:
"""Get the element computed label. Get the accessibility name."""
try:
url = f"{server_url}/session/{session}/element/{element}/computedlabel"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to get the element computed label.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to get the element computed label.") from e
def get_computed_role(server_url, session, element) -> str:
"""Get the element computed role (the element role)"""
try:
url = f"{server_url}/session/{session}/element/{element}/computedrole"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to get the element computed role.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to get the element computed role.") from e
def get_tag_name(server_url, session, element) -> str:
"""Get the element tag name"""
try:
url = f"{server_url}/session/{session}/element/{element}/name"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to get the element name.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to get the element name.") from e
def get_shadow_root(server_url, session, element) -> dict:
@@ -285,18 +285,18 @@ def get_shadow_root(server_url, session, element) -> dict:
try:
root_element = "shadow-6066-11e4-a52e-4f735466cecf"
url = f"{server_url}/session/{session}/element/{element}/shadow"
- return __get(url).get("value", {}).get(root_element)
- except Exception as error:
- raise WebDriverError("Failed to get the element shadow.") from error
+ return _get(url).get("value", {}).get(root_element)
+ except Exception as e:
+ raise WebDriverError("Failed to get the element shadow.") from e
def get_rect(server_url, session, element) -> dict:
"""Get the element rectangle"""
try:
url = f"{server_url}/session/{session}/element/{element}/rect"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to get the element rect.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to get the element rect.") from e
def actions_move_to_element(server_url, session, element):
@@ -326,8 +326,8 @@ def actions_move_to_element(server_url, session, element):
]
}
return actions(server_url, session, payload)
- except Exception as error:
- raise WebDriverError("Failed to move to element.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to move to element.") from e
def actions_scroll_to_element(server_url, session, element):
@@ -353,13 +353,13 @@ def actions_scroll_to_element(server_url, session, element):
]
}
return actions(server_url, session, payload)
- except Exception as error:
- raise WebDriverError("Failed to scroll to element.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to scroll to element.") from e
def actions(server_url, session, payload):
url = f"{server_url}/session/{session}/actions"
- __post(url, payload)
+ _post(url, payload)
return True
@@ -376,8 +376,8 @@ def submit(server_url, session, element):
locator_value="//*[@type='submit']",
)
return click(server_url, session, submit_element)
- except Exception as error:
- raise WebDriverError("Failed to submit form.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to submit form.") from e
def actions_click(server_url, session, element):
@@ -413,8 +413,8 @@ def actions_click(server_url, session, element):
]
}
return actions(server_url, session, payload)
- except Exception as error:
- raise WebDriverError("Failed to click the element.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to click the element.") from e
def set_timeouts(server_url, session, timeouts):
@@ -424,10 +424,10 @@ def set_timeouts(server_url, session, timeouts):
payload = {
"implicit": timeouts,
}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError("Failed to set timeouts.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to set timeouts.") from e
def find_children_elements(server_url, session, parent_element, locator_type, locator_value):
@@ -439,12 +439,12 @@ def find_children_elements(server_url, session, parent_element, locator_type, lo
try:
url = f"{server_url}/session/{session}/element/{parent_element}/elements"
payload = {"using": locator_type, "value": locator_value, "id": parent_element}
- response = __post(url, payload)
- return __helper.get_elements(response)
- except Exception as error:
+ response = _post(url, payload)
+ return helper.get_elements(response)
+ except Exception as e:
raise WebDriverError(
f"Failed to find the children elements from '{parent_element}'."
- ) from error
+ ) from e
def find_child_element(server_url, session, parent_element, locator_type, locator_value):
@@ -452,21 +452,21 @@ def find_child_element(server_url, session, parent_element, locator_type, locato
try:
url = f"{server_url}/session/{session}/element/{parent_element}/element"
payload = {"using": locator_type, "value": locator_value, "id": parent_element}
- response = __post(url, payload)
- return __helper.get_element(response)
- except Exception as error:
+ response = _post(url, payload)
+ return helper.get_element(response)
+ except Exception as e:
raise WebDriverError(
f"Failed to find the child element from '{parent_element}'."
- ) from error
+ ) from e
def get_page_source(server_url, session) -> str:
"""Get the page source (all content)"""
try:
url = f"{server_url}/session/{session}/source"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to get the page source.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to get the page source.") from e
def execute_script(server_url, session, script, args=[]):
@@ -474,29 +474,29 @@ def execute_script(server_url, session, script, args=[]):
try:
url = f"{server_url}/session/{session}/execute/sync"
payload = {"script": script, "args": args}
- response = __post(url, payload)
+ response = _post(url, payload)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to run the script.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to run the script.") from e
def get_alert_text(server_url, session) -> str:
"""Get the text from an alert"""
try:
url = f"{server_url}/session/{session}/alert/text"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to get the alert text.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to get the alert text.") from e
def get_active_element(server_url, session):
"""Get the active element"""
try:
url = f"{server_url}/session/{session}/element/active"
- response = __get(url)
- return __helper.get_element(response)
- except Exception as error:
- raise WebDriverError("Failed to get the active element.") from error
+ response = _get(url)
+ return helper.get_element(response)
+ except Exception as e:
+ raise WebDriverError("Failed to get the active element.") from e
def clear_element(server_url, session, element):
@@ -504,73 +504,73 @@ def clear_element(server_url, session, element):
try:
url = f"{server_url}/session/{session}/element/{element}/clear"
payload = {"id": element}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError("Failed to clear the element text.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to clear the element text.") from e
def is_element_enabled(server_url, session, element) -> bool:
"""Check if element is enabled"""
try:
url = f"{server_url}/session/{session}/element/{element}/enabled"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to check if element is enabled.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to check if element is enabled.") from e
def get_css_value(server_url, session, element, property_name) -> str:
"""Get the css property value"""
try:
url = f"{server_url}/session/{session}/element/{element}/css/{property_name}"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to get the css property value.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to get the css property value.") from e
def is_element_selected(server_url, session, element) -> bool:
"""Check if element is selected"""
try:
url = f"{server_url}/session/{session}/element/{element}/selected"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to check if element is selected.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to check if element is selected.") from e
def get_window_rectangle(server_url, session) -> dict:
"""Get window rectangle"""
try:
url = f"{server_url}/session/{session}/window/rect"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to get window rectangle.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to get window rectangle.") from e
def get_window_handles(server_url, session):
"""Get window handles"""
try:
url = f"{server_url}/session/{session}/window/handles"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to get window handles.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to get window handles.") from e
def close_window(server_url, session) -> list:
"""Close active window"""
try:
url = f"{server_url}/session/{session}/window"
- return __delete(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to close active window.") from error
+ return _delete(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to close active window.") from e
def get_window(server_url, session) -> str:
"""Get window"""
try:
url = f"{server_url}/session/{session}/window"
- return __get(url).get("value")
- except Exception as error:
- raise WebDriverError("Failed to get window.") from error
+ return _get(url).get("value")
+ except Exception as e:
+ raise WebDriverError("Failed to get window.") from e
def go_back(server_url, session):
@@ -581,20 +581,20 @@ def go_back(server_url, session):
"""
try:
url = f"{server_url}/session/{session}/back"
- __post(url, {})
+ _post(url, {})
return True
- except Exception as error:
- raise WebDriverError("Failed to go back to page.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to go back to page.") from e
def get_url(server_url, session) -> str:
"""Return the URL from web page:"""
try:
url = f"{server_url}/session/{session}/url"
- response = __get(url)
+ response = _get(url)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get page url.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get page url.") from e
def get_timeouts(server_url, session) -> dict:
@@ -604,29 +604,29 @@ def get_timeouts(server_url, session) -> dict:
"""
try:
url = f"{server_url}/session/{session}/timeouts"
- response = __get(url)
+ response = _get(url)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get timeouts.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get timeouts.") from e
def get_status(server_url) -> dict:
"""Return the status and details of the WebDriver:"""
try:
url = f"{server_url}/status"
- return __get(url)
- except Exception as error:
- raise WebDriverError("Failed to get status.") from error
+ return _get(url)
+ except Exception as e:
+ raise WebDriverError("Failed to get status.") from e
def get_title(server_url, session) -> str:
"""Get the page title"""
try:
url = f"{server_url}/session/{session}/title"
- response = __get(url)
+ response = _get(url)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get page title.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get page title.") from e
def find_elements(server_url, session, locator_type, locator_value) -> list:
@@ -634,42 +634,42 @@ def find_elements(server_url, session, locator_type, locator_value) -> list:
try:
url = f"{server_url}/session/{session}/elements"
payload = {"using": locator_type, "value": locator_value}
- response = __post(url, payload)
+ response = _post(url, payload)
return [x.get("ELEMENT") for x in response.get("value")]
- except Exception as error:
+ except Exception as e:
raise WebDriverError(
f"Failed to find elements by '{locator_type}'-'{locator_value}'."
- ) from error
+ ) from e
def get_property(server_url, session, element, property_name) -> str:
"""Get the given HTML property of an element, for example, 'href'"""
try:
url = f"{server_url}/session/{session}/element/{element}/property/{property_name}"
- response = __get(url)
+ response = _get(url)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get value from element.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get value from element.") from e
def get_attribute(server_url, session, element, attribute) -> str:
"""Get the given HTML attribute of an element, for example, 'aria-valuenow'"""
try:
url = f"{server_url}/session/{session}/element/{element}/attribute/{attribute}"
- response = __get(url)
+ response = _get(url)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get value from element.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get value from element.") from e
def get_cookies(server_url, session) -> list:
"""Get the page cookies"""
try:
url = f"{server_url}/session/{session}/cookie"
- response = __get(url)
+ response = _get(url)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get page cookies.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get page cookies.") from e
def get(server_url, session, page_url):
@@ -682,30 +682,30 @@ def go_to_page(server_url, session, page_url):
try:
url = f"{server_url}/session/{session}/url"
payload = {"url": page_url}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError(f"Failed to navigate to '{page_url}'") from error
+ except Exception as e:
+ raise WebDriverError(f"Failed to navigate to '{page_url}'") from e
def close_session(server_url, session):
"""Close an opened session and close the browser"""
try:
url = f"{server_url}/session/{session}"
- __delete(url)
+ _delete(url)
return True
- except Exception as error:
- raise WebDriverError("Failed to close session.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to close session.") from e
def get_text(server_url, session, element) -> str:
"""Get the text of an element"""
try:
url = f"{server_url}/session/{session}/element/{element}/text"
- response = __get(url)
+ response = _get(url)
return response.get("value")
- except Exception as error:
- raise WebDriverError("Failed to get text from element.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to get text from element.") from e
def send_keys(server_url, session, element, text):
@@ -713,10 +713,10 @@ def send_keys(server_url, session, element, text):
try:
url = f"{server_url}/session/{session}/element/{element}/value"
payload = {"text": text, "value": [*text], "id": element}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError(f"Failed to send key '{text}'.") from error
+ except Exception as e:
+ raise WebDriverError(f"Failed to send key '{text}'.") from e
def click(server_url, session, element):
@@ -724,13 +724,13 @@ def click(server_url, session, element):
try:
url = f"{server_url}/session/{session}/element/{element}/click"
payload = {"id": element}
- __post(url, payload)
+ _post(url, payload)
return True
- except Exception as error:
- raise WebDriverError("Failed to click on element.") from error
+ except Exception as e:
+ raise WebDriverError("Failed to click on element.") from e
-def __get_session(response) -> str:
+def _get_session(response) -> str:
# Firefox response
value = response.get("value")
session_id = value.get("sessionId")
@@ -750,10 +750,10 @@ def get_session(server_url: str, capabilities: Optional[dict] = None):
url = f"{server_url}/session"
if not capabilities:
capabilities = {}
- response = __post(url, payload=capabilities)
- return __get_session(response)
- except Exception as error:
- raise WebDriverError("Failed to open session. Check the browser capabilities.") from error
+ response = _post(url, payload=capabilities)
+ return _get_session(response)
+ except Exception as e:
+ raise WebDriverError("Failed to open session. Check the browser capabilities.") from e
def find_element(server_url, session, locator_type, locator_value) -> dict:
@@ -761,15 +761,15 @@ def find_element(server_url, session, locator_type, locator_value) -> dict:
try:
url = f"{server_url}/session/{session}/element"
payload = {"using": locator_type, "value": locator_value}
- response = __post(url, payload)
+ response = _post(url, payload)
# Firefox does not support id locator, so it prints the error message to the user
# It helps on debug
if response.get("value").get("error"):
raise WebDriverError(f"Failed to find element. {response}")
- return __helper.get_element(response)
- except Exception as error:
+ return helper.get_element(response)
+ except Exception as e:
raise WebDriverError(
f"Failed to find element by '{locator_type}'-'{locator_value}'."
- ) from error
+ ) from e
diff --git a/dev-requirements.txt b/dev-requirements.txt
index 0267580..9d9ca4f 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -1,4 +1,5 @@
requests
aiohttp
webdriver_manager
-types-requests
\ No newline at end of file
+types-requests
+orjson
\ No newline at end of file
diff --git a/samples/sample-web-driver.py b/samples/sample-web-driver.py
index 1e7b9f5..13295a6 100644
--- a/samples/sample-web-driver.py
+++ b/samples/sample-web-driver.py
@@ -28,7 +28,7 @@ async def get_all_links(server):
all_anchors = []
for i in range(4):
i += 1
- anchors = await __get_links(server_url, session, i)
+ anchors = await _get_links(server_url, session, i)
all_anchors.extend(anchors)
for anchor in all_anchors:
@@ -38,7 +38,7 @@ async def get_all_links(server):
synchronous.close_session(server_url, session)
-async def __get_links(server_url, session, i):
+async def _get_links(server_url, session, i):
locator_value = f"//a[@id='a{i}']"
locator_type = "xpath"
anchors = []
diff --git a/tests/conftest.py b/tests/conftest.py
index f4830e8..4a1d562 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -13,7 +13,7 @@
CAPTURES = "captures"
-def __build_capabilities():
+def _build_capabilities():
options = ChromeOptionsBuilder().args(["headless"])
capabilities = (
ChromeCapabilitiesBuilder()
@@ -28,14 +28,14 @@ def __build_capabilities():
def setup_server():
server = Server.get_instance(port=SERVER_PORT)
server.start()
- yield
- server.dispose(delay=3)
+ # yield
+ # server.dispose(delay=3)
@fixture
def setup_functional_environment():
server_url = SERVER_URL
- capabilities = __build_capabilities()
+ capabilities = _build_capabilities()
session = synchronous.get_session(server_url, capabilities)
synchronous.go_to_page(
server_url,
@@ -50,10 +50,11 @@ def setup_functional_environment():
finally:
synchronous.close_session(server_url, session)
+
@pytest_asyncio.fixture
async def setup_environment():
server_url = SERVER_URL
- capabilities = __build_capabilities()
+ capabilities = _build_capabilities()
async with ClientSession() as session_http:
page = AsyncPage(server_url, capabilities, PAGE_URL, session_http=session_http)
yield page
diff --git a/tests/feature/test_async_with_http_session.py b/tests/feature/test_async_with_http_session.py
index d35c5fc..60e150e 100644
--- a/tests/feature/test_async_with_http_session.py
+++ b/tests/feature/test_async_with_http_session.py
@@ -4,84 +4,10 @@
from caqui.exceptions import WebDriverError
from caqui.by import By
from tests.constants import COOKIE
-from caqui.easy import AsyncPage
-from tests.constants import PAGE_URL
from pytest import mark
from tests.constants import COOKIE
-@mark.asyncio
-async def test_big_scenario_of_functions_with_session_http(setup_environment: AsyncPage):
- page = setup_environment
- await page.implicitly_wait(10)
-
- # Need to navigate to a web page. If use 'playgound.html' the error
- # 'Document is cookie-averse' happens
- await page.get(
- "https://example.org/",
- )
- cookies = COOKIE
- await page.add_cookie(cookies)
- cookie = (await page.get_cookies())[0]
- cookie["name"] = "other"
- await page.add_cookie(cookie)
- await page.delete_cookie("other")
- await page.delete_all_cookies()
- await page.get(
- PAGE_URL,
- )
-
- await page.switch_to.active_element.get_attribute("value")
- element = await page.find_element(By.XPATH, "//a")
- # Returns and base64 encoded string into image
- await element.screenshot("/tmp/image.png")
-
- await page.back()
- await page.forward()
- await page.refresh()
-
- alert_element = await page.find_element(By.CSS_SELECTOR, "#alert-button-prompt")
- await alert_element.click()
- alert_object = page.switch_to.alert
- await page.alert.accept()
-
- await alert_element.click()
- await alert_object.send_keys("Caqui")
- await alert_object.dismiss()
-
- iframe = await page.find_element(By.ID, "my-iframe")
- # switch to selected iframe
- await page.switch_to.frame(iframe)
- await page.switch_to.default_content()
- # switching to second iframe based on index
- iframe = (await page.find_elements(By.ID, "my-iframe"))[0]
-
- # switch to selected iframe
- await page.switch_to.frame(iframe)
- # switch back to default content
- await page.switch_to.default_content()
-
- window_handle = page.current_window_handle
- assert len(page.window_handles) >= 1
- await page.switch_to.window(window_handle)
- # Opens a new tab and switches to new tab
- await page.switch_to.new_window("tab")
- # Opens a new window and switches to new window
- await page.switch_to.new_window("window")
-
- # Access each dimension individually
- await page.set_window_size(1024, 768)
- # Move the window to the top left of the primary monitor
- await page.set_window_position(0, 0)
- await page.maximize_window()
- # await driver.minimize_window() # does not work on headless mode
- await page.save_screenshot("/tmp/image.png")
-
- # Executing JavaScript to capture innerText of header element
- await page.execute_script('alert("any warn")')
-
-
-
@mark.asyncio
async def test_add_cookie(setup_functional_environment):
server_url, session = setup_functional_environment
@@ -103,9 +29,7 @@ async def test_add_cookie(setup_functional_environment):
async with ClientSession() as session_http:
assert (
- await asynchronous.add_cookie(
- server_url, session, cookie, session_http=session_http
- )
+ await asynchronous.add_cookie(server_url, session, cookie, session_http=session_http)
is True
)
cookies_after = synchronous.get_cookies(server_url, session)
@@ -122,9 +46,7 @@ async def test_delete_cookie_asynchronous(setup_functional_environment):
async with ClientSession() as session_http:
assert (
- await asynchronous.delete_cookie(
- server_url, session, name, session_http=session_http
- )
+ await asynchronous.delete_cookie(server_url, session, name, session_http=session_http)
is True
)
cookies = synchronous.get_cookies(server_url, session)
@@ -163,10 +85,7 @@ async def test_refresh_page(setup_functional_environment):
element_before = element_after
async with ClientSession() as session_http:
assert (
- await asynchronous.refresh_page(
- server_url, session, session_http=session_http
- )
- is True
+ await asynchronous.refresh_page(server_url, session, session_http=session_http) is True
)
element_after = synchronous.find_element(server_url, session, By.XPATH, "//input")
@@ -190,12 +109,7 @@ async def test_go_forward(setup_functional_environment):
synchronous.go_back(server_url, session)
async with ClientSession() as session_http:
- assert (
- await asynchronous.go_forward(
- server_url, session, session_http=session_http
- )
- is True
- )
+ assert await asynchronous.go_forward(server_url, session, session_http=session_http) is True
assert synchronous.get_title(server_url, session) == title
@@ -208,10 +122,7 @@ async def test_set_window_rectangle(setup_functional_environment):
x = window_rectangle_before.get("x") + 1
y = window_rectangle_before.get("y") + 1
- assert (
- synchronous.set_window_rectangle(server_url, session, width, height, x, y)
- is True
- )
+ assert synchronous.set_window_rectangle(server_url, session, width, height, x, y) is True
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
@@ -256,9 +167,7 @@ async def test_fullscreen_window(setup_functional_environment):
async with ClientSession() as session_http:
assert (
- await asynchronous.fullscreen_window(
- server_url, session, session_http=session_http
- )
+ await asynchronous.fullscreen_window(server_url, session, session_http=session_http)
is True
)
@@ -286,9 +195,7 @@ async def test_minimize_window(setup_functional_environment):
async with ClientSession() as session_http:
assert (
- await asynchronous.minimize_window(
- server_url, session, session_http=session_http
- )
+ await asynchronous.minimize_window(server_url, session, session_http=session_http)
is True
)
@@ -307,9 +214,7 @@ async def test_maximize_window_asynchronous(setup_functional_environment):
async with ClientSession() as session_http:
assert (
- await asynchronous.maximize_window(
- server_url, session, session_http=session_http
- )
+ await asynchronous.maximize_window(server_url, session, session_http=session_http)
is True
)
@@ -381,9 +286,7 @@ async def test_switch_to_parent_frame_asynchronous(setup_functional_environment)
locator_type = By.ID
locator_value = "my-iframe"
- element_frame = synchronous.find_element(
- server_url, session, locator_type, locator_value
- )
+ element_frame = synchronous.find_element(server_url, session, locator_type, locator_value)
async with ClientSession() as session_http:
assert (
await asynchronous.switch_to_parent_frame(
@@ -398,12 +301,8 @@ def test_switch_to_parent_frame_synchronous(setup_functional_environment):
locator_type = By.ID
locator_value = "my-iframe"
- element_frame = synchronous.find_element(
- server_url, session, locator_type, locator_value
- )
- assert (
- synchronous.switch_to_parent_frame(server_url, session, element_frame) is True
- )
+ element_frame = synchronous.find_element(server_url, session, locator_type, locator_value)
+ assert synchronous.switch_to_parent_frame(server_url, session, element_frame) is True
@mark.asyncio
@@ -412,12 +311,13 @@ async def test_switch_to_frame_asynchronous(setup_functional_environment):
locator_type = By.ID
locator_value = "my-iframe"
- element_frame = synchronous.find_element(
- server_url, session, locator_type, locator_value
- )
+ element_frame = synchronous.find_element(server_url, session, locator_type, locator_value)
async with ClientSession() as session_http:
assert (
- await asynchronous.switch_to_frame(server_url, session, element_frame, session_http=session_http) is True
+ await asynchronous.switch_to_frame(
+ server_url, session, element_frame, session_http=session_http
+ )
+ is True
)
@@ -426,9 +326,7 @@ def test_switch_to_frame_synchronous(setup_functional_environment):
locator_type = By.ID
locator_value = "my-iframe"
- element_frame = synchronous.find_element(
- server_url, session, locator_type, locator_value
- )
+ element_frame = synchronous.find_element(server_url, session, locator_type, locator_value)
assert synchronous.switch_to_frame(server_url, session, element_frame) is True
@@ -446,7 +344,12 @@ async def test_send_alert_text(setup_functional_environment):
synchronous.click(server_url, session, element)
async with ClientSession() as session_http:
- assert await asynchronous.send_alert_text(server_url, session, "any2", session_http=session_http) is True
+ assert (
+ await asynchronous.send_alert_text(
+ server_url, session, "any2", session_http=session_http
+ )
+ is True
+ )
synchronous.accept_alert(server_url, session) is True
@@ -463,7 +366,9 @@ async def test_accept_alert(setup_functional_environment):
synchronous.click(server_url, session, element)
async with ClientSession() as session_http:
- assert await asynchronous.accept_alert(server_url, session, session_http=session_http) is True
+ assert (
+ await asynchronous.accept_alert(server_url, session, session_http=session_http) is True
+ )
@mark.asyncio
@@ -479,7 +384,9 @@ async def test_dismiss_alert(setup_functional_environment):
synchronous.click(server_url, session, element)
async with ClientSession() as session_http:
- assert await asynchronous.dismiss_alert(server_url, session, session_http=session_http) is True
+ assert (
+ await asynchronous.dismiss_alert(server_url, session, session_http=session_http) is True
+ )
@mark.asyncio
@@ -507,9 +414,7 @@ async def test_take_screenshot(setup_functional_environment):
assert synchronous.take_screenshot(server_url, session) is True
async with ClientSession() as session_http:
assert (
- await asynchronous.take_screenshot(
- server_url, session, session_http=session_http
- )
+ await asynchronous.take_screenshot(server_url, session, session_http=session_http)
is True
)
@@ -522,7 +427,9 @@ async def test_delete_cookies_asynchronous(setup_functional_environment):
cookies_before = synchronous.get_cookies(server_url, session)
async with ClientSession() as session_http:
- response = await asynchronous.delete_all_cookies(server_url, session, session_http=session_http)
+ response = await asynchronous.delete_all_cookies(
+ server_url, session, session_http=session_http
+ )
assert response is True
cookies_after = synchronous.get_cookies(server_url, session)
@@ -549,11 +456,11 @@ async def test_get_named_cookie(setup_functional_environment):
name = "username" # cookie created on page load
expected = "John Doe"
- assert (
- synchronous.get_named_cookie(server_url, session, name).get("value") == expected
- )
+ assert synchronous.get_named_cookie(server_url, session, name).get("value") == expected
async with ClientSession() as session_http:
- response = await asynchronous.get_named_cookie(server_url, session, name, session_http=session_http)
+ response = await asynchronous.get_named_cookie(
+ server_url, session, name, session_http=session_http
+ )
assert response.get("value") == expected
@@ -570,7 +477,10 @@ async def test_get_computed_label(setup_functional_environment):
async with ClientSession() as session_http:
assert (
- await asynchronous.get_computed_label(server_url, session, element, session_http=session_http) == expected
+ await asynchronous.get_computed_label(
+ server_url, session, element, session_http=session_http
+ )
+ == expected
)
@@ -587,7 +497,10 @@ async def test_get_computed_role(setup_functional_environment):
async with ClientSession() as session_http:
assert (
- await asynchronous.get_computed_role(server_url, session, element, session_http=session_http) == expected
+ await asynchronous.get_computed_role(
+ server_url, session, element, session_http=session_http
+ )
+ == expected
)
@@ -602,16 +515,15 @@ async def test_get_tag_name(setup_functional_environment):
assert synchronous.get_tag_name(server_url, session, element) == expected
async with ClientSession() as session_http:
- assert await asynchronous.get_tag_name(server_url, session, element, session_http=session_http) == expected
+ assert (
+ await asynchronous.get_tag_name(server_url, session, element, session_http=session_http)
+ == expected
+ )
-@mark.parametrize(
- "locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")]
-)
+@mark.parametrize("locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")])
@mark.asyncio
-async def test_find_element_from_shadow_root(
- setup_functional_environment, locator, value
-):
+async def test_find_element_from_shadow_root(setup_functional_environment, locator, value):
server_url, session = setup_functional_environment
locator_type = By.ID
locator_value = "shadow-root"
@@ -620,9 +532,7 @@ async def test_find_element_from_shadow_root(
shadow_root = synchronous.get_shadow_root(server_url, session, element)
- actual = synchronous.find_child_element(
- server_url, session, shadow_root, locator, value
- )
+ actual = synchronous.find_child_element(server_url, session, shadow_root, locator, value)
assert actual is not None
async with ClientSession() as session_http:
@@ -633,13 +543,9 @@ async def test_find_element_from_shadow_root(
assert actual is not None
-@mark.parametrize(
- "locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")]
-)
+@mark.parametrize("locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")])
@mark.asyncio
-async def test_find_elements_from_shadow_root(
- setup_functional_environment, locator, value
-):
+async def test_find_elements_from_shadow_root(setup_functional_environment, locator, value):
server_url, session = setup_functional_environment
locator_type = By.ID
locator_value = "shadow-root"
@@ -649,9 +555,7 @@ async def test_find_elements_from_shadow_root(
shadow_root = synchronous.get_shadow_root(server_url, session, element)
- actual = synchronous.find_children_elements(
- server_url, session, shadow_root, locator, value
- )
+ actual = synchronous.find_children_elements(server_url, session, shadow_root, locator, value)
assert len(actual) == one
@@ -674,7 +578,9 @@ async def test_get_shadow_root(setup_functional_environment):
assert synchronous.get_shadow_root(server_url, session, element) is not None
async with ClientSession() as session_http:
- response = await asynchronous.get_shadow_root(server_url, session, element, session_http=session_http)
+ response = await asynchronous.get_shadow_root(
+ server_url, session, element, session_http=session_http
+ )
assert response is not None
@@ -689,7 +595,10 @@ async def test_get_rect(setup_functional_environment):
assert synchronous.get_rect(server_url, session, element) == expected
async with ClientSession() as session_http:
- assert await asynchronous.get_rect(server_url, session, element, session_http=session_http) == expected
+ assert (
+ await asynchronous.get_rect(server_url, session, element, session_http=session_http)
+ == expected
+ )
@mark.asyncio
@@ -702,7 +611,10 @@ async def test_move_to_element(setup_functional_environment):
assert synchronous.actions_move_to_element(server_url, session, element) is True
async with ClientSession() as session_http:
assert (
- await asynchronous.actions_move_to_element(server_url, session, element, session_http=session_http) is True
+ await asynchronous.actions_move_to_element(
+ server_url, session, element, session_http=session_http
+ )
+ is True
)
@@ -716,7 +628,9 @@ async def test_actions_scroll_to_element(setup_functional_environment):
assert synchronous.actions_scroll_to_element(server_url, session, element) is True
async with ClientSession() as session_http:
assert (
- await asynchronous.actions_scroll_to_element(server_url, session, element, session_http=session_http)
+ await asynchronous.actions_scroll_to_element(
+ server_url, session, element, session_http=session_http
+ )
is True
)
@@ -733,7 +647,10 @@ async def test_submit(setup_functional_environment):
synchronous.refresh_page(server_url, session)
element = synchronous.find_element(server_url, session, locator_type, locator_value)
async with ClientSession() as session_http:
- assert await asynchronous.submit(server_url, session, element, session_http=session_http) is True
+ assert (
+ await asynchronous.submit(server_url, session, element, session_http=session_http)
+ is True
+ )
@mark.asyncio
@@ -745,7 +662,12 @@ async def test_actions_click(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
assert synchronous.actions_click(server_url, session, element) is True
async with ClientSession() as session_http:
- assert await asynchronous.actions_click(server_url, session, element,session_http=session_http) is True
+ assert (
+ await asynchronous.actions_click(
+ server_url, session, element, session_http=session_http
+ )
+ is True
+ )
@mark.asyncio
@@ -797,7 +719,12 @@ async def test_find_children_elements(setup_functional_environment):
assert len(children_elements) > expected
async with ClientSession() as session_http:
children_elements = await asynchronous.find_children_elements(
- server_url, session, parent_element, locator_type, locator_value, session_http=session_http
+ server_url,
+ session,
+ parent_element,
+ locator_type,
+ locator_value,
+ session_http=session_http,
)
assert len(children_elements) > expected
@@ -823,7 +750,12 @@ async def test_find_child_element(setup_functional_environment):
assert text == expected
async with ClientSession() as session_http:
child_element = await asynchronous.find_child_element(
- server_url, session, parent_element, locator_type, locator_value, session_http=session_http
+ server_url,
+ session,
+ parent_element,
+ locator_type,
+ locator_value,
+ session_http=session_http,
)
text = synchronous.get_text(server_url, session, child_element)
assert text == expected
@@ -836,7 +768,9 @@ async def test_get_page_source(setup_functional_environment):
assert expected in synchronous.get_page_source(server_url, session)
async with ClientSession() as session_http:
- assert expected in await asynchronous.get_page_source(server_url, session, session_http=session_http)
+ assert expected in await asynchronous.get_page_source(
+ server_url, session, session_http=session_http
+ )
@mark.asyncio
@@ -844,7 +778,12 @@ async def test_execute_script_asynchronous(setup_functional_environment):
server_url, session = setup_functional_environment
script = "alert('any warn')"
async with ClientSession() as session_http:
- assert await asynchronous.execute_script(server_url, session, script, session_http=session_http) is None
+ assert (
+ await asynchronous.execute_script(
+ server_url, session, script, session_http=session_http
+ )
+ is None
+ )
def test_execute_script_synchronous(setup_functional_environment):
@@ -860,14 +799,15 @@ async def test_get_alert_text(setup_functional_environment):
locator_value = "#alert-button"
expected = "any warn"
- alert_button = synchronous.find_element(
- server_url, session, locator_type, locator_value
- )
+ alert_button = synchronous.find_element(server_url, session, locator_type, locator_value)
synchronous.click(server_url, session, alert_button)
assert synchronous.get_alert_text(server_url, session) == expected
async with ClientSession() as session_http:
- assert await asynchronous.get_alert_text(server_url, session, session_http=session_http) == expected
+ assert (
+ await asynchronous.get_alert_text(server_url, session, session_http=session_http)
+ == expected
+ )
@mark.asyncio
@@ -881,7 +821,10 @@ async def test_get_active_element(setup_functional_environment):
assert synchronous.get_active_element(server_url, session) == element
async with ClientSession() as session_http:
- assert await asynchronous.get_active_element(server_url, session, session_http=session_http) == element
+ assert (
+ await asynchronous.get_active_element(server_url, session, session_http=session_http)
+ == element
+ )
@mark.asyncio
@@ -894,7 +837,9 @@ async def test_clear_element_fails_when_invalid_inputs(setup_functional_environm
with raises(WebDriverError):
async with ClientSession() as session_http:
- await asynchronous.clear_element(server_url, session, element, session_http=session_http)
+ await asynchronous.clear_element(
+ server_url, session, element, session_http=session_http
+ )
@mark.asyncio
@@ -910,7 +855,12 @@ async def test_clear_element(setup_functional_environment):
synchronous.send_keys(server_url, session, element, text)
async with ClientSession() as session_http:
- assert await asynchronous.clear_element(server_url, session, element, session_http=session_http) is True
+ assert (
+ await asynchronous.clear_element(
+ server_url, session, element, session_http=session_http
+ )
+ is True
+ )
@mark.asyncio
@@ -923,7 +873,12 @@ async def test_is_element_enabled(setup_functional_environment):
assert synchronous.is_element_enabled(server_url, session, element) is True
async with ClientSession() as session_http:
- assert await asynchronous.is_element_enabled(server_url, session, element, session_http=session_http) is True
+ assert (
+ await asynchronous.is_element_enabled(
+ server_url, session, element, session_http=session_http
+ )
+ is True
+ )
@mark.asyncio
@@ -936,13 +891,12 @@ async def test_get_css_value(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
- assert (
- synchronous.get_css_value(server_url, session, element, property_name)
- == expected
- )
+ assert synchronous.get_css_value(server_url, session, element, property_name) == expected
async with ClientSession() as session_http:
assert (
- await asynchronous.get_css_value(server_url, session, element, property_name, session_http=session_http)
+ await asynchronous.get_css_value(
+ server_url, session, element, property_name, session_http=session_http
+ )
== expected
)
@@ -957,8 +911,12 @@ async def test_is_element_selected(setup_functional_environment):
assert synchronous.is_element_selected(server_url, session, element) is False
async with ClientSession() as session_http:
- assert await asynchronous.is_element_selected(server_url, session, element, session_http=session_http) is False
-
+ assert (
+ await asynchronous.is_element_selected(
+ server_url, session, element, session_http=session_http
+ )
+ is False
+ )
@mark.asyncio
@@ -968,7 +926,9 @@ async def test_get_window_rectangle(setup_functional_environment):
assert expected in synchronous.get_window_rectangle(server_url, session)
async with ClientSession() as session_http:
- rectangle = await asynchronous.get_window_rectangle(server_url, session, session_http=session_http)
+ rectangle = await asynchronous.get_window_rectangle(
+ server_url, session, session_http=session_http
+ )
assert expected in rectangle
@@ -978,7 +938,9 @@ async def test_get_window_handles(setup_functional_environment):
assert isinstance(synchronous.get_window_handles(server_url, session), list)
async with ClientSession() as session_http:
- handles = await asynchronous.get_window_handles(server_url, session, session_http=session_http)
+ handles = await asynchronous.get_window_handles(
+ server_url, session, session_http=session_http
+ )
assert isinstance(handles, list)
@@ -1001,7 +963,10 @@ async def test_get_window(setup_functional_environment):
assert synchronous.get_window(server_url, session) is not None
async with ClientSession() as session_http:
- assert await asynchronous.get_window(server_url, session, session_http=session_http) is not None
+ assert (
+ await asynchronous.get_window(server_url, session, session_http=session_http)
+ is not None
+ )
@mark.asyncio
@@ -1015,7 +980,9 @@ async def test_get_attribute_fails_when_invalid_attribute(setup_functional_envir
with raises(WebDriverError):
async with ClientSession() as session_http:
- await asynchronous.get_attribute(server_url, session, element, attribute, session_http=session_http)
+ await asynchronous.get_attribute(
+ server_url, session, element, attribute, session_http=session_http
+ )
@mark.asyncio
@@ -1024,13 +991,12 @@ async def test_get_attribute(setup_functional_environment):
attribute = "href"
element = synchronous.find_element(server_url, session, By.XPATH, "//a[@id='a1']")
- assert (
- synchronous.get_attribute(server_url, session, element, attribute)
- == "http://any1.com/"
- )
+ assert synchronous.get_attribute(server_url, session, element, attribute) == "http://any1.com/"
async with ClientSession() as session_http:
assert (
- await asynchronous.get_attribute(server_url, session, element, attribute, session_http=session_http)
+ await asynchronous.get_attribute(
+ server_url, session, element, attribute, session_http=session_http
+ )
== "http://any1.com/"
)
@@ -1065,7 +1031,9 @@ async def test_get_url(setup_functional_environment):
assert expected in synchronous.get_url(server_url, session)
async with ClientSession() as session_http:
- assert expected in await asynchronous.get_url(server_url, session, session_http=session_http)
+ assert expected in await asynchronous.get_url(
+ server_url, session, session_http=session_http
+ )
@mark.asyncio
@@ -1075,7 +1043,9 @@ async def test_get_timeouts(setup_functional_environment):
assert expected in synchronous.get_timeouts(server_url, session)
async with ClientSession() as session_http:
- assert expected in await asynchronous.get_timeouts(server_url, session, session_http=session_http)
+ assert expected in await asynchronous.get_timeouts(
+ server_url, session, session_http=session_http
+ )
@mark.asyncio
@@ -1095,7 +1065,9 @@ async def test_get_title(setup_functional_environment):
assert synchronous.get_title(server_url, session) == expected
async with ClientSession() as session_http:
- assert await asynchronous.get_title(server_url, session, session_http=session_http) == expected
+ assert (
+ await asynchronous.get_title(server_url, session, session_http=session_http) == expected
+ )
@mark.asyncio
@@ -1122,9 +1094,7 @@ async def test_find_elements(setup_functional_environment):
locator_type = By.XPATH
locator_value = "//input"
- elements = synchronous.find_elements(
- server_url, session, locator_type, locator_value
- )
+ elements = synchronous.find_elements(server_url, session, locator_type, locator_value)
async with ClientSession() as session_http:
async_elements = await asynchronous.find_elements(
server_url, session, locator_type, locator_value, session_http=session_http
@@ -1156,10 +1126,7 @@ async def test_find_element(setup_functional_environment):
locator_type = By.XPATH
locator_value = "//input"
- assert (
- synchronous.find_element(server_url, session, locator_type, locator_value)
- is not None
- )
+ assert synchronous.find_element(server_url, session, locator_type, locator_value) is not None
async with ClientSession() as session_http:
assert (
await asynchronous.find_element(
@@ -1200,9 +1167,7 @@ async def test_get_text(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
async with ClientSession() as session_http:
assert (
- await asynchronous.get_text(
- server_url, session, element, session_http=session_http
- )
+ await asynchronous.get_text(server_url, session, element, session_http=session_http)
== expected
)
assert synchronous.get_text(server_url, session, element) == expected
@@ -1237,9 +1202,7 @@ async def test_click(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
async with ClientSession() as session_http:
assert (
- await asynchronous.click(
- server_url, session, element, session_http=session_http
- )
+ await asynchronous.click(server_url, session, element, session_http=session_http)
is True
)
assert synchronous.click(server_url, session, element) is True
diff --git a/tests/feature/test_sync_and_async.py b/tests/feature/test_sync_and_async.py
index b02cee9..389c402 100644
--- a/tests/feature/test_sync_and_async.py
+++ b/tests/feature/test_sync_and_async.py
@@ -108,10 +108,7 @@ async def test_set_window_rectangle(setup_functional_environment):
x = window_rectangle_before.get("x") + 1
y = window_rectangle_before.get("y") + 1
- assert (
- synchronous.set_window_rectangle(server_url, session, width, height, x, y)
- is True
- )
+ assert synchronous.set_window_rectangle(server_url, session, width, height, x, y) is True
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
@@ -122,12 +119,7 @@ async def test_set_window_rectangle(setup_functional_environment):
synchronous.maximize_window(server_url, session)
- assert (
- await asynchronous.set_window_rectangle(
- server_url, session, width, height, x, y
- )
- is True
- )
+ assert await asynchronous.set_window_rectangle(server_url, session, width, height, x, y) is True
window_rectangle_after = None
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
@@ -228,10 +220,7 @@ async def test_switch_to_window(setup_functional_environment, window_type):
assert synchronous.get_title(server_url, session) == ""
synchronous.switch_to_window(server_url, session, handle=sample_page) is True
- assert (
- await asynchronous.switch_to_window(server_url, session, handle=new_page)
- is True
- )
+ assert await asynchronous.switch_to_window(server_url, session, handle=new_page) is True
assert synchronous.get_title(server_url, session) == ""
@@ -253,13 +242,8 @@ async def test_switch_to_parent_frame_asynchronous(setup_functional_environment)
locator_type = By.ID
locator_value = "my-iframe"
- element_frame = synchronous.find_element(
- server_url, session, locator_type, locator_value
- )
- assert (
- await asynchronous.switch_to_parent_frame(server_url, session, element_frame)
- is True
- )
+ element_frame = synchronous.find_element(server_url, session, locator_type, locator_value)
+ assert await asynchronous.switch_to_parent_frame(server_url, session, element_frame) is True
def test_switch_to_parent_frame_synchronous(setup_functional_environment):
@@ -267,12 +251,8 @@ def test_switch_to_parent_frame_synchronous(setup_functional_environment):
locator_type = By.ID
locator_value = "my-iframe"
- element_frame = synchronous.find_element(
- server_url, session, locator_type, locator_value
- )
- assert (
- synchronous.switch_to_parent_frame(server_url, session, element_frame) is True
- )
+ element_frame = synchronous.find_element(server_url, session, locator_type, locator_value)
+ assert synchronous.switch_to_parent_frame(server_url, session, element_frame) is True
@mark.asyncio
@@ -281,12 +261,8 @@ async def test_switch_to_frame_asynchronous(setup_functional_environment):
locator_type = By.ID
locator_value = "my-iframe"
- element_frame = synchronous.find_element(
- server_url, session, locator_type, locator_value
- )
- assert (
- await asynchronous.switch_to_frame(server_url, session, element_frame) is True
- )
+ element_frame = synchronous.find_element(server_url, session, locator_type, locator_value)
+ assert await asynchronous.switch_to_frame(server_url, session, element_frame) is True
def test_switch_to_frame_synchronous(setup_functional_environment):
@@ -294,9 +270,7 @@ def test_switch_to_frame_synchronous(setup_functional_environment):
locator_type = By.ID
locator_value = "my-iframe"
- element_frame = synchronous.find_element(
- server_url, session, locator_type, locator_value
- )
+ element_frame = synchronous.find_element(server_url, session, locator_type, locator_value)
assert synchronous.switch_to_frame(server_url, session, element_frame) is True
@@ -407,9 +381,7 @@ async def test_get_named_cookie(setup_functional_environment):
name = "username" # cookie created on page load
expected = "John Doe"
- assert (
- synchronous.get_named_cookie(server_url, session, name).get("value") == expected
- )
+ assert synchronous.get_named_cookie(server_url, session, name).get("value") == expected
response = await asynchronous.get_named_cookie(server_url, session, name)
assert response.get("value") == expected
@@ -425,9 +397,7 @@ async def test_get_computed_label(setup_functional_environment):
assert synchronous.get_computed_label(server_url, session, element) == expected
- assert (
- await asynchronous.get_computed_label(server_url, session, element) == expected
- )
+ assert await asynchronous.get_computed_label(server_url, session, element) == expected
@mark.asyncio
@@ -441,9 +411,7 @@ async def test_get_computed_role(setup_functional_environment):
assert synchronous.get_computed_role(server_url, session, element) == expected
- assert (
- await asynchronous.get_computed_role(server_url, session, element) == expected
- )
+ assert await asynchronous.get_computed_role(server_url, session, element) == expected
@mark.asyncio
@@ -460,13 +428,9 @@ async def test_get_tag_name(setup_functional_environment):
assert await asynchronous.get_tag_name(server_url, session, element) == expected
-@mark.parametrize(
- "locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")]
-)
+@mark.parametrize("locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")])
@mark.asyncio
-async def test_find_element_from_shadow_root(
- setup_functional_environment, locator, value
-):
+async def test_find_element_from_shadow_root(setup_functional_environment, locator, value):
server_url, session = setup_functional_environment
locator_type = By.ID
locator_value = "shadow-root"
@@ -475,26 +439,18 @@ async def test_find_element_from_shadow_root(
shadow_root = synchronous.get_shadow_root(server_url, session, element)
- actual = synchronous.find_child_element(
- server_url, session, shadow_root, locator, value
- )
+ actual = synchronous.find_child_element(server_url, session, shadow_root, locator, value)
assert actual is not None
- actual = await asynchronous.find_child_element(
- server_url, session, shadow_root, locator, value
- )
+ actual = await asynchronous.find_child_element(server_url, session, shadow_root, locator, value)
assert actual is not None
-@mark.parametrize(
- "locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")]
-)
+@mark.parametrize("locator, value", [(By.ID, "shadow-button"), (By.CSS_SELECTOR, "button")])
@mark.asyncio
-async def test_find_elements_from_shadow_root(
- setup_functional_environment, locator, value
-):
+async def test_find_elements_from_shadow_root(setup_functional_environment, locator, value):
server_url, session = setup_functional_environment
locator_type = By.ID
locator_value = "shadow-root"
@@ -504,9 +460,7 @@ async def test_find_elements_from_shadow_root(
shadow_root = synchronous.get_shadow_root(server_url, session, element)
- actual = synchronous.find_children_elements(
- server_url, session, shadow_root, locator, value
- )
+ actual = synchronous.find_children_elements(server_url, session, shadow_root, locator, value)
assert len(actual) == one
@@ -553,9 +507,7 @@ async def test_move_to_element(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
assert synchronous.actions_move_to_element(server_url, session, element) is True
- assert (
- await asynchronous.actions_move_to_element(server_url, session, element) is True
- )
+ assert await asynchronous.actions_move_to_element(server_url, session, element) is True
@mark.asyncio
@@ -566,10 +518,7 @@ async def test_actions_scroll_to_element(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
assert synchronous.actions_scroll_to_element(server_url, session, element) is True
- assert (
- await asynchronous.actions_scroll_to_element(server_url, session, element)
- is True
- )
+ assert await asynchronous.actions_scroll_to_element(server_url, session, element) is True
@mark.asyncio
@@ -607,9 +556,7 @@ async def test_raise_exception_when_element_not_found(setup_functional_environme
synchronous.find_element(server_url, session, locator_type, locator_value)
with raises(WebDriverError):
- await asynchronous.find_element(
- server_url, session, locator_type, locator_value
- )
+ await asynchronous.find_element(server_url, session, locator_type, locator_value)
@mark.asyncio
@@ -707,9 +654,7 @@ async def test_get_alert_text(setup_functional_environment):
locator_value = "#alert-button"
expected = "any warn"
- alert_button = synchronous.find_element(
- server_url, session, locator_type, locator_value
- )
+ alert_button = synchronous.find_element(server_url, session, locator_type, locator_value)
synchronous.click(server_url, session, alert_button)
assert synchronous.get_alert_text(server_url, session) == expected
@@ -778,14 +723,8 @@ async def test_get_css_value(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
- assert (
- synchronous.get_css_value(server_url, session, element, property_name)
- == expected
- )
- assert (
- await asynchronous.get_css_value(server_url, session, element, property_name)
- == expected
- )
+ assert synchronous.get_css_value(server_url, session, element, property_name) == expected
+ assert await asynchronous.get_css_value(server_url, session, element, property_name) == expected
@mark.asyncio
@@ -859,10 +798,7 @@ async def test_get_attribute(setup_functional_environment):
attribute = "href"
element = synchronous.find_element(server_url, session, By.XPATH, "//a[@id='a1']")
- assert (
- synchronous.get_attribute(server_url, session, element, attribute)
- == "http://any1.com/"
- )
+ assert synchronous.get_attribute(server_url, session, element, attribute) == "http://any1.com/"
assert (
await asynchronous.get_attribute(server_url, session, element, attribute)
== "http://any1.com/"
@@ -938,9 +874,7 @@ async def test_find_elements_fails_when_invalid_data_input(
synchronous.find_elements(server_url, session, locator_type, locator_value)
with raises(WebDriverError):
- await asynchronous.find_elements(
- server_url, session, locator_type, locator_value
- )
+ await asynchronous.find_elements(server_url, session, locator_type, locator_value)
@mark.asyncio
@@ -949,9 +883,7 @@ async def test_find_elements(setup_functional_environment):
locator_type = By.XPATH
locator_value = "//input"
- elements = synchronous.find_elements(
- server_url, session, locator_type, locator_value
- )
+ elements = synchronous.find_elements(server_url, session, locator_type, locator_value)
async_elements = await asynchronous.find_elements(
server_url, session, locator_type, locator_value
)
@@ -970,9 +902,7 @@ async def test_find_element_fails_when_invalid_data_input(setup_functional_envir
synchronous.find_element(server_url, session, locator_type, locator_value)
with raises(WebDriverError):
- await asynchronous.find_element(
- server_url, session, locator_type, locator_value
- )
+ await asynchronous.find_element(server_url, session, locator_type, locator_value)
@mark.asyncio
@@ -981,14 +911,9 @@ async def test_find_element(setup_functional_environment):
locator_type = By.XPATH
locator_value = "//input"
+ assert synchronous.find_element(server_url, session, locator_type, locator_value) is not None
assert (
- synchronous.find_element(server_url, session, locator_type, locator_value)
- is not None
- )
- assert (
- await asynchronous.find_element(
- server_url, session, locator_type, locator_value
- )
+ await asynchronous.find_element(server_url, session, locator_type, locator_value)
is not None
)
@@ -1005,9 +930,7 @@ async def test_get_property(setup_functional_environment):
synchronous.send_keys(server_url, session, element, text)
assert synchronous.get_property(server_url, session, element, property) == text
- assert (
- await asynchronous.get_property(server_url, session, element, property) == text
- )
+ assert await asynchronous.get_property(server_url, session, element, property) == text
@mark.asyncio
@@ -1033,9 +956,7 @@ async def test_send_keys(setup_functional_environment):
element = synchronous.find_element(server_url, session, locator_type, locator_value)
- assert (
- await asynchronous.send_keys(server_url, session, element, text_async) is True
- )
+ assert await asynchronous.send_keys(server_url, session, element, text_async) is True
assert synchronous.send_keys(server_url, session, element, text_sync) is True
diff --git a/tests/integration/test_async_scenarios.py b/tests/integration/test_async_scenarios.py
index d9ba381..f3dc302 100644
--- a/tests/integration/test_async_scenarios.py
+++ b/tests/integration/test_async_scenarios.py
@@ -2,7 +2,6 @@
from pytest import mark
-
@mark.asyncio
async def test_get_all_links(setup_functional_environment):
server_url, session = setup_functional_environment
@@ -12,11 +11,6 @@ async def test_get_all_links(setup_functional_environment):
for i in range(4):
i += 1
locator_value = f"//a[@id='a{i}']"
- anchor = synchronous.find_element(
- server_url, session, locator_type, locator_value
- )
+ anchor = synchronous.find_element(server_url, session, locator_type, locator_value)
anchors.append(anchor)
- assert (
- await asynchronous.get_text(server_url, session, anchors[i - 1])
- == f"any{i}.com"
- )
+ assert await asynchronous.get_text(server_url, session, anchors[i - 1]) == f"any{i}.com"
diff --git a/tests/performance/README.md b/tests/performance/README.md
new file mode 100644
index 0000000..26b0e3f
--- /dev/null
+++ b/tests/performance/README.md
@@ -0,0 +1,858 @@
+# Scenario 1 - No concurrence
+## Execution 1
+### No shared session
+```bash
+python -m pytest -k test_big_scenario_of_functions_without_session_http --durations=0 -random-order
+===================================================== test session starts ======================================================
+platform linux -- Python 3.12.3, pytest-9.0.1, pluggy-1.6.0
+Using --randomly-seed=1382528414
+rootdir: /home/douglas/repo/caqui
+configfile: pytest.ini
+plugins: xdist-3.8.0, randomly-4.0.1, asyncio-1.3.0
+asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
+collected 301 items / 291 deselected / 10 selected
+
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1 PASSED [ 10%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5 PASSED [ 20%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9 PASSED [ 30%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10 PASSED [ 40%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4 PASSED [ 50%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8 PASSED [ 60%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2 PASSED [ 70%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6 PASSED [ 80%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7 PASSED [ 90%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3 PASSED [100%]
+
+====================================================== slowest durations =======================================================
+3.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+2.23s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+1.84s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+1.79s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+1.78s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+1.78s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+1.77s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+1.73s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+1.70s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+1.69s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+1.55s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.40s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.40s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.40s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+============================================= 10 passed, 291 deselected in 28.95s ==============================================
+
+```
+
+## Shared session
+```bash
+python -m pytest -k test_big_scenario_of_functions_with_session_http --durations=0 -random-order
+===================================================== test session starts ======================================================
+platform linux -- Python 3.12.3, pytest-9.0.1, pluggy-1.6.0
+Using --randomly-seed=2805815262
+rootdir: /home/douglas/repo/caqui
+configfile: pytest.ini
+plugins: xdist-3.8.0, randomly-4.0.1, asyncio-1.3.0
+asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
+collected 301 items / 291 deselected / 10 selected
+
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10 PASSED [ 10%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8 PASSED [ 20%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4 PASSED [ 30%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9 PASSED [ 40%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1 PASSED [ 50%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5 PASSED [ 60%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7 PASSED [ 70%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3 PASSED [ 80%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2 PASSED [ 90%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6 PASSED [100%]
+
+====================================================== slowest durations =======================================================
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.65s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+1.63s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.62s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.54s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+1.54s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+1.51s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+1.50s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+1.49s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+1.45s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+1.40s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+1.38s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.59s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.47s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.44s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.40s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+============================================= 10 passed, 291 deselected in 24.69s ==============================================
+```
+
+## Execution 2
+### No shared session
+```bash
+python -m pytest -k test_big_scenario_of_functions_without_session_http --durations=0 -random-order
+===================================================== test session starts ======================================================
+platform linux -- Python 3.12.3, pytest-9.0.1, pluggy-1.6.0
+Using --randomly-seed=55218217
+rootdir: /home/douglas/repo/caqui
+configfile: pytest.ini
+plugins: xdist-3.8.0, randomly-4.0.1, asyncio-1.3.0
+asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
+collected 301 items / 291 deselected / 10 selected
+
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5 PASSED [ 10%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1 PASSED [ 20%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9 PASSED [ 30%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4 PASSED [ 40%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8 PASSED [ 50%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6 PASSED [ 60%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2 PASSED [ 70%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3 PASSED [ 80%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7 PASSED [ 90%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10 PASSED [100%]
+
+====================================================== slowest durations =======================================================
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+2.01s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+1.86s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+1.84s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+1.79s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+1.73s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+1.65s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+1.61s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+1.59s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+1.58s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+1.53s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+1.27s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.61s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.60s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.57s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.53s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+============================================= 10 passed, 291 deselected in 26.84s ==============================================
+
+```
+### Shared session
+```bash
+python -m pytest -k test_big_scenario_of_functions_with_session_http --durations=0 -random-order
+===================================================== test session starts ======================================================
+platform linux -- Python 3.12.3, pytest-9.0.1, pluggy-1.6.0
+Using --randomly-seed=1872312787
+rootdir: /home/douglas/repo/caqui
+configfile: pytest.ini
+plugins: xdist-3.8.0, randomly-4.0.1, asyncio-1.3.0
+asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
+collected 301 items / 291 deselected / 10 selected
+
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4 PASSED [ 10%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8 PASSED [ 20%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1 PASSED [ 30%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5 PASSED [ 40%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9 PASSED [ 50%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7 PASSED [ 60%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3 PASSED [ 70%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10 PASSED [ 80%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2 PASSED [ 90%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6 PASSED [100%]
+
+====================================================== slowest durations =======================================================
+3.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.91s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.69s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+1.61s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+1.56s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+1.56s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+1.48s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+1.47s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+1.46s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.44s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+1.44s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.52s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.51s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+0.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.44s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+============================================= 10 passed, 291 deselected in 25.11s ==============================================
+```
+
+## Execution 3
+### No shared session
+```bash
+python -m pytest -k test_big_scenario_of_functions_without_session_http --durations=0 -random-order
+===================================================== test session starts ======================================================
+platform linux -- Python 3.12.3, pytest-9.0.1, pluggy-1.6.0
+Using --randomly-seed=299171876
+rootdir: /home/douglas/repo/caqui
+configfile: pytest.ini
+plugins: xdist-3.8.0, randomly-4.0.1, asyncio-1.3.0
+asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
+collected 301 items / 291 deselected / 10 selected
+
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10 PASSED [ 10%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6 PASSED [ 20%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2 PASSED [ 30%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3 PASSED [ 40%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7 PASSED [ 50%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5 PASSED [ 60%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1 PASSED [ 70%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9 PASSED [ 80%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4 PASSED [ 90%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8 PASSED [100%]
+
+====================================================== slowest durations =======================================================
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+1.88s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+1.72s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+1.67s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+1.66s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+1.62s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+1.62s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+1.62s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+1.51s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+1.50s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+1.46s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+1.32s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.63s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.47s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+0.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.44s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.40s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+============================================= 10 passed, 291 deselected in 25.62s ==============================================
+```
+### Shared session
+```bash
+python -m pytest -k test_big_scenario_of_functions_with_session_http --durations=0 -random-order
+===================================================== test session starts ======================================================
+platform linux -- Python 3.12.3, pytest-9.0.1, pluggy-1.6.0
+Using --randomly-seed=874562232
+rootdir: /home/douglas/repo/caqui
+configfile: pytest.ini
+plugins: xdist-3.8.0, randomly-4.0.1, asyncio-1.3.0
+asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
+collected 301 items / 291 deselected / 10 selected
+
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5 PASSED [ 10%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1 PASSED [ 20%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9 PASSED [ 30%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4 PASSED [ 40%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8 PASSED [ 50%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10 PASSED [ 60%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6 PASSED [ 70%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2 PASSED [ 80%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3 PASSED [ 90%]
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7 PASSED [100%]
+
+====================================================== slowest durations =======================================================
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+1.67s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+1.60s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+1.51s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+1.48s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.48s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+1.47s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.44s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+1.44s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+1.43s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+1.43s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+1.28s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.49s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.47s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+0.44s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+============================================= 10 passed, 291 deselected in 24.23s ==============================================
+```
+# Secenario 2 - with concurrence (-n auto)
+## Execution 1
+### Shared session
+```bash
+python -m pytest -k test_big_scenario_of_functions_with_session_http --durations=0 -random-order -n auto
+===================================================== test session starts ======================================================
+platform linux -- Python 3.12.3, pytest-9.0.1, pluggy-1.6.0
+Using --randomly-seed=4074239062
+rootdir: /home/douglas/repo/caqui
+configfile: pytest.ini
+plugins: xdist-3.8.0, randomly-4.0.1, asyncio-1.3.0
+asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
+4 workers [10 items]
+scheduling tests via LoadScheduling
+
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+[gw3] [ 10%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+[gw1] [ 20%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+[gw2] [ 30%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+[gw0] [ 40%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+[gw3] [ 50%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+[gw2] [ 60%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+[gw0] [ 70%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+[gw1] [ 80%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+[gw3] [ 90%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+[gw1] [100%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+
+====================================================== slowest durations =======================================================
+3.79s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+3.75s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+3.69s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+3.60s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+3.59s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+3.56s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+3.48s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+3.41s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+3.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+3.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+2.23s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+2.14s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+2.12s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+2.12s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+1.72s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+1.31s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.30s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+1.17s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+1.08s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+1.04s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.82s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.51s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+===================================================== 10 passed in 18.04s ======================================================
+```
+### No shared session
+```bash
+python -m pytest -k test_big_scenario_of_functions_without_session_http --durations=0 -random-order -n auto
+===================================================== test session starts ======================================================
+platform linux -- Python 3.12.3, pytest-9.0.1, pluggy-1.6.0
+Using --randomly-seed=1525082352
+rootdir: /home/douglas/repo/caqui
+configfile: pytest.ini
+plugins: xdist-3.8.0, randomly-4.0.1, asyncio-1.3.0
+asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
+4 workers [10 items]
+scheduling tests via LoadScheduling
+
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+[gw0] [ 10%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+[gw1] [ 20%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+[gw2] [ 30%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+[gw3] [ 40%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+[gw1] [ 50%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+[gw0] [ 60%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+[gw2] [ 70%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+[gw3] [ 80%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+[gw1] [ 90%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+[gw0] [100%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+
+====================================================== slowest durations =======================================================
+3.69s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+3.63s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+3.60s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+3.58s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+3.48s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+3.47s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+3.34s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+3.33s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+3.15s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+3.14s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+3.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+2.47s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+2.47s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+2.38s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+2.31s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+1.93s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+1.85s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+1.66s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+1.64s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+1.59s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+1.54s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.94s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.91s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.15s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.13s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.11s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.11s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+===================================================== 10 passed in 18.93s ======================================================
+
+```
+
+## Execution 2
+### Shared session
+```bash
+python -m pytest -k test_big_scenario_of_functions_with_session_http --durations=0 -random-order -n auto
+===================================================== test session starts ======================================================
+platform linux -- Python 3.12.3, pytest-9.0.1, pluggy-1.6.0
+Using --randomly-seed=3270874462
+rootdir: /home/douglas/repo/caqui
+configfile: pytest.ini
+plugins: xdist-3.8.0, randomly-4.0.1, asyncio-1.3.0
+asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
+4 workers [10 items]
+scheduling tests via LoadScheduling
+
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+[gw2] [ 10%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+[gw0] [ 20%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+[gw1] [ 30%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+[gw3] [ 40%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+[gw0] [ 50%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+[gw2] [ 60%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+[gw3] [ 70%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+[gw1] [ 80%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+[gw0] [ 90%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+[gw2] [100%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+
+====================================================== slowest durations =======================================================
+3.81s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+3.69s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+3.65s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+3.62s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+3.55s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+3.36s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+3.32s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+3.32s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+3.14s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+3.12s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+3.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+3.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+2.70s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+2.63s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+2.39s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+2.29s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+1.90s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+1.88s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+1.47s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+1.37s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.34s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.85s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.85s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.17s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.13s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+0.10s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+===================================================== 10 passed in 18.89s ======================================================
+
+```
+### No shared session
+```bash
+python -m pytest -k test_big_scenario_of_functions_without_session_http --durations=0 -random-order -n auto
+===================================================== test session starts ======================================================
+platform linux -- Python 3.12.3, pytest-9.0.1, pluggy-1.6.0
+Using --randomly-seed=1413430422
+rootdir: /home/douglas/repo/caqui
+configfile: pytest.ini
+plugins: xdist-3.8.0, randomly-4.0.1, asyncio-1.3.0
+asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
+4 workers [10 items]
+scheduling tests via LoadScheduling
+
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+[gw2] [ 10%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+[gw1] [ 20%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+[gw3] [ 30%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+[gw0] [ 40%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+[gw0] [ 50%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+[gw2] [ 60%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+[gw1] [ 70%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+[gw3] [ 80%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+[gw2] [ 90%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+[gw1] [100%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+
+====================================================== slowest durations =======================================================
+3.51s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+3.46s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+3.45s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+3.44s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+3.43s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+3.43s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+3.37s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+3.33s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+3.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+3.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+3.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+2.49s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+2.39s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+2.29s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+2.29s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+1.93s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+1.90s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+1.56s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+1.55s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+1.55s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+1.36s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.77s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.75s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.15s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.12s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+===================================================== 10 passed in 18.52s ======================================================
+
+```
+
+## Execution 3
+### Shared session
+```bash
+python -m pytest -k test_big_scenario_of_functions_with_session_http --durations=0 -random-order -n auto
+===================================================== test session starts ======================================================
+platform linux -- Python 3.12.3, pytest-9.0.1, pluggy-1.6.0
+Using --randomly-seed=700748289
+rootdir: /home/douglas/repo/caqui
+configfile: pytest.ini
+plugins: xdist-3.8.0, randomly-4.0.1, asyncio-1.3.0
+asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
+4 workers [10 items]
+scheduling tests via LoadScheduling
+
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+[gw0] [ 10%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+[gw3] [ 20%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+[gw2] [ 30%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+[gw1] [ 40%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+[gw2] [ 50%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+[gw0] [ 60%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+[gw3] [ 70%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+[gw1] [ 80%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+[gw0] [ 90%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+[gw3] [100%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+
+====================================================== slowest durations =======================================================
+3.86s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+3.82s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+3.79s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+3.61s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+3.57s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+3.35s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+3.26s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+3.24s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+3.14s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+3.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+2.59s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+2.52s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+2.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+2.34s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+1.90s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+1.89s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+1.88s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.77s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.74s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+1.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.93s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.86s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.19s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.15s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.12s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+===================================================== 10 passed in 19.41s ======================================================
+```
+### No shared session
+```bash
+python -m pytest -k test_big_scenario_of_functions_without_session_http --durations=0 -random-order -n auto
+===================================================== test session starts ======================================================
+platform linux -- Python 3.12.3, pytest-9.0.1, pluggy-1.6.0
+Using --randomly-seed=3110200315
+rootdir: /home/douglas/repo/caqui
+configfile: pytest.ini
+plugins: xdist-3.8.0, randomly-4.0.1, asyncio-1.3.0
+asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
+4 workers [10 items]
+scheduling tests via LoadScheduling
+
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+[gw3] [ 10%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+[gw2] [ 20%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+[gw0] [ 30%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+[gw1] [ 40%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+[gw3] [ 50%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+[gw2] [ 60%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+[gw0] [ 70%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+[gw1] [ 80%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+[gw3] [ 90%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+[gw2] [100%] PASSED tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+
+====================================================== slowest durations =======================================================
+3.67s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+3.56s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+3.54s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+3.54s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+3.45s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+3.43s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+3.43s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+3.38s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+3.14s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+3.10s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+2.52s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+2.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+2.40s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+2.26s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+1.93s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+1.88s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+1.51s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+1.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+1.39s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+1.22s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.86s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.85s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.14s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.10s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+===================================================== 10 passed in 18.60s ======================================================
+
+```
+
+# Data processing
+```bash
+python -m pytest -k process_data -s
+```
+# Result
+- In scenarios without concurrence all executions using shared session (code bellow) performed better
+```python
+ async with ClientSession() as session_http:
+ page = AsyncPage(server_url, capabilities, PAGE_URL, session_http=session_http)
+```
+- In scenarios with concurrent (`pytest -n auto`) the results were almost the same for shared and non-shared session
+
+```bash
+# Data organized by lowest 'duration'
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.80, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 28.63, 'call': 17.86, 'setup': 7.11, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+```
+
+```bash
+# Data organized by lowest accumulated duration (sum the duration of all threads)
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.70, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.00, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.90, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'call': 32.10, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.90, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.90, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+```
+
+# Tuning web driver
+TO run all tests do `python -m pytest -k TestPerformance`. All results are ordered by lowest duration.
+## Scenario 1 - no aditional arguments in driver
+- Execution 1 (duration): 64.65s
+- Execution 2 (duration): 66.40s
+- Execution 3 (duration): 67.16s
+
+## Scenario 2 - added arguments to driver
+```python
+options = ChromeOptionsBuilder().args([
+ "headless",
+ "blink-settings=imagesEnabled=false",
+ "disable-extensions",
+ "disable-plugins",
+ "disable-background-timer-throttling"
+ ])
+# and page_load_strategy("eager")
+capabilities = (
+ ChromeCapabilitiesBuilder()
+ .accept_insecure_certs(True)
+ .add_options(options)
+ .page_load_strategy("eager")
+```
+- Execution 3 (duration): 46.42s
+- Execution 1 (duration): 47.54s
+- Execution 2 (duration): 48.12s
+
+## Scenario 3 - reuse server instance
+Not dispose the server after finishe the test
+```python
+@fixture(autouse=True, scope="session")
+def setup_server():
+ server = Server.get_instance(port=SERVER_PORT)
+ server.start()
+ # yield
+ # server.dispose(delay=3)
+```
+- Execution 3 (duration): 42.80s
+- Execution 2 (duration): 42.93s
+- Execution 1 (duration): 43.27s
+
+## Scenario 4 - run in multiprocessing
+```python
+# add -n auto
+python -m pytest -k TestPerformance -n auto
+```
+- Execution 2 (duration): 28.19s
+- Execution 3 (duration): 28.53s
+- Execution 1 (duration): 29.96s
+
+## Scenario 5 - using `ujson` module instead of built-in `json`
+Executed with a fresh server instance
+- Execution 1 (duration): 27.49s
+- Execution 2 (duration): 27.68s
+- Execution 3 (duration): 28.44s
+- mean: 27.87s
+
+## Scenario 6 - using `orjson` module
+Executed with a fresh server instance
+- Execution 1 (duration): 27.57s
+- Execution 3 (duration): 27.90s
+- Execution 2 (duration): 28.11s
+- mean: 27.86s
+
+## Scenario 7 - using `urllib3` module instead of `requests`
+- Execution 1 (duration): 27.84s
+- Execution 2 (duration): 34.95s
+- Execution 3 (duration): 28.32s
\ No newline at end of file
diff --git a/tests/performance/test_process_data.py b/tests/performance/test_process_data.py
new file mode 100644
index 0000000..052f154
--- /dev/null
+++ b/tests/performance/test_process_data.py
@@ -0,0 +1,463 @@
+import re
+from collections import OrderedDict
+
+DATA = [
+ {
+ "title": "# Scenario 1 | No concurrence | Execution 1 | No Shared session\n",
+ "output": """
+3.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+2.23s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+1.84s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+1.79s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+1.78s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+1.78s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+1.77s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+1.73s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+1.70s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+1.69s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+1.55s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.40s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.40s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.40s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+""",
+ },
+ {
+ "title": "# Scenario 1 | No concurrence | Execution 1 | Shared session\n",
+ "output": """
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.65s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+1.63s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.62s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.54s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+1.54s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+1.51s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+1.50s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+1.49s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+1.45s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+1.40s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+1.38s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.59s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.47s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.44s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.40s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+""",
+ },
+ {
+ "title": "# Scenario 1 | No concurrence | Execution 2 | No Shared session\n",
+ "output": """
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+2.01s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+1.86s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+1.84s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+1.79s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+1.73s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+1.65s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+1.61s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+1.59s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+1.58s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+1.53s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+1.27s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.61s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.60s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.57s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.53s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+ """,
+ },
+ {
+ "title": "# Scenario 1 | No concurrence | Execution 2 | Shared session\n",
+ "output": """
+3.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.91s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.69s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+1.61s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+1.56s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+1.56s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+1.48s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+1.47s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+1.46s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.44s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+1.44s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.52s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.51s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+0.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.44s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+ """,
+ },
+ {
+ "title": "# Scenario 1 | No concurrence | Execution 3 | No Shared session\n",
+ "output": """
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+1.88s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+1.72s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+1.67s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+1.66s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+1.62s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+1.62s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+1.62s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+1.51s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+1.50s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+1.46s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+1.32s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.63s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.47s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+0.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.44s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.40s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+ """,
+ },
+ {
+ "title": "# Scenario 1 | No concurrence | Execution 3 | Shared session\n",
+ "output": """
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+1.67s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+1.60s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+1.51s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+1.48s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.48s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+1.47s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.44s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+1.44s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+1.43s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+1.43s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+1.28s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.49s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.47s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+0.44s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.42s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.41s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+ """,
+ },
+ {
+ "title": "# Scenario 2 | With concurrence | Execution 1 | Shared session\n",
+ "output": """
+3.79s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+3.75s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+3.69s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+3.60s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+3.59s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+3.56s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+3.48s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+3.41s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+3.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+3.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+2.23s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+2.14s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+2.12s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+2.12s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+1.72s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+1.31s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.30s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+1.17s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+1.08s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+1.04s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.82s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.51s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+ """,
+ },
+ {
+ "title": "# Scenario 2 | With concurrence | Execution 1 | No Shared session\n",
+ "output": """
+3.69s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+3.63s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+3.60s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+3.58s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+3.48s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+3.47s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+3.34s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+3.33s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+3.15s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+3.14s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+3.06s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+2.47s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+2.47s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+2.38s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+2.31s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+1.93s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+1.85s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+1.66s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+1.64s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+1.59s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+1.54s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.94s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.91s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.15s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.13s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.11s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.11s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+ """,
+ },
+ {
+ "title": "# Scenario 2 | With concurrence | Execution 2 | Shared session\n",
+ "output": """
+3.81s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+3.69s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+3.65s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+3.62s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+3.55s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+3.36s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+3.32s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+3.32s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+3.14s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+3.12s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+3.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+3.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+2.70s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+2.63s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+2.39s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+2.29s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+1.90s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+1.88s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+1.47s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+1.37s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.34s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.85s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.85s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.17s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.13s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+0.10s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+ """,
+ },
+ {
+ "title": "# Scenario 2 | With concurrence | Execution 2 | No Shared session\n",
+ "output": """
+3.51s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+3.46s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+3.45s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+3.44s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+3.43s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+3.43s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+3.37s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+3.33s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+3.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+3.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+3.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+2.49s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+2.39s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+2.29s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+2.29s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+1.93s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+1.90s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+1.56s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+1.55s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+1.55s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+1.36s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+0.77s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.75s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.15s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.12s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+0.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+ """,
+ },
+ {
+ "title": "# Scenario 2 | With concurrence | Execution 3 | Shared session\n",
+ "output": """
+3.86s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+3.82s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+3.79s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+3.61s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+3.57s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+3.35s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+3.26s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+3.24s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+3.14s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+3.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+2.59s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+2.52s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+2.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+2.34s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+1.90s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+1.89s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+1.88s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+1.77s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+1.74s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http3
+1.45s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http9
+0.93s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http4
+0.86s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http8
+0.19s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http10
+0.15s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http7
+0.12s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http1
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http5
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http6
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_with_session_http2
+ """,
+ },
+ {
+ "title": "# Scenario 2 | With concurrence | Execution 3 | No Shared session\n",
+ "output": """
+3.67s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+3.56s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+3.54s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+3.54s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+3.45s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+3.43s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+3.43s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+3.38s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+3.14s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+3.10s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+3.07s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+2.52s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+2.43s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+2.40s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+2.26s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+1.93s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+1.88s call tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+1.51s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+1.46s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http8
+1.39s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http5
+1.22s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.86s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http6
+0.85s setup tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http2
+0.14s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http10
+0.10s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http4
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http7
+0.09s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http1
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http9
+0.08s teardown tests/performance/test_single_session_http.py::test_big_scenario_of_functions_without_session_http3
+ """,
+ },
+]
+
+
+def test_convert_to_csv():
+ FILE = "data-processed.txt"
+ for item in DATA:
+ data = item["output"]
+ data = data.split("\n")
+ # format data in csv
+ result = []
+ for row in data:
+ # remove seconds (s) from duration
+ row = row.replace("s ", " ")
+ # convert spaces to comma
+ row = re.sub(r"\s+", ",", row)
+ result.append(row)
+
+ result_dict = OrderedDict()
+ for row in result:
+ if not row:
+ continue
+ new = row.split(",")
+ if not new[0]:
+ continue
+ duration = float(new[0])
+ stage = new[1]
+ # sum duration of stages
+ result_dict[stage] = round(result_dict.get(stage, 0) + duration, 2)
+ result_dict["duration"] = result_dict.get("duration", 0) + duration
+ result_dict["title"] = item["title"]
+ result_dict[stage] = round(result_dict[stage], 2)
+ result_dict["duration"] = round(result_dict["duration"], 2)
+ # sample: {'setup': 7.11, 'teardown': 3.66, 'call': 17.86}
+ print(result_dict)
+ with open(FILE, "a") as f:
+ f.write(f"{str(result_dict)}\n")
+ with open(FILE, "a") as f:
+ f.write("=====\n")
+ print(f"Data saved to {FILE}")
diff --git a/tests/performance/test_single_session_http.py b/tests/performance/test_single_session_http.py
new file mode 100644
index 0000000..d7ced8c
--- /dev/null
+++ b/tests/performance/test_single_session_http.py
@@ -0,0 +1,278 @@
+from aiohttp import ClientSession
+from pytest import mark
+from caqui import synchronous
+from caqui.by import By
+from caqui.easy import AsyncPage
+from tests.constants import PAGE_URL
+from pytest import mark
+import pytest_asyncio
+from caqui.easy.capabilities import ChromeCapabilitiesBuilder
+from caqui.easy.options import ChromeOptionsBuilder
+
+SERVER_PORT = 9999
+SERVER_URL = f"http://localhost:{SERVER_PORT}"
+CAPTURES = "captures"
+LOAD = 10 # requests
+
+# @mark.skip(reason="Used for performance tests")
+class TestPerformance:
+ def _build_capabilities(self):
+ options = ChromeOptionsBuilder().args([
+ "headless",
+ "blink-settings=imagesEnabled=false",
+ "disable-extensions",
+ "disable-plugins",
+ "disable-background-timer-throttling"
+ ])
+ capabilities = (
+ ChromeCapabilitiesBuilder()
+ .accept_insecure_certs(True)
+ .add_options(options)
+ .page_load_strategy("eager")
+ ).to_dict()
+ return capabilities
+
+ async def _body(self,page):
+ await page.implicitly_wait(10)
+ await page.get(
+ PAGE_URL,
+ )
+ for _ in range(LOAD):
+ click_button = await page.find_element(By.ID, "button")
+ await click_button.click()
+
+ await page.switch_to.active_element.get_attribute("value")
+ element = await page.find_element(By.XPATH, "//a")
+ # Returns and base64 encoded string into image
+ await element.screenshot("/tmp/image.png")
+
+ await page.back()
+ await page.forward()
+ await page.refresh()
+
+ alert_element = await page.find_element(By.CSS_SELECTOR, "#alert-button-prompt")
+ await alert_element.click()
+ alert_object = page.switch_to.alert
+ await page.alert.accept()
+
+ await alert_element.click()
+ await alert_object.send_keys("Caqui")
+ await alert_object.dismiss()
+
+ iframe = await page.find_element(By.ID, "my-iframe")
+ # switch to selected iframe
+ await page.switch_to.frame(iframe)
+ await page.switch_to.default_content()
+ # switching to second iframe based on index
+ iframe = (await page.find_elements(By.ID, "my-iframe"))[0]
+
+ # switch to selected iframe
+ await page.switch_to.frame(iframe)
+ # switch back to default content
+ await page.switch_to.default_content()
+
+ window_handle = page.current_window_handle
+ assert len(page.window_handles) >= 1
+ await page.switch_to.window(window_handle)
+ # Opens a new tab and switches to new tab
+ await page.switch_to.new_window("tab")
+ # Opens a new window and switches to new window
+ await page.switch_to.new_window("window")
+
+ # Access each dimension individually
+ await page.set_window_size(1024, 768)
+ # Move the window to the top left of the primary monitor
+ await page.set_window_position(0, 0)
+ await page.maximize_window()
+ # await driver.minimize_window() # does not work on headless mode
+ await page.save_screenshot("/tmp/image.png")
+
+ # Executing JavaScript to capture innerText of header element
+ await page.execute_script('alert("any warn")')
+
+ @pytest_asyncio.fixture
+ async def setup_environment_without_session_http(self):
+ server_url = SERVER_URL
+ capabilities = self._build_capabilities()
+ page = AsyncPage(server_url, capabilities, PAGE_URL)
+ yield page
+ try:
+ synchronous.dismiss_alert(server_url, page.session)
+ except Exception:
+ pass
+ finally:
+ page.quit()
+
+ @pytest_asyncio.fixture
+ async def setup_environment_with_session_http(self):
+ server_url = SERVER_URL
+ capabilities = self._build_capabilities()
+ async with ClientSession() as session_http:
+ page = AsyncPage(server_url, capabilities, PAGE_URL, session_http=session_http)
+ yield page
+ try:
+ synchronous.dismiss_alert(server_url, page.session)
+ except Exception:
+ pass
+ finally:
+ page.quit()
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_with_session_http1(
+ self,
+ setup_environment_with_session_http: AsyncPage,
+ ):
+ page = setup_environment_with_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_without_session_http1(
+ self,
+ setup_environment_without_session_http: AsyncPage,
+ ):
+ page = setup_environment_without_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_with_session_http2(
+ self,
+ setup_environment_with_session_http: AsyncPage,
+ ):
+ page = setup_environment_with_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_without_session_http2(
+ self,
+ setup_environment_without_session_http: AsyncPage,
+ ):
+ page = setup_environment_without_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_with_session_http3(
+ self,
+ setup_environment_with_session_http: AsyncPage,
+ ):
+ page = setup_environment_with_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_without_session_http3(
+ self,
+ setup_environment_without_session_http: AsyncPage,
+ ):
+ page = setup_environment_without_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_with_session_http4(
+ self,
+ setup_environment_with_session_http: AsyncPage,
+ ):
+ page = setup_environment_with_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_without_session_http4(
+ self,
+ setup_environment_without_session_http: AsyncPage,
+ ):
+ page = setup_environment_without_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_with_session_http5(
+ self,
+ setup_environment_with_session_http: AsyncPage,
+ ):
+ page = setup_environment_with_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_without_session_http5(
+ self,
+ setup_environment_without_session_http: AsyncPage,
+ ):
+ page = setup_environment_without_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_with_session_http6(
+ self,
+ setup_environment_with_session_http: AsyncPage,
+ ):
+ page = setup_environment_with_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_without_session_http6(
+ self,
+ setup_environment_without_session_http: AsyncPage,
+ ):
+ page = setup_environment_without_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_with_session_http7(
+ self,
+ setup_environment_with_session_http: AsyncPage,
+ ):
+ page = setup_environment_with_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_without_session_http7(
+ self,
+ setup_environment_without_session_http: AsyncPage,
+ ):
+ page = setup_environment_without_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_with_session_http8(
+ self,
+ setup_environment_with_session_http: AsyncPage,
+ ):
+ page = setup_environment_with_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_without_session_http8(
+ self,
+ setup_environment_without_session_http: AsyncPage,
+ ):
+ page = setup_environment_without_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_with_session_http9(
+ self,
+ setup_environment_with_session_http: AsyncPage,
+ ):
+ page = setup_environment_with_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_without_session_http9(
+ self,
+ setup_environment_without_session_http: AsyncPage,
+ ):
+ page = setup_environment_without_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_with_session_http10(
+ self,
+ setup_environment_with_session_http: AsyncPage,
+ ):
+ page = setup_environment_with_session_http
+ await self._body(page)
+
+ @mark.asyncio
+ async def test_big_scenario_of_functions_without_session_http10(
+ self,
+ setup_environment_without_session_http: AsyncPage,
+ ):
+ page = setup_environment_without_session_http
+ await self._body(page)
diff --git a/tests/unit/test_async_unit.py b/tests/unit/test_async_unit.py
index daafc89..43e52f6 100644
--- a/tests/unit/test_async_unit.py
+++ b/tests/unit/test_async_unit.py
@@ -18,7 +18,7 @@ async def test_get_rect():
async def mock_request(*args, **kwargs):
return fake_responses.GET_RECT
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.get_rect("", "", "") == expected
@@ -27,7 +27,7 @@ async def test_actions_scroll_to_element():
async def mock_request(*args, **kwargs):
return fake_responses.ACTIONS
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.actions_scroll_to_element("", "", "") is True
@@ -36,7 +36,7 @@ async def test_submit():
async def mock_request(*args, **kwargs):
return fake_responses.CLICK
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.submit("", "", "") is True
@@ -45,7 +45,7 @@ async def test_actions_click():
async def mock_request(*args, **kwargs):
return fake_responses.ACTIONS
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.actions_click("", "", "") is True
@@ -54,7 +54,7 @@ async def test_set_timeouts():
async def mock_request(*args, **kwargs):
return fake_responses.GET_TIMEOUTS
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.set_timeouts("", "", "") is True
@@ -65,7 +65,7 @@ async def test_find_children_elements():
async def mock_request(*args, **kwargs):
return fake_responses.FIND_ELEMENTS
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert element in await asynchronous.find_children_elements("", "", "", "", "")
@@ -76,7 +76,7 @@ async def test_find_child_element():
async def mock_request(*args, **kwargs):
return fake_responses.FIND_ELEMENT
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.find_child_element("", "", "", "", "") == element
@@ -87,7 +87,7 @@ async def test_execute_script():
async def mock_request(*args, **kwargs):
return fake_responses.EXECUTE_SCRIPT
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.execute_script("", "", "", "") == expected
@@ -98,7 +98,7 @@ async def test_get_page_source():
async def mock_request(*args, **kwargs):
return fake_responses.GET_PAGE_SOURCE
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert expected in await asynchronous.get_page_source("", "")
@@ -109,7 +109,7 @@ async def test_get_alert_text():
async def mock_request(*args, **kwargs):
return fake_responses.GET_ALERT_TEXT
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.get_alert_text("", "") == expected
@@ -120,7 +120,7 @@ async def test_get_active_element():
async def mock_request(*args, **kwargs):
return fake_responses.GET_ACTIVE_ELEMENT
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.get_active_element("", "") == expected
@@ -129,7 +129,7 @@ async def test_clear_element():
async def mock_request(*args, **kwargs):
return fake_responses.CLEAR_ELEMENT
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.clear_element("", "", "") is True
@@ -138,7 +138,7 @@ async def test_is_element_enabled():
async def mock_request(*args, **kwargs):
return fake_responses.IS_ELEMENT_ENABLED
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.is_element_enabled("", "", "") is True
@@ -149,7 +149,7 @@ async def test_get_css_value():
async def mock_request(*args, **kwargs):
return fake_responses.GET_CSS_COLOR_VALUE
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.get_css_value("", "", "", "") == expected
@@ -158,7 +158,7 @@ async def test_is_element_selected():
async def mock_request(*args, **kwargs):
return fake_responses.IS_ELEMENT_SELECTED
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.is_element_selected("", "", "") is False
@@ -169,7 +169,7 @@ async def test_get_window_rectangle():
async def mock_request(*args, **kwargs):
return fake_responses.GET_WINDOW_RECTANGLE
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert expected in await asynchronous.get_window_rectangle("", "")
@@ -180,7 +180,7 @@ async def test_get_window_handles():
async def mock_request(*args, **kwargs):
return fake_responses.GET_WINDOW_HANDLES
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.get_window_handles("", "") == expected
@@ -191,7 +191,7 @@ async def test_close_window():
async def mock_request(*args, **kwargs):
return fake_responses.CLOSE_WINDOW
- with patch("caqui.asynchronous.__delete", mock_request):
+ with patch("caqui.asynchronous._delete", mock_request):
assert await asynchronous.close_window("", "") == expected
@@ -202,13 +202,13 @@ async def test_get_window():
async def mock_request(*args, **kwargs):
return fake_responses.GET_WINDOW
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.get_window("", "") == expected
@mark.asyncio
async def test_go_back():
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.go_back("", "") is True
@@ -219,7 +219,7 @@ async def test_get_property():
async def mock_request(*args, **kwargs):
return fake_responses.GET_PROPERTY_VALUE
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.get_property("", "", "", "") == expected
@@ -230,7 +230,7 @@ async def test_get_attribute():
async def mock_request(*args, **kwargs):
return fake_responses.GET_ATTRIBUTE_VALUE
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.get_attribute("", "", "", "") == expected
@@ -241,7 +241,7 @@ async def test_get_url():
async def mock_request(*args, **kwargs):
return fake_responses.GET_URL
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
response = await asynchronous.get_url("", "")
assert expected in response
@@ -253,7 +253,7 @@ async def test_get_timeouts():
async def mock_request(*args, **kwargs):
return fake_responses.GET_TIMEOUTS
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
response = await asynchronous.get_timeouts("", "")
assert expected in response
@@ -263,7 +263,7 @@ async def test_get_status():
async def mock_request(*args, **kwargs):
return fake_responses.GET_STATUS
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
response = await asynchronous.get_status("")
assert response.get("value").get("ready") is True
@@ -275,7 +275,7 @@ async def test_get_title():
async def mock_request(*args, **kwargs):
return fake_responses.GET_TITLE
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.get_title("", "") == expected
@@ -286,7 +286,7 @@ async def test_get_cookies():
async def mock_request(*args, **kwargs):
return fake_responses.GET_COOKIES
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.get_cookies("", "") == expected
@@ -297,31 +297,31 @@ async def test_get_text():
async def mock_request(*args, **kwargs):
return fake_responses.GET_TEXT
- with patch("caqui.asynchronous.__get", mock_request):
+ with patch("caqui.asynchronous._get", mock_request):
assert await asynchronous.get_text("", "", "") == expected
@mark.asyncio
async def test_close_session():
- with patch("caqui.asynchronous.__delete", mock_request):
+ with patch("caqui.asynchronous._delete", mock_request):
assert await asynchronous.close_session("", "") is True
@mark.asyncio
async def test_go_to_page():
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.go_to_page("", "", "") is True
@mark.asyncio
async def test_send_keys():
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.send_keys("", "", "", "") is True
@mark.asyncio
async def test_click():
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.click("", "", "") is True
@@ -332,7 +332,7 @@ async def test_find_elements():
async def mock_request(*args, **kwargs):
return fake_responses.FIND_ELEMENTS
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert element in await asynchronous.find_elements("", "", "", "")
@@ -343,7 +343,7 @@ async def test_find_element():
async def mock_request(*args, **kwargs):
return fake_responses.FIND_ELEMENT
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.find_element("", "", "", "") == element
@@ -354,5 +354,5 @@ async def test_get_session():
async def mock_request(*args, **kwargs):
return fake_responses.GET_SESSION
- with patch("caqui.asynchronous.__post", mock_request):
+ with patch("caqui.asynchronous._post", mock_request):
assert await asynchronous.get_session(server_url="", capabilities={}) == expected
diff --git a/tests/unit/test_sync_unit.py b/tests/unit/test_sync_unit.py
index 570d4d2..74f83e3 100644
--- a/tests/unit/test_sync_unit.py
+++ b/tests/unit/test_sync_unit.py
@@ -3,33 +3,33 @@
from tests import fake_responses
-@patch("requests.request", return_value=fake_responses.GET_RECT)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_RECT)
def test_get_rect(*args):
expected = {"height": 23, "width": 183, "x": 10, "y": 9652.12}
assert synchronous.get_rect("", "", "") == expected
-@patch("requests.request", return_value=fake_responses.ACTIONS)
+@patch("caqui.synchronous.request", return_value=fake_responses.ACTIONS)
def test_actions_scroll_to_element(*args):
assert synchronous.actions_scroll_to_element("", "", "") is True
-@patch("requests.request", return_value=fake_responses.CLICK)
+@patch("caqui.synchronous.request", return_value=fake_responses.CLICK)
def test_submit(*args):
assert synchronous.submit("", "", "") is True
-@patch("requests.request", return_value=fake_responses.ACTIONS)
+@patch("caqui.synchronous.request", return_value=fake_responses.ACTIONS)
def test_actions_click(*args):
assert synchronous.actions_click("", "", "") is True
-@patch("requests.request", return_value=fake_responses.GET_TIMEOUTS)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_TIMEOUTS)
def test_set_timeouts(*args):
assert synchronous.set_timeouts("", "", "") is True
-@patch("requests.request", return_value=fake_responses.FIND_ELEMENTS)
+@patch("caqui.synchronous.request", return_value=fake_responses.FIND_ELEMENTS)
def test_find_children_elements(*args):
element = "C230605181E69CB2C4C36B8E83FE1245_element_2"
@@ -39,121 +39,121 @@ def test_find_children_elements(*args):
assert len(elements) == 3
-@patch("requests.request", return_value=fake_responses.FIND_ELEMENT)
+@patch("caqui.synchronous.request", return_value=fake_responses.FIND_ELEMENT)
def test_find_child_element(*args):
expected = "0.8851292311864847-1"
assert synchronous.find_child_element("", "", "", "", "") == expected
-@patch("requests.request", return_value=fake_responses.EXECUTE_SCRIPT)
+@patch("caqui.synchronous.request", return_value=fake_responses.EXECUTE_SCRIPT)
def test_execute_script(*args):
expected = "any"
assert synchronous.execute_script("", "", "", "") == expected
-@patch("requests.request", return_value=fake_responses.GET_PAGE_SOURCE)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_PAGE_SOURCE)
def test_get_page_source(*args):
expected = "Sample page"
assert expected in synchronous.get_page_source("", "")
-@patch("requests.request", return_value=fake_responses.GET_ALERT_TEXT)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_ALERT_TEXT)
def test_get_alert_text(*args):
expected = "any warn"
assert synchronous.get_alert_text("", "") == expected
-@patch("requests.request", return_value=fake_responses.GET_ACTIVE_ELEMENT)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_ACTIVE_ELEMENT)
def test_get_active_element(*args):
expected = "0.8851292311864847-1"
assert synchronous.get_active_element("", "") == expected
-@patch("requests.request", return_value=fake_responses.CLEAR_ELEMENT)
+@patch("caqui.synchronous.request", return_value=fake_responses.CLEAR_ELEMENT)
def test_clear_element(*args):
assert synchronous.clear_element("", "", "") is True
-@patch("requests.request", return_value=fake_responses.IS_ELEMENT_ENABLED)
+@patch("caqui.synchronous.request", return_value=fake_responses.IS_ELEMENT_ENABLED)
def test_is_element_enabled(*args):
assert synchronous.is_element_enabled("", "", "") is True
-@patch("requests.request", return_value=fake_responses.GET_CSS_COLOR_VALUE)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_CSS_COLOR_VALUE)
def test_get_css_value(*args):
expected = "rgba(0, 0, 0, 1)"
assert synchronous.get_css_value("", "", "", "") == expected
-@patch("requests.request", return_value=fake_responses.IS_ELEMENT_SELECTED)
+@patch("caqui.synchronous.request", return_value=fake_responses.IS_ELEMENT_SELECTED)
def test_is_element_selected(*args):
assert synchronous.is_element_selected("", "", "") is False
-@patch("requests.request", return_value=fake_responses.GET_WINDOW_RECTANGLE)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_WINDOW_RECTANGLE)
def test_get_window_rectangle(*args):
expected = "height"
assert expected in synchronous.get_window_rectangle("", "")
-@patch("requests.request", return_value=fake_responses.GET_WINDOW_HANDLES)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_WINDOW_HANDLES)
def test_get_window_handles(*args):
expected = "2E55CCE389196328988ED244DAA52A5D"
assert expected in synchronous.get_window_handles("", "")
-@patch("requests.request", return_value=fake_responses.CLOSE_WINDOW)
+@patch("caqui.synchronous.request", return_value=fake_responses.CLOSE_WINDOW)
def test_close_window(*args):
expected = []
assert synchronous.close_window("", "") == expected
-@patch("requests.request", return_value=fake_responses.GET_WINDOW)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_WINDOW)
def test_get_window(*args):
expected = "845623CAE8115F2B60C9AE8596F13D94"
assert expected in synchronous.get_window("", "")
-@patch("requests.request", return_value=fake_responses.GET_URL)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_URL)
def test_get_url(*args):
expected = "playground.html"
assert expected in synchronous.get_url("", "")
-@patch("requests.request", return_value=fake_responses.GET_TIMEOUTS)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_TIMEOUTS)
def test_get_timeouts(*args):
expected = "implicit"
assert expected in synchronous.get_timeouts("", "")
-@patch("requests.request", return_value=fake_responses.GET_STATUS)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_STATUS)
def test_get_status(*args):
assert synchronous.get_status("").get("value").get("ready") is True
-@patch("requests.request", return_value=fake_responses.GET_TITLE)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_TITLE)
def test_get_title(*args):
expected = "Sample page"
assert synchronous.get_title("", "") == expected
-@patch("requests.request", return_value=fake_responses.GET_COOKIES)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_COOKIES)
def test_get_cookies(*args):
expected = []
assert synchronous.get_cookies("", "") == expected
-@patch("requests.request", return_value=fake_responses.FIND_ELEMENTS)
+@patch("caqui.synchronous.request", return_value=fake_responses.FIND_ELEMENTS)
def test_find_elements(*args):
element = "C230605181E69CB2C4C36B8E83FE1245_element_2"
@@ -163,55 +163,55 @@ def test_find_elements(*args):
assert len(elements) == 3
-@patch("requests.request", return_value=fake_responses.GET_PROPERTY_VALUE)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_PROPERTY_VALUE)
def test_get_property(*args):
expected = "any_value"
assert synchronous.get_property("", "", "", "") == expected
-@patch("requests.request", return_value=fake_responses.GET_ATTRIBUTE_VALUE)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_ATTRIBUTE_VALUE)
def test_get_attribute(*args):
expected = "any_value"
assert synchronous.get_attribute("", "", "", "") == expected
-@patch("requests.request", return_value=fake_responses.GO_TO_PAGE)
+@patch("caqui.synchronous.request", return_value=fake_responses.GO_TO_PAGE)
def test_go_to_page(*args):
assert synchronous.go_to_page("", "", "") is True
-@patch("requests.request", return_value=fake_responses.CLOSE_SESSION)
+@patch("caqui.synchronous.request", return_value=fake_responses.CLOSE_SESSION)
def test_close_session(*args):
assert synchronous.close_session("", "") is True
-@patch("requests.request", return_value=fake_responses.GET_TEXT)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_TEXT)
def test_get_text(*args):
expected = "any"
assert synchronous.get_text("", "", "") == expected
-@patch("requests.request", return_value=fake_responses.SEND_KEYS)
+@patch("caqui.synchronous.request", return_value=fake_responses.SEND_KEYS)
def test_send_keys(*args):
assert synchronous.send_keys("", "", "", "") is True
-@patch("requests.request", return_value=fake_responses.CLICK)
+@patch("caqui.synchronous.request", return_value=fake_responses.CLICK)
def test_click(*args):
assert synchronous.click("", "", "") is True
-@patch("requests.request", return_value=fake_responses.GET_SESSION)
+@patch("caqui.synchronous.request", return_value=fake_responses.GET_SESSION)
def test_get_session(*args):
expected = "4358a5b53794586af59678fc1653dc40"
assert synchronous.get_session(server_url="", capabilities={}) == expected
-@patch("requests.request", return_value=fake_responses.FIND_ELEMENT)
+@patch("caqui.synchronous.request", return_value=fake_responses.FIND_ELEMENT)
def test_find_element(*args):
expected = "0.8851292311864847-1"
From 0438c578291c5d2494df2c3a4f2d2dd8e793180b Mon Sep 17 00:00:00 2001
From: Douglas Cardoso <29078346+douglasdcm@users.noreply.github.com>
Date: Sat, 29 Nov 2025 02:50:19 -0300
Subject: [PATCH 04/40] review readme
---
tests/performance/README.md | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/tests/performance/README.md b/tests/performance/README.md
index 26b0e3f..9698c50 100644
--- a/tests/performance/README.md
+++ b/tests/performance/README.md
@@ -847,12 +847,17 @@ Executed with a fresh server instance
## Scenario 6 - using `orjson` module
Executed with a fresh server instance
+Note: This was the choosen library as it has more starts in github, recent commits, a more liberative license and better/equal performance than `ujson`
- Execution 1 (duration): 27.57s
- Execution 3 (duration): 27.90s
- Execution 2 (duration): 28.11s
- mean: 27.86s
## Scenario 7 - using `urllib3` module instead of `requests`
-- Execution 1 (duration): 27.84s
-- Execution 2 (duration): 34.95s
-- Execution 3 (duration): 28.32s
\ No newline at end of file
+Not planned. Need many refactoring and has gain for specific scenarios
+
+## Scenario 8 - convert code to CPython
+- Execution 1 (duration): 27.57s
+- Execution 3 (duration): 27.90s
+- Execution 2 (duration): 28.11s
+- mean: 27.86s
From ca41d7ae8ce519035b345c16c52effea8bb30f63 Mon Sep 17 00:00:00 2001
From: Douglas Cardoso <29078346+douglasdcm@users.noreply.github.com>
Date: Sat, 29 Nov 2025 14:47:01 -0300
Subject: [PATCH 05/40] fix issues in python3.7
---
caqui/easy/capabilities.py | 60 +++++++++++++++++++-------------------
pyproject.toml | 4 ++-
2 files changed, 33 insertions(+), 31 deletions(-)
diff --git a/caqui/easy/capabilities.py b/caqui/easy/capabilities.py
index 72ba3af..7c04295 100644
--- a/caqui/easy/capabilities.py
+++ b/caqui/easy/capabilities.py
@@ -1,5 +1,5 @@
from math import ceil
-
+from typing import Union
from caqui.easy.options import BaseOptions
@@ -21,7 +21,7 @@ class ProxyConfigurationBuilder:
"""
def __init__(self) -> None:
- self.__proxy: dict = {}
+ self._proxy: dict = {}
def proxy_type(self, proxy: str):
"""
@@ -31,8 +31,8 @@ def proxy_type(self, proxy: str):
Reference: https://www.w3.org/TR/webdriver/#dfn-proxy-configuration
"""
- self.__proxy = {
- **self.__proxy,
+ self._proxy = {
+ **self._proxy,
"proxyType": proxy,
}
return self
@@ -41,8 +41,8 @@ def proxy_autoconfig_url(self, url: str):
"""
Defines the URL for a proxy auto-config file if proxyType is equal to "pac".
"""
- self.__proxy = {
- **self.__proxy,
+ self._proxy = {
+ **self._proxy,
"proxyAutoconfigUrl": url,
}
return self
@@ -53,8 +53,8 @@ def ftp_proxy(self, proxy: str):
proxy: A host and optional port for scheme "ftp".
"""
- self.__proxy = {
- **self.__proxy,
+ self._proxy = {
+ **self._proxy,
"ftpProxy": proxy,
}
return self
@@ -65,8 +65,8 @@ def http_proxy(self, proxy: str):
proxy: A host and optional port for scheme "http".
"""
- self.__proxy = {
- **self.__proxy,
+ self._proxy = {
+ **self._proxy,
"httpProxy": proxy,
}
return self
@@ -77,8 +77,8 @@ def no_proxy(self, proxies: list):
proxies: A List containing any number of Strings.
"""
- self.__proxy = {
- **self.__proxy,
+ self._proxy = {
+ **self._proxy,
"noProxy": proxies,
}
return self
@@ -89,8 +89,8 @@ def ssl_proxy(self, proxy: str):
proxy: A host and optional port for scheme "https".
"""
- self.__proxy = {
- **self.__proxy,
+ self._proxy = {
+ **self._proxy,
"sslProxy": proxy,
}
return self
@@ -101,8 +101,8 @@ def socks_proxy(self, proxy: str):
proxy: A host and optional port with an undefined scheme.
"""
- self.__proxy = {
- **self.__proxy,
+ self._proxy = {
+ **self._proxy,
"socksProxy": proxy,
}
return self
@@ -113,14 +113,14 @@ def socks_version(self, version: int):
version: Any integer between 0 and 255 inclusive.
"""
- self.__proxy = {
- **self.__proxy,
+ self._proxy = {
+ **self._proxy,
"socksVersion": version,
}
return self
def to_dict(self):
- return {"proxy": self.__proxy}
+ return {"proxy": self._proxy}
class TimeoutsBuilder:
@@ -129,13 +129,13 @@ class TimeoutsBuilder:
"""
def __init__(self) -> None:
- self.__timeouts: dict = {}
+ self._timeouts: dict = {}
def implicit(self, timeout: int):
"""Notice: if the number is a float, converts it to an integer"""
timeout = ceil(timeout)
- self.__timeouts = {
- **self.__timeouts,
+ self._timeouts = {
+ **self._timeouts,
"implicit": timeout,
}
return self
@@ -143,8 +143,8 @@ def implicit(self, timeout: int):
def page_load(self, timeout: int):
"""Notice: if the number is a float, converts it to an integer"""
timeout = ceil(timeout)
- self.__timeouts = {
- **self.__timeouts,
+ self._timeouts = {
+ **self._timeouts,
"pageLoad": timeout,
}
return self
@@ -152,14 +152,14 @@ def page_load(self, timeout: int):
def script(self, timeout: int):
"""Notice: if the number is a float, converts it to an integer"""
timeout = ceil(timeout)
- self.__timeouts = {
- **self.__timeouts,
+ self._timeouts = {
+ **self._timeouts,
"script": timeout,
}
return self
def to_dict(self):
- return {"timeouts": self.__timeouts}
+ return {"timeouts": self._timeouts}
class BaseCapabilities:
@@ -219,7 +219,7 @@ def page_load_strategy(self, strategy: str):
}
return self
- def proxy(self, proxy_configuration: dict | ProxyConfigurationBuilder):
+ def proxy(self, proxy_configuration: Union[dict, ProxyConfigurationBuilder]):
"""
Defines the current session’s proxy configuration.
Use the ProxyConfigurationBuilder class for simplicity.
@@ -242,7 +242,7 @@ def set_window_rect(self, decison: bool):
}
return self
- def timeouts(self, session_timeouts: dict | TimeoutsBuilder):
+ def timeouts(self, session_timeouts: Union[dict , TimeoutsBuilder]):
"""
Describes the timeouts imposed on certain session operations.
Use the TimeoutsBuilder class for simplicity.
@@ -299,7 +299,7 @@ def user_agent(self, agent: str):
}
return self
- def add_options(self, options: dict | BaseOptions):
+ def add_options(self, options: Union[dict , BaseOptions]):
"""Add vendor options, for example
{"goog:chromeOptions": {"extensions": [], "args": ["--headless"]}} or
{"moz:experimental-webdriver": true}
diff --git a/pyproject.toml b/pyproject.toml
index 7566698..d99ffef 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -25,7 +25,9 @@ classifiers = [
dependencies = [
"requests",
"aiohttp",
- "webdriver_manager"
+ "webdriver_manager",
+ "types-requests",
+ "orjson",
]
[project.urls]
From 4ed335be74a01f34d2fc324002f8a569e603170b Mon Sep 17 00:00:00 2001
From: Douglas Cardoso <29078346+douglasdcm@users.noreply.github.com>
Date: Sat, 29 Nov 2025 15:25:52 -0300
Subject: [PATCH 06/40] Fix python 3.7
---
.gitignore | 2 +
caqui/easy/capabilities.py | 4 +-
caqui/helper.py | 4 +-
caqui/synchronous.py | 8 +-
data-processed.txt | 236 ++++++++++++++++++
setup.py | 26 ++
test-requirements.txt | 1 +
tests/performance/test_single_session_http.py | 19 +-
utils/generate-pyx-files.py | 49 ++++
9 files changed, 331 insertions(+), 18 deletions(-)
create mode 100644 data-processed.txt
create mode 100644 setup.py
create mode 100644 utils/generate-pyx-files.py
diff --git a/.gitignore b/.gitignore
index b87ea49..24c9fc1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,8 @@ __pycache__/
# C extensions
*.so
+*.pyx
+*.c
# Distribution / packaging
.Python
diff --git a/caqui/easy/capabilities.py b/caqui/easy/capabilities.py
index 7c04295..a5c90e6 100644
--- a/caqui/easy/capabilities.py
+++ b/caqui/easy/capabilities.py
@@ -242,7 +242,7 @@ def set_window_rect(self, decison: bool):
}
return self
- def timeouts(self, session_timeouts: Union[dict , TimeoutsBuilder]):
+ def timeouts(self, session_timeouts: Union[dict, TimeoutsBuilder]):
"""
Describes the timeouts imposed on certain session operations.
Use the TimeoutsBuilder class for simplicity.
@@ -299,7 +299,7 @@ def user_agent(self, agent: str):
}
return self
- def add_options(self, options: Union[dict , BaseOptions]):
+ def add_options(self, options: Union[dict, BaseOptions]):
"""Add vendor options, for example
{"goog:chromeOptions": {"extensions": [], "args": ["--headless"]}} or
{"moz:experimental-webdriver": true}
diff --git a/caqui/helper.py b/caqui/helper.py
index 5240f93..cecec9b 100644
--- a/caqui/helper.py
+++ b/caqui/helper.py
@@ -6,12 +6,12 @@ def save_picture(session, path, file_name, response):
f.write(base64.b64decode((response)))
-def get_elements(response):
+def get_elements(response) -> list:
values = response.get("value")
return [list(value.values())[0] for value in values]
-def get_element(response) -> dict:
+def get_element(response) -> str:
value = response.get("value")
# Google Chrome
element = value.get("ELEMENT")
diff --git a/caqui/synchronous.py b/caqui/synchronous.py
index 38bb3ed..5293db8 100644
--- a/caqui/synchronous.py
+++ b/caqui/synchronous.py
@@ -30,9 +30,7 @@ def _get(url):
def _post(url, payload):
try:
- response = request(
- "POST", url, headers=HEADERS, data= dumps(payload), timeout=60
- )
+ response = request("POST", url, headers=HEADERS, data=dumps(payload), timeout=60)
return _handle_response(response)
except Exception as e:
raise WebDriverError("'POST' request failed.") from e
@@ -455,9 +453,7 @@ def find_child_element(server_url, session, parent_element, locator_type, locato
response = _post(url, payload)
return helper.get_element(response)
except Exception as e:
- raise WebDriverError(
- f"Failed to find the child element from '{parent_element}'."
- ) from e
+ raise WebDriverError(f"Failed to find the child element from '{parent_element}'.") from e
def get_page_source(server_url, session) -> str:
diff --git a/data-processed.txt b/data-processed.txt
new file mode 100644
index 0000000..6a0b15d
--- /dev/null
+++ b/data-processed.txt
@@ -0,0 +1,236 @@
+OrderedDict({'teardown': 3.67, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.66, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'call': 17.86, 'setup': 7.11, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+
+OrderedDict({'call': 32.73, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.81, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'call': 31.25, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.9, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+=====OrderedDict({'setup': 7.11, 'duration': 28.629999999999995, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.409999999999997, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.590000000000007, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.350000000000005, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.939999999999998, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.239999999999995, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.88999999999999, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52000000000001, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.90000000000001, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+=====
+OrderedDict({'setup': 7.110000000000002, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.169999999999998, 'setup': 5.5600000000000005, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.620000000000001, 'setup': 5.5200000000000005, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.420000000000001, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.320000000000001, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.730000000000004, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.700000000000001, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.910000000000004, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.350000000000005, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.000000000000004, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.549999999999997, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.809999999999995, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.900000000000002, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.80, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 28.63, 'call': 17.86, 'setup': 7.11, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.70, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.00, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.90, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'call': 32.10, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.90, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.90, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict([('setup', 7.11), ('duration', 28.63), ('teardown', 3.66), ('call', 17.86), ('title', '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 24.41), ('call', 15.17), ('setup', 5.56), ('title', '# Scenario 1 | No concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 26.59), ('call', 17.19), ('setup', 5.72), ('title', '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('teardown', 3.66), ('duration', 24.8), ('call', 15.62), ('setup', 5.52), ('title', '# Scenario 1 | No concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 25.35), ('call', 16.26), ('setup', 5.42), ('title', '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 23.94), ('call', 14.95), ('setup', 5.32), ('title', '# Scenario 1 | No concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 32.73), ('duration', 59.24), ('teardown', 12.81), ('setup', 13.7), ('title', '# Scenario 2 | With concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('call', 31.9), ('duration', 62.89), ('teardown', 13.08), ('setup', 17.91), ('title', '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('call', 32.1), ('duration', 62.52), ('teardown', 13.07), ('setup', 17.35), ('title', '# Scenario 2 | With concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup', 17.0), ('title', '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
+=====
+OrderedDict([('setup', 7.11), ('duration', 28.63), ('teardown', 3.66), ('call', 17.86), ('title', '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 24.41), ('call', 15.17), ('setup', 5.56), ('title', '# Scenario 1 | No concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 26.59), ('call', 17.19), ('setup', 5.72), ('title', '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('teardown', 3.66), ('duration', 24.8), ('call', 15.62), ('setup', 5.52), ('title', '# Scenario 1 | No concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 25.35), ('call', 16.26), ('setup', 5.42), ('title', '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 23.94), ('call', 14.95), ('setup', 5.32), ('title', '# Scenario 1 | No concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 32.73), ('duration', 59.24), ('teardown', 12.81), ('setup', 13.7), ('title', '# Scenario 2 | With concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('call', 31.9), ('duration', 62.89), ('teardown', 13.08), ('setup', 17.91), ('title', '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('call', 32.1), ('duration', 62.52), ('teardown', 13.07), ('setup', 17.35), ('title', '# Scenario 2 | With concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup', 17.0), ('title', '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
+=====
+OrderedDict([('setup', 7.11), ('duration', 28.63), ('teardown', 3.66), ('call', 17.86), ('title', '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 24.41), ('call', 15.17), ('setup', 5.56), ('title', '# Scenario 1 | No concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 26.59), ('call', 17.19), ('setup', 5.72), ('title', '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('teardown', 3.66), ('duration', 24.8), ('call', 15.62), ('setup', 5.52), ('title', '# Scenario 1 | No concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 25.35), ('call', 16.26), ('setup', 5.42), ('title', '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 23.94), ('call', 14.95), ('setup', 5.32), ('title', '# Scenario 1 | No concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 32.73), ('duration', 59.24), ('teardown', 12.81), ('setup', 13.7), ('title', '# Scenario 2 | With concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('call', 31.9), ('duration', 62.89), ('teardown', 13.08), ('setup', 17.91), ('title', '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('call', 32.1), ('duration', 62.52), ('teardown', 13.07), ('setup', 17.35), ('title', '# Scenario 2 | With concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup', 17.0), ('title', '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
+=====
+OrderedDict([('setup', 7.11), ('duration', 28.63), ('teardown', 3.66), ('call', 17.86), ('title', '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 24.41), ('call', 15.17), ('setup', 5.56), ('title', '# Scenario 1 | No concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 26.59), ('call', 17.19), ('setup', 5.72), ('title', '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('teardown', 3.66), ('duration', 24.8), ('call', 15.62), ('setup', 5.52), ('title', '# Scenario 1 | No concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 25.35), ('call', 16.26), ('setup', 5.42), ('title', '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 23.94), ('call', 14.95), ('setup', 5.32), ('title', '# Scenario 1 | No concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 32.73), ('duration', 59.24), ('teardown', 12.81), ('setup', 13.7), ('title', '# Scenario 2 | With concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('call', 31.9), ('duration', 62.89), ('teardown', 13.08), ('setup', 17.91), ('title', '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('call', 32.1), ('duration', 62.52), ('teardown', 13.07), ('setup', 17.35), ('title', '# Scenario 2 | With concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup', 17.0), ('title', '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
+=====
+OrderedDict([('setup', 7.11), ('duration', 28.63), ('teardown', 3.66), ('call', 17.86), ('title', '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 24.41), ('call', 15.17), ('setup', 5.56), ('title', '# Scenario 1 | No concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 26.59), ('call', 17.19), ('setup', 5.72), ('title', '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('teardown', 3.66), ('duration', 24.8), ('call', 15.62), ('setup', 5.52), ('title', '# Scenario 1 | No concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 25.35), ('call', 16.26), ('setup', 5.42), ('title', '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 23.94), ('call', 14.95), ('setup', 5.32), ('title', '# Scenario 1 | No concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 32.73), ('duration', 59.24), ('teardown', 12.81), ('setup', 13.7), ('title', '# Scenario 2 | With concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('call', 31.9), ('duration', 62.89), ('teardown', 13.08), ('setup', 17.91), ('title', '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('call', 32.1), ('duration', 62.52), ('teardown', 13.07), ('setup', 17.35), ('title', '# Scenario 2 | With concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup', 17.0), ('title', '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
+=====
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..eee1001
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,26 @@
+from distutils.core import setup
+from Cython.Build import cythonize
+
+setup(
+ ext_modules=cythonize(
+ [
+ "./caqui/asynchronous.pyx",
+ "./caqui/constants.pyx",
+ "./caqui/helper.pyx",
+ "./caqui/exceptions.pyx",
+ "./caqui/synchronous.pyx",
+ "./caqui/by.pyx",
+ "./caqui/__init__.pyx",
+ "./caqui/easy/capabilities.pyx",
+ "./caqui/easy/options.pyx",
+ "./caqui/easy/action_chains.pyx",
+ "./caqui/easy/alert.pyx",
+ "./caqui/easy/page.pyx",
+ "./caqui/easy/switch_to.pyx",
+ "./caqui/easy/window.pyx",
+ "./caqui/easy/element.pyx",
+ "./caqui/easy/__init__.pyx",
+ "./caqui/easy/server.pyx",
+ ]
+ )
+)
diff --git a/test-requirements.txt b/test-requirements.txt
index ec3406d..be27dee 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,3 +1,4 @@
+cython
pytest
pytest-xdist
selenium
diff --git a/tests/performance/test_single_session_http.py b/tests/performance/test_single_session_http.py
index d7ced8c..5e3a75b 100644
--- a/tests/performance/test_single_session_http.py
+++ b/tests/performance/test_single_session_http.py
@@ -14,16 +14,19 @@
CAPTURES = "captures"
LOAD = 10 # requests
+
# @mark.skip(reason="Used for performance tests")
class TestPerformance:
def _build_capabilities(self):
- options = ChromeOptionsBuilder().args([
- "headless",
- "blink-settings=imagesEnabled=false",
- "disable-extensions",
- "disable-plugins",
- "disable-background-timer-throttling"
- ])
+ options = ChromeOptionsBuilder().args(
+ [
+ "headless",
+ "blink-settings=imagesEnabled=false",
+ "disable-extensions",
+ "disable-plugins",
+ "disable-background-timer-throttling",
+ ]
+ )
capabilities = (
ChromeCapabilitiesBuilder()
.accept_insecure_certs(True)
@@ -32,7 +35,7 @@ def _build_capabilities(self):
).to_dict()
return capabilities
- async def _body(self,page):
+ async def _body(self, page):
await page.implicitly_wait(10)
await page.get(
PAGE_URL,
diff --git a/utils/generate-pyx-files.py b/utils/generate-pyx-files.py
new file mode 100644
index 0000000..dc81066
--- /dev/null
+++ b/utils/generate-pyx-files.py
@@ -0,0 +1,49 @@
+import os
+import shutil
+import subprocess
+
+
+def convert_python_to_pyx(root_folder: str):
+ """
+ Scans all subfolders of `root_folder` for .py files,
+ copies each next to the original file with a .pyx extension,
+ overwriting existing copies.
+ """
+ result = []
+ for current_path, _, files in os.walk(root_folder):
+ for filename in files:
+ if filename.endswith(".py"):
+ original_file = os.path.join(current_path, filename)
+ pyx_filename = filename[:-3] + ".pyx" # change extension
+ pyx_path = os.path.join(current_path, pyx_filename)
+
+ # Copy and overwrite
+ shutil.copyfile(original_file, pyx_path)
+ result.append(pyx_path)
+
+ content = f"""
+from distutils.core import setup
+from Cython.Build import cythonize
+setup(
+ ext_modules = cythonize(
+ {result}
+ )
+)
+"""
+ with open("setup.py", "w") as f:
+ f.write(content)
+
+
+def build_pyx():
+ # Run a simple command and capture output
+ result = subprocess.run(
+ ["python", "setup.py", "build_ext", "--inplace"], capture_output=True, text=True, check=True
+ )
+ print("Stdout:", result.stdout)
+ print("Stderr:", result.stderr)
+
+
+if __name__ == "__main__":
+ target_folder = "./caqui"
+ convert_python_to_pyx(target_folder)
+ build_pyx()
From 177c8bc30a4fbdfbd55327a7f36130c9860b06db Mon Sep 17 00:00:00 2001
From: Douglas Cardoso <29078346+douglasdcm@users.noreply.github.com>
Date: Sat, 29 Nov 2025 16:07:44 -0300
Subject: [PATCH 07/40] fix typing issues before build
---
caqui/asynchronous.py | 196 +++++++++++-------
caqui/easy/action_chains.py | 8 +-
caqui/easy/capabilities.py | 4 +-
caqui/easy/element.py | 4 +-
caqui/easy/options.py | 2 +-
caqui/easy/page.py | 6 +-
caqui/synchronous.py | 2 +-
data-processed.txt | 13 ++
...nerate-pyx-files.py => build-pyx-files.py} | 0
utils/cleanup-cpython-files.py | 32 +++
10 files changed, 182 insertions(+), 85 deletions(-)
rename utils/{generate-pyx-files.py => build-pyx-files.py} (100%)
create mode 100644 utils/cleanup-cpython-files.py
diff --git a/caqui/asynchronous.py b/caqui/asynchronous.py
index 7b6b4a6..42b20be 100644
--- a/caqui/asynchronous.py
+++ b/caqui/asynchronous.py
@@ -3,7 +3,7 @@
from caqui.constants import HEADERS
from caqui.exceptions import WebDriverError
from caqui.helper import save_picture, get_elements, get_element
-from typing import Optional
+from typing import Any, List, Optional, Union
async def _handle_response(resp):
@@ -21,7 +21,7 @@ async def _handle_response(resp):
return result
-async def _delete(url, session_http: ClientSession = None):
+async def _delete(url, session_http: Union[ClientSession, None] = None):
if session_http:
try:
async with session_http.delete(url, headers=HEADERS) as resp:
@@ -38,7 +38,7 @@ async def _delete(url, session_http: ClientSession = None):
raise WebDriverError("'DELETE' request failed.") from e
-async def _post(url, payload, session_http: ClientSession = None):
+async def _post(url, payload, session_http: Union[ClientSession, None] = None):
if session_http:
try:
async with session_http.post(url, data=dumps(payload), headers=HEADERS) as resp:
@@ -54,7 +54,7 @@ async def _post(url, payload, session_http: ClientSession = None):
raise WebDriverError("'POST' request failed.") from e
-async def _get(url, session_http: ClientSession = None):
+async def _get(url, session_http: Union[ClientSession, None] = None):
if session_http:
try:
async with session_http.get(url, headers=HEADERS) as resp:
@@ -79,14 +79,16 @@ async def _handle_alert(server_url, session, command, session_http) -> bool:
return True
-async def _handle_window(server_url, session, command, session_http: ClientSession = None):
+async def _handle_window(
+ server_url, session, command, session_http: Union[ClientSession, None] = None
+):
url = f"{server_url}/session/{session}/window/{command}"
- payload = {}
+ payload: dict = {}
await _post(url, payload, session_http=session_http)
return True
-async def add_cookie(server_url, session, cookie, session_http: ClientSession = None):
+async def add_cookie(server_url, session, cookie, session_http: Union[ClientSession, None] = None):
"""Add cookie"""
try:
url = f"{server_url}/session/{session}/cookie"
@@ -97,7 +99,7 @@ async def add_cookie(server_url, session, cookie, session_http: ClientSession =
raise WebDriverError("Failed to add cookie.") from e
-async def delete_cookie(server_url, session, name, session_http: ClientSession = None):
+async def delete_cookie(server_url, session, name, session_http: Union[ClientSession, None] = None):
"""Delete cookie by name"""
try:
url = f"{server_url}/session/{session}/cookie/{name}"
@@ -107,22 +109,22 @@ async def delete_cookie(server_url, session, name, session_http: ClientSession =
raise WebDriverError(f"Failed to delete cookie '{name}'.") from e
-async def refresh_page(server_url, session, session_http: ClientSession = None):
+async def refresh_page(server_url, session, session_http: Union[ClientSession, None] = None):
"""Refresh page"""
try:
url = f"{server_url}/session/{session}/refresh"
- payload = {}
+ payload: dict = {}
await _post(url, payload, session_http=session_http)
return True
except Exception as e:
raise WebDriverError("Failed to refresh page.") from e
-async def go_forward(server_url, session, session_http: ClientSession = None):
+async def go_forward(server_url, session, session_http: Union[ClientSession, None] = None):
"""Go to page forward"""
try:
url = f"{server_url}/session/{session}/forward"
- payload = {}
+ payload: dict = {}
await _post(url, payload, session_http=session_http)
return True
except Exception as e:
@@ -140,7 +142,7 @@ async def set_window_rectangle(server_url, session, width, height, x, y, session
raise WebDriverError("Failed to set window rectangle.") from e
-async def fullscreen_window(server_url, session, session_http: ClientSession = None):
+async def fullscreen_window(server_url, session, session_http: Union[ClientSession, None] = None):
"""Fullscreen window"""
try:
return await _handle_window(
@@ -150,7 +152,7 @@ async def fullscreen_window(server_url, session, session_http: ClientSession = N
raise WebDriverError("Failed to fullscreen window.") from e
-async def minimize_window(server_url, session, session_http: ClientSession = None):
+async def minimize_window(server_url, session, session_http: Union[ClientSession, None] = None):
"""Minimize window"""
try:
return await _handle_window(
@@ -160,7 +162,7 @@ async def minimize_window(server_url, session, session_http: ClientSession = Non
raise WebDriverError("Failed to minimize window.") from e
-async def maximize_window(server_url, session, session_http: ClientSession = None):
+async def maximize_window(server_url, session, session_http: Union[ClientSession, None] = None):
"""Maximize window"""
try:
return await _handle_window(
@@ -170,7 +172,9 @@ async def maximize_window(server_url, session, session_http: ClientSession = Non
raise WebDriverError("Failed to maximize window.") from e
-async def switch_to_window(server_url, session, handle, session_http: ClientSession = None):
+async def switch_to_window(
+ server_url, session, handle, session_http: Union[ClientSession, None] = None
+):
"""Switch to window"""
try:
url = f"{server_url}/session/{session}/window"
@@ -182,7 +186,7 @@ async def switch_to_window(server_url, session, handle, session_http: ClientSess
async def new_window(
- server_url, session, window_type="tab", session_http: ClientSession = None
+ server_url, session, window_type="tab", session_http: Union[ClientSession, None] = None
) -> str:
"""Open a new window
:param window_type (str): tab or window
@@ -199,7 +203,7 @@ async def new_window(
async def switch_to_parent_frame(
- server_url, session, element_frame, session_http: ClientSession = None
+ server_url, session, element_frame, session_http: Union[ClientSession, None] = None
):
"""Switch to parent frame of 'element_frame'"""
try:
@@ -211,7 +215,9 @@ async def switch_to_parent_frame(
raise WebDriverError("Failed to switch to parent frame.") from e
-async def switch_to_frame(server_url, session, element_frame, session_http: ClientSession = None):
+async def switch_to_frame(
+ server_url, session, element_frame, session_http: Union[ClientSession, None] = None
+):
"""Switch to frame 'element_frame'"""
try:
url = f"{server_url}/session/{session}/frame"
@@ -222,7 +228,7 @@ async def switch_to_frame(server_url, session, element_frame, session_http: Clie
raise WebDriverError("Failed to switch to frame.") from e
-async def delete_all_cookies(server_url, session, session_http: ClientSession = None):
+async def delete_all_cookies(server_url, session, session_http: Union[ClientSession, None] = None):
"""Delete all cookies"""
try:
url = f"{server_url}/session/{session}/cookie"
@@ -232,7 +238,9 @@ async def delete_all_cookies(server_url, session, session_http: ClientSession =
raise WebDriverError("Failed to delete cookies.") from e
-async def send_alert_text(server_url, session, text, session_http: ClientSession = None):
+async def send_alert_text(
+ server_url, session, text, session_http: Union[ClientSession, None] = None
+):
"""Fill the alert text area and send the text"""
try:
url = f"{server_url}/session/{session}/alert/text"
@@ -245,7 +253,7 @@ async def send_alert_text(server_url, session, text, session_http: ClientSession
raise WebDriverError("Failed to sent text to alert.") from e
-async def accept_alert(server_url, session, session_http: ClientSession = None):
+async def accept_alert(server_url, session, session_http: Union[ClientSession, None] = None):
"""Accept alert"""
try:
return await _handle_alert(server_url, session, "accept", session_http=session_http)
@@ -253,7 +261,7 @@ async def accept_alert(server_url, session, session_http: ClientSession = None):
raise WebDriverError("Failed to accept alert.") from e
-async def dismiss_alert(server_url, session, session_http: ClientSession = None):
+async def dismiss_alert(server_url, session, session_http: Union[ClientSession, None] = None):
"""Dismiss alert"""
try:
return await _handle_alert(server_url, session, "dismiss", session_http=session_http)
@@ -267,7 +275,7 @@ async def take_screenshot_element(
element,
path="/tmp",
file_name="caqui",
- session_http: ClientSession = None,
+ session_http: Union[ClientSession, None] = None,
):
"""Take screenshot of element"""
try:
@@ -285,7 +293,7 @@ async def take_screenshot(
session,
path="/tmp",
file_name="caqui",
- session_http: ClientSession = None,
+ session_http: Union[ClientSession, None] = None,
):
"""Take screenshot"""
try:
@@ -298,7 +306,9 @@ async def take_screenshot(
raise WebDriverError("Failed to take screenshot.") from e
-async def get_named_cookie(server_url, session, name, session_http: ClientSession = None) -> str:
+async def get_named_cookie(
+ server_url, session, name, session_http: Union[ClientSession, None] = None
+) -> str:
"""Get cookie by name"""
try:
url = f"{server_url}/session/{session}/cookie/{name}"
@@ -309,7 +319,7 @@ async def get_named_cookie(server_url, session, name, session_http: ClientSessio
async def get_computed_label(
- server_url, session, element, session_http: ClientSession = None
+ server_url, session, element, session_http: Union[ClientSession, None] = None
) -> str:
"""Get the element tag computed label. Get the accessibility name"""
try:
@@ -321,7 +331,7 @@ async def get_computed_label(
async def get_computed_role(
- server_url, session, element, session_http: ClientSession = None
+ server_url, session, element, session_http: Union[ClientSession, None] = None
) -> str:
"""Get the element tag computed role (the element role)"""
try:
@@ -332,7 +342,9 @@ async def get_computed_role(
raise WebDriverError("Failed to get element computed role.") from e
-async def get_tag_name(server_url, session, element, session_http: ClientSession = None) -> str:
+async def get_tag_name(
+ server_url, session, element, session_http: Union[ClientSession, None] = None
+) -> str:
"""Get the element tag name"""
try:
url = f"{server_url}/session/{session}/element/{element}/name"
@@ -342,7 +354,9 @@ async def get_tag_name(server_url, session, element, session_http: ClientSession
raise WebDriverError("Failed to get element name.") from e
-async def get_shadow_root(server_url, session, element, session_http: ClientSession = None) -> dict:
+async def get_shadow_root(
+ server_url, session, element, session_http: Union[ClientSession, None] = None
+) -> dict:
"""Get the shadow root element"""
try:
root_element = "shadow-6066-11e4-a52e-4f735466cecf"
@@ -353,7 +367,9 @@ async def get_shadow_root(server_url, session, element, session_http: ClientSess
raise WebDriverError("Failed to get element shadow.") from e
-async def get_rect(server_url, session, element, session_http: ClientSession = None) -> dict:
+async def get_rect(
+ server_url, session, element, session_http: Union[ClientSession, None] = None
+) -> dict:
"""Get the element rectangle"""
try:
url = f"{server_url}/session/{session}/element/{element}/rect"
@@ -363,13 +379,15 @@ async def get_rect(server_url, session, element, session_http: ClientSession = N
raise WebDriverError("Failed to get element rect.") from e
-async def actions(server_url, session, payload, session_http: ClientSession = None):
+async def actions(server_url, session, payload, session_http: Union[ClientSession, None] = None):
url = f"{server_url}/session/{session}/actions"
await _post(url, payload, session_http=session_http)
return True
-async def actions_move_to_element(server_url, session, element, session_http: ClientSession = None):
+async def actions_move_to_element(
+ server_url, session, element, session_http: Union[ClientSession, None] = None
+):
"""Move to an element simulating a mouse movement"""
try:
payload = {
@@ -401,7 +419,7 @@ async def actions_move_to_element(server_url, session, element, session_http: Cl
async def actions_scroll_to_element(
- server_url, session, element, session_http: ClientSession = None
+ server_url, session, element, session_http: Union[ClientSession, None] = None
):
"""Scroll to an element simulating a mouse movement"""
try:
@@ -429,7 +447,7 @@ async def actions_scroll_to_element(
raise WebDriverError("Failed to scroll to element.") from e
-async def submit(server_url, session, element, session_http: ClientSession = None):
+async def submit(server_url, session, element, session_http: Union[ClientSession, None] = None):
"""Submit a form. It is similar to 'submit' funtion in Seleniu
It is not part of W3C WebDriver. Just added for convenience
"""
@@ -447,7 +465,9 @@ async def submit(server_url, session, element, session_http: ClientSession = Non
raise WebDriverError("Failed to submit form.") from e
-async def actions_click(server_url, session, element, session_http: ClientSession = None):
+async def actions_click(
+ server_url, session, element, session_http: Union[ClientSession, None] = None
+):
"""Click an element simulating a mouse movement"""
try:
payload = {
@@ -484,7 +504,9 @@ async def actions_click(server_url, session, element, session_http: ClientSessio
raise WebDriverError("Failed to click the element.") from e
-async def set_timeouts(server_url, session, timeouts, session_http: ClientSession = None):
+async def set_timeouts(
+ server_url, session, timeouts, session_http: Union[ClientSession, None] = None
+):
"""Set timeouts"""
try:
url = f"{server_url}/session/{session}/timeouts"
@@ -503,7 +525,7 @@ async def find_children_elements(
parent_element,
locator_type,
locator_value,
- session_http: ClientSession = None,
+ session_http: Union[ClientSession, None] = None,
):
"""Find the children elements by 'locator_type'
@@ -527,7 +549,7 @@ async def find_child_element(
parent_element,
locator_type,
locator_value,
- session_http: ClientSession = None,
+ session_http: Union[ClientSession, None] = None,
):
"""Find the child element by 'locator_type'"""
try:
@@ -539,7 +561,9 @@ async def find_child_element(
raise WebDriverError(f"Failed to find the child element from '{parent_element}'.") from e
-async def get_page_source(server_url, session, session_http: ClientSession = None) -> str:
+async def get_page_source(
+ server_url, session, session_http: Union[ClientSession, None] = None
+) -> str:
"""Get the page source (all content)"""
try:
url = f"{server_url}/session/{session}/source"
@@ -549,7 +573,9 @@ async def get_page_source(server_url, session, session_http: ClientSession = Non
raise WebDriverError("Failed to get the page source.") from e
-async def execute_script(server_url, session, script, args=[], session_http: ClientSession = None):
+async def execute_script(
+ server_url, session, script, args=[], session_http: Union[ClientSession, None] = None
+):
"""Executes a script, like 'alert('something')' to open an alert window"""
try:
url = f"{server_url}/session/{session}/execute/sync"
@@ -560,7 +586,9 @@ async def execute_script(server_url, session, script, args=[], session_http: Cli
raise WebDriverError("Failed to execute script.") from e
-async def get_alert_text(server_url, session, session_http: ClientSession = None) -> str:
+async def get_alert_text(
+ server_url, session, session_http: Union[ClientSession, None] = None
+) -> str:
"""Get the text from an alert"""
try:
url = f"{server_url}/session/{session}/alert/text"
@@ -570,7 +598,7 @@ async def get_alert_text(server_url, session, session_http: ClientSession = None
raise WebDriverError("Failed to get the alert text.") from e
-async def get_active_element(server_url, session, session_http: ClientSession = None):
+async def get_active_element(server_url, session, session_http: Union[ClientSession, None] = None):
"""Get the active element"""
try:
url = f"{server_url}/session/{session}/element/active"
@@ -580,7 +608,9 @@ async def get_active_element(server_url, session, session_http: ClientSession =
raise WebDriverError("Failed to check if element is selected.") from e
-async def clear_element(server_url, session, element, session_http: ClientSession = None):
+async def clear_element(
+ server_url, session, element, session_http: Union[ClientSession, None] = None
+):
"""Clear the element text"""
try:
url = f"{server_url}/session/{session}/element/{element}/clear"
@@ -592,7 +622,7 @@ async def clear_element(server_url, session, element, session_http: ClientSessio
async def is_element_enabled(
- server_url, session, element, session_http: ClientSession = None
+ server_url, session, element, session_http: Union[ClientSession, None] = None
) -> bool:
"""Check if element is enabled"""
try:
@@ -604,7 +634,7 @@ async def is_element_enabled(
async def get_css_value(
- server_url, session, element, property_name, session_http: ClientSession = None
+ server_url, session, element, property_name, session_http: Union[ClientSession, None] = None
) -> str:
"""Check if element is selected"""
try:
@@ -616,18 +646,20 @@ async def get_css_value(
async def is_element_selected(
- server_url, session, element, session_http: ClientSession = None
-) -> str:
+ server_url, session, element, session_http: Union[ClientSession, None] = None
+) -> bool:
"""Check if element is selected"""
try:
url = f"{server_url}/session/{session}/element/{element}/selected"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return bool(response.get("value"))
except Exception as e:
raise WebDriverError("Failed to check if element is selected.") from e
-async def get_window_rectangle(server_url, session, session_http: ClientSession = None) -> dict:
+async def get_window_rectangle(
+ server_url, session, session_http: Union[ClientSession, None] = None
+) -> dict:
"""Get window rectangle"""
try:
url = f"{server_url}/session/{session}/window/rect"
@@ -637,7 +669,9 @@ async def get_window_rectangle(server_url, session, session_http: ClientSession
raise WebDriverError("Failed to get window rectangle.") from e
-async def get_window_handles(server_url, session, session_http: ClientSession = None) -> list:
+async def get_window_handles(
+ server_url, session, session_http: Union[ClientSession, None] = None
+) -> list:
"""Get window handles"""
try:
url = f"{server_url}/session/{session}/window/handles"
@@ -647,7 +681,9 @@ async def get_window_handles(server_url, session, session_http: ClientSession =
raise WebDriverError("Failed to get window handles.") from e
-async def close_window(server_url, session, session_http: ClientSession = None) -> list:
+async def close_window(
+ server_url, session, session_http: Union[ClientSession, None] = None
+) -> list:
"""Close active window"""
try:
url = f"{server_url}/session/{session}/window"
@@ -657,7 +693,7 @@ async def close_window(server_url, session, session_http: ClientSession = None)
raise WebDriverError("Failed to close active window.") from e
-async def get_window(server_url, session, session_http: ClientSession = None) -> str:
+async def get_window(server_url, session, session_http: Union[ClientSession, None] = None) -> str:
"""Get window"""
try:
url = f"{server_url}/session/{session}/window"
@@ -667,7 +703,7 @@ async def get_window(server_url, session, session_http: ClientSession = None) ->
raise WebDriverError("Failed to get window.") from e
-async def go_back(server_url, session, session_http: ClientSession = None):
+async def go_back(server_url, session, session_http: Union[ClientSession, None] = None):
"""
This command causes the browser to traverse one step backward
in the joint session history of the
@@ -681,7 +717,7 @@ async def go_back(server_url, session, session_http: ClientSession = None):
raise WebDriverError("Failed to go back to page.") from e
-async def get_url(server_url, session, session_http: ClientSession = None) -> str:
+async def get_url(server_url, session, session_http: Union[ClientSession, None] = None) -> str:
"""Returns the URL from web page:"""
try:
url = f"{server_url}/session/{session}/url"
@@ -691,7 +727,9 @@ async def get_url(server_url, session, session_http: ClientSession = None) -> st
raise WebDriverError("Failed to get page url.") from e
-async def get_timeouts(server_url, session, session_http: ClientSession = None) -> dict:
+async def get_timeouts(
+ server_url, session, session_http: Union[ClientSession, None] = None
+) -> dict:
"""
Returns the configured timeouts:
{"implicit": 0, "pageLoad": 300000, "script": 30000}
@@ -704,7 +742,7 @@ async def get_timeouts(server_url, session, session_http: ClientSession = None)
raise WebDriverError("Failed to get timeouts.") from e
-async def get_status(server_url, session_http: ClientSession = None) -> dict:
+async def get_status(server_url, session_http: Union[ClientSession, None] = None) -> dict:
"""Returns the status and details of the WebDriver"""
try:
url = f"{server_url}/status"
@@ -714,7 +752,7 @@ async def get_status(server_url, session_http: ClientSession = None) -> dict:
raise WebDriverError("Failed to get status.") from e
-async def get_title(server_url, session, session_http: ClientSession = None) -> str:
+async def get_title(server_url, session, session_http: Union[ClientSession, None] = None) -> str:
"""Get the page title"""
try:
url = f"{server_url}/session/{session}/title"
@@ -725,8 +763,12 @@ async def get_title(server_url, session, session_http: ClientSession = None) ->
async def find_elements(
- server_url, session, locator_type, locator_value, session_http: ClientSession = None
-) -> str:
+ server_url,
+ session,
+ locator_type,
+ locator_value,
+ session_http: Union[ClientSession, None] = None,
+) -> List[Any]:
"""Search the DOM elements by 'locator', for example, 'xpath'"""
try:
payload = {"using": locator_type, "value": locator_value}
@@ -740,7 +782,7 @@ async def find_elements(
async def get_property(
- server_url, session, element, property, session_http: ClientSession = None
+ server_url, session, element, property, session_http: Union[ClientSession, None] = None
) -> str:
"""Get the given HTML property of an element, for example, 'href'"""
try:
@@ -752,7 +794,7 @@ async def get_property(
async def get_attribute(
- server_url, session, element, attribute, session_http: ClientSession = None
+ server_url, session, element, attribute, session_http: Union[ClientSession, None] = None
) -> str:
"""Get the given HTML attribute of an element, for example, 'aria-valuenow'"""
try:
@@ -763,7 +805,9 @@ async def get_attribute(
raise WebDriverError("Failed to get value from element.") from e
-async def get_text(server_url, session, element, session_http: ClientSession = None) -> str:
+async def get_text(
+ server_url, session, element, session_http: Union[ClientSession, None] = None
+) -> str:
"""Get the text of an element"""
try:
url = f"{server_url}/session/{session}/element/{element}/text"
@@ -773,7 +817,7 @@ async def get_text(server_url, session, element, session_http: ClientSession = N
raise WebDriverError("Failed to get text from element.") from e
-async def get_cookies(server_url, session, session_http: ClientSession = None) -> list:
+async def get_cookies(server_url, session, session_http: Union[ClientSession, None] = None) -> list:
"""Get the page cookies"""
try:
url = f"{server_url}/session/{session}/cookie"
@@ -783,7 +827,7 @@ async def get_cookies(server_url, session, session_http: ClientSession = None) -
raise WebDriverError("Failed to get page cookies.") from e
-async def close_session(server_url, session, session_http: ClientSession = None):
+async def close_session(server_url, session, session_http: Union[ClientSession, None] = None):
"""Close an opened session and close the browser"""
try:
url = f"{server_url}/session/{session}"
@@ -793,12 +837,14 @@ async def close_session(server_url, session, session_http: ClientSession = None)
raise WebDriverError("Failed to close session.") from e
-async def get(server_url, session, page_url, session_http: ClientSession = None):
+async def get(server_url, session, page_url, session_http: Union[ClientSession, None] = None):
"""Does the same of 'go_to_page'. Added to be compatible with selenium method name'"""
return go_to_page(server_url, session, page_url, session_http=session_http)
-async def go_to_page(server_url, session, page_url, session_http: ClientSession = None):
+async def go_to_page(
+ server_url, session, page_url, session_http: Union[ClientSession, None] = None
+):
"""Navigate to 'page_url'"""
try:
url = f"{server_url}/session/{session}/url"
@@ -809,7 +855,9 @@ async def go_to_page(server_url, session, page_url, session_http: ClientSession
raise WebDriverError(f"Failed to navigate to page '{page_url}'.") from e
-async def send_keys(server_url, session, element, text, session_http: ClientSession = None):
+async def send_keys(
+ server_url, session, element, text, session_http: Union[ClientSession, None] = None
+):
"""Fill an editable element, for example a textarea, with a given text"""
try:
url = f"{server_url}/session/{session}/element/{element}/value"
@@ -820,7 +868,7 @@ async def send_keys(server_url, session, element, text, session_http: ClientSess
raise WebDriverError(f"Failed to send key '{text}'.") from e
-async def click(server_url, session, element, session_http: ClientSession = None):
+async def click(server_url, session, element, session_http: Union[ClientSession, None] = None):
"""Click on an element"""
try:
payload = {"id": element}
@@ -832,8 +880,12 @@ async def click(server_url, session, element, session_http: ClientSession = None
async def find_element(
- server_url, session, locator_type, locator_value, session_http: ClientSession = None
-) -> dict:
+ server_url,
+ session,
+ locator_type,
+ locator_value,
+ session_http: Union[ClientSession, None] = None,
+) -> str:
"""Find an element by a 'locator', for example 'xpath'"""
try:
@@ -855,7 +907,7 @@ async def find_element(
async def get_session(
server_url: str,
capabilities: Optional[dict] = None,
- session_http: ClientSession = None,
+ session_http: Union[ClientSession, None] = None,
) -> str:
"""
Opens a browser and a session.
diff --git a/caqui/easy/action_chains.py b/caqui/easy/action_chains.py
index cc7181e..fc1002a 100644
--- a/caqui/easy/action_chains.py
+++ b/caqui/easy/action_chains.py
@@ -1,6 +1,6 @@
from caqui import asynchronous
from caqui.easy.element import Element
-from typing import Coroutine
+from typing import Coroutine, Union, List
class ActionChains:
@@ -8,8 +8,8 @@ def __init__(self, driver) -> None:
self._remote = driver.remote
self._session = driver.session
self._session_http = driver.session_http
- self._coroutines: list[Coroutine] = []
- self._element = None
+ self._coroutines: List[Coroutine] = []
+ self._element = Union[Element, None]
def click(self, element: Element):
"""
@@ -31,7 +31,7 @@ def move_to_element(self, element: Element):
self._coroutines.append(coroutine)
return self
- def scroll_to_element(self, element: Element):
+ def scroll_to_element(self, element: Element) -> "ActionChains":
"""Scrolls the screen to the element `element`"""
self._element = element
coroutine = asynchronous.actions_scroll_to_element(
diff --git a/caqui/easy/capabilities.py b/caqui/easy/capabilities.py
index a5c90e6..7429f20 100644
--- a/caqui/easy/capabilities.py
+++ b/caqui/easy/capabilities.py
@@ -228,7 +228,7 @@ def proxy(self, proxy_configuration: Union[dict, ProxyConfigurationBuilder]):
proxy_configuration = proxy_configuration.to_dict()
self.desired_capabilities = {
**self.desired_capabilities,
- **proxy_configuration,
+ **proxy_configuration, # type: ignore
}
return self
@@ -251,7 +251,7 @@ def timeouts(self, session_timeouts: Union[dict, TimeoutsBuilder]):
session_timeouts = session_timeouts.to_dict()
self.desired_capabilities = {
**self.desired_capabilities,
- **session_timeouts,
+ **session_timeouts, # type: ignore
}
return self
diff --git a/caqui/easy/element.py b/caqui/easy/element.py
index fd96643..1fcbd3a 100644
--- a/caqui/easy/element.py
+++ b/caqui/easy/element.py
@@ -149,7 +149,7 @@ async def click(self):
self._remote, self._session, self._element, session_http=self._session_http
)
- async def find_elements(self, locator, value):
+ async def find_elements(self, locator, value) -> list:
"""
Find the children elements by 'locator_type'
@@ -169,7 +169,7 @@ async def find_elements(self, locator, value):
result.append(Element(element, self._driver))
return result
- async def find_element(self, locator, value):
+ async def find_element(self, locator, value) -> "Element":
"""Find the element by `locator_type`"""
element = await asynchronous.find_child_element(
self._remote,
diff --git a/caqui/easy/options.py b/caqui/easy/options.py
index 71cb008..b9e68b3 100644
--- a/caqui/easy/options.py
+++ b/caqui/easy/options.py
@@ -93,7 +93,7 @@ def windows_types(self, values: list):
self.options = {**self.options, **{"windowsTypes": values}}
return self
- def to_dict(self):
+ def to_dict(self) -> dict:
"""Converts the options to a dict"""
return {"goog:chromeOptions": self.options}
diff --git a/caqui/easy/page.py b/caqui/easy/page.py
index 8bbccbf..5c2a6f3 100644
--- a/caqui/easy/page.py
+++ b/caqui/easy/page.py
@@ -17,7 +17,7 @@ def __init__(
server_url: str,
capabilities: Optional[dict] = None,
url: Union[str, None] = None,
- session_http: ClientSession = None,
+ session_http: Union[ClientSession, None] = None,
) -> None:
"""Mimics Selenium methods"""
self.session_http = session_http
@@ -231,7 +231,7 @@ async def get(self, url):
self._server_url, self._session, url, session_http=self.session_http
)
- async def find_elements(self, locator, value):
+ async def find_elements(self, locator, value) -> list:
"""Search the DOM elements by 'locator', for example, 'xpath'"""
elements = await asynchronous.find_elements(
self._server_url, self._session, locator, value, session_http=self.session_http
@@ -241,7 +241,7 @@ async def find_elements(self, locator, value):
result.append(Element(element, self))
return result
- async def find_element(self, locator, value):
+ async def find_element(self, locator, value) -> Element:
"""Find an element by a 'locator', for example 'xpath'"""
element = await asynchronous.find_element(
self._server_url, self._session, locator, value, session_http=self.session_http
diff --git a/caqui/synchronous.py b/caqui/synchronous.py
index 5293db8..315c39b 100644
--- a/caqui/synchronous.py
+++ b/caqui/synchronous.py
@@ -752,7 +752,7 @@ def get_session(server_url: str, capabilities: Optional[dict] = None):
raise WebDriverError("Failed to open session. Check the browser capabilities.") from e
-def find_element(server_url, session, locator_type, locator_value) -> dict:
+def find_element(server_url, session, locator_type, locator_value) -> str:
"""Find an element by a 'locator', for example 'xpath'"""
try:
url = f"{server_url}/session/{session}/element"
diff --git a/data-processed.txt b/data-processed.txt
index 6a0b15d..4a52274 100644
--- a/data-processed.txt
+++ b/data-processed.txt
@@ -234,3 +234,16 @@ OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup'
OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
=====
+OrderedDict([('setup', 7.11), ('duration', 28.63), ('teardown', 3.66), ('call', 17.86), ('title', '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 24.41), ('call', 15.17), ('setup', 5.56), ('title', '# Scenario 1 | No concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 26.59), ('call', 17.19), ('setup', 5.72), ('title', '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('teardown', 3.66), ('duration', 24.8), ('call', 15.62), ('setup', 5.52), ('title', '# Scenario 1 | No concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 25.35), ('call', 16.26), ('setup', 5.42), ('title', '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 23.94), ('call', 14.95), ('setup', 5.32), ('title', '# Scenario 1 | No concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 32.73), ('duration', 59.24), ('teardown', 12.81), ('setup', 13.7), ('title', '# Scenario 2 | With concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('call', 31.9), ('duration', 62.89), ('teardown', 13.08), ('setup', 17.91), ('title', '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('call', 32.1), ('duration', 62.52), ('teardown', 13.07), ('setup', 17.35), ('title', '# Scenario 2 | With concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup', 17.0), ('title', '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
+=====
diff --git a/utils/generate-pyx-files.py b/utils/build-pyx-files.py
similarity index 100%
rename from utils/generate-pyx-files.py
rename to utils/build-pyx-files.py
diff --git a/utils/cleanup-cpython-files.py b/utils/cleanup-cpython-files.py
new file mode 100644
index 0000000..f528cfe
--- /dev/null
+++ b/utils/cleanup-cpython-files.py
@@ -0,0 +1,32 @@
+import os
+
+
+def remove_cython_build_files(root_dir):
+ """
+ Removes .pyx and .c files from the specified root directory and its subdirectories.
+
+ Args:
+ root_dir (str): The path to the root directory to clean.
+ """
+ for dirpath, dirnames, filenames in os.walk(root_dir):
+ for filename in filenames:
+ if filename.endswith(".pyx") or filename.endswith(".c") or filename.endswith(".so"):
+ file_path = os.path.join(dirpath, filename)
+ try:
+ os.remove(file_path)
+ print(f"Removed: {file_path}")
+ except OSError as e:
+ print(f"Error removing {file_path}: {e}")
+
+
+if __name__ == "__main__":
+ # Specify the directory to clean.
+ # For example, to clean the current directory:
+ # directory_to_clean = "."
+ # Or a specific path:
+ directory_to_clean = "./caqui"
+
+ if os.path.exists(directory_to_clean):
+ remove_cython_build_files(directory_to_clean)
+ else:
+ print(f"Error: Directory '{directory_to_clean}' not found.")
From 51bf4250f5eaeb96aa8c0b3ce6bacd960a441717 Mon Sep 17 00:00:00 2001
From: Douglas Cardoso <29078346+douglasdcm@users.noreply.github.com>
Date: Sun, 30 Nov 2025 11:51:01 -0300
Subject: [PATCH 08/40] build using cython working
---
caqui/asynchronous.py | 50 +++++-----
caqui/easy/page.py | 2 +-
caqui/easy/server.py | 4 +-
caqui/easy/switch_to.py | 5 +-
caqui/easy/window.py | 6 +-
caqui/synchronous.py | 22 +++--
data-processed.txt | 91 +++++++++++++++++++
pyproject.toml | 16 +++-
pytest.ini | 2 +-
setup.py | 26 +-----
tests/conftest.py | 14 +--
tests/feature/test_async_with_http_session.py | 41 ++++-----
tests/feature/test_sync_and_async.py | 37 ++++----
tests/integration/test_capabilities.py | 4 +-
tests/integration/test_options.py | 4 +-
tests/performance/README.md | 5 +-
tests/unit/test_async_unit.py | 6 +-
tests/unit/test_by.py | 3 +-
tests/unit/test_sync_unit.py | 6 +-
19 files changed, 219 insertions(+), 125 deletions(-)
diff --git a/caqui/asynchronous.py b/caqui/asynchronous.py
index 42b20be..e4a8315 100644
--- a/caqui/asynchronous.py
+++ b/caqui/asynchronous.py
@@ -6,7 +6,7 @@
from typing import Any, List, Optional, Union
-async def _handle_response(resp):
+async def _handle_response(resp) -> Any:
result = None
if resp.status in range(200, 399):
result = await resp.json()
@@ -54,7 +54,7 @@ async def _post(url, payload, session_http: Union[ClientSession, None] = None):
raise WebDriverError("'POST' request failed.") from e
-async def _get(url, session_http: Union[ClientSession, None] = None):
+async def _get(url, session_http: Union[ClientSession, None] = None) -> dict:
if session_http:
try:
async with session_http.get(url, headers=HEADERS) as resp:
@@ -308,12 +308,12 @@ async def take_screenshot(
async def get_named_cookie(
server_url, session, name, session_http: Union[ClientSession, None] = None
-) -> str:
+) -> dict:
"""Get cookie by name"""
try:
url = f"{server_url}/session/{session}/cookie/{name}"
response = await _get(url, session_http)
- return response.get("value")
+ return response.get("value", {})
except Exception as e:
raise WebDriverError(f"Failed to get cookie '{name}'.") from e
@@ -325,7 +325,7 @@ async def get_computed_label(
try:
url = f"{server_url}/session/{session}/element/{element}/computedlabel"
response = await _get(url, session_http)
- return response.get("value")
+ return response.get("value", "")
except Exception as e:
raise WebDriverError("Failed to get element computed label.") from e
@@ -337,7 +337,7 @@ async def get_computed_role(
try:
url = f"{server_url}/session/{session}/element/{element}/computedrole"
response = await _get(url, session_http)
- return response.get("value")
+ return response.get("value", "")
except Exception as e:
raise WebDriverError("Failed to get element computed role.") from e
@@ -349,14 +349,14 @@ async def get_tag_name(
try:
url = f"{server_url}/session/{session}/element/{element}/name"
response = await _get(url, session_http)
- return response.get("value")
+ return response.get("value", "")
except Exception as e:
raise WebDriverError("Failed to get element name.") from e
async def get_shadow_root(
server_url, session, element, session_http: Union[ClientSession, None] = None
-) -> dict:
+) -> str:
"""Get the shadow root element"""
try:
root_element = "shadow-6066-11e4-a52e-4f735466cecf"
@@ -374,7 +374,7 @@ async def get_rect(
try:
url = f"{server_url}/session/{session}/element/{element}/rect"
response = await _get(url, session_http)
- return response.get("value")
+ return response.get("value", {})
except Exception as e:
raise WebDriverError("Failed to get element rect.") from e
@@ -568,7 +568,7 @@ async def get_page_source(
try:
url = f"{server_url}/session/{session}/source"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", "")
except Exception as e:
raise WebDriverError("Failed to get the page source.") from e
@@ -593,7 +593,7 @@ async def get_alert_text(
try:
url = f"{server_url}/session/{session}/alert/text"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", "")
except Exception as e:
raise WebDriverError("Failed to get the alert text.") from e
@@ -628,7 +628,7 @@ async def is_element_enabled(
try:
url = f"{server_url}/session/{session}/element/{element}/enabled"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", False)
except Exception as e:
raise WebDriverError("Failed to check if element is enabled.") from e
@@ -636,13 +636,13 @@ async def is_element_enabled(
async def get_css_value(
server_url, session, element, property_name, session_http: Union[ClientSession, None] = None
) -> str:
- """Check if element is selected"""
+ """Get CSS value"""
try:
url = f"{server_url}/session/{session}/element/{element}/css/{property_name}"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", "")
except Exception as e:
- raise WebDriverError("Failed to check if element is selected.") from e
+ raise WebDriverError("Failed to get css value.") from e
async def is_element_selected(
@@ -664,7 +664,7 @@ async def get_window_rectangle(
try:
url = f"{server_url}/session/{session}/window/rect"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", {})
except Exception as e:
raise WebDriverError("Failed to get window rectangle.") from e
@@ -676,7 +676,7 @@ async def get_window_handles(
try:
url = f"{server_url}/session/{session}/window/handles"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", [])
except Exception as e:
raise WebDriverError("Failed to get window handles.") from e
@@ -698,7 +698,7 @@ async def get_window(server_url, session, session_http: Union[ClientSession, Non
try:
url = f"{server_url}/session/{session}/window"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", "")
except Exception as e:
raise WebDriverError("Failed to get window.") from e
@@ -722,7 +722,7 @@ async def get_url(server_url, session, session_http: Union[ClientSession, None]
try:
url = f"{server_url}/session/{session}/url"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", "")
except Exception as e:
raise WebDriverError("Failed to get page url.") from e
@@ -737,7 +737,7 @@ async def get_timeouts(
try:
url = f"{server_url}/session/{session}/timeouts"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", {})
except Exception as e:
raise WebDriverError("Failed to get timeouts.") from e
@@ -757,7 +757,7 @@ async def get_title(server_url, session, session_http: Union[ClientSession, None
try:
url = f"{server_url}/session/{session}/title"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", "")
except Exception as e:
raise WebDriverError("Failed to get page title.") from e
@@ -783,7 +783,7 @@ async def find_elements(
async def get_property(
server_url, session, element, property, session_http: Union[ClientSession, None] = None
-) -> str:
+) -> Any:
"""Get the given HTML property of an element, for example, 'href'"""
try:
url = f"{server_url}/session/{session}/element/{element}/property/{property}"
@@ -800,7 +800,7 @@ async def get_attribute(
try:
url = f"{server_url}/session/{session}/element/{element}/attribute/{attribute}"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", "")
except Exception as e:
raise WebDriverError("Failed to get value from element.") from e
@@ -812,7 +812,7 @@ async def get_text(
try:
url = f"{server_url}/session/{session}/element/{element}/text"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", "")
except Exception as e:
raise WebDriverError("Failed to get text from element.") from e
@@ -822,7 +822,7 @@ async def get_cookies(server_url, session, session_http: Union[ClientSession, No
try:
url = f"{server_url}/session/{session}/cookie"
response = await _get(url, session_http=session_http)
- return response.get("value")
+ return response.get("value", [])
except Exception as e:
raise WebDriverError("Failed to get page cookies.") from e
diff --git a/caqui/easy/page.py b/caqui/easy/page.py
index 5c2a6f3..5801861 100644
--- a/caqui/easy/page.py
+++ b/caqui/easy/page.py
@@ -169,7 +169,7 @@ async def get_cookies(self):
self._server_url, self._session, session_http=self.session_http
)
- async def get_cookie(self, cookie_name):
+ async def get_cookie(self, cookie_name) -> dict:
"""Get the desired cookie"""
return await asynchronous.get_named_cookie(
self._server_url, self._session, cookie_name, session_http=self.session_http
diff --git a/caqui/easy/server.py b/caqui/easy/server.py
index 89c1d00..3546e5f 100644
--- a/caqui/easy/server.py
+++ b/caqui/easy/server.py
@@ -45,7 +45,7 @@ def _wait_server(self):
break
except ConnectionError:
sleep(0.5)
- if i == (MAX_RETIES - 1):
+ if i == (MAX_RETIES - 1) and self._process:
self._process.kill()
self._process.wait()
raise Exception("Driver not started")
@@ -67,7 +67,7 @@ def start(self):
raise
driver_manager = self._browser_factory()
- self._process = subprocess.Popen(
+ self._process : Union[subprocess.Popen, None] = subprocess.Popen(
[driver_manager, f"--port={self._port}"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
diff --git a/caqui/easy/switch_to.py b/caqui/easy/switch_to.py
index 4c068d3..d7f8546 100644
--- a/caqui/easy/switch_to.py
+++ b/caqui/easy/switch_to.py
@@ -1,3 +1,4 @@
+from typing import Union
from caqui import asynchronous, synchronous
from caqui.easy.element import Element
from caqui.easy.alert import Alert
@@ -6,8 +7,8 @@
class SwitchTo:
def __init__(self, driver) -> None:
self._driver = driver
- self._iframe = None
- self._window_handle = None
+ self._iframe :Union[str, None]= None
+ self._window_handle:Union[str, None] = None
self._session_http = driver.session_http
@property
diff --git a/caqui/easy/window.py b/caqui/easy/window.py
index c7a67e2..d8746ab 100644
--- a/caqui/easy/window.py
+++ b/caqui/easy/window.py
@@ -3,8 +3,8 @@
class Window:
def __init__(self, driver) -> None:
- self.__remote = driver.remote
- self.__session = driver.session
+ self._remote = driver.remote
+ self._ssession = driver.session
async def new(self, window_type="tab"):
"""
@@ -14,4 +14,4 @@ async def new(self, window_type="tab"):
return (str): window handle
"""
- return await asynchronous.new_window(self.__remote, self.__session, window_type)
+ return await asynchronous.new_window(self._remote, self._session, window_type)
diff --git a/caqui/synchronous.py b/caqui/synchronous.py
index 315c39b..4c3af06 100644
--- a/caqui/synchronous.py
+++ b/caqui/synchronous.py
@@ -3,7 +3,7 @@
from caqui.exceptions import WebDriverError
from caqui import helper
from caqui.constants import HEADERS
-from typing import Optional
+from typing import Any, Optional
def _handle_response(response):
@@ -53,7 +53,7 @@ def _handle_alerts(server_url, session, command):
def _handle_window(server_url, session, command):
url = f"{server_url}/session/{session}/window/{command}"
- payload = {}
+ payload:dict = {}
_post(url, payload)
return True
@@ -83,7 +83,7 @@ def refresh_page(server_url, session):
"""Refresh page"""
try:
url = f"{server_url}/session/{session}/refresh"
- payload = {}
+ payload: dict = {}
_post(url, payload)
return True
except Exception as e:
@@ -94,7 +94,7 @@ def go_forward(server_url, session):
"""Go to page forward"""
try:
url = f"{server_url}/session/{session}/forward"
- payload = {}
+ payload: dict = {}
_post(url, payload)
return True
except Exception as e:
@@ -242,7 +242,7 @@ def take_screenshot(server_url, session, path="/tmp", file_name="caqui"):
raise WebDriverError("Failed to take screeshot.") from e
-def get_named_cookie(server_url, session, name) -> str:
+def get_named_cookie(server_url, session, name) -> dict:
"""Get cookie by name."""
try:
url = f"{server_url}/session/{session}/cookie/{name}"
@@ -278,7 +278,7 @@ def get_tag_name(server_url, session, element) -> str:
raise WebDriverError("Failed to get the element name.") from e
-def get_shadow_root(server_url, session, element) -> dict:
+def get_shadow_root(server_url, session, element) -> str:
"""Get the shadow root element"""
try:
root_element = "shadow-6066-11e4-a52e-4f735466cecf"
@@ -638,7 +638,7 @@ def find_elements(server_url, session, locator_type, locator_value) -> list:
) from e
-def get_property(server_url, session, element, property_name) -> str:
+def get_property(server_url, session, element, property_name) -> Any:
"""Get the given HTML property of an element, for example, 'href'"""
try:
url = f"{server_url}/session/{session}/element/{element}/property/{property_name}"
@@ -751,9 +751,17 @@ def get_session(server_url: str, capabilities: Optional[dict] = None):
except Exception as e:
raise WebDriverError("Failed to open session. Check the browser capabilities.") from e
+# from cssify import cssify
def find_element(server_url, session, locator_type, locator_value) -> str:
"""Find an element by a 'locator', for example 'xpath'"""
+ # try:
+ # if locator_type.lower() == "xpath":
+ # locator_type = "css selector"
+ # locator_value = cssify(locator_value)
+ # except Exception:
+ # # just ignore it and keep using the xpath selector
+ # pass
try:
url = f"{server_url}/session/{session}/element"
payload = {"using": locator_type, "value": locator_value}
diff --git a/data-processed.txt b/data-processed.txt
index 4a52274..642f5ce 100644
--- a/data-processed.txt
+++ b/data-processed.txt
@@ -247,3 +247,94 @@ OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup'
OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
=====
+OrderedDict([('setup', 7.11), ('duration', 28.63), ('teardown', 3.66), ('call', 17.86), ('title', '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 24.41), ('call', 15.17), ('setup', 5.56), ('title', '# Scenario 1 | No concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 26.59), ('call', 17.19), ('setup', 5.72), ('title', '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('teardown', 3.66), ('duration', 24.8), ('call', 15.62), ('setup', 5.52), ('title', '# Scenario 1 | No concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 25.35), ('call', 16.26), ('setup', 5.42), ('title', '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 23.94), ('call', 14.95), ('setup', 5.32), ('title', '# Scenario 1 | No concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 32.73), ('duration', 59.24), ('teardown', 12.81), ('setup', 13.7), ('title', '# Scenario 2 | With concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('call', 31.9), ('duration', 62.89), ('teardown', 13.08), ('setup', 17.91), ('title', '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('call', 32.1), ('duration', 62.52), ('teardown', 13.07), ('setup', 17.35), ('title', '# Scenario 2 | With concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup', 17.0), ('title', '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
+=====
+OrderedDict([('setup', 7.11), ('duration', 28.63), ('teardown', 3.66), ('call', 17.86), ('title', '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 24.41), ('call', 15.17), ('setup', 5.56), ('title', '# Scenario 1 | No concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 26.59), ('call', 17.19), ('setup', 5.72), ('title', '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('teardown', 3.66), ('duration', 24.8), ('call', 15.62), ('setup', 5.52), ('title', '# Scenario 1 | No concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 25.35), ('call', 16.26), ('setup', 5.42), ('title', '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 23.94), ('call', 14.95), ('setup', 5.32), ('title', '# Scenario 1 | No concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 32.73), ('duration', 59.24), ('teardown', 12.81), ('setup', 13.7), ('title', '# Scenario 2 | With concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('call', 31.9), ('duration', 62.89), ('teardown', 13.08), ('setup', 17.91), ('title', '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('call', 32.1), ('duration', 62.52), ('teardown', 13.07), ('setup', 17.35), ('title', '# Scenario 2 | With concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup', 17.0), ('title', '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
+=====
+OrderedDict([('setup', 7.11), ('duration', 28.63), ('teardown', 3.66), ('call', 17.86), ('title', '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 24.41), ('call', 15.17), ('setup', 5.56), ('title', '# Scenario 1 | No concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 26.59), ('call', 17.19), ('setup', 5.72), ('title', '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('teardown', 3.66), ('duration', 24.8), ('call', 15.62), ('setup', 5.52), ('title', '# Scenario 1 | No concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 25.35), ('call', 16.26), ('setup', 5.42), ('title', '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 23.94), ('call', 14.95), ('setup', 5.32), ('title', '# Scenario 1 | No concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 32.73), ('duration', 59.24), ('teardown', 12.81), ('setup', 13.7), ('title', '# Scenario 2 | With concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('call', 31.9), ('duration', 62.89), ('teardown', 13.08), ('setup', 17.91), ('title', '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('call', 32.1), ('duration', 62.52), ('teardown', 13.07), ('setup', 17.35), ('title', '# Scenario 2 | With concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup', 17.0), ('title', '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
+=====
+OrderedDict([('setup', 7.11), ('duration', 28.63), ('teardown', 3.66), ('call', 17.86), ('title', '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 24.41), ('call', 15.17), ('setup', 5.56), ('title', '# Scenario 1 | No concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 26.59), ('call', 17.19), ('setup', 5.72), ('title', '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('teardown', 3.66), ('duration', 24.8), ('call', 15.62), ('setup', 5.52), ('title', '# Scenario 1 | No concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 25.35), ('call', 16.26), ('setup', 5.42), ('title', '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 23.94), ('call', 14.95), ('setup', 5.32), ('title', '# Scenario 1 | No concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 32.73), ('duration', 59.24), ('teardown', 12.81), ('setup', 13.7), ('title', '# Scenario 2 | With concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('call', 31.9), ('duration', 62.89), ('teardown', 13.08), ('setup', 17.91), ('title', '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('call', 32.1), ('duration', 62.52), ('teardown', 13.07), ('setup', 17.35), ('title', '# Scenario 2 | With concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup', 17.0), ('title', '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
+=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
diff --git a/pyproject.toml b/pyproject.toml
index d99ffef..1361491 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -13,15 +13,17 @@ authors = [
{ name="Douglas Cardoso", email="noemail@noemail.com" },
]
description = "Run asynchronous commands in WebDrivers"
+keywords = ["automation", "asynchronous", "test", "crawler", "robotic process automation", "rpa"]
readme = "README.md"
requires-python = ">=3.7"
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python :: 3",
- "License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
+license="MIT"
+
dependencies = [
"requests",
"aiohttp",
@@ -33,3 +35,15 @@ dependencies = [
[project.urls]
"Homepage" = "https://github.com/douglasdcm/caqui"
"Bug Tracker" = "https://github.com/douglasdcm/caqui/issues"
+
+[tool.mypy]
+exclude=["tests/performance/test_process_data.py", "tests/test_sniffer.py"]
+disallow_any_unimported = false
+disallow_any_expr = false
+disallow_any_decorated = false
+disallow_any_explicit = false
+disallow_any_generics = false
+disallow_subclassing_any = false
+disallow_untyped_calls = false
+disallow_untyped_defs=false
+check_untyped_defs = true
\ No newline at end of file
diff --git a/pytest.ini b/pytest.ini
index def8ab1..1a992ef 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -3,4 +3,4 @@ log_format = %(asctime)s.%(msecs)03d %(levelname)s %(message)s
log_date_format = %Y-%m-%d %H:%M:%S
log_cli = true
log_cli_level = WARNING
-asyncio_default_fixture_loop_scope=function
\ No newline at end of file
+; asyncio_d efault_fixture_loop_scope=function
\ No newline at end of file
diff --git a/setup.py b/setup.py
index eee1001..55c9a85 100644
--- a/setup.py
+++ b/setup.py
@@ -1,26 +1,8 @@
-from distutils.core import setup
-from Cython.Build import cythonize
+from distutils.core import setup
+from Cython.Build import cythonize
setup(
- ext_modules=cythonize(
- [
- "./caqui/asynchronous.pyx",
- "./caqui/constants.pyx",
- "./caqui/helper.pyx",
- "./caqui/exceptions.pyx",
- "./caqui/synchronous.pyx",
- "./caqui/by.pyx",
- "./caqui/__init__.pyx",
- "./caqui/easy/capabilities.pyx",
- "./caqui/easy/options.pyx",
- "./caqui/easy/action_chains.pyx",
- "./caqui/easy/alert.pyx",
- "./caqui/easy/page.pyx",
- "./caqui/easy/switch_to.pyx",
- "./caqui/easy/window.pyx",
- "./caqui/easy/element.pyx",
- "./caqui/easy/__init__.pyx",
- "./caqui/easy/server.pyx",
- ]
+ ext_modules = cythonize(
+ ['./caqui/asynchronous.pyx', './caqui/constants.pyx', './caqui/helper.pyx', './caqui/exceptions.pyx', './caqui/synchronous.pyx', './caqui/by.pyx', './caqui/__init__.pyx', './caqui/easy/capabilities.pyx', './caqui/easy/options.pyx', './caqui/easy/action_chains.pyx', './caqui/easy/alert.pyx', './caqui/easy/page.pyx', './caqui/easy/switch_to.pyx', './caqui/easy/window.pyx', './caqui/easy/element.pyx', './caqui/easy/__init__.pyx', './caqui/easy/server.pyx']
)
)
diff --git a/tests/conftest.py b/tests/conftest.py
index 4a1d562..30110e2 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -13,6 +13,13 @@
CAPTURES = "captures"
+@fixture(autouse=True, scope="session")
+def setup_server():
+ server = Server.get_instance(port=SERVER_PORT)
+ server.start()
+ # yield
+ # server.dispose(delay=3)
+
def _build_capabilities():
options = ChromeOptionsBuilder().args(["headless"])
capabilities = (
@@ -24,13 +31,6 @@ def _build_capabilities():
return capabilities
-@fixture(autouse=True, scope="session")
-def setup_server():
- server = Server.get_instance(port=SERVER_PORT)
- server.start()
- # yield
- # server.dispose(delay=3)
-
@fixture
def setup_functional_environment():
diff --git a/tests/feature/test_async_with_http_session.py b/tests/feature/test_async_with_http_session.py
index 60e150e..1d0c8e7 100644
--- a/tests/feature/test_async_with_http_session.py
+++ b/tests/feature/test_async_with_http_session.py
@@ -1,3 +1,4 @@
+from typing import Union
from aiohttp import ClientSession
from pytest import mark, raises
from caqui import asynchronous, synchronous
@@ -119,8 +120,8 @@ async def test_set_window_rectangle(setup_functional_environment):
width = 500
height = 300
window_rectangle_before = synchronous.get_window_rectangle(server_url, session)
- x = window_rectangle_before.get("x") + 1
- y = window_rectangle_before.get("y") + 1
+ x = window_rectangle_before.get("x", 0) + 1
+ y = window_rectangle_before.get("y", 0) + 1
assert synchronous.set_window_rectangle(server_url, session, width, height, x, y) is True
@@ -141,7 +142,6 @@ async def test_set_window_rectangle(setup_functional_environment):
is True
)
- window_rectangle_after = None
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
assert window_rectangle_after.get("height") != window_rectangle_before.get("height")
@@ -160,8 +160,8 @@ async def test_fullscreen_window(setup_functional_environment):
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height") > window_rectangle_before.get("height")
- assert window_rectangle_after.get("width") > window_rectangle_before.get("width")
+ assert window_rectangle_after.get("height", 0) > window_rectangle_before.get("height", 0)
+ assert window_rectangle_after.get("width", 0) > window_rectangle_before.get("width", 0)
synchronous.maximize_window(server_url, session)
@@ -171,11 +171,10 @@ async def test_fullscreen_window(setup_functional_environment):
is True
)
- window_rectangle_after = None
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height") > window_rectangle_before.get("height")
- assert window_rectangle_after.get("width") > window_rectangle_before.get("width")
+ assert window_rectangle_after.get("height", 0) > window_rectangle_before.get("height", 0)
+ assert window_rectangle_after.get("width", 0) > window_rectangle_before.get("width", 0)
@mark.skip(reason="does not work in headless mode")
@@ -186,10 +185,10 @@ async def test_minimize_window(setup_functional_environment):
assert synchronous.minimize_window(server_url, session) is True
- window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
+ window_rectangle_after :dict= synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height") < window_rectangle_before.get("height")
- assert window_rectangle_after.get("width") < window_rectangle_before.get("width")
+ assert window_rectangle_after.get("height", 0) < window_rectangle_before.get("height", 0)
+ assert window_rectangle_after.get("width", 0) < window_rectangle_before.get("width", 0)
synchronous.maximize_window(server_url, session)
@@ -199,11 +198,10 @@ async def test_minimize_window(setup_functional_environment):
is True
)
- window_rectangle_after = None
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height") < window_rectangle_before.get("height")
- assert window_rectangle_after.get("width") < window_rectangle_before.get("width")
+ assert window_rectangle_after.get("height", 0) < window_rectangle_before.get("height", 0)
+ assert window_rectangle_after.get("width", 0) < window_rectangle_before.get("width", 0)
@mark.skip(reason="does not work in headless mode")
@@ -220,8 +218,8 @@ async def test_maximize_window_asynchronous(setup_functional_environment):
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height") > window_rectangle_before.get("height")
- assert window_rectangle_after.get("width") > window_rectangle_before.get("width")
+ assert window_rectangle_after.get("height", 0) > window_rectangle_before.get("height", 0)
+ assert window_rectangle_after.get("width", 0) > window_rectangle_before.get("width", 0)
@mark.skip(reason="does not work in headless mode")
@@ -234,8 +232,8 @@ def test_maximize_window_synchronous(setup_functional_environment):
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height") > window_rectangle_before.get("height")
- assert window_rectangle_after.get("width") > window_rectangle_before.get("width")
+ assert window_rectangle_after.get("height", 0) > window_rectangle_before.get("height", 0)
+ assert window_rectangle_after.get("width", 0) > window_rectangle_before.get("width", 0)
@mark.parametrize("window_type", ("tab", "window"))
@@ -461,7 +459,7 @@ async def test_get_named_cookie(setup_functional_environment):
response = await asynchronous.get_named_cookie(
server_url, session, name, session_http=session_http
)
- assert response.get("value") == expected
+ assert response == expected
@mark.asyncio
@@ -572,7 +570,6 @@ async def test_get_shadow_root(setup_functional_environment):
server_url, session = setup_functional_environment
locator_type = By.ID
locator_value = "shadow-root"
-
element = synchronous.find_element(server_url, session, locator_type, locator_value)
assert synchronous.get_shadow_root(server_url, session, element) is not None
@@ -1052,10 +1049,10 @@ async def test_get_timeouts(setup_functional_environment):
async def test_get_status(setup_functional_environment):
server_url, _ = setup_functional_environment
expected = "ready"
- assert expected in synchronous.get_status(server_url).get("value")
+ assert expected in synchronous.get_status(server_url).get("value", [])
async with ClientSession() as session_http:
response = await asynchronous.get_status(server_url, session_http=session_http)
- assert expected in response.get("value")
+ assert expected in response.get("value", [])
@mark.asyncio
diff --git a/tests/feature/test_sync_and_async.py b/tests/feature/test_sync_and_async.py
index 389c402..b5b7e74 100644
--- a/tests/feature/test_sync_and_async.py
+++ b/tests/feature/test_sync_and_async.py
@@ -105,8 +105,8 @@ async def test_set_window_rectangle(setup_functional_environment):
width = 500
height = 300
window_rectangle_before = synchronous.get_window_rectangle(server_url, session)
- x = window_rectangle_before.get("x") + 1
- y = window_rectangle_before.get("y") + 1
+ x = window_rectangle_before.get("x", 0) + 1
+ y = window_rectangle_before.get("y", 0) + 1
assert synchronous.set_window_rectangle(server_url, session, width, height, x, y) is True
@@ -121,7 +121,6 @@ async def test_set_window_rectangle(setup_functional_environment):
assert await asynchronous.set_window_rectangle(server_url, session, width, height, x, y) is True
- window_rectangle_after = None
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
assert window_rectangle_after.get("height") != window_rectangle_before.get("height")
@@ -140,18 +139,17 @@ async def test_fullscreen_window(setup_functional_environment):
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height") > window_rectangle_before.get("height")
- assert window_rectangle_after.get("width") > window_rectangle_before.get("width")
+ assert window_rectangle_after.get("height", 0) > window_rectangle_before.get("height", 0)
+ assert window_rectangle_after.get("width", 0) > window_rectangle_before.get("width", 0)
synchronous.maximize_window(server_url, session)
assert await asynchronous.fullscreen_window(server_url, session) is True
- window_rectangle_after = None
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height") > window_rectangle_before.get("height")
- assert window_rectangle_after.get("width") > window_rectangle_before.get("width")
+ assert window_rectangle_after.get("height", 0) > window_rectangle_before.get("height",0)
+ assert window_rectangle_after.get("width", 0) > window_rectangle_before.get("width", 0)
@mark.skip(reason="does not work in headless mode")
@@ -164,18 +162,17 @@ async def test_minimize_window(setup_functional_environment):
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height") < window_rectangle_before.get("height")
- assert window_rectangle_after.get("width") < window_rectangle_before.get("width")
+ assert window_rectangle_after.get("height", 0) < window_rectangle_before.get("height", 0)
+ assert window_rectangle_after.get("width", 0) < window_rectangle_before.get("width",0)
synchronous.maximize_window(server_url, session)
assert await asynchronous.minimize_window(server_url, session) is True
- window_rectangle_after = None
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height") < window_rectangle_before.get("height")
- assert window_rectangle_after.get("width") < window_rectangle_before.get("width")
+ assert window_rectangle_after.get("height", 0) < window_rectangle_before.get("height", 0)
+ assert window_rectangle_after.get("width", 0) < window_rectangle_before.get("width", 0)
@mark.skip(reason="does not work in headless mode")
@@ -188,8 +185,8 @@ async def test_maximize_window_asynchronous(setup_functional_environment):
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height") > window_rectangle_before.get("height")
- assert window_rectangle_after.get("width") > window_rectangle_before.get("width")
+ assert window_rectangle_after.get("height", 0) > window_rectangle_before.get("height", 0)
+ assert window_rectangle_after.get("width", 0) > window_rectangle_before.get("width", 0)
@mark.skip(reason="does not work in headless mode")
@@ -202,8 +199,8 @@ def test_maximize_window_synchronous(setup_functional_environment):
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height") > window_rectangle_before.get("height")
- assert window_rectangle_after.get("width") > window_rectangle_before.get("width")
+ assert window_rectangle_after.get("height", 0) > window_rectangle_before.get("height", 0)
+ assert window_rectangle_after.get("width", 0) > window_rectangle_before.get("width", 0)
@mark.parametrize("window_type", ("tab", "window"))
@@ -383,7 +380,7 @@ async def test_get_named_cookie(setup_functional_environment):
assert synchronous.get_named_cookie(server_url, session, name).get("value") == expected
response = await asynchronous.get_named_cookie(server_url, session, name)
- assert response.get("value") == expected
+ assert response == expected
@mark.asyncio
@@ -848,9 +845,9 @@ async def test_get_timeouts(setup_functional_environment):
async def test_get_status(setup_functional_environment):
server_url, _ = setup_functional_environment
expected = "ready"
- assert expected in synchronous.get_status(server_url).get("value")
+ assert expected in synchronous.get_status(server_url).get("value", [])
response = await asynchronous.get_status(server_url)
- assert expected in response.get("value")
+ assert expected in response.get("value", [])
@mark.asyncio
diff --git a/tests/integration/test_capabilities.py b/tests/integration/test_capabilities.py
index c0496b2..b0e4d01 100644
--- a/tests/integration/test_capabilities.py
+++ b/tests/integration/test_capabilities.py
@@ -61,7 +61,7 @@ def test_chrome_capabilities_with_options():
"excludeSwitches": ["sw1", "sw2"],
"minidumpPath": "any",
"mobileEmulation": {"any": "any"},
- "windowsTypes": "any",
+ "windowsTypes": ["any"],
"perfLoggingPrefs": {
"enableNetwork": False,
"enablePage": False,
@@ -84,7 +84,7 @@ def test_chrome_capabilities_with_options():
.exclude_switches(["sw1", "sw2"])
.minidump_path("any")
.mobile_emulation({"any": "any"})
- .windows_types("any")
+ .windows_types(["any"])
.perf_logging_prefs(
{
"enableNetwork": False,
diff --git a/tests/integration/test_options.py b/tests/integration/test_options.py
index cc6c92c..cebc39a 100644
--- a/tests/integration/test_options.py
+++ b/tests/integration/test_options.py
@@ -64,7 +64,7 @@ def test_chrome_options():
"enablePage": False,
"traceCategories": "devtools.network",
},
- "windowsTypes": "any",
+ "windowsTypes": ["any"],
}
}
options = options = (
@@ -79,7 +79,7 @@ def test_chrome_options():
.exclude_switches(["sw1", "sw2"])
.minidump_path("any")
.mobile_emulation({"any": "any"})
- .windows_types("any")
+ .windows_types(["any"])
.perf_logging_prefs(
{
"enableNetwork": False,
diff --git a/tests/performance/README.md b/tests/performance/README.md
index 9698c50..7b25236 100644
--- a/tests/performance/README.md
+++ b/tests/performance/README.md
@@ -857,7 +857,10 @@ Note: This was the choosen library as it has more starts in github, recent commi
Not planned. Need many refactoring and has gain for specific scenarios
## Scenario 8 - convert code to CPython
+No sensitive improvement
+
+## Scenario 9 - convert `XPATH` to `CSS Selector` automatically
- Execution 1 (duration): 27.57s
-- Execution 3 (duration): 27.90s
- Execution 2 (duration): 28.11s
+- Execution 3 (duration): 27.90s
- mean: 27.86s
diff --git a/tests/unit/test_async_unit.py b/tests/unit/test_async_unit.py
index 43e52f6..4c3c7d8 100644
--- a/tests/unit/test_async_unit.py
+++ b/tests/unit/test_async_unit.py
@@ -186,7 +186,7 @@ async def mock_request(*args, **kwargs):
@mark.asyncio
async def test_close_window():
- expected = []
+ expected:list = []
async def mock_request(*args, **kwargs):
return fake_responses.CLOSE_WINDOW
@@ -265,7 +265,7 @@ async def mock_request(*args, **kwargs):
with patch("caqui.asynchronous._get", mock_request):
response = await asynchronous.get_status("")
- assert response.get("value").get("ready") is True
+ assert response.get("value", {}).get("ready", False) is True
@mark.asyncio
@@ -281,7 +281,7 @@ async def mock_request(*args, **kwargs):
@mark.asyncio
async def test_get_cookies():
- expected = []
+ expected:list = []
async def mock_request(*args, **kwargs):
return fake_responses.GET_COOKIES
diff --git a/tests/unit/test_by.py b/tests/unit/test_by.py
index a48091a..1232c0d 100644
--- a/tests/unit/test_by.py
+++ b/tests/unit/test_by.py
@@ -17,4 +17,5 @@
],
)
def test_locators(setup_functional_environment, locator, value):
- assert synchronous.find_element(*setup_functional_environment, locator, value) is not None
+ server_url, session = setup_functional_environment
+ assert synchronous.find_element(server_url, session, locator, value) is not None
diff --git a/tests/unit/test_sync_unit.py b/tests/unit/test_sync_unit.py
index 74f83e3..3e35eeb 100644
--- a/tests/unit/test_sync_unit.py
+++ b/tests/unit/test_sync_unit.py
@@ -108,7 +108,7 @@ def test_get_window_handles(*args):
@patch("caqui.synchronous.request", return_value=fake_responses.CLOSE_WINDOW)
def test_close_window(*args):
- expected = []
+ expected:list = []
assert synchronous.close_window("", "") == expected
@@ -136,7 +136,7 @@ def test_get_timeouts(*args):
@patch("caqui.synchronous.request", return_value=fake_responses.GET_STATUS)
def test_get_status(*args):
- assert synchronous.get_status("").get("value").get("ready") is True
+ assert synchronous.get_status("").get("value", {}).get("ready", False) is True
@patch("caqui.synchronous.request", return_value=fake_responses.GET_TITLE)
@@ -148,7 +148,7 @@ def test_get_title(*args):
@patch("caqui.synchronous.request", return_value=fake_responses.GET_COOKIES)
def test_get_cookies(*args):
- expected = []
+ expected :list= []
assert synchronous.get_cookies("", "") == expected
From fb447394a384728f89097d04021f5ccb46656391 Mon Sep 17 00:00:00 2001
From: Douglas Cardoso <29078346+douglasdcm@users.noreply.github.com>
Date: Sun, 30 Nov 2025 12:51:20 -0300
Subject: [PATCH 09/40] add cssify
---
caqui/asynchronous.py | 43 ++++++++-------
caqui/easy/server.py | 2 +-
caqui/easy/switch_to.py | 4 +-
caqui/easy/window.py | 2 +-
caqui/helper.py | 12 +++++
caqui/synchronous.py | 40 +++++++-------
data-processed.txt | 52 +++++++++++++++++++
dev-requirements.txt | 3 +-
pyproject.toml | 6 ++-
setup.py | 26 ++++++++--
tests/conftest.py | 2 +-
tests/feature/test_async_with_http_session.py | 2 +-
tests/feature/test_sync_and_async.py | 4 +-
tests/unit/test_async_unit.py | 4 +-
tests/unit/test_sync_unit.py | 4 +-
utils/run-mypy.sh | 1 +
16 files changed, 148 insertions(+), 59 deletions(-)
create mode 100644 utils/run-mypy.sh
diff --git a/caqui/asynchronous.py b/caqui/asynchronous.py
index e4a8315..b237d53 100644
--- a/caqui/asynchronous.py
+++ b/caqui/asynchronous.py
@@ -2,7 +2,7 @@
from orjson import dumps
from caqui.constants import HEADERS
from caqui.exceptions import WebDriverError
-from caqui.helper import save_picture, get_elements, get_element
+from caqui.helper import convert_xpath_to_css_selector, save_picture, get_elements, get_element
from typing import Any, List, Optional, Union
@@ -520,11 +520,11 @@ async def set_timeouts(
async def find_children_elements(
- server_url,
- session,
- parent_element,
- locator_type,
- locator_value,
+ server_url: str,
+ session: str,
+ parent_element: str,
+ locator_type: str,
+ locator_value: str,
session_http: Union[ClientSession, None] = None,
):
"""Find the children elements by 'locator_type'
@@ -532,6 +532,7 @@ async def find_children_elements(
If the 'parent_element' is a shadow element, set the 'locator_type' as 'id' or
'css selector'
"""
+ locator_type, locator_value = convert_xpath_to_css_selector(locator_type, locator_value)
try:
url = f"{server_url}/session/{session}/element/{parent_element}/elements"
payload = {"using": locator_type, "value": locator_value, "id": parent_element}
@@ -544,14 +545,15 @@ async def find_children_elements(
async def find_child_element(
- server_url,
- session,
- parent_element,
- locator_type,
- locator_value,
+ server_url: str,
+ session: str,
+ parent_element: str,
+ locator_type: str,
+ locator_value: str,
session_http: Union[ClientSession, None] = None,
):
"""Find the child element by 'locator_type'"""
+ locator_type, locator_value = convert_xpath_to_css_selector(locator_type, locator_value)
try:
url = f"{server_url}/session/{session}/element/{parent_element}/element"
payload = {"using": locator_type, "value": locator_value, "id": parent_element}
@@ -763,13 +765,14 @@ async def get_title(server_url, session, session_http: Union[ClientSession, None
async def find_elements(
- server_url,
- session,
- locator_type,
- locator_value,
+ server_url: str,
+ session: str,
+ locator_type: str,
+ locator_value: str,
session_http: Union[ClientSession, None] = None,
) -> List[Any]:
"""Search the DOM elements by 'locator', for example, 'xpath'"""
+ locator_type, locator_value = convert_xpath_to_css_selector(locator_type, locator_value)
try:
payload = {"using": locator_type, "value": locator_value}
url = f"{server_url}/session/{session}/elements"
@@ -880,14 +883,14 @@ async def click(server_url, session, element, session_http: Union[ClientSession,
async def find_element(
- server_url,
- session,
- locator_type,
- locator_value,
+ server_url: str,
+ session: str,
+ locator_type: str,
+ locator_value: str,
session_http: Union[ClientSession, None] = None,
) -> str:
"""Find an element by a 'locator', for example 'xpath'"""
-
+ locator_type, locator_value = convert_xpath_to_css_selector(locator_type, locator_value)
try:
payload = {"using": locator_type, "value": locator_value}
url = f"{server_url}/session/{session}/element"
diff --git a/caqui/easy/server.py b/caqui/easy/server.py
index 3546e5f..c5575b3 100644
--- a/caqui/easy/server.py
+++ b/caqui/easy/server.py
@@ -67,7 +67,7 @@ def start(self):
raise
driver_manager = self._browser_factory()
- self._process : Union[subprocess.Popen, None] = subprocess.Popen(
+ self._process: Union[subprocess.Popen, None] = subprocess.Popen(
[driver_manager, f"--port={self._port}"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
diff --git a/caqui/easy/switch_to.py b/caqui/easy/switch_to.py
index d7f8546..c864f7d 100644
--- a/caqui/easy/switch_to.py
+++ b/caqui/easy/switch_to.py
@@ -7,8 +7,8 @@
class SwitchTo:
def __init__(self, driver) -> None:
self._driver = driver
- self._iframe :Union[str, None]= None
- self._window_handle:Union[str, None] = None
+ self._iframe: Union[str, None] = None
+ self._window_handle: Union[str, None] = None
self._session_http = driver.session_http
@property
diff --git a/caqui/easy/window.py b/caqui/easy/window.py
index d8746ab..59f7912 100644
--- a/caqui/easy/window.py
+++ b/caqui/easy/window.py
@@ -4,7 +4,7 @@
class Window:
def __init__(self, driver) -> None:
self._remote = driver.remote
- self._ssession = driver.session
+ self._session = driver.session
async def new(self, window_type="tab"):
"""
diff --git a/caqui/helper.py b/caqui/helper.py
index cecec9b..8925715 100644
--- a/caqui/helper.py
+++ b/caqui/helper.py
@@ -1,4 +1,5 @@
import base64
+from cssify import cssify # type: ignore
def save_picture(session, path, file_name, response):
@@ -20,3 +21,14 @@ def get_element(response) -> str:
# Firefox
return list(value.values())[0]
+
+
+def convert_xpath_to_css_selector(locator_type: str, locator_value: str):
+ try:
+ if locator_type.lower() == "xpath":
+ locator_value = cssify(locator_value)
+ locator_type = "css selector"
+ except Exception:
+ # just ignore it and keep using the xpath selector
+ pass
+ return locator_type, locator_value
diff --git a/caqui/synchronous.py b/caqui/synchronous.py
index 4c3af06..e02b154 100644
--- a/caqui/synchronous.py
+++ b/caqui/synchronous.py
@@ -1,7 +1,7 @@
from requests import request
from orjson import dumps
from caqui.exceptions import WebDriverError
-from caqui import helper
+from caqui.helper import convert_xpath_to_css_selector, save_picture, get_element, get_elements
from caqui.constants import HEADERS
from typing import Any, Optional
@@ -53,7 +53,7 @@ def _handle_alerts(server_url, session, command):
def _handle_window(server_url, session, command):
url = f"{server_url}/session/{session}/window/{command}"
- payload:dict = {}
+ payload: dict = {}
_post(url, payload)
return True
@@ -225,7 +225,7 @@ def take_screenshot_element(server_url, session, element, path="/tmp", file_name
try:
url = f"{server_url}/session/{session}/element/{element}/screenshot"
response = _get(url).get("value")
- helper.save_picture(session, path, file_name, response)
+ save_picture(session, path, file_name, response)
return True
except Exception as e:
raise WebDriverError("Failed to take screeshot.") from e
@@ -236,7 +236,7 @@ def take_screenshot(server_url, session, path="/tmp", file_name="caqui"):
try:
url = f"{server_url}/session/{session}/screenshot"
response = _get(url).get("value")
- helper.save_picture(session, path, file_name, response)
+ save_picture(session, path, file_name, response)
return True
except Exception as e:
raise WebDriverError("Failed to take screeshot.") from e
@@ -428,30 +428,36 @@ def set_timeouts(server_url, session, timeouts):
raise WebDriverError("Failed to set timeouts.") from e
-def find_children_elements(server_url, session, parent_element, locator_type, locator_value):
+def find_children_elements(
+ server_url: str, session: str, parent_element: str, locator_type: str, locator_value: str
+):
"""Find the children elements by 'locator_type'
If the 'parent_element' is a shadow element, set the 'locator_type' as 'id' or
'css selector'
"""
+ locator_type, locator_value = convert_xpath_to_css_selector(locator_type, locator_value)
try:
url = f"{server_url}/session/{session}/element/{parent_element}/elements"
payload = {"using": locator_type, "value": locator_value, "id": parent_element}
response = _post(url, payload)
- return helper.get_elements(response)
+ return get_elements(response)
except Exception as e:
raise WebDriverError(
f"Failed to find the children elements from '{parent_element}'."
) from e
-def find_child_element(server_url, session, parent_element, locator_type, locator_value):
+def find_child_element(
+ server_url: str, session: str, parent_element: str, locator_type: str, locator_value: str
+):
"""Find the child element by 'locator_type'"""
+ locator_type, locator_value = convert_xpath_to_css_selector(locator_type, locator_value)
try:
url = f"{server_url}/session/{session}/element/{parent_element}/element"
payload = {"using": locator_type, "value": locator_value, "id": parent_element}
response = _post(url, payload)
- return helper.get_element(response)
+ return get_element(response)
except Exception as e:
raise WebDriverError(f"Failed to find the child element from '{parent_element}'.") from e
@@ -490,7 +496,7 @@ def get_active_element(server_url, session):
try:
url = f"{server_url}/session/{session}/element/active"
response = _get(url)
- return helper.get_element(response)
+ return get_element(response)
except Exception as e:
raise WebDriverError("Failed to get the active element.") from e
@@ -625,8 +631,9 @@ def get_title(server_url, session) -> str:
raise WebDriverError("Failed to get page title.") from e
-def find_elements(server_url, session, locator_type, locator_value) -> list:
+def find_elements(server_url: str, session: str, locator_type: str, locator_value: str) -> list:
"""Search the DOM elements by 'locator', for example, 'xpath'"""
+ locator_type, locator_value = convert_xpath_to_css_selector(locator_type, locator_value)
try:
url = f"{server_url}/session/{session}/elements"
payload = {"using": locator_type, "value": locator_value}
@@ -751,17 +758,10 @@ def get_session(server_url: str, capabilities: Optional[dict] = None):
except Exception as e:
raise WebDriverError("Failed to open session. Check the browser capabilities.") from e
-# from cssify import cssify
-def find_element(server_url, session, locator_type, locator_value) -> str:
+def find_element(server_url: str, session: str, locator_type: str, locator_value: str) -> str:
"""Find an element by a 'locator', for example 'xpath'"""
- # try:
- # if locator_type.lower() == "xpath":
- # locator_type = "css selector"
- # locator_value = cssify(locator_value)
- # except Exception:
- # # just ignore it and keep using the xpath selector
- # pass
+ locator_type, locator_value = convert_xpath_to_css_selector(locator_type, locator_value)
try:
url = f"{server_url}/session/{session}/element"
payload = {"using": locator_type, "value": locator_value}
@@ -772,7 +772,7 @@ def find_element(server_url, session, locator_type, locator_value) -> str:
if response.get("value").get("error"):
raise WebDriverError(f"Failed to find element. {response}")
- return helper.get_element(response)
+ return get_element(response)
except Exception as e:
raise WebDriverError(
f"Failed to find element by '{locator_type}'-'{locator_value}'."
diff --git a/data-processed.txt b/data-processed.txt
index 642f5ce..0c05da4 100644
--- a/data-processed.txt
+++ b/data-processed.txt
@@ -338,3 +338,55 @@ OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0,
OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict({'setup': 7.11, 'duration': 28.63, 'teardown': 3.66, 'call': 17.86, 'title': '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 24.41, 'call': 15.17, 'setup': 5.56, 'title': '# Scenario 1 | No concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'teardown': 3.68, 'duration': 26.59, 'call': 17.19, 'setup': 5.72, 'title': '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'teardown': 3.66, 'duration': 24.8, 'call': 15.62, 'setup': 5.52, 'title': '# Scenario 1 | No concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 25.35, 'call': 16.26, 'setup': 5.42, 'title': '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n'})
+OrderedDict({'teardown': 3.67, 'duration': 23.94, 'call': 14.95, 'setup': 5.32, 'title': '# Scenario 1 | No concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 32.73, 'duration': 59.24, 'teardown': 12.81, 'setup': 13.7, 'title': '# Scenario 2 | With concurrence | Execution 1 | Shared session\n'})
+OrderedDict({'call': 31.9, 'duration': 62.89, 'teardown': 13.08, 'setup': 17.91, 'title': '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n'})
+OrderedDict({'call': 32.1, 'duration': 62.52, 'teardown': 13.07, 'setup': 17.35, 'title': '# Scenario 2 | With concurrence | Execution 2 | Shared session\n'})
+OrderedDict({'call': 31.25, 'duration': 61.18, 'teardown': 12.93, 'setup': 17.0, 'title': '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n'})
+OrderedDict({'call': 32.27, 'duration': 63.9, 'teardown': 13.08, 'setup': 18.55, 'title': '# Scenario 2 | With concurrence | Execution 3 | Shared session\n'})
+OrderedDict({'call': 31.81, 'duration': 61.67, 'teardown': 12.96, 'setup': 16.9, 'title': '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n'})
+=====
+OrderedDict([('setup', 7.11), ('duration', 28.63), ('teardown', 3.66), ('call', 17.86), ('title', '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 24.41), ('call', 15.17), ('setup', 5.56), ('title', '# Scenario 1 | No concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 26.59), ('call', 17.19), ('setup', 5.72), ('title', '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('teardown', 3.66), ('duration', 24.8), ('call', 15.62), ('setup', 5.52), ('title', '# Scenario 1 | No concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 25.35), ('call', 16.26), ('setup', 5.42), ('title', '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 23.94), ('call', 14.95), ('setup', 5.32), ('title', '# Scenario 1 | No concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 32.73), ('duration', 59.24), ('teardown', 12.81), ('setup', 13.7), ('title', '# Scenario 2 | With concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('call', 31.9), ('duration', 62.89), ('teardown', 13.08), ('setup', 17.91), ('title', '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('call', 32.1), ('duration', 62.52), ('teardown', 13.07), ('setup', 17.35), ('title', '# Scenario 2 | With concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup', 17.0), ('title', '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
+=====
+OrderedDict([('setup', 7.11), ('duration', 28.63), ('teardown', 3.66), ('call', 17.86), ('title', '# Scenario 1 | No concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 24.41), ('call', 15.17), ('setup', 5.56), ('title', '# Scenario 1 | No concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('teardown', 3.68), ('duration', 26.59), ('call', 17.19), ('setup', 5.72), ('title', '# Scenario 1 | No concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('teardown', 3.66), ('duration', 24.8), ('call', 15.62), ('setup', 5.52), ('title', '# Scenario 1 | No concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 25.35), ('call', 16.26), ('setup', 5.42), ('title', '# Scenario 1 | No concurrence | Execution 3 | No Shared session\n')])
+OrderedDict([('teardown', 3.67), ('duration', 23.94), ('call', 14.95), ('setup', 5.32), ('title', '# Scenario 1 | No concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 32.73), ('duration', 59.24), ('teardown', 12.81), ('setup', 13.7), ('title', '# Scenario 2 | With concurrence | Execution 1 | Shared session\n')])
+OrderedDict([('call', 31.9), ('duration', 62.89), ('teardown', 13.08), ('setup', 17.91), ('title', '# Scenario 2 | With concurrence | Execution 1 | No Shared session\n')])
+OrderedDict([('call', 32.1), ('duration', 62.52), ('teardown', 13.07), ('setup', 17.35), ('title', '# Scenario 2 | With concurrence | Execution 2 | Shared session\n')])
+OrderedDict([('call', 31.25), ('duration', 61.18), ('teardown', 12.93), ('setup', 17.0), ('title', '# Scenario 2 | With concurrence | Execution 2 | No Shared session\n')])
+OrderedDict([('call', 32.27), ('duration', 63.9), ('teardown', 13.08), ('setup', 18.55), ('title', '# Scenario 2 | With concurrence | Execution 3 | Shared session\n')])
+OrderedDict([('call', 31.81), ('duration', 61.67), ('teardown', 12.96), ('setup', 16.9), ('title', '# Scenario 2 | With concurrence | Execution 3 | No Shared session\n')])
+=====
diff --git a/dev-requirements.txt b/dev-requirements.txt
index 9d9ca4f..6954fa1 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -2,4 +2,5 @@ requests
aiohttp
webdriver_manager
types-requests
-orjson
\ No newline at end of file
+orjson
+cssify
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 1361491..6ed1655 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -20,9 +20,10 @@ classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
+ "License :: OSI Approved :: MIT License",
]
-license="MIT"
+
dependencies = [
"requests",
@@ -30,6 +31,7 @@ dependencies = [
"webdriver_manager",
"types-requests",
"orjson",
+ "cssify",
]
[project.urls]
@@ -46,4 +48,4 @@ disallow_any_generics = false
disallow_subclassing_any = false
disallow_untyped_calls = false
disallow_untyped_defs=false
-check_untyped_defs = true
\ No newline at end of file
+check_untyped_defs = true
diff --git a/setup.py b/setup.py
index 55c9a85..eee1001 100644
--- a/setup.py
+++ b/setup.py
@@ -1,8 +1,26 @@
-
-from distutils.core import setup
+from distutils.core import setup
from Cython.Build import cythonize
+
setup(
- ext_modules = cythonize(
- ['./caqui/asynchronous.pyx', './caqui/constants.pyx', './caqui/helper.pyx', './caqui/exceptions.pyx', './caqui/synchronous.pyx', './caqui/by.pyx', './caqui/__init__.pyx', './caqui/easy/capabilities.pyx', './caqui/easy/options.pyx', './caqui/easy/action_chains.pyx', './caqui/easy/alert.pyx', './caqui/easy/page.pyx', './caqui/easy/switch_to.pyx', './caqui/easy/window.pyx', './caqui/easy/element.pyx', './caqui/easy/__init__.pyx', './caqui/easy/server.pyx']
+ ext_modules=cythonize(
+ [
+ "./caqui/asynchronous.pyx",
+ "./caqui/constants.pyx",
+ "./caqui/helper.pyx",
+ "./caqui/exceptions.pyx",
+ "./caqui/synchronous.pyx",
+ "./caqui/by.pyx",
+ "./caqui/__init__.pyx",
+ "./caqui/easy/capabilities.pyx",
+ "./caqui/easy/options.pyx",
+ "./caqui/easy/action_chains.pyx",
+ "./caqui/easy/alert.pyx",
+ "./caqui/easy/page.pyx",
+ "./caqui/easy/switch_to.pyx",
+ "./caqui/easy/window.pyx",
+ "./caqui/easy/element.pyx",
+ "./caqui/easy/__init__.pyx",
+ "./caqui/easy/server.pyx",
+ ]
)
)
diff --git a/tests/conftest.py b/tests/conftest.py
index 30110e2..ad84690 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -20,6 +20,7 @@ def setup_server():
# yield
# server.dispose(delay=3)
+
def _build_capabilities():
options = ChromeOptionsBuilder().args(["headless"])
capabilities = (
@@ -31,7 +32,6 @@ def _build_capabilities():
return capabilities
-
@fixture
def setup_functional_environment():
server_url = SERVER_URL
diff --git a/tests/feature/test_async_with_http_session.py b/tests/feature/test_async_with_http_session.py
index 1d0c8e7..fdf4e95 100644
--- a/tests/feature/test_async_with_http_session.py
+++ b/tests/feature/test_async_with_http_session.py
@@ -185,7 +185,7 @@ async def test_minimize_window(setup_functional_environment):
assert synchronous.minimize_window(server_url, session) is True
- window_rectangle_after :dict= synchronous.get_window_rectangle(server_url, session)
+ window_rectangle_after: dict = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
assert window_rectangle_after.get("height", 0) < window_rectangle_before.get("height", 0)
assert window_rectangle_after.get("width", 0) < window_rectangle_before.get("width", 0)
diff --git a/tests/feature/test_sync_and_async.py b/tests/feature/test_sync_and_async.py
index b5b7e74..a40d0be 100644
--- a/tests/feature/test_sync_and_async.py
+++ b/tests/feature/test_sync_and_async.py
@@ -148,7 +148,7 @@ async def test_fullscreen_window(setup_functional_environment):
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
- assert window_rectangle_after.get("height", 0) > window_rectangle_before.get("height",0)
+ assert window_rectangle_after.get("height", 0) > window_rectangle_before.get("height", 0)
assert window_rectangle_after.get("width", 0) > window_rectangle_before.get("width", 0)
@@ -163,7 +163,7 @@ async def test_minimize_window(setup_functional_environment):
window_rectangle_after = synchronous.get_window_rectangle(server_url, session)
assert window_rectangle_after != window_rectangle_before
assert window_rectangle_after.get("height", 0) < window_rectangle_before.get("height", 0)
- assert window_rectangle_after.get("width", 0) < window_rectangle_before.get("width",0)
+ assert window_rectangle_after.get("width", 0) < window_rectangle_before.get("width", 0)
synchronous.maximize_window(server_url, session)
diff --git a/tests/unit/test_async_unit.py b/tests/unit/test_async_unit.py
index 4c3c7d8..f9e74b0 100644
--- a/tests/unit/test_async_unit.py
+++ b/tests/unit/test_async_unit.py
@@ -186,7 +186,7 @@ async def mock_request(*args, **kwargs):
@mark.asyncio
async def test_close_window():
- expected:list = []
+ expected: list = []
async def mock_request(*args, **kwargs):
return fake_responses.CLOSE_WINDOW
@@ -281,7 +281,7 @@ async def mock_request(*args, **kwargs):
@mark.asyncio
async def test_get_cookies():
- expected:list = []
+ expected: list = []
async def mock_request(*args, **kwargs):
return fake_responses.GET_COOKIES
diff --git a/tests/unit/test_sync_unit.py b/tests/unit/test_sync_unit.py
index 3e35eeb..8f4d04f 100644
--- a/tests/unit/test_sync_unit.py
+++ b/tests/unit/test_sync_unit.py
@@ -108,7 +108,7 @@ def test_get_window_handles(*args):
@patch("caqui.synchronous.request", return_value=fake_responses.CLOSE_WINDOW)
def test_close_window(*args):
- expected:list = []
+ expected: list = []
assert synchronous.close_window("", "") == expected
@@ -148,7 +148,7 @@ def test_get_title(*args):
@patch("caqui.synchronous.request", return_value=fake_responses.GET_COOKIES)
def test_get_cookies(*args):
- expected :list= []
+ expected: list = []
assert synchronous.get_cookies("", "") == expected
diff --git a/utils/run-mypy.sh b/utils/run-mypy.sh
new file mode 100644
index 0000000..d931bd9
--- /dev/null
+++ b/utils/run-mypy.sh
@@ -0,0 +1 @@
+mypy caqui/ tests/ --config-file=pyproject.toml
From d110ab39da2aefabe9ec43b7e5c292ea7a9a1a36 Mon Sep 17 00:00:00 2001
From: Douglas Cardoso <29078346+douglasdcm@users.noreply.github.com>
Date: Mon, 1 Dec 2025 02:53:18 -0300
Subject: [PATCH 10/40] Add copyright anf put improve cssify
---
caqui/__init__.py | 5 +
caqui/asynchronous.py | 7 +-
caqui/by.py | 5 +
caqui/constants.py | 5 +
caqui/cssify.py | 94 +++++++++++++++++++
caqui/easy/__init__.py | 5 +
caqui/easy/action_chains.py | 5 +
caqui/easy/alert.py | 5 +
caqui/easy/capabilities.py | 5 +
caqui/easy/element.py | 9 ++
caqui/easy/options.py | 5 +
caqui/easy/page.py | 6 ++
caqui/easy/server.py | 5 +
caqui/easy/switch_to.py | 5 +
caqui/easy/window.py | 5 +
caqui/exceptions.py | 5 +
caqui/helper.py | 7 +-
caqui/synchronous.py | 7 +-
data-processed.txt | 26 +++++
docs/conf.py | 2 +-
pyproject.toml | 51 ----------
setup.py | 35 +++----
tests/performance/README.md | 27 +++++-
tests/performance/test_single_session_http.py | 2 +-
utils/build-pyx-files.py | 33 +++++--
utils/run-mypy.sh | 2 +-
26 files changed, 280 insertions(+), 88 deletions(-)
create mode 100644 caqui/cssify.py
delete mode 100644 pyproject.toml
mode change 100644 => 100755 utils/run-mypy.sh
diff --git a/caqui/__init__.py b/caqui/__init__.py
index e69de29..ac64211 100644
--- a/caqui/__init__.py
+++ b/caqui/__init__.py
@@ -0,0 +1,5 @@
+# Copyright (C) 2023 Caqui - All Rights Reserved
+# You may use, distribute and modify this code under the
+# terms of the MIT license.
+# Visit: https://github.com/douglasdcm/caqui
+
diff --git a/caqui/asynchronous.py b/caqui/asynchronous.py
index b237d53..91e6d93 100644
--- a/caqui/asynchronous.py
+++ b/caqui/asynchronous.py
@@ -1,8 +1,13 @@
+# Copyright (C) 2023 Caqui - All Rights Reserved
+# You may use, distribute and modify this code under the
+# terms of the MIT license.
+# Visit: https://github.com/douglasdcm/caqui
+
from aiohttp import ClientSession
from orjson import dumps
from caqui.constants import HEADERS
from caqui.exceptions import WebDriverError
-from caqui.helper import convert_xpath_to_css_selector, save_picture, get_elements, get_element
+from caqui.helper import save_picture, get_elements, get_element, convert_xpath_to_css_selector
from typing import Any, List, Optional, Union
diff --git a/caqui/by.py b/caqui/by.py
index d87b2c0..89e52f2 100644
--- a/caqui/by.py
+++ b/caqui/by.py
@@ -1,3 +1,8 @@
+# Copyright (C) 2023 Caqui - All Rights Reserved
+# You may use, distribute and modify this code under the
+# terms of the MIT license.
+# Visit: https://github.com/douglasdcm/caqui
+
class By:
"""List of locator strategies"""
diff --git a/caqui/constants.py b/caqui/constants.py
index ded3e77..9fae696 100644
--- a/caqui/constants.py
+++ b/caqui/constants.py
@@ -1,3 +1,8 @@
+# Copyright (C) 2023 Caqui - All Rights Reserved
+# You may use, distribute and modify this code under the
+# terms of the MIT license.
+# Visit: https://github.com/douglasdcm/caqui
+
HEADERS = {
"Accept-Encoding": "identity",
"Accept": "application/json",
diff --git a/caqui/cssify.py b/caqui/cssify.py
new file mode 100644
index 0000000..5a94652
--- /dev/null
+++ b/caqui/cssify.py
@@ -0,0 +1,94 @@
+# Copyright (c) 2025 Santiycr
+#
+# This file is part of Santiycr/cssify.
+# Visit: https://github.com/santiycr/cssify
+#
+# Copyright (C) 2025 Caqui - All Rights Reserved
+# You may use, distribute and modify this code under the
+# terms of the MIT license.
+# Visit: https://github.com/douglasdcm/caqui
+
+import re
+
+sub_regexes = {
+ "tag": r"([a-zA-Z][a-zA-Z0-9]{0,10}|\*)",
+ "attribute": r"[.a-zA-Z_:][-\w:.]*(\(\))?)",
+ "value": r"\s*[\w/:][-/\w\s,:;.]*",
+}
+
+validation_re = (
+ "(?P"
+ "("
+ "^id\\([\"']?(?P%(value)s)[\"']?\\)" # special case! id(idValue)
+ "|"
+ "(?P