Files
2026-07-13 13:39:12 +08:00

193 lines
6.3 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { gotoDashboardRoute } from "./helpers/dashboardAuth";
async function mockCombosPageApis(page: import("@playwright/test").Page) {
await page.route("**/api/combos", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
combos: [
{
id: "combo-auto",
name: "combo-auto",
models: ["openai/gpt-4o-mini"],
strategy: "auto",
config: { candidatePool: ["openai", "anthropic"], modePack: "ship-fast" },
isActive: true,
},
{
id: "combo-priority",
name: "combo-priority",
models: ["anthropic/claude-sonnet-4-6"],
strategy: "priority",
isActive: true,
},
],
}),
});
});
await page.route("**/api/combos/metrics", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ metrics: {} }),
});
});
await page.route("**/api/providers", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
connections: [
{ id: "conn-openai", provider: "openai", name: "OpenAI", testStatus: "active" },
{
id: "conn-anthropic",
provider: "anthropic",
name: "Anthropic",
testStatus: "active",
},
],
}),
});
});
await page.route("**/api/provider-nodes", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ nodes: [] }),
});
});
await page.route("**/api/settings/proxy", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ combos: {} }),
});
});
await page.route("**/api/monitoring/health", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
circuitBreakers: [
{ provider: "openai", state: "CLOSED" },
{ provider: "anthropic", state: "OPEN", lastFailure: new Date().toISOString() },
],
}),
});
});
}
async function mockBuilderApis(page: import("@playwright/test").Page) {
await page.route("**/api/models/alias", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ aliases: {} }),
});
});
await page.route("**/api/pricing", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({}),
});
});
await page.route("**/api/settings/combo-defaults", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ comboDefaults: {} }),
});
});
await page.route("**/api/combos/builder/options", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
providers: [
{
providerId: "openai",
displayName: "OpenAI",
connectionCount: 1,
models: [{ id: "gpt-4o-mini", name: "gpt-4o-mini" }],
connections: [{ id: "conn-openai", label: "OpenAI Main", status: "active" }],
},
],
comboRefs: [],
}),
});
});
}
test.describe("Combo Unification", () => {
test.beforeEach(async ({ page }) => {
await mockCombosPageApis(page);
await mockBuilderApis(page);
});
test("combos page exposes strategy tabs and intelligent panel", async ({ page }) => {
await gotoDashboardRoute(page, "/dashboard/combos?filter=intelligent");
await expect(
page
.locator("button")
.filter({ has: page.locator("span", { hasText: "layers" }) })
.filter({ hasText: "All" })
).toBeVisible();
await expect(page.getByRole("button", { name: /intelligent/i })).toBeVisible();
await expect(page.getByRole("button", { name: /deterministic/i })).toBeVisible();
await expect(page.getByText("Intelligent Routing Dashboard")).toBeVisible();
await expect(page.getByText("Provider Scores")).toBeVisible();
});
test("legacy auto-combo route redirects to intelligent combos filter", async ({ page }) => {
await gotoDashboardRoute(page, "/dashboard/auto-combo");
await page.waitForURL(/\/dashboard\/combos\?filter=intelligent/);
await expect(page).toHaveURL(/\/dashboard\/combos\?filter=intelligent/);
});
test("sidebar no longer shows auto combo entry", async ({ page }) => {
await gotoDashboardRoute(page, "/dashboard/combos");
const sidebar = page.locator("aside, nav").first();
await expect(sidebar.getByText("Combos", { exact: true })).toBeVisible();
await expect(sidebar.getByText("Auto Combo")).toHaveCount(0);
});
test("builder shows intelligent step when auto strategy is selected", async ({ page }) => {
await gotoDashboardRoute(page, "/dashboard/combos");
await page.getByRole("button", { name: /create combo/i }).click();
await page.getByLabel(/combo name/i).waitFor({ state: "visible" });
await page.getByLabel(/combo name/i).fill("e2e-auto-builder");
await page.getByTestId("combo-builder-next").click();
await page.getByTestId("combo-builder-provider").waitFor({ state: "visible" });
await page.getByTestId("combo-builder-provider").selectOption("openai");
await page.getByTestId("combo-builder-model").waitFor({ state: "attached" });
await page.getByTestId("combo-builder-model").selectOption("gpt-4o-mini");
await page.getByTestId("combo-builder-add-step").click();
await page.getByTestId("combo-builder-next").click();
await page.getByTestId("strategy-option-auto").waitFor({ state: "visible" });
await page.getByTestId("strategy-option-auto").click();
await page.getByTestId("combo-builder-next").click();
await expect(page.getByText("Candidate Pool", { exact: true })).toBeVisible({ timeout: 15000 });
await expect(page.getByText("Mode Pack", { exact: true })).toBeVisible({ timeout: 15000 });
await expect(page.getByText("Exploration Rate", { exact: true })).toBeVisible({
timeout: 15000,
});
});
});