evOo-local/apps/web/e2e/onboarding-model-labels.spec.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

102 lines
4.9 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { captureScreenshot, signup } from "./helpers";
test("onboarding uses compact model selects without misleading latest labels", async ({
page,
}, testInfo) => {
await page.route("**/rpc/me", async (route) => {
const response = await route.fetch();
const body = (await response.json()) as { json: Record<string, unknown> };
await route.fulfill({
response,
json: {
json: {
...body.json,
needsModel: true,
defaultProvider: "openrouter",
defaultModel: "openai/gpt-5.6-luna",
},
},
});
});
const stamp = Date.now();
await signup(page, `model-labels-${stamp}@rakazo.test`, "password12", `Model labels ${stamp}`);
await expect(page.getByRole("heading", { name: "Connect a model" })).toBeVisible({
timeout: 20_000,
});
const provider = page.getByRole("combobox", { name: "Provider" });
await expect(provider).toContainText("OpenRouter");
await page.getByLabel("API key").fill("openrouter-only-key");
await provider.click();
await expect(page.getByRole("option", { name: "ChatGPT" })).toBeVisible();
await expect(page.getByRole("option", { name: "Vercel AI Gateway" })).toBeVisible();
await page.getByRole("option", { name: "Anthropic" }).click();
await expect(provider).toContainText("Anthropic");
await expect(page.getByLabel(/API key/)).toHaveValue("");
const models = page.getByRole("combobox", { name: "Model", exact: true });
await models.click();
const labels = await page.getByRole("option").allTextContents();
// "latest" is an upstream alias marker, so it lands on families like Claude Opus 4.5 while
// newer models carry no marker. Rendered as-is it tells the user the opposite of the truth.
expect(labels.filter((label) => /\blatest\b/i.test(label))).toEqual([]);
// Select a non-default model and keep its user-facing alias visible in the compact trigger.
const alias = labels.find((label) => label.includes("(auto-updates)"));
expect(alias).toBeTruthy();
await page.getByRole("option", { name: alias! }).click();
await expect(models).toContainText(alias!);
await page.route("**/rpc/models/probeOpenAiCompatible", async (route) => {
await route.fulfill({
contentType: "application/json",
body: JSON.stringify({ json: { models: ["probed-model"] } }),
});
});
await provider.click();
await page.getByRole("option", { name: "OpenAI-compatible" }).click();
await page.getByLabel("OpenAI-compatible server URL").fill("http://127.0.0.1:8090/v1");
const manualModel = page.getByLabel("Model id");
await expect(manualModel).toBeVisible();
// Typing before the first probe must keep freeform even if the probe returns that id.
await manualModel.fill("probed-model");
const firstProbeResponse = page.waitForResponse("**/rpc/models/probeOpenAiCompatible");
await page.getByRole("button", { name: "Find models" }).click();
await firstProbeResponse;
await expect(manualModel).toBeVisible();
await expect(manualModel).toHaveValue("probed-model");
await expect(page.getByRole("combobox", { name: "Models from server" })).toHaveCount(0);
await page.getByRole("button", { name: "Use a found model" }).click();
const discovered = page.getByRole("combobox", { name: "Models from server" });
await expect(discovered).toBeVisible();
await expect(discovered).toContainText("probed-model");
await discovered.click();
await page.getByRole("option", { name: "Other model…" }).click();
await expect(manualModel).toBeVisible();
// Typing a discovered id (or its prefix) must keep the freeform field.
await manualModel.fill("probed-model");
await expect(manualModel).toBeVisible();
await expect(manualModel).toHaveValue("probed-model");
// Re-probe while the typed id matches a discovered model must stay freeform.
const reProbeResponse = page.waitForResponse("**/rpc/models/probeOpenAiCompatible");
await page.getByRole("button", { name: "Find models" }).click();
await reProbeResponse;
await expect(manualModel).toBeVisible();
await expect(manualModel).toHaveValue("probed-model");
await expect(page.getByRole("combobox", { name: "Models from server" })).toHaveCount(0);
// Editing the server URL must not drop Other model… mode either.
await page.getByLabel("OpenAI-compatible server URL").fill("http://127.0.0.1:8091/v1");
const editedUrlProbeResponse = page.waitForResponse("**/rpc/models/probeOpenAiCompatible");
await page.getByRole("button", { name: "Find models" }).click();
await editedUrlProbeResponse;
await expect(manualModel).toBeVisible();
await expect(manualModel).toHaveValue("probed-model");
await expect(page.getByRole("combobox", { name: "Models from server" })).toHaveCount(0);
await manualModel.fill("probed-model-custom");
await expect(manualModel).toHaveValue("probed-model-custom");
await captureScreenshot(page, testInfo, "onboarding-model-labels");
});