Improve operational UX, recovery flows, and action safety
Implement the approved UX review across Fleet, Betas, Library, deployments, and Settings. Add reviewed promotion and reconciliation plans, atomic queued-removal cancellation, recoverable beta drafts and launch inputs, accessible controls, and mobile improvements. Validated with 473 tests, a clean typecheck, production build, and isolated desktop/mobile browser walkthroughs. Include the review and implementation coverage notes.
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
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', 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');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user