Files
ragflow/test/playwright/helpers/_auth_helpers.py
Idriss Sbaaoui 2f4ca38adf Fix : make playwright tests idempotent (#13332)
### What problem does this PR solve?

Playwright tests previously depended on cross-file execution order
(`auth -> provider -> dataset -> chat`).
This change makes setup explicit and idempotent via fixtures so tests
can run independently.

- Added/standardized prerequisite fixtures in
`test/playwright/conftest.py`:
- `ensure_auth_context`, `ensure_model_provider_configured`,
`ensure_dataset_ready`, `ensure_chat_ready`
- Made provisioning reusable/idempotent with `RUN_ID`-based resource
naming.
- Synced auth envs (`E2E_ADMIN_EMAIL`, `E2E_ADMIN_PASSWORD`) into seeded
creds.
- Fixed provider cache freshness (`auth_header`/`page` refresh on cache
hit).

Also included minimal stability fixes:
- dataset create stale-element click handling,
- search wait logic for results/empty-state,
- agent create-menu handling,
- agent run-step retry when run UI doesn’t open first click.

### Type of change

- [x] Test fix
- [x] Refactoring

---------

Co-authored-by: Liu An <asiro@qq.com>
2026-03-04 10:07:14 +08:00

83 lines
2.5 KiB
Python

import os
import pytest
from playwright.sync_api import expect
RESULT_TIMEOUT_MS = 15000
def _wait_for_login_complete(page, timeout_ms: int = RESULT_TIMEOUT_MS) -> None:
wait_js = """
() => {
const path = window.location.pathname || '';
if (path.includes('/login')) return false;
const token = localStorage.getItem('Token');
const auth = localStorage.getItem('Authorization');
return Boolean((token && token.length) || (auth && auth.length));
}
"""
page.wait_for_function(wait_js, timeout=timeout_ms)
def ensure_authed(
page,
login_url: str,
active_auth_context,
auth_click,
seeded_user_credentials=None,
timeout_ms: int = RESULT_TIMEOUT_MS,
) -> None:
if seeded_user_credentials:
email, password = seeded_user_credentials
else:
email = os.getenv("SEEDED_USER_EMAIL") or os.getenv("E2E_ADMIN_EMAIL")
password = os.getenv("SEEDED_USER_PASSWORD") or os.getenv(
"E2E_ADMIN_PASSWORD"
)
if not email or not password:
pytest.skip("SEEDED_USER_EMAIL/SEEDED_USER_PASSWORD not set.")
token_wait_js = """
() => {
const token = localStorage.getItem('Token');
const auth = localStorage.getItem('Authorization');
return Boolean((token && token.length) || (auth && auth.length));
}
"""
try:
if "/login" not in page.url:
page.wait_for_function(token_wait_js, timeout=2000)
return
except Exception:
pass
page.goto(login_url, wait_until="domcontentloaded")
if "/login" not in page.url:
return
form, _ = active_auth_context()
email_input = form.locator(
"input[data-testid='auth-email'], [data-testid='auth-email'] input"
)
password_input = form.locator(
"input[data-testid='auth-password'], [data-testid='auth-password'] input"
)
expect(email_input).to_have_count(1)
expect(password_input).to_have_count(1)
email_input.fill(email)
password_input.fill(password)
password_input.blur()
submit_button = form.locator(
"button[data-testid='auth-submit'], [data-testid='auth-submit'] button, [data-testid='auth-submit']"
)
expect(submit_button).to_have_count(1)
auth_click(submit_button, "submit_login")
_wait_for_login_complete(page, timeout_ms=timeout_ms)
expect(page.locator("form[data-testid='auth-form'][data-active='true']")).to_have_count(
0, timeout=timeout_ms
)