Repository navigation
test(e2e): make auth.setup.ts idempotent across retries and disable external resources - #17818
Conversation
…xternal resources Checks /auth/login responses for already-reset passwords, skips re-creating member/viewer accounts if already present in /settings/users, and sets PHOENIX_ALLOW_EXTERNAL_RESOURCES=False in standard e2e runs so page.goto does not wait on external fonts or Scarf telemetry. Fixes Arize-ai#17789
Preview approval requiredThis pull request comes from a fork, so Mintlify won't build a preview until someone with write access approves commit |
|
The factory recommends ✅ Approve for 59a5f17 and labeled this pull request cc @RogerHYang |
There was a problem hiding this comment.
✅ Factory review of 59a5f17: Approve
The diff does what the PR and #17789 ask, every check passes, and there is no blocking finding.
| Fit | Checks | Tests | Blocking | Non-blocking | Risk | Depth |
|---|---|---|---|---|---|---|
| ✅ Pass | ✅ Pass | ✅ Not needed | ✅ 0 | ✅ Glance |
Needs attention
⚠️ Non-blocking: Existence check misses users past the first 50 rowsjs/app/tests/auth.setup.ts:141⚠️ Risk (Low): Side effects. The standard E2E server now refuses all external resources: fonts, the GitHub star count, the PyPI version check, and the WASM binary download. Sandbox specs still get WASM from the pre-warmed cache or fromPHOENIX_WASM_BINARY_PATHin CI.
Details
Intent: Make the Playwright auth bootstrap (js/app/tests/auth.setup.ts) safe to repeat across retries and reuseExistingServer runs against the same in-memory server, where admin, member and viewer may already exist or may have already reset their passwords. Also set PHOENIX_ALLOW_EXTERNAL_RESOURCES=False on the standard E2E server so page.goto doesn't wait on third-party CDNs (#17789).
Fit: Both parts are present.
login()now returns thePOST /auth/loginresponse.- A 401 for admin on
adminfalls back toadmin123. - Member and viewer are created only if they aren't already listed.
- Their password reset is skipped on a 401.
testServer.mjssetsPHOENIX_ALLOW_EXTERNAL_RESOURCES=Falsein the non-PXI branch.- Nothing unrelated is changed.
Verified: oxfmt --check,oxlint(whole app) andtsc --noEmit(js/app) all pass.- I started the E2E test server once and ran
playwright test --project=setupagainst it three times in a row (Chromium). All three passed, and the second and third runs took the new already-set-up paths. - With
main'sauth.setup.tsagainst the same server, setup fails withpage.waitForURLtiming out atauth.setup.ts:63. That is the failure the issue reports, so the change fixes it. tests/user-management.spec.tspasses on top of the new setup.- The rendered
/loginHTML has no Google Fonts or Scarf references. - After I added 50 users through
createUser, setup failed at line 160, which reproduces the inline finding.
Not verified: - Firefox and WebKit projects, the full E2E suite, and the app-frame and PXI projects.
- The sandbox had Node 22 and needed a symlinked Chromium 141 for Playwright 1.64, so the browser runs are close to CI but not identical.
Findings without a diff line: none
Resolved threads: none
Risk: side effects low, performance none, backwards compatibility low, from the area reviewers
Graded against the review criteria.
| if ( | ||
| !(await page | ||
| .getByText("[email protected]", { exact: true }) | ||
| .isVisible()) | ||
| ) { | ||
| await page.getByRole("button", { name: "Add User" }).click(); | ||
| await page.getByLabel("Email").fill("[email protected]"); | ||
| await page.getByLabel("Username").fill("member"); | ||
| await page.getByLabel("Password", { exact: true }).fill("member"); | ||
| await page.getByLabel("Confirm Password").fill("member"); | ||
| await page | ||
| .getByRole("dialog") | ||
| .getByLabel("member", { exact: true }) | ||
| .click(); | ||
| await page.getByRole("option", { name: "member" }).click(); | ||
| await page | ||
| .getByRole("dialog") | ||
| .getByRole("button", { name: "Add User" }) | ||
| .click(); | ||
| await expect(page.getByTestId("dialog")).not.toBeVisible(); | ||
| } | ||
|
|
||
| // Add viewer user | ||
| await page.getByRole("button", { name: "Add User" }).click(); | ||
| await page.getByLabel("Email").fill("[email protected]"); | ||
| await page.getByLabel("Username").fill("viewer"); | ||
| await page.getByLabel("Password", { exact: true }).fill("viewer"); | ||
| await page.getByLabel("Confirm Password").fill("viewer"); | ||
| await page | ||
| .getByRole("dialog") | ||
| .getByLabel("member", { exact: true }) | ||
| .click(); | ||
| await page.getByRole("option", { name: "viewer" }).click(); | ||
| await page | ||
| .getByRole("dialog") | ||
| .getByRole("button", { name: "Add User" }) | ||
| .click(); | ||
| await expect(page.getByTestId("dialog")).not.toBeVisible(); | ||
| if ( | ||
| !(await page | ||
| .getByText("[email protected]", { exact: true }) | ||
| .isVisible()) | ||
| ) { |
There was a problem hiding this comment.
Non-blocking: These existence checks only look at the users table's first page. Once more than 50 users sort ahead of [email protected] or [email protected], the setup tries to add a user that already exists and fails. That is the same retry/reuse failure this PR is fixing.
Evidence:
- The table is ordered by email (
src/phoenix/server/api/queries.py:409-414) and loads 50 rows at a time, with more rows only on scroll (UsersTable.tsx:39,91). user-management.spec.ts:8,33,66createsmember-<uuid>@…,viewer-<uuid>@…andpassword-reset-<uuid>@…users on every run and never deletes them. All of them sort before[email protected], because-sorts before@.- With
reuseExistingServer: !isCI(playwright.config.ts:139),[email protected]drops off the first page after roughly 16 local runs. - I reproduced this against a long-lived test server:
- Setup passed on a second and third run.
- I then added 50 more users through
createUser, which left[email protected]at row 56. - The next setup run failed at
auth.setup.ts:160withexpect(locator).not.toBeVisible(), because the Add User dialog stayed open on the duplicate email.
isVisible()also doesn't wait. It works only because theadmin@localhostassertion above has already waited for the query.
CI retries happen before other specs add users, so the CI case the issue reports is fixed. This only affects local reuse.
Fix: Don't use the DOM as the record of which users exist. Pick one of these:
- Probe with a login first, for example
[email protected]/member123. Treat a success as already set up, and a 401 on both passwords as not created. - Or, when Add User reports that the email already exists, close the dialog and continue.
RogerHYang
left a comment
There was a problem hiding this comment.
Thank you for your contribution!
Fixes #17789
When
js/app/tests/auth.setup.tsfails part-way through Attempt 0 against the long-lived in-memory test server, Playwright retries fail becauseadmin@localhost,[email protected], or[email protected]may have already reset their initial passwords or been created on the earlier attempt. In addition,js/app/tests/utils/testServer.mjsleftPHOENIX_ALLOW_EXTERNAL_RESOURCESat its default (True) in standard E2E runs, causingpage.goto(waitUntil: "load") to block on external Google Fonts and Scarf pixel requests.This updates
auth.setup.tsto inspect thePOST /auth/loginresponse status so already-reset accounts log in with their updated password instead of hanging on the password-reset redirect, checks whether[email protected]and[email protected]already exist in/settings/usersbefore opening the Add User dialog, and setsPHOENIX_ALLOW_EXTERNAL_RESOURCES = "False"in the standard E2E branch oftestServer.mjs.