171 lines
5.3 KiB
TypeScript
171 lines
5.3 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
import {
|
|
THREAD_WITH_ARTIFACTS,
|
|
THREAD_WITH_HISTORY,
|
|
openChat,
|
|
reuseThreadChatEntry,
|
|
setTheme,
|
|
skipIfMissingThread,
|
|
} from "./support/chat-helpers";
|
|
|
|
function isTransparent(color: string) {
|
|
const normalized = color.replace(/\s+/g, "").toLowerCase();
|
|
return normalized === "transparent" || normalized.endsWith(",0)");
|
|
}
|
|
|
|
test.describe("聊天工作台 / 主题颜色回归", () => {
|
|
test("DF-THEME-001 thread 页面在 light/dark 根容器颜色不同且非透明", async ({
|
|
page,
|
|
}, testInfo) => {
|
|
skipIfMissingThread(
|
|
testInfo,
|
|
THREAD_WITH_HISTORY,
|
|
"FRONTEND_E2E_THREAD_ID",
|
|
);
|
|
await openChat(page, reuseThreadChatEntry(THREAD_WITH_HISTORY!));
|
|
|
|
await setTheme(page, "light");
|
|
const lightState = await page.evaluate(() => {
|
|
const probe = document.createElement("div");
|
|
probe.className = "bg-background";
|
|
probe.style.position = "fixed";
|
|
probe.style.left = "-9999px";
|
|
probe.style.top = "-9999px";
|
|
document.body.appendChild(probe);
|
|
const bg = getComputedStyle(probe).backgroundColor;
|
|
probe.remove();
|
|
return {
|
|
bg,
|
|
rootBackground: getComputedStyle(document.documentElement)
|
|
.getPropertyValue("--background")
|
|
.trim(),
|
|
};
|
|
});
|
|
|
|
await setTheme(page, "dark");
|
|
const darkState = await page.evaluate(() => {
|
|
const probe = document.createElement("div");
|
|
probe.className = "bg-background";
|
|
probe.style.position = "fixed";
|
|
probe.style.left = "-9999px";
|
|
probe.style.top = "-9999px";
|
|
document.body.appendChild(probe);
|
|
const bg = getComputedStyle(probe).backgroundColor;
|
|
probe.remove();
|
|
return {
|
|
bg,
|
|
rootBackground: getComputedStyle(document.documentElement)
|
|
.getPropertyValue("--background")
|
|
.trim(),
|
|
};
|
|
});
|
|
|
|
expect(isTransparent(lightState.bg)).toBe(false);
|
|
expect(isTransparent(darkState.bg)).toBe(false);
|
|
expect(darkState.rootBackground).not.toBe(lightState.rootBackground);
|
|
});
|
|
|
|
test("DF-THEME-002 dark 模式下发送按钮 hover 前后颜色变化存在且可见", async ({
|
|
page,
|
|
}, testInfo) => {
|
|
skipIfMissingThread(
|
|
testInfo,
|
|
THREAD_WITH_HISTORY,
|
|
"FRONTEND_E2E_THREAD_ID",
|
|
);
|
|
await openChat(page, reuseThreadChatEntry(THREAD_WITH_HISTORY!));
|
|
await setTheme(page, "dark");
|
|
|
|
const textarea = page.locator("textarea[name='message']");
|
|
const submit = page.locator("button[aria-label='Submit']");
|
|
await textarea.fill("theme hover regression");
|
|
await expect(submit).toBeEnabled();
|
|
|
|
const before = await submit.evaluate((element) => {
|
|
const style = getComputedStyle(element);
|
|
return {
|
|
background: style.backgroundColor,
|
|
color: style.color,
|
|
border: style.borderTopColor,
|
|
};
|
|
});
|
|
|
|
await submit.hover();
|
|
|
|
const after = await submit.evaluate((element) => {
|
|
const style = getComputedStyle(element);
|
|
return {
|
|
background: style.backgroundColor,
|
|
color: style.color,
|
|
border: style.borderTopColor,
|
|
};
|
|
});
|
|
|
|
const changed =
|
|
before.background !== after.background ||
|
|
before.color !== after.color ||
|
|
before.border !== after.border;
|
|
|
|
expect(changed).toBe(true);
|
|
expect(isTransparent(after.background) && isTransparent(after.border)).toBe(
|
|
false,
|
|
);
|
|
expect(isTransparent(after.color)).toBe(false);
|
|
});
|
|
|
|
test("DF-THEME-003 artifact detail 面板在 light/dark 渲染 token 颜色", async ({
|
|
page,
|
|
}, testInfo) => {
|
|
skipIfMissingThread(
|
|
testInfo,
|
|
THREAD_WITH_ARTIFACTS,
|
|
"FRONTEND_E2E_ARTIFACTS_THREAD_ID",
|
|
);
|
|
await openChat(page, reuseThreadChatEntry(THREAD_WITH_ARTIFACTS!));
|
|
|
|
const openArtifacts = page.getByTestId("artifacts-open-button");
|
|
testInfo.skip(
|
|
(await openArtifacts.count()) === 0,
|
|
"当前线程未展示 artifacts 入口。",
|
|
);
|
|
await openArtifacts.click();
|
|
|
|
const firstCard = page.getByTestId("artifact-file-card").first();
|
|
testInfo.skip((await firstCard.count()) === 0, "当前线程没有 artifact 文件。");
|
|
await firstCard.click();
|
|
|
|
const detailRoot = page
|
|
.locator("div.bg-background.relative.h-full.overflow-hidden.rounded-2xl")
|
|
.first();
|
|
await expect(detailRoot).toBeVisible();
|
|
|
|
await setTheme(page, "light");
|
|
const light = await detailRoot.evaluate((element) => {
|
|
const style = getComputedStyle(element);
|
|
const header = element.querySelector("header");
|
|
const headerStyle = header ? getComputedStyle(header) : null;
|
|
return {
|
|
panelBg: style.backgroundColor,
|
|
headerBorder: headerStyle?.borderBottomColor ?? "",
|
|
};
|
|
});
|
|
|
|
await setTheme(page, "dark");
|
|
const dark = await detailRoot.evaluate((element) => {
|
|
const style = getComputedStyle(element);
|
|
const header = element.querySelector("header");
|
|
const headerStyle = header ? getComputedStyle(header) : null;
|
|
return {
|
|
panelBg: style.backgroundColor,
|
|
headerBorder: headerStyle?.borderBottomColor ?? "",
|
|
};
|
|
});
|
|
|
|
expect(isTransparent(light.panelBg)).toBe(false);
|
|
expect(isTransparent(dark.panelBg)).toBe(false);
|
|
expect(light.panelBg).not.toBe(dark.panelBg);
|
|
expect(light.headerBorder).not.toBe(dark.headerBorder);
|
|
});
|
|
});
|