Files
electric-cherry/tests/unit/beta-setup.test.ts
T
josh 981fb27c1c Preserve deleted server history
Retain historical server identities, results, and evidence after deletion. Mark archived entries as Deleted and prevent old work from targeting servers that reuse the same name.

Fixes #16.
2026-09-27 21:48:55 -04:00

41 lines
3.1 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { defaultPlan, betaPlanIssues, requirement } from '../../src/lib/beta-plan.js';
import { readBetaDraft, compatibleBetaServers } from '../../src/lib/beta-draft.js';
import { betaWaitingCondition, betaEvidenceSummary } from '../../src/lib/beta-evidence.js';
describe('beta draft and plan recovery', () => {
it('retains exact version IDs and incomplete plan fields in a recoverable draft', () => {
const plan = defaultPlan();
const raw = JSON.stringify({ version: 1, savedAt: new Date().toISOString(), step: 2, picks: [{ scriptId: 12, versionId: 45 }], servers: ['town'], testPlan: { ...plan, timeoutHours: null } });
const draft = readBetaDraft(raw)!;
expect(draft.picks).toEqual([{ scriptId: 12, versionId: 45 }]);
expect(betaPlanIssues(draft.testPlan, 1)).toContainEqual(expect.objectContaining({ field: 'timeoutHours' }));
expect(readBetaDraft('{bad')).toBeNull();
expect(readBetaDraft(JSON.stringify({ version: 1, picks: [{ scriptId: '12', versionId: 45 }] }))).toBeNull();
});
it('keeps compatible explicit selections without selecting newly eligible servers', () => {
const result = compatibleBetaServers(['town1', 'town2'], ['town2', 'town3']);
expect([...result.kept]).toEqual(['town2']);
expect(result.removed).toEqual(['town1']);
});
it('identifies the precise requirement and rejects an impossible quorum before review', () => {
const plan = { ...defaultPlan(), scope: 'quorum' as const, quorum: 3, requirements: [{ ...requirement('matches', 'matches'), target: 1.5, minPlayers: 0 }] };
expect(betaPlanIssues(plan, 2).map(issue => issue.field)).toEqual(['quorum', 'matches-target', 'matches-minPlayers']);
expect(betaPlanIssues(plan, 2).find(issue => issue.field === 'matches-target')?.requirementId).toBe('matches');
});
});
describe('beta evidence explanations', () => {
const observation = { lastGameplayAt: new Date().toISOString(), lastEvent: 'round_change', players: 2, round: 12, matchStarted: true, gameEnded: false, healthy: true, healthCheckedAt: new Date().toISOString() };
it('distinguishes missing reports, insufficient population, and report-driven time', () => {
const r = { ...requirement('populated-minutes', 'play'), minPlayers: 3 };
expect(betaWaitingCondition(r)).toContain('No gameplay report');
expect(betaWaitingCondition(r, observation)).toContain('latest report has 2 players');
expect(betaWaitingCondition(r, { ...observation, players: 3 })).toContain('next report arrives');
});
it('summarizes telemetry while keeping arbitrary or legacy payloads readable', () => {
const event = { id: 1, server: 'town', server_deleted_at: null, received_at: '', kind: 'game_end', payload: JSON.stringify({ round: 25, players: [{ name: 'A' }], map: 'zm_transit' }) };
expect(betaEvidenceSummary(event)).toBe('Game ended at round 25 with 1 players on zm_transit.');
expect(betaEvidenceSummary({ ...event, kind: 'old-event', payload: 'invalid' })).toBe('old event');
});
});