Playwright-паттерны для Phoenix: серийные тесты и RBAC
Примеры Playwright-тестов для Phoenix: CRUD, RBAC, серийные тесты с общим состоянием, проверка прав доступа.
Примеры Playwright-тестов для Phoenix: CRUD, RBAC, серийные тесты с общим состоянием, проверка прав доступа.
Примеры можно адаптировать для автоматизации тестирования собственных интерфейсов оркестрации моделей: использовать паттерны авторизации, серийные тесты для сценариев с зависимостями, проверку прав доступа. Это ускорит регрессионное тестирование и повысит надежность.
расшифровка ролика ↓
Title:
URL Source: https://raw.githubusercontent.com/Arize-ai/phoenix/main/.agents/skills/phoenix-playwright-tests/EXAMPLES.md
Markdown Content: # Phoenix Playwright Test Examples
Complete examples from the Phoenix test suite.
## Example 1: Basic CRUD Test (Prompt Management)
```typescript import { expect, test } from "@playwright/test"; import { randomUUID } from "crypto";
test.describe("Prompt Management", () => { test.beforeEach(async ({ page }) => { page.goto(`/login`); await page.getByLabel("Email").fill("admin@localhost"); await page.getByLabel("Password").fill("admin123"); await page.getByRole("button", { name: "Log In", exact: true }).click(); await page.waitForURL("**/projects"); });
test("can create a prompt", async ({ page }) => { await page.goto("/prompts"); await page.waitForURL("**/prompts"); await page.getByRole("link", { name: "New Prompt" }).click(); await page.waitForURL("**/playground"); await page .getByText("You are a chatbot") .fill("You are a helpful assistant"); await page.getByRole("button", { name: "Save Prompt" }).click(); await page.getByPlaceholder("Select or enter new prompt").click(); const promptName = `chatbot-${randomUUID()}`; await page.getByPlaceholder("Select or enter new prompt").fill(promptName); await page.getByLabel("Prompt Description").click(); await page.getByLabel("Prompt Description").fill("very kind chatbot"); await page.getByRole("button", { name: "Create Prompt" }).click(); await page.getByRole("button", { name: "View Prompt" }).click();
await expect(page.getByRole("heading", { name: promptName })).toBeVisible(); await expect( page.getByText("You are a helpful assistant").first() ).toBeVisible(); }); }); ```
## Example 2: User Management (Admin Actions)
```typescript import { expect, test } from "@playwright/test"; import { randomUUID } from "crypto";
test.beforeEach(async ({ page }) => { page.goto(`/login`); await page.getByLabel("Email").fill("admin@localhost"); await page.getByLabel("Password").fill("admin123"); await page.getByRole("button", { name: "Log In", exact: true }).click(); await page.waitForURL("**/projects"); });
test("can create a user", async ({ page }) => { await page.goto("/settings/general"); await page.waitForURL("**/settings/general"); await page.getByRole("button", { name: "Add User" }).click();
const email = `member-${randomUUID()}@localhost.com`; await page.getByLabel("Email").fill(email); await page.getByLabel("Username").fill(email); await page.getByLabel("Password", { exact: true }).fill("member123"); await page.getByLabel("Confirm Password").fill("member123"); await page.getByRole("dialog").getByLabel("member", { exact: true }).click(); await page .getByRole("dialog") .getByRole("option", { name: "member" }) .click(); await page .getByRole("dialog") .getByRole("button", { name: "Add User" }) .click();
await expect(page.getByRole("cell", { name: email })).toBeVisible(); }); ```
## Example 3: Serial Tests with Shared State (Evaluators)
```typescript import { expect, test } from "@playwright/test"; import { randomUUID } from "crypto";
test.describe.serial("Server Evaluators", () => { const datasetName = `test-dataset-${randomUUID()}`; const customEvaluatorName = `custom-eval-${randomUUID().slice(0, 8)}`; const updatedDescription = "Updated description for testing";
test.beforeEach(async ({ page }) => { await page.goto(`/login`); await page.getByLabel("Email").fill("admin@localhost"); await page.getByLabel("Password").fill("admin123"); await page.getByRole("button", { name: "Log In", exact: true }).click(); await page.waitForURL("**/projects"); });
test("can create a dataset", async ({ page }) => { await page.goto("/datasets"); await page.waitForURL("**/datasets");
await page.getByRole("button", { name: "New Dataset" }).click(); await page.getByRole("menuitem", { name: "New Dataset" }).click();
await page.getByLabel("Dataset Name").clear(); await page.getByLabel("Dataset Name").fill(datasetName); await page.getByLabel("Description").fill("Test dataset for evaluators");
await page.getByRole("button", { name: "Create Dataset" }).click(); await expect(page.getByRole("dialog")).not.toBeVisible({ timeout: 10000 });
await expect(page.getByRole("link", { name: datasetName })).toBeVisible({ timeout: 10000, }); });
test("can create a custom LLM evaluator", async ({ page }) => { await page.goto("/datasets"); await page.getByRole("link", { name: datasetName }).click(); await page.waitForURL("**/datasets/**/examples"); await page.getByRole("tab", { name: /Evaluators/i }).click(); await page.waitForURL("**/evaluators");
await page.getByRole("button", { name: "Add evaluator" }).click(); await page .getByRole("menuitem", { name: "Create new LLM evaluator" }) .click();
await expect( page.getByRole("heading", { name: "Create Evaluator" }) ).toBeVisible();
await page .getByRole("textbox", { name: "Name" }) .first() .fill(customEvaluatorName); await page .getByRole("textbox", { name: /Description/i }) .fill("Initial description for custom evaluator");
const systemSection = page.locator( 'button:has-text("System"):not([role="menuitem"])' ); const systemTextbox = systemSection .locator("..") .locator("..") .getByRole("textbox"); await systemTextbox.fill("You are an evaluator.");
const userSection = page.locator( 'button:has-text("User"):not([role="menuitem"])' ); const userTextbox = userSection .locator("..") .locator("..") .getByRole("textbox"); await userTextbox.fill("Evaluate: {{output}}");
await page.getByRole("button", { name: "Create" }).click(); await expect(page.getByRole("dialog")).not.toBeVisible({ timeout: 10000 });
await expect( page.getByRole("cell", { name: customEvaluatorName }) ).toBeVisible(); });
test("can edit an LLM evaluator", async ({ page }) => { await page.goto("/datasets"); await page.getByRole("link", { name: datasetName }).click(); await page.waitForURL("**/datasets/**/examples"); await page.getByRole("tab", { name: /Evaluators/i }).click(); await page.waitForURL("**/evaluators");
const evaluatorRow = page.getByRole("row").filter({ has: page.getByRole("cell", { name: customEvaluatorName }), }); await evaluatorRow.getByRole("button").last().click(); await page.getByRole("menuitem", { name: "Edit" }).click();
await expect( page.getByRole("heading", { name: "Edit Evaluator" }) ).toBeVisible();
const descriptionInput = page.getByRole("textbox", { name: /Description/i, }); await descriptionInput.clear(); await descriptionInput.fill(updatedDescription);
await page.getByRole("button", { name: "Update" }).click(); await expect(page.getByRole("dialog")).not.toBeVisible({ timeout: 10000 });
await expect( page.getByRole("cell", { name: customEvaluatorName }) ).toBeVisible(); });
test("can verify edits were saved", async ({ page }) => { await page.goto("/datasets"); await page.getByRole("link", { name: datasetName }).click(); await page.waitForURL("**/datasets/**/examples"); await page.getByRole("tab", { name: /Evaluators/i }).click(); await page.waitForURL("**/evaluators");
const evaluatorRow = page.getByRole("row").filter({ has: page.getByRole("cell", { name: customEvaluatorName }), }); await evaluatorRow.getByRole("button").last().click(); await page.getByRole("menuitem", { name: "Edit" }).click();
const descriptionInput = page.getByRole("textbox", { name: /Description/i, }); await expect(descriptionInput).toHaveValue(updatedDescription);
await page.getByRole("button", { name: "Cancel" }).click(); }); }); ```
## Example 4: Role-Based Access Control
```typescript import { expect, test } from "@playwright/test";
test.describe("Viewer Access", () => { test.beforeEach(async ({ page }) => { page.goto(`/login`); await page.getByLabel("Email").fill("viewer@localhost.com"); await page.getByLabel("Password").fill("viewer123"); await page.getByRole("button", { name: "Log In", exact: true }).click(); await page.waitForURL("**/projects"); });
test("viewer cannot access settings", async ({ page }) => { await page.goto("/settings/general"); // Viewer should be redirected or see access denied await expect(page.getByText("Access Denied")).toBeVisible(); }); }); ```
## Example 5: Testing with Playground Integration
```typescript test("evaluators are visible in playground when dataset is selected", async ({ page, }) => { await page.goto("/datasets"); await page.getByRole("link", { name: datasetName }).click(); await page.waitForURL("**/datasets/**/examples");
const datasetUrl = page.url(); const datasetIdMatch = datasetUrl.match(/datasets\/([^/]+)/); const datasetIdForUrl = datasetIdMatch ? datasetIdMatch[1] : "";
await page.goto(`/playground?datasetId=${datasetIdForUrl}`); await page.waitForURL("**/playground**");
await expect( page.getByRole("button", { name: new RegExp(datasetName) }) ).toBeVisible();
await expect(page.getByRole("heading", { name: "Experiment" })).toBeVisible();
const experimentSection = page.locator("text=Experiment").locator(".."); await expect( experimentSection.getByRole("button", { name: "Evaluators" }) ).toBeVisible(); }); ```