Skip to content

Commit e558c1a

Browse files
committed
Add a browser e2e scenario for the multi-server add form
Records the UI side of per-call server selection: pasting a spec that declares more than one server turns the Add OpenAPI source form's Base URL field into a picker over those servers and relabels it an optional override, with a hint that the host is otherwise chosen per tool call. The session video and step screenshots are the artifact; the scenario skips on targets without a browser surface.
1 parent 3eb8d67 commit e558c1a

1 file changed

Lines changed: 72 additions & 0 deletions

File tree

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Cross-target (browser): the UI side of per-call server selection. When a
2+
// pasted spec declares more than one server, the Add OpenAPI source form turns
3+
// the Base URL field into a picker over those servers and relabels it an
4+
// optional override — the host is otherwise resolved per tool call. The session
5+
// video + per-step screenshots are the artifact; this scenario skips on targets
6+
// without a browser surface (selfhost today).
7+
import { expect } from "@effect/vitest";
8+
import { Effect } from "effect";
9+
10+
import { scenario } from "../src/scenario";
11+
import { Browser, Target } from "../src/services";
12+
13+
// Two servers — production and staging — so the form offers a base-URL picker
14+
// instead of the single locked input a one-server spec gets.
15+
const multiServerSpec = JSON.stringify({
16+
openapi: "3.0.3",
17+
info: { title: "Regions API", version: "1.0.0" },
18+
servers: [
19+
{ url: "https://api.example.com", description: "Production" },
20+
{ url: "https://staging.example.com", description: "Staging" },
21+
],
22+
paths: {
23+
"/ping": { get: { operationId: "ping", responses: { "200": { description: "pong" } } } },
24+
},
25+
});
26+
27+
scenario(
28+
"OpenAPI · the add form offers a server picker and an optional base URL for a multi-server spec",
29+
{},
30+
Effect.scoped(
31+
Effect.gen(function* () {
32+
const target = yield* Target;
33+
const browser = yield* Browser;
34+
const identity = yield* target.newIdentity();
35+
36+
yield* browser.session(identity, async ({ page, step }) => {
37+
await step("Open the Add OpenAPI source form", async () => {
38+
await page.goto("/integrations/add/openapi", { waitUntil: "networkidle" });
39+
await page.getByPlaceholder("https://api.example.com/openapi.json").waitFor();
40+
});
41+
42+
await step("Paste a spec that declares two servers", async () => {
43+
await page.getByPlaceholder("https://api.example.com/openapi.json").fill(multiServerSpec);
44+
// The form auto-analyzes (debounced) and renders the preview details,
45+
// where the base URL is now an OPTIONAL override.
46+
await page.getByText("Base URL override (optional)").waitFor({ timeout: 20_000 });
47+
});
48+
49+
await step("The base URL is optional — the server is chosen per call", async () => {
50+
// The hint spells out that leaving it empty defers the host (and its
51+
// variables) to each tool call: the heart of per-call selection.
52+
await page.getByText(/leave empty to choose the server.*per tool call/i).waitFor();
53+
});
54+
55+
await step("The field is a picker over the spec's two servers", async () => {
56+
// Opening the combobox reveals both declared servers as choices.
57+
await page.getByPlaceholder("https://api.example.com", { exact: true }).click();
58+
const options = page.getByRole("option");
59+
await options.filter({ hasText: "staging.example.com" }).waitFor({ timeout: 10_000 });
60+
const labels = await options.allInnerTexts();
61+
expect(
62+
labels.join(" | "),
63+
"both declared servers are offered as base-URL choices",
64+
).toEqual(expect.stringContaining("https://staging.example.com"));
65+
expect(labels.join(" | "), "production is offered too").toEqual(
66+
expect.stringContaining("https://api.example.com"),
67+
);
68+
});
69+
});
70+
}),
71+
),
72+
);

0 commit comments

Comments
 (0)