Reputation: 21
So this is my first time with Playwright so I thought to try out the examples only to find none of the work and the errors dont make sense:
I have tried all the examples in the docs and on the github pages and keep getting errors that I simply dont understand. CODE:
`
from playwright.sync_api import sync_playwright
playwright = sync_playwright().start()
browser = playwright.chromium.launch()
page = browser.new_page()
page.goto("https://playwright.dev/")
page.screenshot(path="example.png")
browser.close()
playwright.stop()
` **ERROR: **
---------------------------------------------------------------------------
Error Traceback (most recent call last)
Cell In[23], line 3
1 from playwright.sync_api import sync_playwright
----> 3 playwright = sync_playwright().start()
5 browser = playwright.chromium.launch()
6 page = browser.new_page()
File ~/Downloads/Packaging Industry Anomaly DEtection (PIADE)/venv/lib/python3.12/site-packages/playwright/sync_api/_context_manager.py:84, in PlaywrightContextManager.start(self)
83 def start(self) -> SyncPlaywright:
---> 84 return self.__enter__()
File ~/Downloads/Packaging Industry Anomaly DEtection (PIADE)/venv/lib/python3.12/site-packages/playwright/sync_api/_context_manager.py:47, in PlaywrightContextManager.__enter__(self)
45 self._own_loop = True
46 if self._loop.is_running():
---> 47 raise Error(
48 """It looks like you are using Playwright Sync API inside the asyncio loop.
49 Please use the Async API instead."""
50 )
52 # Create a new fiber for the protocol dispatcher. It will be pumping events
53 # until the end of times. We will pass control to that fiber every time we
54 # block while waiting for a response.
55 def greenlet_main() -> None:
Error: It looks like you are using Playwright Sync API inside the asyncio loop.
Please use the Async API instead.
Upvotes: 2
Views: 3195
Reputation: 5578
Same thing happens to me when I run these two very simple examples from the documentation!
See fix at very bottom of this answer...
import re
import pytest
from playwright.sync_api import Page, expect
def test_has_title(page: Page):
"""
Demo test from Playwright documentation
https://playwright.dev/python/docs/intro#running-the-example-test
"""
page.goto("https://playwright.dev/")
# Expect a title "to contain" a substring.
expect(page).to_have_title(re.compile("Playwright"))
def test_get_started_link(page: Page):
"""
Demo test from Playwright documentation
https://playwright.dev/python/docs/intro#running-the-example-test
"""
page.goto("https://playwright.dev/")
# Click the get started link.
page.get_by_role("link", name="Get started").click()
# Expects page to have a heading with the name of Installation.
expect(page.get_by_role("heading", name="Installation")).to_be_visible()
Here's the long error message....
Exception has occurred: Error (note: full exception trace is shown but execution is paused at: _run_module_as_main)
It looks like you are using Playwright Sync API inside the asyncio loop.
Please use the Async API instead.
File "/workspace/.venv/lib/python3.12/site-packages/playwright/sync_api/_context_manager.py", line 47, in __enter__
raise Error(
File "/workspace/tests/conftest.py", line 897, in browser_session_scope
with sync_playwright() as p:
^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/fixtures.py", line 891, in call_fixture_func
fixture_result = next(generator)
^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/fixtures.py", line 1140, in pytest_fixture_setup
result = call_fixture_func(fixturefunc, request, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/setuponly.py", line 36, in pytest_fixture_setup
return (yield)
^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 513, in __call__
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/fixtures.py", line 1091, in execute
result = ihook.pytest_fixture_setup(fixturedef=self, request=request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/fixtures.py", line 617, in _get_active_fixturedef
fixturedef.execute(request=subrequest)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/fixtures.py", line 532, in getfixturevalue
fixturedef = self._get_active_fixturedef(argname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/fixtures.py", line 697, in _fillfixtures
item.funcargs[argname] = self.getfixturevalue(argname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/python.py", line 1630, in setup
self._request._fillfixtures()
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/runner.py", line 514, in setup
col.setup()
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/runner.py", line 160, in pytest_runtest_setup
item.session._setupstate.setup(item)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/threadexception.py", line 68, in thread_exception_runtest_hook
yield
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/threadexception.py", line 87, in pytest_runtest_setup
yield from thread_exception_runtest_hook()
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/capture.py", line 875, in pytest_runtest_setup
return (yield)
^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/logging.py", line 829, in _runtest_for
yield
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/logging.py", line 840, in pytest_runtest_setup
yield from self._runtest_for(item, "setup")
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/unraisableexception.py", line 70, in unraisable_exception_runtest_hook
yield
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/unraisableexception.py", line 90, in pytest_runtest_setup
yield from unraisable_exception_runtest_hook()
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 513, in __call__
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/runner.py", line 242, in <lambda>
lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/runner.py", line 341, in from_call
result: TResult | None = func()
^^^^^^
File "/workspace/tests/conftest.py", line 92, in pytest_exception_interact
raise call.excinfo.value
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 513, in __call__
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/runner.py", line 248, in call_and_report
ihook.pytest_exception_interact(node=item, call=call, report=report)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/runner.py", line 126, in runtestprotocol
rep = call_and_report(item, "setup", log)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/runner.py", line 113, in pytest_runtest_protocol
runtestprotocol(item, nextitem=nextitem)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/faulthandler.py", line 88, in pytest_runtest_protocol
return (yield)
^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/unittest.py", line 429, in pytest_runtest_protocol
res = yield
^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/assertion/__init__.py", line 176, in pytest_runtest_protocol
return (yield)
^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/warnings.py", line 112, in pytest_runtest_protocol
return (yield)
^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 513, in __call__
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/main.py", line 362, in pytest_runtestloop
item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/terminal.py", line 673, in pytest_runtestloop
result = yield
^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/logging.py", line 803, in pytest_runtestloop
return (yield) # Run all the tests.
^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 513, in __call__
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/main.py", line 337, in _main
config.hook.pytest_runtestloop(session=session)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/main.py", line 303, in wrap_session
config.notify_exception(excinfo, config.option)
File "/workspace/tests/conftest.py", line 96, in pytest_internalerror
raise excinfo.value
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 513, in __call__
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 1173, in notify_exception
res = self.hook.pytest_internalerror(excrepr=excrepr, excinfo=excinfo)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/main.py", line 303, in wrap_session
config.notify_exception(excinfo, config.option)
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/main.py", line 330, in pytest_cmdline_main
return wrap_session(config, _main)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 513, in __call__
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 175, in main
ret: ExitCode | int = config.hook.pytest_cmdline_main(config=config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 201, in console_main
code = main()
^^^^^^
File "/workspace/.venv/lib/python3.12/site-packages/pytest/__main__.py", line 9, in <module>
raise SystemExit(pytest.console_main())
^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/runpy.py", line 88, in _run_code
exec(code, run_globals)
File "/usr/local/lib/python3.12/runpy.py", line 198, in _run_module_as_main (Current frame)
return _run_code(code, main_globals, None,
playwright._impl._errors.Error: It looks like you are using Playwright Sync API inside the asyncio loop.
Please use the Async API instead.
Here's the Dockerfile inside which I'm running Pytest:
FROM nikolaik/python-nodejs:python3.12-nodejs22-slim
# Use Docker BuildKit for better caching and faster builds
ARG DOCKER_BUILDKIT=1
ARG BUILDKIT_INLINE_CACHE=1
# Enable BuildKit for Docker-Compose
ARG COMPOSE_DOCKER_CLI_BUILD=1
ARG POETRY_VERSION=1.8.5
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
# Configure apt and install packages
# I had to add --insecure since curl didn't work...
RUN apt-get update && \
apt-get install -y --no-install-recommends docker.io docker-compose apt-utils build-essential dialog \
curl netcat-traditional iputils-ping unzip dos2unix gcc 2>&1 && \
# Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
apt-get install -y --no-install-recommends sudo git redis-server libpq-dev sass \
procps iproute2 lsb-release gnupg apt-transport-https \
# For display testing
xvfb xserver-xephyr tigervnc-standalone-server xfonts-base \
g++ protobuf-compiler libprotobuf-dev && \
# Clean up
apt-get autoremove -y && \
apt-get clean -y && \
rm -rf /var/lib/apt/lists/*
WORKDIR /workspace
# Install Poetry with the root user
# Ensure pip is the latest version
RUN pip install --upgrade pip poetry==$POETRY_VERSION && \
# Create a virtualenv at .venv in /workspace directory so we can easily see the site-packages
poetry config virtualenvs.create true && \
poetry config virtualenvs.in-project true && \
poetry config virtualenvs.path "/workspace/.venv"
# # Install Playwright for testing (must install the Python package first)
# RUN playwright install-deps && \
# playwright install
# BEFORE installing packages with Poetry (so "user" has permissions in future),
# set the user so nobody can run as root on the Docker host (security)
# USER $USER_UID_OLD
# USER $USER_UID_NEW
# ARG TEST=testing
# Make port 5000 available to the world outside this container
EXPOSE 5000
# Copy my preferred .bashrc to /root/ so that it's automatically "sourced" when the container starts
COPY .bashrc /root/
# Copy the entrypoint script to install the Python and Node dependencies if the .venv or node_modules directories don't exist
COPY entrypoint.dev.sh entrypoint.dev.local.sh /
RUN chmod +x /entrypoint.dev.sh /entrypoint.dev.local.sh
# ENTRYPOINT ["/entrypoint.dev.sh"]
Here are my dependencies in my "pyproject.toml":
[tool.poetry.dependencies]
python = ">=3.11,<3.14"
dash = {extras = ["compress", "testing"], version = "^2.18.2"}
dash-bootstrap-components = "^1.6.0"
dash-table = "^5.0.0"
dash-mantine-components = "^0.15.1"
dash-ag-grid = "^31.2.0"
scikit-learn = "^1.5.2"
pandas = "^2.2.1"
Flask = "^3.0.3"
flask-login = "^0.6.3"
flask-caching = "^2.1.0"
flask-sqlalchemy = "^3.1.1"
flask-redis = "^0.4.0"
flask-bootstrap4 = "^4.0.2"
Flask-FlatPages = "^0.8.2"
Flask-WTF = "^1.2.1"
flask-restx = "^1.3.0"
flask-dance = "^7.1.0"
joblib = "^1.2.0"
boto3 = "^1.35.72"
urllib3 = "1.26.18"
gunicorn = "^22.0.0"
python-dotenv = "^1.0.1"
requests = "^2.31.0"
pyjwt = "1.7.1"
sqlalchemy = "^2.0.30"
colour = "^0.1.5"
psycopg2-binary = "^2.9.9"
twilio = "^6.54.0"
openpyxl = "^3.0.7"
phonenumbers = "^8.12.29"
celery = "^5.4.0"
Flask-HTMLmin = "^2.2.1"
ipinfo = "^4.2.1"
Werkzeug = "^3.0.1"
Pillow = "^10.4.0"
gcld3 = "^3.0.13"
plotly = "^5.22.0"
numpy = "^1.26.4"
dash-signature = "^0.1.9"
webauthn = "^2.2.0"
flask-cors = "^5.0.0"
protobuf = "^5.28.2"
pyright = "^1.1.392.post0"
rich = "^13.9.1"
alembic = "^1.13.3"
flask-migrate = "^4.0.7"
botocore = "^1.35.75"
gevent = "^24.11.1"
psycogreen = "^1.0.2"
flask-admin = "2.0.0a3"
email-validator = "^2.2.0"
paho-mqtt = "^2.1.0"
google-cloud-recaptcha-enterprise = "^1.26.1"
[tool.poetry.group.dev.dependencies]
pytest = "^8.3.2"
pytest-mock = "^3.14.0"
tabulate = "^0.8.7"
kaleido = "0.2.0"
beautifulsoup4 = "^4.9.3"
pre-commit = "^3.4.0"
ruff = "^0.5.5"
make-responsive-images = "^0.1.17"
wtforms-alchemy = "^0.18.0"
djlint = "^1.35.2"
playwright = "^1.49.1"
pytest-playwright = "^0.6.2"
pyvirtualdisplay = "^3.0"
To fix it, I made my own pytest fixtures:
# @pytest.fixture(scope="function")
@pytest.fixture(scope="session")
def auth_page(
# dash_thread_server: ThreadedRunner,
dash_process_server: BackgroundProcessRunner,
auth_context: BrowserContext,
base_url: str,
) -> Generator[Page, None, None]:
"""
Provide an authenticated page for each test
"""
page = auth_context.new_page()
# setattr(page, "server", dash_thread_server)
setattr(page, "server", dash_process_server)
try:
# Go to the login page
page.goto(f"{base_url}/login/")
perform_login_sequence(page)
# Verify login success
# page.wait_for_load_state("networkidle")
if "Authenticate" in page.title():
raise AuthenticationError("Failed to authenticate - still on login page")
# Store authentication state
auth_context.storage_state(path="auth.json")
yield page
except Exception as err:
logger.error("Auth page creation failed: %s", err)
playwright_screenshot(page, "auth_page_failure")
raise err
finally:
page.close()
@pytest.fixture(scope="session")
def auth_context(
browser_session_scope: Browser,
) -> Generator[BrowserContext, None, None]:
"""
Create and maintain an authenticated browser context for the test session
"""
# Create a persistent context
context = browser_session_scope.new_context()
try:
yield context
finally:
context.close()
def main_url():
"""Get the main URL for the application."""
return "http://localhost:5000"
@pytest.fixture(scope="session")
def base_url():
"""Get the base URL for the application."""
return main_url()
@pytest.fixture(scope="session")
def dash_process_server(
# dash_app_complex_session_scope: Dash,
# dash_app_simple_session_scope: Dash,
base_url: str,
) -> Generator[BackgroundProcessRunner, None, None]:
"""Start a local dash server in a new process."""
with BackgroundProcessRunner(
keep_open=True, # Keep server running for all tests
stop_timeout=5,
) as starter:
# Start the server
set_testing_environment_vars()
try:
time_start: float = time.time()
starter.start(
# app_module=str(PROJECT_FOLDER.joinpath("wsgi.py")),
app_module="wsgi",
application_name="flask_app",
host=os.getenv("FLASK_RUN_HOST", "0.0.0.0"),
port=int(os.getenv("FLASK_RUN_PORT", 5000)),
# raw_command="gunicorn --chdir /project --config /project/app/config_gunicorn.py --bind 0.0.0.0:5000 wsgi:flask_app",
# raw_command="flask run --no-reload --no-debugger --host 0.0.0.0 --port 5000 --with-threads",
start_timeout=20,
)
time_end: float = time.time()
seconds_taken: float = time_end - time_start
logger.info(f"Server started in {seconds_taken:.2f} seconds")
except Exception as e:
logger.error(f"Failed to start server: {e}")
starter.stop()
raise e
if not verify_server_running(base_url):
raise RuntimeError("Server failed to start and be accessible")
try:
yield starter
finally:
# Stop the server
starter.stop()
@pytest.fixture(scope="session")
def auth_context(
browser_session_scope: Browser,
) -> Generator[BrowserContext, None, None]:
"""
Create and maintain an authenticated browser context for the test session
"""
# Create a persistent context
context = browser_session_scope.new_context()
try:
yield context
finally:
context.close()
@pytest.fixture(scope="session")
def browser_session_scope() -> Generator[Browser, None, None]:
"""
Create a browser instance for testing
"""
# # Display is active
# disp = Display().start()
# Start the display with Xvfb
# with Display(visible=os.getenv("FLASK_ENV") == "development", size=(1920, 1080)):
with sync_playwright() as p:
options = get_browser_launch_options()
# Launch browser with WebSockets enabled
# browser = await p.chromium.connect("ws://127.0.0.1:5000/")
browser: Browser = p.chromium.launch(**options)
try:
yield browser
finally:
browser.close()
# # Display is stopped
# disp.stop()
Then I changed the tests to use my own auth_page
fixture:
def test_has_title(auth_page: Page):
"""
Demo test from Playwright documentation
https://playwright.dev/python/docs/intro#running-the-example-test
"""
auth_page.goto("https://playwright.dev/")
# Expect a title "to contain" a substring.
expect(auth_page).to_have_title(re.compile("Playwright"))
def test_get_started_link(auth_page: Page):
"""
Demo test from Playwright documentation
https://playwright.dev/python/docs/intro#running-the-example-test
"""
auth_page.goto("https://playwright.dev/")
# Click the get started link.
auth_page.get_by_role("link", name="Get started").click()
# Expects page to have a heading with the name of Installation.
expect(auth_page.get_by_role("heading", name="Installation")).to_be_visible()
Upvotes: 1
Reputation: 51
I assume you're running this code in a notebook kernel. This is not possible to use the sync API in this context since there is a running asyncio eventloop.
Use the async API or run your code outside of a notebook kernel.
Upvotes: 5