mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
dd06dd89d1
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.
129 lines
4.9 KiB
TypeScript
129 lines
4.9 KiB
TypeScript
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);
|
||
});
|
||
});
|