Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions apps/admin/e2e/mobile-workspace.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,20 @@ test("mobile dashboard uses the compact header, period picker, and KPI grid", as
await expect(page.getByRole("menuitem", { name: "Previous cycles" })).toBeVisible();
await page.keyboard.press("Escape");

const commitment = page.locator("p").filter({ hasText: /^Subscription commitment$/ }).first().locator("..");
const people = page.locator("p").filter({ hasText: /^People$/ }).first().locator("..");
const usage = page.locator("p").filter({ hasText: /^Estimated usage$/ }).first().locator("..");
const spendPerDay = page.locator("p").filter({ hasText: /^Est\. spend\/day$/ }).first().locator("..");
const [commitmentBox, usageBox, spendPerDayBox] = await Promise.all([
commitment.boundingBox(),
const [peopleBox, usageBox, spendPerDayBox] = await Promise.all([
people.boundingBox(),
usage.boundingBox(),
spendPerDay.boundingBox(),
]);
expect(commitmentBox).not.toBeNull();
expect(peopleBox).not.toBeNull();
expect(usageBox).not.toBeNull();
expect(spendPerDayBox).not.toBeNull();
expect(Math.abs(commitmentBox!.y - usageBox!.y)).toBeLessThan(4);
expect(usageBox!.x).toBeGreaterThan(commitmentBox!.x);
expect(spendPerDayBox!.y).toBeGreaterThan(commitmentBox!.y);
expect(Math.abs(peopleBox!.y - usageBox!.y)).toBeLessThan(4);
expect(usageBox!.x).toBeGreaterThan(peopleBox!.x);
expect(spendPerDayBox!.y).toBeGreaterThan(peopleBox!.y);

const syncStatus = page.getByText(/^Last synced/);
const syncButton = page.getByRole("button", { name: /Sync now|Syncing/ });
Expand Down
29 changes: 20 additions & 9 deletions apps/admin/e2e/workspace.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,18 @@ test("workspace startup has no bootstrap gate or duplicate page-data request", a
const appRequests: string[] = [];
const failedAppRequests: string[] = [];
page.on("request", (request) => {
const path = new URL(request.url()).pathname;
if (path.startsWith("/api/app/")) appRequests.push(path);
const url = new URL(request.url());
if (url.pathname.startsWith("/api/app/")) {
appRequests.push(`${url.pathname}${url.search}`);
}
});
page.on("requestfailed", (request) => {
const path = new URL(request.url()).pathname;
if (path.startsWith("/api/app/")) failedAppRequests.push(path);
const failure = request.failure()?.errorText ?? "";
if (failure.includes("ERR_ABORTED") || failure.includes("NS_BINDING_ABORTED")) return;
const url = new URL(request.url());
if (url.pathname.startsWith("/api/app/")) {
failedAppRequests.push(`${url.pathname}${url.search}`);
}
});

await page.goto("/dashboard");
Expand All @@ -45,7 +51,12 @@ test("workspace startup has no bootstrap gate or duplicate page-data request", a
expect(appRequests).not.toContain("/api/app/bootstrap");
// The client workspace context and destination page model each load at most once.
expect(appRequests.filter((path) => path === "/api/app/workspace-context").length).toBeLessThanOrEqual(1);
expect(appRequests.filter((path) => path === "/api/app/dashboard").length).toBeLessThanOrEqual(1);
const dashboardRequests = appRequests.filter((path) => path.startsWith("/api/app/dashboard"));
expect(dashboardRequests.filter((path) => path.includes("slice=shell")).length).toBeLessThanOrEqual(2);
expect(dashboardRequests.filter((path) => path.includes("slice=metrics")).length).toBeLessThanOrEqual(2);
expect(
dashboardRequests.filter((path) => !path.includes("slice=shell") && !path.includes("slice=metrics")).length,
).toBeLessThanOrEqual(1);
expect(failedAppRequests).toEqual([]);
});

Expand Down Expand Up @@ -169,7 +180,9 @@ test("dashboard exposes seeded calculation output and all period controls", asyn
await expect(page.getByRole("heading", { name: "Spend, traffic, coverage." })).toBeVisible();
await expect(page.getByRole("heading", { name: "Requests." })).toBeVisible();
await expect(page.getByText("Subscription commitment")).toBeVisible();
await expect(page.getByText("purchased seats · current cycle")).toBeVisible();
await expect(
page.getByText(/All tracked plans on track|Purchased seats · run-out from allowance pace|Earliest run-out/i),
).toBeVisible();
await expect(page.getByText("$40.00").first()).toBeVisible();
await expect(page.getByText("Estimated usage").first()).toBeVisible();
await expect(page.getByText("$27.00").first()).toBeVisible();
Expand All @@ -180,17 +193,15 @@ test("dashboard exposes seeded calculation output and all period controls", asyn
// Free/detected tools (OpenCode, ChatGPT Free) appear in Current cycles.
await expect(page.getByRole("link", { name: /OpenCode/i }).first()).toBeVisible();
await expect(page.getByRole("link", { name: /ChatGPT.*Free/i }).first()).toBeVisible();
await expect(page.getByText("1.5M")).toHaveCount(0);
await expect(page.getByRole("heading", { name: "Top models." })).toBeVisible();
await expect(page.getByRole("heading", { name: "Current cycles." })).toBeVisible();
await page.getByRole("link", { name: "Previous cycles" }).click();
await expect(page).toHaveURL(/view=previous_cycles/);
await expect(page.getByRole("heading", { name: "Previous cycles." })).toBeVisible();
await expect(page.getByText("purchased seats · previous cycle")).toBeVisible();
await expect(page.getByText("verified + estimated · previous cycles")).toBeVisible();
await page.getByRole("link", { name: "Current cycles" }).click();
await expect(page).toHaveURL(/view=current_cycles/);
await expect(page.getByRole("heading", { name: "Current cycles." })).toBeVisible();
await expect(page.getByText("purchased seats · current cycle")).toBeVisible();
await page.goto("/dashboard?view=last_30_days");
await page.getByRole("button", { name: "Adjust rolling period" }).click();
await page.getByText("Last 14 days").click();
Expand Down
Loading