import { expect, it } from 'vitest'; import { render } from 'svelte/server'; import { provisioningContext } from '../../src/lib/ui/provisioning-presentation.js'; import { provisioningStatus, provisioningWarnings } from '../../src/lib/ui/provisioning-queue.js'; import ProvisioningStatusBadge from '../../src/lib/ui/components/ProvisioningStatusBadge.svelte'; it.each([ ['queued', 'Queued', 'neutral'], ['waiting', 'Waiting', 'neutral'], ['running', 'Running', 'info'], ['awaiting-health', 'Validating', 'info'], ['done', 'Completed', 'online'], ['warning', 'Completed with warnings', 'warning'], ['failed', 'Failed', 'danger'], ['interrupted', 'Interrupted', 'danger'], ['cancelled', 'Cancelled', 'neutral'] ])('renders the recorded %s lifecycle state consistently', (state, label, tone) => { expect(provisioningStatus(state)).toMatchObject({ label, tone }); const body = render(ProvisioningStatusBadge, { props: { state } }).body; expect(body).toContain(label); expect(body).toContain(`v-${tone}`); expect(body).toContain('aria-hidden="true"'); }); it('keeps waiting reasons and preparation separate from the recorded state', () => { const row = { state: 'running', action: 'restart' as const, phase: 'container-action', stage: 'Waiting for host acknowledgment', waitMessage: 'Waiting for another operation to finish' }; expect(provisioningContext(row)).toEqual({ step: 'Restart container', detail: 'Waiting for another operation to finish' }); expect(provisioningStatus(row.state).label).toBe('Running'); const preparing = { ...row, state: 'queued', phase: 'prepare', waitMessage: null }; expect(provisioningContext(preparing)?.step).toBe('Prepare server files'); expect(provisioningStatus(preparing.state).label).toBe('Queued'); }); it('preserves legacy stage text without parsing it into a lifecycle label', () => { const row = { state: 'waiting', action: 'rebuild' as const, stage: 'Waiting for 3 player(s) to leave.' }; expect(provisioningContext(row)).toEqual({ step: row.stage, detail: null }); expect(provisioningContext({ ...row, phase: 'future-phase' })).toEqual({ step: row.stage, detail: null }); expect(provisioningStatus(row.state).label).toBe('Waiting'); }); it.each(['done', 'warning', 'failed', 'interrupted', 'cancelled'])( 'does not describe leftover progress as current for %s jobs', (state) => { expect( provisioningContext({ state, action: 'restart', stage: 'Waiting for startup capacity', waitMessage: 'Waiting for recovery', phase: 'cleanup' }) ).toBeNull(); } ); it('only displays strings from recorded warning arrays', () => { expect(provisioningWarnings('["Warning",null,3]')).toEqual(['Warning']); expect(provisioningWarnings('null')).toEqual([]); expect(provisioningWarnings('invalid')).toEqual([]); });