test(ui): cover narrowed dashboard form journeys

This commit is contained in:
Yuneng Jiang 2026-09-17 22:44:03 -07:00
parent b1f9da79a8
commit c34adb4ab2
No known key found for this signature in database
5 changed files with 220 additions and 0 deletions

View file

@ -0,0 +1,55 @@
import { test, expect } from "@playwright/test";
import { ADMIN_STORAGE_PATH } from "../../constants";
import { Page as DashboardPage } from "../../fixtures/pages";
import { navigateToPage } from "../../helpers/navigation";
import { readBack } from "../../helpers/roundTrip";
import { masterKey, uniqueSuffix } from "../../helpers/traffic";
test.use({ storageState: ADMIN_STORAGE_PATH });
test.describe("Prompt upload form", () => {
test("uploads a prompt file and reads the created prompt back", async ({
page,
}) => {
const promptId = `e2e-prompt-${uniqueSuffix()}`;
await navigateToPage(page, DashboardPage.Prompts);
await page.getByRole("button", { name: "Upload .prompt File" }).click();
try {
await expect(
page.getByRole("dialog", { name: "Add New Prompt" }),
).toBeVisible();
await page.getByLabel("Prompt ID").fill(promptId);
await page.locator('input[type="file"]').setInputFiles({
name: "e2e.prompt",
mimeType: "text/plain",
buffer: Buffer.from(
'model: fake-openai-gpt-4\ntemplate: "Hello {{name}}"\n',
),
});
await expect(page.getByText("Selected: e2e.prompt")).toBeVisible();
await page.getByRole("button", { name: "Create Prompt" }).click();
await expect
.poll(async () => {
const response = await page.request.get(
`/prompts/${encodeURIComponent(promptId)}/info?environment=development`,
{
headers: { Authorization: `Bearer ${masterKey()}` },
},
);
return response.ok();
})
.toBe(true);
await expect(page.getByText(promptId, { exact: true })).toBeVisible();
} finally {
await page.request.delete(
`/prompts/${encodeURIComponent(promptId)}?environment=development`,
{
headers: { Authorization: `Bearer ${masterKey()}` },
},
);
}
});
});

View file

@ -0,0 +1,76 @@
import { test, expect } from "@playwright/test";
import { ADMIN_STORAGE_PATH } from "../../constants";
import { Page as DashboardPage } from "../../fixtures/pages";
import { navigateToPage } from "../../helpers/navigation";
import { captureRequestBody, readBack } from "../../helpers/roundTrip";
import { masterKey, uniqueSuffix } from "../../helpers/traffic";
test.use({ storageState: ADMIN_STORAGE_PATH });
test.describe("Tag management", () => {
test("creates, edits, reopens, and reads back a tag", async ({ page }) => {
const tagName = `e2e-tag-${uniqueSuffix()}`;
const description = "synthetic tag description";
const updatedDescription = `${description} updated`;
await navigateToPage(page, DashboardPage.TagManagement);
await page.getByRole("button", { name: "+ Create New Tag" }).click();
try {
await expect(
page.getByRole("dialog", { name: "Create New Tag" }),
).toBeVisible();
await page.getByLabel("Tag Name").fill(tagName);
await page.getByLabel("Description").fill(description);
await page.getByRole("button", { name: "Create Tag" }).click();
await expect
.poll(async () => {
const response = await readBack<
Record<string, Record<string, unknown>>
>(page, "/tag/list");
return Object.values(response).some((tag) => tag.name === tagName);
})
.toBe(true);
await expect(page.getByText(tagName, { exact: true })).toBeVisible();
await page.getByText(tagName, { exact: true }).click();
await expect(page.getByText("Tag Name:")).toBeVisible();
await page.getByRole("button", { name: "Edit Tag" }).click();
await page.getByLabel("Description").fill(updatedDescription);
const updateBody = await captureRequestBody(
page,
{ method: "POST", urlIncludes: "/tag/update" },
() => page.getByRole("button", { name: "Save Changes" }).click(),
);
expect(updateBody).toMatchObject({
name: tagName,
description: updatedDescription,
});
await expect
.poll(async () => {
const infoResponse = await page.request.post("/tag/info", {
headers: { Authorization: `Bearer ${masterKey()}` },
data: { names: [tagName] },
});
expect(infoResponse.ok()).toBe(true);
const info = (await infoResponse.json()) as Record<
string,
{ description?: string }
>;
return info[tagName]?.description;
})
.toBe(updatedDescription);
} finally {
await page.request.post("/tag/delete", {
headers: {
Authorization: `Bearer ${masterKey()}`,
"Content-Type": "application/json",
},
data: { name: tagName },
});
}
});
});

