// Cloud-specific (browser): the onboarding MCP-setup step gives the user an// org-scoped MCP server URL and a matching install command. Driven through the// real web UI as a fresh user who has no organization yet.import { expect } from "@effect/vitest";import { Effect } from "effect";import { scenario } from "../src/scenario";import { Browser, Target } from "../src/services";scenario( "Onboarding · the MCP setup step hands the user their org-scoped MCP server URL", {}, Effect.gen(function* () { const target = yield* Target; const browser = yield* Browser; const identity = yield* target.newIdentity({ org: false }); yield* browser.session(identity, async ({ page, step }) => { await step( "A fresh user without an org lands on the create-org onboarding page", async () => { await page.goto("/", { waitUntil: "networkidle" }); // Step 1 of 2 — the org-name input is the landmark that proves we're on onboarding. await page.getByPlaceholder("Northwind Labs").waitFor(); }, ); await step("Create an organization to advance to the MCP setup step", async () => { await page.getByPlaceholder("Northwind Labs").fill("Test Org"); await page.getByRole("button", { name: "Create organization" }).click(); // Successful creation navigates to the 'Connect your MCP client' step. await page.getByText("Connect your MCP client").waitFor(); }); await step("Read the MCP server URL displayed on the setup page", async () => { const urlSection = page.getByRole("region", { name: "MCP server URL" }); await urlSection.waitFor(); // Wait until the endpoint is populated (the component defers origin to useEffect). await page.waitForFunction(() => { const section = document.querySelector('[aria-label="MCP server URL"]'); const span = section?.querySelector("span.font-mono"); return span && span.textContent !== "…" && span.textContent !== ""; }); }); const mcpUrlSection = page.getByRole("region", { name: "MCP server URL" }); const mcpUrl = await mcpUrlSection.locator("span.font-mono").innerText(); // Org-scoped via the org's URL slug (the readable form), not the raw // WorkOS org_… id — and not the bare /mcp path. expect(mcpUrl, "MCP URL is slug-scoped").toMatch(/\/[a-z0-9-]+\/mcp/); expect(mcpUrl, "the slug form, not the org_ id").not.toMatch(/\/org_[^/]+\/mcp/); const installSection = page.getByRole("region", { name: "Install command" }); await installSection.waitFor(); const installCommand = await installSection.locator("code").innerText(); // The install command must reference the SAME org as the displayed URL // — not a different one or a bare /mcp path. const orgSlug = /\/([a-z0-9-]+)\/mcp/.exec(mcpUrl)?.[1] ?? "(no org segment in MCP URL)"; expect(installCommand, "the install command references the same org").toContain( `/${orgSlug}/mcp`, ); }); }),);
// Cloud-specific (browser): the onboarding MCP-setup step gives the user an
// org-scoped MCP server URL and a matching install command. Driven through the
// real web UI as a fresh user who has no organization yet.
import { expect } from "@effect/vitest";
import { Effect } from "effect";
import { scenario } from "../src/scenario";
import { Browser, Target } from "../src/services";
scenario(
"Onboarding · the MCP setup step hands the user their org-scoped MCP server URL",
{},
Effect.gen(function* () {
const target = yield* Target;
const browser = yield* Browser;
const identity = yield* target.newIdentity({ org: false });
yield* browser.session(identity, async ({ page, step }) => {
await step(
"A fresh user without an org lands on the create-org onboarding page",
async () => {
await page.goto("/", { waitUntil: "networkidle" });
// Step 1 of 2 — the org-name input is the landmark that proves we're on onboarding.
await page.getByPlaceholder("Northwind Labs").waitFor();
},
);
await step("Create an organization to advance to the MCP setup step", async () => {
await page.getByPlaceholder("Northwind Labs").fill("Test Org");
await page.getByRole("button", { name: "Create organization" }).click();
// Successful creation navigates to the 'Connect your MCP client' step.
await page.getByText("Connect your MCP client").waitFor();
});
await step("Read the MCP server URL displayed on the setup page", async () => {
const urlSection = page.getByRole("region", { name: "MCP server URL" });
await urlSection.waitFor();
// Wait until the endpoint is populated (the component defers origin to useEffect).
await page.waitForFunction(() => {
const section = document.querySelector('[aria-label="MCP server URL"]');
const span = section?.querySelector("span.font-mono");
return span && span.textContent !== "…" && span.textContent !== "";
});
});
const mcpUrlSection = page.getByRole("region", { name: "MCP server URL" });
const mcpUrl = await mcpUrlSection.locator("span.font-mono").innerText();
// Org-scoped via the org's URL slug (the readable form), not the raw
// WorkOS org_… id — and not the bare /mcp path.
expect(mcpUrl, "MCP URL is slug-scoped").toMatch(/\/[a-z0-9-]+\/mcp/);
expect(mcpUrl, "the slug form, not the org_ id").not.toMatch(/\/org_[^/]+\/mcp/);
const installSection = page.getByRole("region", { name: "Install command" });
await installSection.waitFor();
const installCommand = await installSection.locator("code").innerText();
// The install command must reference the SAME org as the displayed URL
// — not a different one or a bare /mcp path.
const orgSlug = /\/([a-z0-9-]+)\/mcp/.exec(mcpUrl)?.[1] ?? "(no org segment in MCP URL)";
expect(installCommand, "the install command references the same org").toContain(
`/${orgSlug}/mcp`,
);
});
}),
);