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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ local/
test_output.txt
scripts/verify-counts.ts
marketing/

# Playwright test results
test-results/
4 changes: 4 additions & 0 deletions src/core/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,8 @@ export const CONTEXT_GROWING_SESSION_GROWTH_RATE = 0.8; // 80%+ sequential inc
export const TOKEN_DATA_AVAILABLE_FROM = '2026-04-01';

/* ---- Feature flags ---- */
// When flipping this back to `true`, also update the burndown e2e tests, which
// are skipped while it is off and contain stale assertions + an incomplete mock:
// tests/e2e/burndown.spec.ts and the getAiCreditBurndown mock in
// tests/e2e/harness.html (see the TODO(FF_TOKEN_REPORTING_ENABLED) notes there).
export const FF_TOKEN_REPORTING_ENABLED = false;
26 changes: 25 additions & 1 deletion tests/e2e/burndown.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,45 @@ import { test, expect, Page } from '@playwright/test';

const HARNESS_URL = 'http://localhost:3999/tests/e2e/harness.html';

async function navigateToBurndown(page: Page) {
async function bootHarness(page: Page) {
await page.goto(HARNESS_URL);
await page.waitForFunction(() => {
const content = document.getElementById('content');
return content && content.innerHTML.length > 200 && !content.querySelector('.loading-spinner') && !content.querySelector('.error-boundary');
}, { timeout: 10000 });
}

async function navigateToBurndown(page: Page) {
await page.locator('[data-page="burndown"]').first().click();
await page.waitForFunction(() => {
const content = document.getElementById('content');
return content && !content.querySelector('.loading-spinner') && content.innerHTML.length > 200;
}, { timeout: 10000 });
}

// TODO(FF_TOKEN_REPORTING_ENABLED): These tests are SKIPPED while the burndown
// feature flag is off (see beforeEach). When the flag is switched back on, two
// things below are known to be stale and MUST be fixed before they will pass:
// 1. The value assertions in this file still expect the OLD getBurndown mock
// (budget 1500 / consumed 248 / projected 2480). The page now reads
// getAiCreditBurndown (budget 300 / consumed 42.5 / projected 425). Either
// update these to the new numbers, or switch to structural checks
// (presence of "Budget" / "Consumed:" / "Projected:" / "All Models").
// 2. The getAiCreditBurndown mock in tests/e2e/harness.html is incomplete
// (missing byModel/missingPct/countedRequests/partialRequests/
// pendingRequests/noDataRequests/finalizableRequests/coverageByDay, etc.),
// so the status section never renders. Fill it out to match the real
// AiCreditBurndownData shape in src/core/analyzer-consumption.ts.
test.describe('Burndown', () => {
test.beforeEach(async ({ page }) => {
await bootHarness(page);
// When FF_TOKEN_REPORTING_ENABLED is off, app.ts removes the Burndown nav
// link at runtime (and the page renders only a "disabled" notice). The link
// removal runs synchronously on app.js load, so by the time the harness has
// booted it is already gone. Skip gracefully instead of timing out on a
// click target that no longer exists.
const hasBurndown = (await page.locator('[data-page="burndown"]').count()) > 0;
test.skip(!hasBurndown, 'Burndown is gated by FF_TOKEN_REPORTING_ENABLED');
await navigateToBurndown(page);
});

Expand Down
8 changes: 8 additions & 0 deletions tests/e2e/harness.html
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,14 @@
budgetLine: Array.from({ length: 31 }, () => 300),
status: 'warning',
recommendation: 'At current pace you will exceed your credit budget.'
// TODO(FF_TOKEN_REPORTING_ENABLED): This mock is INCOMPLETE. The real
// getAiCreditBurndown (src/core/analyzer-consumption.ts) also returns
// byModel, missingPct, countedRequests, partialRequests, pendingRequests,
// noDataRequests, finalizableRequests, delegatedRequests, coverageByDay,
// daysUntilExhaustion, safeDailyBudget, projectedOverage and totalRequests.
// Without them page-burndown.ts cannot render the status section. When the
// burndown feature flag is re-enabled, fill these in so tests/e2e/
// burndown.spec.ts can exercise the page (those tests are skipped today).
}),

getWorkflowOptimization: () => ({
Expand Down
Loading