Files
copilotkit__copilotkit/showcase/integrations/langgraph-python/tests/e2e/open-gen-ui-advanced.spec.ts
Jordan Ritter dd06dd89d1 refactor(showcase): rename packages/ to integrations/
The showcase framework directories better reflect their role as
integration examples rather than distributable packages.
Renames showcase/packages/ -> showcase/integrations/ and updates
the test docker-compose file reference accordingly.
2026-04-28 07:47:35 -07:00

129 lines
4.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test, expect } from "@playwright/test";
// QA reference: qa/open-gen-ui-advanced.md
// Demo source: src/app/demos/open-gen-ui-advanced/{page.tsx,
// sandbox-functions.ts, suggestions.ts}
//
// Advanced Open-Gen-UI: the sandboxed iframe can call two host-side
// sandbox functions via Websandbox.connection.remote.*:
// - evaluateExpression({ expression }) → console.log
// "[open-gen-ui/advanced] evaluateExpression <expr> = <value>"
// - notifyHost({ message }) → console.log
// "[open-gen-ui/advanced] notifyHost: <message>"
// Both handlers live in sandbox-functions.ts (host page).
//
// We assert on:
// 1) page load + 3 suggestion pills render
// 2) typed "hi" prompt mounts an iframe with sandbox="allow-scripts"
// (no allow-forms, no allow-same-origin)
// 3) clicking the Calculator / Ping suggestions eventually mounts an
// iframe (end-to-end round-trip is skipped — see W8 note).
//
// Driving buttons INSIDE the sandboxed iframe is not reliable: the
// iframe is srcdoc-loaded with sandbox="allow-scripts" only, which in
// Playwright often blocks same-origin frame access, and the generated
// HTML layout varies between LLM runs. We therefore skip the deep
// "click a digit and assert console.log" flow and keep a mount-level
// assertion that the advanced demo wires the sandbox attribute
// correctly. Un-skip when a stable post-mount testid is added.
test.describe("Open Generative UI (advanced)", () => {
test.setTimeout(120_000);
test.beforeEach(async ({ page }) => {
await page.goto("/demos/open-gen-ui-advanced");
});
test("page loads with chat composer and 3 suggestion pills", async ({
page,
}) => {
await expect(page.getByPlaceholder("Type a message")).toBeVisible({
timeout: 15_000,
});
// Suggestion titles are verbatim from openGenUiSuggestions.
const expected = [
"Calculator (calls evaluateExpression)",
"Ping the host (calls notifyHost)",
"Inline expression evaluator",
];
const suggestions = page.locator('[data-testid="copilot-suggestion"]');
for (const title of expected) {
await expect(suggestions.filter({ hasText: title }).first()).toBeVisible({
timeout: 15_000,
});
}
});
// SKIP: same Railway latency as the minimal open-gen-ui demo — the
// LLM authors full HTML/CSS/JS for an interactive sandboxed UI, which
// consistently exceeds a 120s timeout. The suggestion-pill render +
// sandbox-attribute intent are documented in the assertion body; the
// round-trip end-to-end cannot be asserted until a post-mount testid
// is added. See W8-OGUI-2.
test.skip('Ping suggestion mounts a sandbox="allow-scripts" iframe', async ({
page,
}) => {
const suggestion = page
.locator('[data-testid="copilot-suggestion"]', {
hasText: "Ping the host (calls notifyHost)",
})
.first();
await expect(suggestion).toBeVisible({ timeout: 15_000 });
await suggestion.click();
const iframe = page.locator('iframe[sandbox*="allow-scripts"]').first();
await expect(iframe).toBeVisible({ timeout: 120_000 });
const sandbox = await iframe.getAttribute("sandbox");
expect(sandbox).toContain("allow-scripts");
expect(sandbox).not.toContain("allow-forms");
expect(sandbox).not.toContain("allow-same-origin");
});
// SKIP: this test exercises the sandbox→host round-trip by clicking
// the "Ping the host (calls notifyHost)" suggestion, waiting for the
// iframe to mount, then looking for the distinctive host-side
// console.log ("[open-gen-ui/advanced] notifyHost: ..."). Two
// blockers on Railway: (a) LLM iframe authoring can take 60–120s and
// sometimes times out, (b) interacting with buttons inside the
// allow-scripts-only iframe is not reliable via Playwright's
// contentFrame. Un-skip once a post-mount testid or a console-log
// fixture is available. See W8-OGUI-2.
test.skip("notifyHost round-trip logs the expected console message", async ({
page,
}) => {
const logs: string[] = [];
page.on("console", (msg) => logs.push(msg.text()));
const suggestion = page
.locator('[data-testid="copilot-suggestion"]', {
hasText: "Ping the host (calls notifyHost)",
})
.first();
await expect(suggestion).toBeVisible({ timeout: 15_000 });
await suggestion.click();
await expect(
page.locator('iframe[sandbox*="allow-scripts"]').first(),
).toBeVisible({ timeout: 120_000 });
// Attempt to drive the "Say hi to the host" button inside the iframe.
const frame = await page
.locator('iframe[sandbox*="allow-scripts"]')
.first()
.contentFrame();
if (frame) {
await frame.getByRole("button").first().click({ timeout: 10_000 });
}
await expect
.poll(
() =>
logs.some((l) => l.includes("[open-gen-ui/advanced] notifyHost:")),
{ timeout: 30_000 },
)
.toBe(true);
});
});