






















1+// Real-browser proof + regression for #93041: the desktop chat composer renders the provider
2+// usage pill from models.authStatus. Screenshots go to the ignored .artifacts/ tree.
3+import path from "node:path";
4+import { chromium, type Browser, type Page } from "playwright";
5+import { afterAll, beforeAll, describe, expect, it } from "vitest";
6+import {
7+canRunPlaywrightChromium,
8+installMockGateway,
9+resolvePlaywrightChromiumExecutablePath,
10+startControlUiE2eServer,
11+type ControlUiE2eServer,
12+} from "../../test-helpers/control-ui-e2e.ts";
13+14+const chromiumExecutablePath = resolvePlaywrightChromiumExecutablePath(chromium.executablePath());
15+const chromiumAvailable = canRunPlaywrightChromium(chromiumExecutablePath);
16+const describeE2e = chromiumAvailable ? describe : describe.skip;
17+18+const baseTime = 1_700_000_000_000;
19+const artifactDir = path.resolve(process.cwd(), ".artifacts/control-ui-e2e/chat-quota-pill-93041");
20+21+const authStatusWithUsage = {
22+ts: baseTime,
23+providers: [
24+{
25+provider: "openai",
26+displayName: "Codex",
27+status: "ok",
28+profiles: [{ profileId: "codex", type: "oauth", status: "ok" }],
29+usage: {
30+windows: [
31+{ label: "5h", usedPercent: 42, resetAt: baseTime + 3 * 3_600_000 },
32+{ label: "Week", usedPercent: 71, resetAt: baseTime + 4 * 86_400_000 },
33+],
34+},
35+},
36+],
37+};
38+39+let browser: Browser;
40+let server: ControlUiE2eServer;
41+42+async function openChat(authStatus: unknown): Promise<{ page: Page; close: () => Promise<void> }> {
43+const context = await browser.newContext({
44+locale: "en-US",
45+serviceWorkers: "block",
46+viewport: { height: 900, width: 1280 },
47+});
48+const page = await context.newPage();
49+page.setDefaultTimeout(15_000);
50+await installMockGateway(page, { methodResponses: { "models.authStatus": authStatus } });
51+await page.goto(`${server.baseUrl}chat`);
52+return { page, close: () => context.close() };
53+}
54+55+describeE2e("Control UI #93041 desktop chat quota pill (mocked Gateway E2E)", () => {
56+beforeAll(async () => {
57+server = await startControlUiE2eServer();
58+browser = await chromium.launch({ executablePath: chromiumExecutablePath });
59+});
60+61+afterAll(async () => {
62+await browser?.close();
63+await server?.close();
64+});
65+66+it("renders the provider usage pill in the desktop chat composer", async () => {
67+const { page, close } = await openChat(authStatusWithUsage);
68+try {
69+const pill = page.locator('[data-chat-provider-usage="true"]');
70+await pill.waitFor({ state: "visible" });
71+await page.screenshot({ path: path.join(artifactDir, "01-chat-with-pill.png") });
72+await page
73+.locator(".agent-chat__composer-controls")
74+.first()
75+.screenshot({ path: path.join(artifactDir, "02-composer-controls.png") });
76+77+const text = (await pill.textContent())?.replace(/\s+/g, " ").trim();
78+expect(text).toContain("Usage");
79+expect(await pill.getAttribute("href")).toBe("/usage");
80+expect(await pill.getAttribute("title")).toContain("Codex");
81+} finally {
82+await close();
83+}
84+});
85+86+it("shows no pill when no provider usage windows are present", async () => {
87+const { page, close } = await openChat({ ts: baseTime, providers: [] });
88+try {
89+await page.locator(".agent-chat__composer-controls").first().waitFor({ state: "visible" });
90+await page.waitForTimeout(500);
91+expect(await page.locator('[data-chat-provider-usage="true"]').count()).toBe(0);
92+} finally {
93+await close();
94+}
95+});
96+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。