vibe-proxy/frontend/tests/quotaTimelineRendering.test.ts
2026-08-24 00:10:41 +02:00

164 lines
4.6 KiB
TypeScript

import { describe, expect, test } from 'vitest';
import { createElement } from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import '../src/i18n/index';
import { QuotaTimeline } from '../src/features/quota/components/QuotaTimeline';
import type { QuotaFileEntry } from '../src/features/quota/logic';
import { buildKimiQuotaRows } from '../src/utils/quota';
const entries: QuotaFileEntry[] = [
{
file: { name: 'weekly-only.json', type: 'claude' },
type: 'claude',
},
];
const baseProps = {
entries,
displayNameFor: (name: string) => name,
resolvedTheme: 'light' as const,
now: new Date(2026, 6, 29, 12).getTime(),
};
describe('QuotaTimeline rendering', () => {
test('shows the selected period date instead of always labelling it Today', () => {
const markup = renderToStaticMarkup(
createElement(QuotaTimeline, {
...baseProps,
initialOffset: 1,
quotaFor: () => ({
status: 'success',
windows: [
{
label: '7-day',
usedPercent: 25,
resetAtMs: new Date(2026, 7, 1, 12).getTime(),
periodHours: 168,
},
],
}),
})
);
// The next weekly period starts on Sunday 08/02. The button remains the
// shortcut back to Today (aria-label/title), but its visible label now
// reflects the period selected with the previous/next arrows.
expect(markup).toMatch(
/<button type="button" aria-label="[^"]+" title="[^"]+">08\/02<\/button>/
);
});
test('keeps the panel and controls visible when 5-hour mode has no matching lanes', () => {
const weeklyOnlyQuota = {
status: 'success' as const,
windows: [
{
label: '7-day',
usedPercent: 25,
resetAtMs: new Date(2026, 7, 1, 12).getTime(),
periodHours: 168,
},
],
};
const markup = renderToStaticMarkup(
createElement(QuotaTimeline, {
...baseProps,
initialMode: 'session',
quotaFor: () => weeklyOnlyQuota,
})
);
expect(markup).toContain('<section');
expect(markup).toContain('aria-pressed="true"');
expect(markup).toContain('role="status"');
});
test('renders a Kimi 5-hour lane from the protobuf-style time unit', () => {
const rows = buildKimiQuotaRows({
usage: {
used: '1',
limit: '100',
resetTime: '2099-08-06T13:59:23.136523Z',
},
limits: [
{
window: { duration: 300, timeUnit: 'TIME_UNIT_MINUTE' },
detail: {
used: '2',
limit: '100',
resetTime: '2099-07-31T06:59:23.136523Z',
},
},
],
});
const markup = renderToStaticMarkup(
createElement(QuotaTimeline, {
entries: [
{
file: { name: 'kimi-real-response.json', type: 'kimi' },
type: 'kimi',
},
],
displayNameFor: (name: string) => name,
resolvedTheme: 'light',
now: new Date('2099-07-31T04:40:00Z').getTime(),
initialMode: 'session',
quotaFor: () => ({ status: 'success', rows }),
})
);
expect(markup).toContain('kimi-real-response.json');
expect(markup).not.toContain('role="status"');
});
test('renders an unexpired Codex reset credit as an expiry tick', () => {
const markup = renderToStaticMarkup(
createElement(QuotaTimeline, {
entries: [
{
file: { name: 'codex-credit.json', type: 'codex' },
type: 'codex',
},
],
displayNameFor: (name: string) => name,
resolvedTheme: 'light',
now: new Date(2026, 6, 29, 12).getTime(),
quotaFor: () => ({
status: 'success',
windows: [
{
label: '7-day',
usedPercent: 90,
resetAtMs: new Date(2026, 7, 1, 12).getTime(),
periodHours: 168,
},
],
rateLimitResetCredits: [
{
id: 'credit-1',
status: 'available',
grantedAt: '2026-07-20T12:00:00Z',
expiresAt: '2026-08-03T12:00:00Z',
},
],
}),
})
);
expect(markup).toContain('role="img"');
expect(markup).toContain('08/03 12:00');
});
test('stays hidden before any credential exposes a usable quota window', () => {
const markup = renderToStaticMarkup(
createElement(QuotaTimeline, {
...baseProps,
quotaFor: () => undefined,
})
);
expect(markup).toBe('');
});
});