Add Prettier and ESLint tooling (Refs #77)

This commit is contained in:
2026-10-09 15:56:13 -04:00
parent 8ed059b8d3
commit 16469e2d43
711 changed files with 99737 additions and 28286 deletions
+115 -47
View File
@@ -5,34 +5,87 @@ import type { ProvisioningDetail, RecoveryObservation } from '../../src/lib/prov
import { provisioningNeedsRefresh } from '../../src/lib/ui/provisioning-presentation.js';
import ProvisioningPage from '../../src/routes/provisioning/[id]/+page.svelte';
vi.mock('$app/stores', () => ({ page: writable({
url: new URL('http://localhost/provisioning/operation-a'), data: { user: null }
}) }));
vi.mock('$app/stores', () => ({
page: writable({
url: new URL('http://localhost/provisioning/operation-a'),
data: { user: null }
})
}));
vi.mock('$app/navigation', () => ({ goto: vi.fn() }));
const start = '2026-10-09T12:00:00Z';
const finish = '2026-10-09T12:01:00Z';
function fixture(state = 'done', recovery: RecoveryObservation | null = null): ProvisioningDetail {
return {
deployment: { id: 'operation-a', server: 't5_zombie_theater_1', action: 'restart', state,
stage: 'Completed', server_deleted_at: null, server_exists: 1, started_at: start, finished_at: finish,
triggered_by: 'watchdog:incident-a', requested_by: 'Maxis', error: null, warnings: '[]' },
generatedAt: finish, events: [], activity: { total: 0, latestId: null, failureExcerpt: null },
sources: [{ kind: 'watchdog', source_id: 'incident-a', label: 'Deleted watchdog incident', href: null }],
recipe: null, blueprintName: null, canResumeCleanup: false, canResumeRebuild: false,
canResumeVerification: false, canCancelRemoval: false,
deployment: {
id: 'operation-a',
server: 't5_zombie_theater_1',
action: 'restart',
state,
stage: 'Completed',
server_deleted_at: null,
server_exists: 1,
started_at: start,
finished_at: finish,
triggered_by: 'watchdog:incident-a',
requested_by: 'Maxis',
error: null,
warnings: '[]'
},
generatedAt: finish,
events: [],
activity: { total: 0, latestId: null, failureExcerpt: null },
sources: [
{
kind: 'watchdog',
source_id: 'incident-a',
label: 'Deleted watchdog incident',
href: null
}
],
recipe: null,
blueprintName: null,
canResumeCleanup: false,
canResumeRebuild: false,
canResumeVerification: false,
canCancelRemoval: false,
collection: { id: 'collection-a', name: 'Evening lobbies' },
progress: { version: 1, phase: 'verify-game', phaseStartedAt: '2026-10-09T12:00:50Z', observedAt: finish,
blocker: null, checks: [], checkpoints: [], command: null, recovery, recipeStatus: null },
agentOperation: { id: 'command-a', hostId: 'host-a', state: 'completed', createdAt: start, updatedAt: finish, error: null },
capacity: { evaluatedAt: finish, pools: [] }, warningMessages: []
progress: {
version: 1,
phase: 'verify-game',
phaseStartedAt: '2026-10-09T12:00:50Z',
observedAt: finish,
blocker: null,
checks: [],
checkpoints: [],
command: null,
recovery,
recipeStatus: null
},
agentOperation: {
id: 'command-a',
hostId: 'host-a',
state: 'completed',
createdAt: start,
updatedAt: finish,
error: null
},
capacity: { evaluatedAt: finish, pools: [] },
warningMessages: []
};
}
function pageBody(detail: ProvisioningDetail) {
return render(ProvisioningPage, { props: { data: { detail, user: null, setupRequired: false } } }).body;
return render(ProvisioningPage, {
props: { data: { detail, user: null, setupRequired: false } }
}).body;
}
function recovery(state: RecoveryObservation['state']): RecoveryObservation {
return { state, at: finish, message: 'Recovery status updated', ...(state === 'transferred' ? { operationId: 'rebuild-a' } : {}) };
return {
state,
at: finish,
message: 'Recovery status updated',
...(state === 'transferred' ? { operationId: 'rebuild-a' } : {})
};
}
describe('provisioning detail summary and technical details', () => {
@@ -53,14 +106,18 @@ describe('provisioning detail summary and technical details', () => {
it('keeps operation, command and source IDs and copy controls in closed Technical details', () => {
const body = pageBody(fixture());
const technical = body.match(/<details\b[^>]*class="technical-details[^>]*>[\s\S]*?<\/details>/)?.[0];
const technical = body.match(
/<details\b[^>]*class="technical-details[^>]*>[\s\S]*?<\/details>/
)?.[0];
expect(technical).toBeDefined();
expect(technical).toContain('Technical details</summary>');
expect(technical!.split('>')[0]).not.toMatch(/\bopen\b/);
const outside = body.replace(technical!, '');
for (const [value, label] of [
['operation-a', 'operation ID'], ['command-a', 'agent command ID'],
['collection-a', 'collection launch ID'], ['incident-a', 'Deleted watchdog incident source ID']
['operation-a', 'operation ID'],
['command-a', 'agent command ID'],
['collection-a', 'collection launch ID'],
['incident-a', 'Deleted watchdog incident source ID']
]) {
const code = new RegExp(`<code\\b[^>]*>${value}</code>`);
expect(technical).toMatch(code);
@@ -100,38 +157,49 @@ describe('provisioning detail summary and technical details', () => {
});
describe('provisioning refresh policy', () => {
it.each(['queued', 'waiting', 'running', 'awaiting-health'])('refreshes %s operations', state => {
expect(provisioningNeedsRefresh(fixture(state))).toBe(true);
});
it.each(['queued', 'waiting', 'running', 'awaiting-health'])(
'refreshes %s operations',
(state) => {
expect(provisioningNeedsRefresh(fixture(state))).toBe(true);
}
);
it.each(['done', 'failed', 'interrupted', 'warning', 'cancelled'])('stops refreshing %s operations without held recovery', state => {
const detail = fixture(state);
expect(provisioningNeedsRefresh(detail)).toBe(false);
for (const value of ['released', 'transferred', 'unknown'] as const) {
detail.progress!.recovery = recovery(value);
it.each(['done', 'failed', 'interrupted', 'warning', 'cancelled'])(
'stops refreshing %s operations without held recovery',
(state) => {
const detail = fixture(state);
expect(provisioningNeedsRefresh(detail)).toBe(false);
for (const value of ['released', 'transferred', 'unknown'] as const) {
detail.progress!.recovery = recovery(value);
expect(provisioningNeedsRefresh(detail)).toBe(false);
}
detail.progress = null;
expect(provisioningNeedsRefresh(detail)).toBe(false);
}
detail.progress = null;
expect(provisioningNeedsRefresh(detail)).toBe(false);
});
);
it.each(['released', 'transferred'] as const)('keeps failed restart recovery refreshing until %s without marking it live', state => {
const detail = fixture('failed', recovery('held'));
expect(provisioningNeedsRefresh(detail)).toBe(true);
const held = pageBody(detail);
expect(held).toContain('Recovery capacity held');
expect(held).not.toContain('Updates every 5 seconds');
expect(held).not.toContain('View recovery operation');
it.each(['released', 'transferred'] as const)(
'keeps failed restart recovery refreshing until %s without marking it live',
(state) => {
const detail = fixture('failed', recovery('held'));
expect(provisioningNeedsRefresh(detail)).toBe(true);
const held = pageBody(detail);
expect(held).toContain('Recovery capacity held');
expect(held).not.toContain('Updates every 5 seconds');
expect(held).not.toContain('View recovery operation');
detail.progress!.recovery = recovery(state);
expect(provisioningNeedsRefresh(detail)).toBe(false);
const settled = pageBody(detail);
expect(settled).not.toContain('Recovery capacity held');
expect(settled).not.toContain('Updates every 5 seconds');
expect(settled).toContain(state === 'released' ? 'Recovery capacity released' : 'Recovery transferred');
if (state === 'transferred') {
expect(settled).toContain('href="/provisioning/rebuild-a"');
expect(settled).toContain('View recovery operation');
detail.progress!.recovery = recovery(state);
expect(provisioningNeedsRefresh(detail)).toBe(false);
const settled = pageBody(detail);
expect(settled).not.toContain('Recovery capacity held');
expect(settled).not.toContain('Updates every 5 seconds');
expect(settled).toContain(
state === 'released' ? 'Recovery capacity released' : 'Recovery transferred'
);
if (state === 'transferred') {
expect(settled).toContain('href="/provisioning/rebuild-a"');
expect(settled).toContain('View recovery operation');
}
}
});
);
});