View file

@ -1,5 +1,6 @@
import { fireEvent, renderWithProviders as render, screen, waitFor } from "../../../tests/test-utils";
import userEvent from "@testing-library/user-event";
import { useQuery } from "@tanstack/react-query";
import { useState } from "react";
import { describe, expect, it, vi } from "vitest";
@ -406,4 +407,48 @@ describe("PaginatedSearchSelect", () => {
expect(input).toHaveValue("aliasalpha");
await waitFor(() => expect(onSearchChange).toHaveBeenLastCalledWith("aliasalpha"));
});
it("keeps the latest query results when an earlier response resolves last", async () => {
const pending = new Map<string, (options: SearchSelectOption[]) => void>();
function QueryBackedSelect() {
const [query, setQuery] = useState("");
const result = useQuery({
queryKey: ["paginated-select-race", query],
queryFn: () =>
new Promise<SearchSelectOption[]>((resolve) => {
pending.set(query, resolve);
}),
enabled: query.length > 0,
});
return (
<>
<button type="button" onClick={() => setQuery("A")}>
Search A
</button>
<button type="button" onClick={() => setQuery("B")}>
Search B
</button>
<PaginatedSearchSelect options={result.data ?? []} onValueChange={vi.fn()} onSearchChange={setQuery} />
</>
);
}
const user = userEvent.setup();
render(<QueryBackedSelect />);
await user.click(screen.getByRole("button", { name: "Search A" }));
await user.click(screen.getByRole("button", { name: "Search B" }));
await waitFor(() => {
expect(pending.has("A")).toBe(true);
expect(pending.has("B")).toBe(true);
});
pending.get("B")?.([{ label: "B result", value: "b" }]);
await user.click(screen.getByRole("combobox"));
expect(await screen.findByText("B result")).toBeInTheDocument();
pending.get("A")?.([{ label: "A result", value: "a" }]);
await waitFor(() => expect(screen.queryByText("A result")).not.toBeInTheDocument());
expect(screen.getByText("B result")).toBeInTheDocument();
});
});

View file

@ -111,4 +111,37 @@ describe("SearchSelect", () => {
expect(screen.queryByText("Growth")).not.toBeInTheDocument();
expect(onValueChange).not.toHaveBeenCalled();
});
it("supports keyboard select, clear, escape, blur, and reopen", async () => {
const onValueChange = vi.fn();
const user = userEvent.setup();
function Controlled() {
const [value, setValue] = useState<string | null>(null);
return (
<SearchSelect
options={OPTIONS}
value={value}
onValueChange={(next) => {
setValue(next);
onValueChange(next);
}}
/>
);
}
render(<Controlled />);
const input = screen.getByRole("combobox");
await user.tab();
await user.keyboard("{Enter}");
await user.keyboard("{ArrowDown}{Enter}");
expect(onValueChange).toHaveBeenLastCalledWith("team-1");
const clear = screen.getByRole("button", { name: "Clear" });
clear.focus();
await user.keyboard("{Enter}");
expect(onValueChange).toHaveBeenLastCalledWith(null);
await user.keyboard("{Escape}");
await user.tab();
await user.tab({ shift: true });
expect(input).toHaveFocus();
});
});

View file

@ -344,4 +344,15 @@ describe("RequestLogsFilters", () => {
expect(set).toHaveBeenCalledWith(LOG_FILTER_IDS.CACHE_STATUS, undefined);
});
it("clears the raw Error Code combobox through the undefined filter contract", async () => {
const user = userEvent.setup();
const { set } = renderFilters({ [LOG_FILTER_IDS.ERROR_CODE]: "429" });
const input = await screen.findByPlaceholderText("Select or type an error code");
await user.click(input);
await user.click(screen.getByRole("button", { name: "Clear", hidden: true }));
expect(set).toHaveBeenCalledWith(LOG_FILTER_IDS.ERROR_CODE, undefined);
});
});