Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⬆️ Upgrade playwright to latest version and fix checking of service readyness #7047

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 22 additions & 19 deletions packages/pytest-simcore/src/pytest_simcore/helpers/playwright.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
from enum import Enum, unique
from typing import Any, Final

import httpx
from playwright._impl._sync_base import EventContextManager
from playwright.sync_api import FrameLocator, Page, Request
from playwright.sync_api import APIRequestContext, FrameLocator, Page, Request
from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
from playwright.sync_api import WebSocket
from pydantic import AnyUrl
Expand Down Expand Up @@ -179,7 +178,7 @@ def _attempt_reconnect(self, logger: logging.Logger) -> None:
self.ws.expect_event(event, predicate)

except Exception as e: # pylint: disable=broad-except
logger.error("🚨 Failed to reconnect WebSocket: %s", e)
logger.exception("🚨 Failed to reconnect WebSocket: %s", e)

def expect_event(
self,
Expand Down Expand Up @@ -294,6 +293,7 @@ class SocketIONodeProgressCompleteWaiter:
node_id: str
logger: logging.Logger
product_url: AnyUrl
api_request_context: APIRequestContext
_current_progress: dict[NodeProgressType, float] = field(
default_factory=defaultdict
)
Expand Down Expand Up @@ -326,7 +326,7 @@ def __call__(self, message: str) -> bool:
self.logger.info(
"Current startup progress [expected number of node-progress-types=%d]: %s",
len(NodeProgressType.required_types_for_started_service()),
f"{json.dumps({k:round(v,1) for k,v in self._current_progress.items()})}",
f"{json.dumps({k: round(v, 1) for k, v in self._current_progress.items()})}",
)

return self.got_expected_node_progress_types() and all(
Expand All @@ -337,23 +337,20 @@ def __call__(self, message: str) -> bool:
_current_timestamp = datetime.now(UTC)
if _current_timestamp - self._last_poll_timestamp > timedelta(seconds=5):
url = f"https://{self.node_id}.services.{self.get_partial_product_url()}"
response = httpx.get(url, timeout=10)
self.logger.info(
"Querying the service endpoint from the E2E test. Url: %s Response: %s TIP: %s",
response = self.api_request_context.get(url, timeout=1000)
self.logger.debug(
"Querying service endpoint in case we missed some websocket messages. Url: %s Response: '%s' TIP: %s",
url,
response,
f"{response.status}: {response.text()}",
(
"Response 401 is OK. It means that service is ready."
if response.status_code == 401
else "We are emulating the frontend; a 500 response is acceptable if the service is not yet ready."
"We are emulating the frontend; a 5XX response is acceptable if the service is not yet ready."
),
)
if response.status_code <= 401:
if response.status <= 400:
# NOTE: If the response status is less than 400, it means that the backend is ready (There are some services that respond with a 3XX)
# MD: for now I have included 401 - as this also means that backend is ready
if self.got_expected_node_progress_types():
self.logger.warning(
"⚠️ Progress bar didn't receive 100 percent but service is already running: %s ⚠️", # https://github.com/ITISFoundation/osparc-simcore/issues/6449
"⚠️ Progress bar didn't receive 100 percent but service is already running: %s. TIP: we missed some websocket messages! ⚠️", # https://github.com/ITISFoundation/osparc-simcore/issues/6449
self.get_current_progress(),
)
return True
Expand Down Expand Up @@ -408,8 +405,9 @@ def _node_started_predicate(request: Request) -> bool:


def _trigger_service_start(page: Page, node_id: str) -> None:
with log_context(logging.INFO, msg="trigger start button"), page.expect_request(
_node_started_predicate, timeout=35 * SECOND
with (
log_context(logging.INFO, msg="trigger start button"),
page.expect_request(_node_started_predicate, timeout=35 * SECOND),
):
page.get_by_test_id(f"Start_{node_id}").click()

Expand All @@ -433,12 +431,14 @@ def expected_service_running(
logging.INFO, msg=f"Waiting for node to run. Timeout: {timeout}"
) as ctx:
waiter = SocketIONodeProgressCompleteWaiter(
node_id=node_id, logger=ctx.logger, product_url=product_url
node_id=node_id,
logger=ctx.logger,
product_url=product_url,
api_request_context=page.request,
)
service_running = ServiceRunning(iframe_locator=None)

try:

with websocket.expect_event("framereceived", waiter, timeout=timeout):
if press_start_button:
_trigger_service_start(page, node_id)
Expand Down Expand Up @@ -475,7 +475,10 @@ def wait_for_service_running(
logging.INFO, msg=f"Waiting for node to run. Timeout: {timeout}"
) as ctx:
waiter = SocketIONodeProgressCompleteWaiter(
node_id=node_id, logger=ctx.logger, product_url=product_url
node_id=node_id,
logger=ctx.logger,
product_url=product_url,
api_request_context=page.request,
)
with websocket.expect_event("framereceived", waiter, timeout=timeout):
if press_start_button:
Expand Down
44 changes: 22 additions & 22 deletions tests/e2e-playwright/requirements/_test.txt
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
annotated-types==0.7.0
# via pydantic
anyio==4.6.2.post1
anyio==4.8.0
# via httpx
arrow==1.3.0
# via -r requirements/_test.in
certifi==2024.8.30
certifi==2024.12.14
# via
# httpcore
# httpx
# requests
charset-normalizer==3.3.2
charset-normalizer==3.4.1
# via requests
dnspython==2.6.1
dnspython==2.7.0
# via email-validator
docker==7.1.0
# via -r requirements/_test.in
email-validator==2.2.0
# via pydantic
faker==29.0.0
faker==33.3.1
# via -r requirements/_test.in
greenlet==3.0.3
greenlet==3.1.1
# via playwright
h11==0.14.0
# via httpcore
httpcore==1.0.7
# via httpx
httpx==0.27.2
httpx==0.28.1
# via -r requirements/_test.in
idna==3.10
# via
Expand All @@ -35,25 +35,25 @@ idna==3.10
# requests
iniconfig==2.0.0
# via pytest
jinja2==3.1.4
jinja2==3.1.5
# via pytest-html
markupsafe==2.1.5
markupsafe==3.0.2
# via jinja2
packaging==24.1
packaging==24.2
# via
# pytest
# pytest-sugar
playwright==1.47.0
playwright==1.49.1
# via pytest-playwright
pluggy==1.5.0
# via pytest
pydantic==2.10.3
pydantic==2.10.5
# via -r requirements/_test.in
pydantic-core==2.27.1
pydantic-core==2.27.2
# via pydantic
pyee==12.0.0
# via playwright
pytest==8.3.3
pytest==8.3.4
# via
# pytest-base-url
# pytest-html
Expand All @@ -69,7 +69,7 @@ pytest-instafail==0.5.0
# via -r requirements/_test.in
pytest-metadata==3.1.1
# via pytest-html
pytest-playwright==0.5.2
pytest-playwright==0.6.2
# via -r requirements/_test.in
pytest-runner==6.0.1
# via -r requirements/_test.in
Expand All @@ -87,26 +87,26 @@ requests==2.32.3
# via
# docker
# pytest-base-url
six==1.16.0
six==1.17.0
# via python-dateutil
sniffio==1.3.1
# via
# anyio
# httpx
# via anyio
tenacity==9.0.0
# via -r requirements/_test.in
termcolor==2.4.0
termcolor==2.5.0
# via pytest-sugar
text-unidecode==1.3
# via python-slugify
types-python-dateutil==2.9.0.20240906
types-python-dateutil==2.9.0.20241206
# via arrow
typing-extensions==4.12.2
# via
# anyio
# faker
# pydantic
# pydantic-core
# pyee
urllib3==2.2.3
urllib3==2.3.0
# via
# docker
# requests
34 changes: 17 additions & 17 deletions tests/e2e-playwright/requirements/_tools.txt
Original file line number Diff line number Diff line change
@@ -1,47 +1,47 @@
astroid==3.3.4
astroid==3.3.8
# via pylint
black==24.8.0
black==24.10.0
# via -r requirements/../../../requirements/devenv.txt
build==1.2.2
build==1.2.2.post1
# via pip-tools
bump2version==1.0.1
# via -r requirements/../../../requirements/devenv.txt
cfgv==3.4.0
# via pre-commit
click==8.1.7
click==8.1.8
# via
# black
# pip-tools
dill==0.3.8
dill==0.3.9
# via pylint
distlib==0.3.8
distlib==0.3.9
# via virtualenv
filelock==3.16.1
# via virtualenv
identify==2.6.1
identify==2.6.5
# via pre-commit
isort==5.13.2
# via
# -r requirements/../../../requirements/devenv.txt
# pylint
mccabe==0.7.0
# via pylint
mypy==1.12.0
mypy==1.14.1
# via -r requirements/../../../requirements/devenv.txt
mypy-extensions==1.0.0
# via
# black
# mypy
nodeenv==1.9.1
# via pre-commit
packaging==24.1
packaging==24.2
# via
# -c requirements/_test.txt
# black
# build
pathspec==0.12.1
# via black
pip==24.2
pip==24.3.1
# via pip-tools
pip-tools==7.4.1
# via -r requirements/../../../requirements/devenv.txt
Expand All @@ -50,11 +50,11 @@ platformdirs==4.3.6
# black
# pylint
# virtualenv
pre-commit==3.8.0
pre-commit==4.0.1
# via -r requirements/../../../requirements/devenv.txt
pylint==3.3.0
pylint==3.3.3
# via -r requirements/../../../requirements/devenv.txt
pyproject-hooks==1.1.0
pyproject-hooks==1.2.0
# via
# build
# pip-tools
Expand All @@ -63,17 +63,17 @@ pyyaml==6.0.2
# -c requirements/../../../requirements/constraints.txt
# -c requirements/_test.txt
# pre-commit
ruff==0.6.7
ruff==0.9.1
# via -r requirements/../../../requirements/devenv.txt
setuptools==75.1.0
setuptools==75.8.0
# via pip-tools
tomlkit==0.13.2
# via pylint
typing-extensions==4.12.2
# via
# -c requirements/_test.txt
# mypy
virtualenv==20.26.5
virtualenv==20.29.0
# via pre-commit
wheel==0.44.0
wheel==0.45.1
# via pip-tools
Loading