test/dashboard-usage.test.js
Rama master · réplica de lectura del repositorio original.
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import {
clampPercent,
formatAcuLimit,
normalizeUsage,
resetCountdown,
} from '../src/dashboard/usage.js';
describe('dashboard usage normalizer', () => {
it('maps quota, plan, cycle and daily rows', () => {
const out = normalizeUsage({
quota: {
is_quota_plan: true,
has_quota_allocation: true,
daily_percentage: 3,
weekly_percentage: 1,
daily_reset_at: '2026-10-18T00:00:00-08:00',
weekly_reset_at: '2026-10-18T00:00:00-08:00',
overage_balance: 0,
hide_daily_quota: false,
},
status: {
plan_slug: 'pro',
is_subscription_valid: true,
billing_method: 'stripe',
available_credits: 0,
overage_credits: 0,
},
dailyUsage: {
cycle_start: '2026-10-16T20:11:50+00:00',
cycle_end: '2026-11-16T20:11:50+00:00',
previous_cycle_available: false,
total: 0,
days: [
{ date: '2026-10-16', amount: 0, cumulative: 0 },
{ date: '2026-10-17', amount: 1.5, cumulative: 1.5 },
],
},
});
assert.equal(out.plan, 'pro');
assert.equal(out.billingValid, true);
assert.equal(out.quota.dailyPercentage, 3);
assert.equal(out.quota.weeklyPercentage, 1);
assert.equal(out.cycle.total, 0);
assert.deepEqual(out.days, [
{ date: '2026-10-16', amount: 0, cumulative: 0 },
{ date: '2026-10-17', amount: 1.5, cumulative: 1.5 },
]);
});
it('degrades malformed/missing fields to null instead of NaN', () => {
const out = normalizeUsage({
quota: { daily_percentage: '3', overage_balance: NaN },
status: null,
dailyUsage: { days: [{ amount: 'x' }, null, { date: '2026-10-18', amount: 2 }] },
});
assert.equal(out.plan, null);
assert.equal(out.availableCredits, null);
assert.equal(out.cycle.total, null);
assert.equal(out.quota.dailyPercentage, null);
assert.equal(out.quota.overageBalance, null);
assert.deepEqual(out.days, [{ date: '2026-10-18', amount: 2, cumulative: null }]);
});
it('passes a signed overage balance through instead of clamping it', () => {
// `overage_credits` is a USD balance: negative means overdrawn. Clamping it
// to zero here would make the panel assert a zero balance the upstream
// never reported; the renderer owns the sign/overdrawn presentation.
assert.equal(normalizeUsage({ status: { overage_credits: -0.1 } }).overageCredits, -0.1);
assert.equal(normalizeUsage({ status: { overage_credits: 12.34 } }).overageCredits, 12.34);
assert.equal(normalizeUsage({ status: { overage_credits: 0 } }).overageCredits, 0);
assert.equal(normalizeUsage({ status: { overage_credits: '-0.1' } }).overageCredits, null);
});
it('caps daily rows at 366', () => {
const days = Array.from({ length: 400 }, (_, i) => ({ date: `d${i}`, amount: 1, cumulative: 1 }));
const out = normalizeUsage({ dailyUsage: { days } });
assert.equal(out.days.length, 366);
});
it('maps ACU limits and product burn-down rows', () => {
const products = Array.from({ length: 9 }, (_, i) => ({
view: `product-${i}`,
total: i,
days: [{ date: '2026-10-16', amount: i, cumulative: i }],
}));
const out = normalizeUsage({
quota: { daily_percentage: 150, weekly_percentage: -1 },
limits: { max_acu_limit: 20, max_total_session_acu_limit: null },
dailyUsage: { total: 36, products },
now: 1000,
});
assert.equal(out.limits.maxAcuLimit, 20);
assert.equal(out.limits.maxTotalSessionAcuLimit, null);
assert.equal(out.quota.dailyPercentage, 100, 'percentages clamp to 100');
assert.equal(out.quota.weeklyPercentage, 0, 'percentages clamp to 0');
assert.equal(out.products.length, 9);
assert.deepEqual(out.products[2], {
view: 'product-2',
total: 2,
days: [{ date: '2026-10-16', amount: 2, cumulative: 2 }],
});
assert.equal(out.serverNow, 1000);
});
it('caps products at 12 and each product day list at 366', () => {
const days = Array.from({ length: 400 }, (_, i) => ({ date: `d${i}`, amount: 1, cumulative: 1 }));
const products = Array.from({ length: 13 }, (_, i) => ({ view: `v${i}`, total: 1, days }));
const out = normalizeUsage({ dailyUsage: { products } });
assert.equal(out.products.length, 12);
assert.equal(out.products[0].days.length, 366);
});
it('derives reset countdowns from the server clock and preserves offsets', () => {
const now = Date.parse('2026-10-17T23:00:00-08:00');
assert.equal(resetCountdown('2026-10-18T00:00:00-08:00', now), 3_600_000);
assert.equal(resetCountdown('2026-10-17T22:00:00-08:00', now), 0, 'past resets clamp to zero');
assert.equal(resetCountdown('not-a-date', now), null);
assert.equal(resetCountdown(null, now), null);
const out = normalizeUsage({
quota: {
daily_reset_at: '2026-10-18T00:00:00-08:00',
weekly_reset_at: '2026-10-17T22:00:00-08:00',
},
now,
});
assert.deepEqual(out.reset, { dailyInMs: 3_600_000, weeklyInMs: 0 });
});
});
describe('quota burn-down helpers', () => {
it('clamps percentages without coercing strings', () => {
assert.equal(clampPercent(150), 100);
assert.equal(clampPercent(-1), 0);
assert.equal(clampPercent(0), 0);
assert.equal(clampPercent(3.5), 3.5);
assert.equal(clampPercent(null), null);
assert.equal(clampPercent('3'), null);
assert.equal(clampPercent(NaN), null);
});
it('renders ACU limits, keeping null as unlimited rather than zero', () => {
assert.equal(formatAcuLimit(null), '∞');
assert.equal(formatAcuLimit(20), '20');
assert.equal(formatAcuLimit(0), '0');
assert.equal(formatAcuLimit('20'), null);
});
});