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
+75 -23
View File
@@ -7,12 +7,32 @@ import FleetActionsDialog from '../../src/lib/ui/components/FleetActionsDialog.s
const now = Date.parse('2026-10-07T12:00:00Z');
const at = new Date(now - 1000).toISOString();
const server: FleetServer = {
name: 't5_zombie_theater_1', game: 't5', map: 'zombie_theater', last_map: 'zombie_theater',
last_gametype: 'zclassic', last_players: 4, last_seen_at: new Date(now - 10_000).toISOString(), last_error: null,
container_state: 'running', container_checked_at: at, last_checked_at: at,
roster: [], health: 'online', held: [], active_since: null, inactive_since: null,
game_started_at: null, game_ended_at: null, host_id: 'host-1',
host: { id: 'host-1', name: 'Dallas 1', connected: true, connectionState: 'online', lastHeartbeat: at }
name: 't5_zombie_theater_1',
game: 't5',
map: 'zombie_theater',
last_map: 'zombie_theater',
last_gametype: 'zclassic',
last_players: 4,
last_seen_at: new Date(now - 10_000).toISOString(),
last_error: null,
container_state: 'running',
container_checked_at: at,
last_checked_at: at,
roster: [],
health: 'online',
held: [],
active_since: null,
inactive_since: null,
game_started_at: null,
game_ended_at: null,
host_id: 'host-1',
host: {
id: 'host-1',
name: 'Dallas 1',
connected: true,
connectionState: 'online',
lastHeartbeat: at
}
};
describe('fleet actions', () => {
@@ -27,34 +47,63 @@ describe('fleet actions', () => {
expect(fleetActionAvailable({ ...server, host: null }, 'destroy', now)).toBe(true);
});
it.each(['restart', 'start', 'stop', 'rebuild'] as const)('queues %s only for selected servers and deduplicates selections', async action => {
const request = vi.fn().mockImplementation(async () => Response.json({ deploymentId: 'job-1' }, { status: 202 }));
const result = await queueFleetAction(action, [server.name, 'second', server.name], request);
expect(request.mock.calls.map(([url, options]) => [url, options.method, JSON.parse(options.body)])).toEqual([
['/api/provisioning', 'POST', { server: server.name, action }],
['/api/provisioning', 'POST', { server: 'second', action }]
]);
expect(result.queued.map(item => item.server)).toEqual([server.name, 'second']);
expect(result.failed).toEqual([]);
});
it.each(['restart', 'start', 'stop', 'rebuild'] as const)(
'queues %s only for selected servers and deduplicates selections',
async (action) => {
const request = vi
.fn()
.mockImplementation(async () =>
Response.json({ deploymentId: 'job-1' }, { status: 202 })
);
const result = await queueFleetAction(
action,
[server.name, 'second', server.name],
request
);
expect(
request.mock.calls.map(([url, options]) => [
url,
options.method,
JSON.parse(options.body)
])
).toEqual([
['/api/provisioning', 'POST', { server: server.name, action }],
['/api/provisioning', 'POST', { server: 'second', action }]
]);
expect(result.queued.map((item) => item.server)).toEqual([server.name, 'second']);
expect(result.failed).toEqual([]);
}
);
it('destroys only the chosen servers through the existing per-server endpoint', async () => {
const request = vi.fn().mockResolvedValue(Response.json({ deploymentId: 'destroy-1' }, { status: 202 }));
const request = vi
.fn()
.mockResolvedValue(Response.json({ deploymentId: 'destroy-1' }, { status: 202 }));
await queueFleetAction('destroy', ['server/a'], request);
expect(request).toHaveBeenCalledTimes(1);
expect(request).toHaveBeenCalledWith('/api/servers/server%2Fa', { method: 'DELETE' });
});
it('reports partial failures and continues without retrying successful requests', async () => {
const request = vi.fn()
.mockResolvedValueOnce(Response.json({ error: 'Another job is pending.' }, { status: 409 }))
const request = vi
.fn()
.mockResolvedValueOnce(
Response.json({ error: 'Another job is pending.' }, { status: 409 })
)
.mockResolvedValueOnce(Response.json({ deploymentId: 'job-2' }, { status: 202 }))
.mockRejectedValueOnce(new Error('offline'));
const result = await queueFleetAction('restart', ['blocked', 'ready', 'uncertain'], request);
const result = await queueFleetAction(
'restart',
['blocked', 'ready', 'uncertain'],
request
);
expect(result.queued).toEqual([{ server: 'ready', deploymentId: 'job-2' }]);
expect(result.failed).toEqual([
{ server: 'blocked', error: 'Another job is pending.' },
{ server: 'uncertain', error: expect.stringContaining('Check Provisioning before trying again') }
{
server: 'uncertain',
error: expect.stringContaining('Check Provisioning before trying again')
}
]);
expect(request).toHaveBeenCalledTimes(3);
});
@@ -69,11 +118,14 @@ describe('fleet actions', () => {
it('renders a named dialog with all five actions and a disabled empty selection', () => {
const body = render(FleetActionsDialog, { props: { open: true, onqueued: vi.fn() } }).body;
for (const action of ['Restart', 'Start', 'Stop', 'Rebuild', 'Destroy']) expect(body).toContain(`>${action}</option>`);
for (const action of ['Restart', 'Start', 'Stop', 'Rebuild', 'Destroy'])
expect(body).toContain(`>${action}</option>`);
expect(body).toContain('Fleet actions');
expect(body).toContain('Select all eligible');
expect(body).toContain('0 selected');
const submit = [...body.matchAll(/<button\b[^>]*>[\s\S]*?<\/button>/g)].find(match => match[0].includes('Restart 0 servers'))?.[0];
const submit = [...body.matchAll(/<button\b[^>]*>[\s\S]*?<\/button>/g)].find((match) =>
match[0].replace(/\s+/g, ' ').includes('Restart 0 servers')
)?.[0];
expect(submit).toContain('disabled');
});
});