mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
e69e67ea12
Two root causes:
1. Tests used messages ("Hello", "Hi", "hello", "Say something short")
that don't match any aimock fixture. With --proxy-only mode, unmatched
requests fall through to real OpenAI which rejects the mock API key
(sk-mock-local-dev) with 502/401. Replaced all test messages with
exact d5-all.json fixture entries: "Say hello in one short sentence",
"Tell me a one-line joke", "Give me a fun fact".
2. The "second assistant turn" test in chat-slots sent its second message
immediately after the first assistant bubble appeared. The assistant
message becomes visible on the first streaming chunk, but the chat
input stays disabled until the full stream ends (aimock streams at
60ms/8-char-chunk). Added a text-stabilization poll between turns to
wait for streaming to finish before sending the next message.
All tests copied identically to both LGP and LGT. Verified 16/16 pass
on both ports (3100 and 3101) across multiple runs.
109 lines
4.3 KiB
TypeScript
109 lines
4.3 KiB
TypeScript
import { test, expect } from "@playwright/test";
|
|
|
|
test.describe("Chat Customization (CSS)", () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto("/demos/chat-customization-css");
|
|
});
|
|
|
|
test("scope wrapper and themed chat input render on load", async ({
|
|
page,
|
|
}) => {
|
|
// The `.chat-css-demo-scope` wrapper is where all `--copilot-kit-*` CSS
|
|
// variable overrides are applied. Its presence is the defining signal
|
|
// that theme.css is loaded and scoped correctly.
|
|
const scope = page.locator(".chat-css-demo-scope");
|
|
await expect(scope).toBeVisible();
|
|
|
|
// v2 CopilotChat exposes its input via data-testid regardless of theme
|
|
// overrides. Use the testid plus the default placeholder to assert the
|
|
// themed input mounted.
|
|
await expect(
|
|
scope.locator('[data-testid="copilot-chat-input"]'),
|
|
).toBeVisible();
|
|
await expect(page.getByPlaceholder("Type a message")).toBeVisible();
|
|
});
|
|
|
|
test("CSS variables from theme.css resolve on the scope wrapper", async ({
|
|
page,
|
|
}) => {
|
|
const scope = page.locator(".chat-css-demo-scope");
|
|
await expect(scope).toBeVisible();
|
|
|
|
// The Halcyon theme sets --halcyon-* custom properties on the scope
|
|
// wrapper. If theme.css didn't load (or its `.chat-css-demo-scope`
|
|
// selector didn't match) these would resolve to empty strings.
|
|
const vars = await scope.evaluate((el) => {
|
|
const cs = getComputedStyle(el);
|
|
return {
|
|
ember: cs.getPropertyValue("--halcyon-ember").trim(),
|
|
paper: cs.getPropertyValue("--halcyon-paper").trim(),
|
|
ink: cs.getPropertyValue("--halcyon-ink").trim(),
|
|
};
|
|
});
|
|
|
|
expect(vars.ember.toLowerCase()).toBe("#c44a1f");
|
|
expect(vars.paper.toLowerCase()).toBe("#f4efe6");
|
|
expect(vars.ink.toLowerCase()).toBe("#1a1714");
|
|
});
|
|
|
|
test("input textarea inherits Inter Tight sans font from theme.css", async ({
|
|
page,
|
|
}) => {
|
|
// theme.css sets `.copilotKitInput textarea { font-family: var(--halcyon-sans) }`
|
|
// which resolves to "Inter Tight", .... The default CopilotKit textarea
|
|
// does not set Inter Tight — asserting on this computed property is a
|
|
// reliable theme-applied signal.
|
|
const textarea = page
|
|
.locator(".chat-css-demo-scope .copilotKitInput textarea")
|
|
.first();
|
|
await expect(textarea).toBeVisible();
|
|
const fontFamily = await textarea.evaluate(
|
|
(el) => getComputedStyle(el).fontFamily,
|
|
);
|
|
expect(fontFamily).toMatch(/Inter Tight/);
|
|
});
|
|
|
|
test("user bubble uses transparent background with ember left-border after sending a message", async ({
|
|
page,
|
|
}) => {
|
|
// Use a message that matches an aimock fixture to get a deterministic
|
|
// response. Lowercase "hello" doesn't reliably match — "Say hello in
|
|
// one short sentence" is an exact d5-all.json fixture entry.
|
|
await page
|
|
.getByPlaceholder("Type a message")
|
|
.fill("Say hello in one short sentence");
|
|
await page.locator('[data-testid="copilot-send-button"]').first().click();
|
|
|
|
const userMsg = page
|
|
.locator('.chat-css-demo-scope [data-testid="copilot-user-message"]')
|
|
.first();
|
|
await expect(userMsg).toBeVisible({ timeout: 30000 });
|
|
|
|
// The Halcyon theme sets the user message outer wrapper to
|
|
// `background: transparent` and styles the inner bg-muted child with
|
|
// `var(--halcyon-paper-elevated)` (#fbf8f2) plus a 2px ember left border.
|
|
// Assert the outer wrapper is transparent.
|
|
await expect(userMsg).toHaveCSS("background-color", "rgba(0, 0, 0, 0)");
|
|
});
|
|
|
|
test("assistant bubble uses transparent background after round-trip", async ({
|
|
page,
|
|
}) => {
|
|
await page
|
|
.getByPlaceholder("Type a message")
|
|
.fill("Tell me a one-line joke");
|
|
await page.locator('[data-testid="copilot-send-button"]').first().click();
|
|
|
|
const assistant = page
|
|
.locator('.chat-css-demo-scope [data-testid="copilot-assistant-message"]')
|
|
.first();
|
|
await expect(assistant).toBeVisible({ timeout: 45000 });
|
|
|
|
// The Halcyon theme sets the assistant message to
|
|
// `background: transparent` — editorial serif text with no bubble, just
|
|
// an ember left-rule via ::before. The default CopilotKit assistant has
|
|
// a visible background, so transparent proves the theme won the cascade.
|
|
await expect(assistant).toHaveCSS("background-color", "rgba(0, 0, 0, 0)");
|
|
});
|
|
});
|