import { afterEach, describe, expect, it, vi } from 'vitest'; import { flushSync, mount, unmount, type ComponentProps } from 'svelte'; import { fromStore, writable } from 'svelte/store'; import ServerCard from '../../src/lib/ui/components/ServerCard.svelte'; import ServerIdentity from '../../src/lib/ui/components/ServerIdentity.svelte'; import PlayerScoreboard from '../../src/lib/ui/components/PlayerScoreboard.svelte'; import { fleetIdentity } from '../../src/lib/fleet-overview.js'; import { gameEvent } from '../helpers/telemetry.js'; afterEach(async () => { await Promise.all(components.splice(0).map((component) => unmount(component))); document.body.replaceChildren(); }); vi.mock('$app/stores', () => ({ page: writable({ url: new URL('http://localhost/') }) })); const components: ReturnType[] = []; type MapServer = Parameters[0]; const town: MapServer = { name: 't6_zombie_town_1', game: 't6', map: 'zm_transit', last_map: 'zm_transit' }; function show( initial: MapServer, options: Partial> = {}, fleetHeading = true ) { const store = writable(initial); const state = fromStore(store); const identity = () => fleetIdentity(state.current); components.push( mount(ServerCard, { target: document.body, props: { get name() { return state.current.name; }, get game() { return state.current.game; }, get map() { return state.current.last_map ?? state.current.map; }, get mapSlug() { return state.current.map_slug; }, get gameMode() { return state.current.game_mode; }, get mapLabelOverride() { return fleetHeading ? identity().map : undefined; }, health: 'online', players: 4, ...options } }), mount(ServerIdentity, { target: document.body, props: { get name() { return state.current.name; }, get mapLabel() { return identity().map; } } }), mount(PlayerScoreboard, { target: document.body, props: { get report() { return { ...gameEvent( 'heartbeat', 12, 4, state.current.name, state.current.last_map ?? state.current.map ?? '' ), receivedAt: new Date().toISOString() }; }, get mapLabel() { return identity().map; } } }) ); flushSync(); return (next: Partial) => { store.update((server) => ({ ...server, ...next })); flushSync(); }; } function expectLabels(label: string) { expect(document.querySelector('h3')?.textContent).toBe(label); expect(document.querySelector('.identity .map')?.textContent).toBe(label); expect(document.querySelector('.match-title h2')?.textContent).toBe(label); expect(document.querySelector('.map-note')).toBeNull(); } const variants = [ ['town', 'Town Survival'], ['farm', 'Farm Survival'], ['busdepot', 'Bus Depot Survival'], ['transit', 'TranZit'] ]; describe('variant-aware rendered map labels', () => { it.each(variants)('keeps %s consistent across card, list, and detail', (slug, label) => { const update = show({ ...town, name: `t6_zombie_${slug}_1` }); expectLabels(label); update({ name: 'Friday lobby', map_slug: slug, game_mode: 'zombie' }); expectLabels(label); }); it.each([undefined, null, 'unknown'])('does not infer TranZit from variant %s', (map_slug) => { const server = { ...town, name: 'Custom lobby', map_slug }; show(server); expectLabels('zm_transit (variant unknown)'); expect(fleetIdentity(server).launch).toBeNull(); }); it('lets unknown stored metadata override a recognized name', () => { show({ ...town, map_slug: 'unknown' }); expectLabels('zm_transit (variant unknown)'); }); it('updates map and variant metadata reactively without retaining an obsolete launch shortcut', () => { const update = show(town); expectLabels('Town Survival'); update({ last_map: 'zm_tomb' }); expectLabels('Origins'); expect(fleetIdentity({ ...town, last_map: 'zm_tomb' }).launch).toBeNull(); update({ last_map: 'zm_transit', map_slug: 'farm' }); expectLabels('Farm Survival'); expect(fleetIdentity({ ...town, map_slug: 'farm' }).launch).toEqual({ game: 't6', slug: 'farm' }); update({ map_slug: 'unknown' }); expectLabels('zm_transit (variant unknown)'); update({ last_map: 'zm_buried' }); expectLabels('Buried'); }); it.each(['stale', 'offline'] as const)( 'keeps the selected variant for %s observations', (health) => { show(town, { health, lastSeenAt: '2026-01-01T00:00:00Z' }); expectLabels('Town Survival'); } ); it.each([true, false])('preserves empty-card compact=%s behavior', (compactEmpty) => { show(town, { players: 0, compactEmpty }); expectLabels('Town Survival'); expect(document.querySelector('article')?.classList.contains('compact')).toBe(compactEmpty); expect(document.querySelector('article .metrics') === null).toBe(compactEmpty); }); it.each([ ['online', 'Current map'], ['stale', 'Last map'], ['offline', 'Last map'] ] as const)('retains useful %s map context with a name-based heading', (health, prefix) => { const update = show(town, { health }, false); expect(document.querySelector('.map-note')).toBeNull(); update({ last_map: 'zm_tomb' }); expect(document.querySelector('h3')?.textContent).toBe('Town Survival'); expect(document.querySelector('.map-note')?.textContent?.trim()).toBe(`${prefix}: Origins`); }); it('hides additional map context in compact cards', () => { show({ ...town, last_map: 'zm_tomb' }, { players: 0 }, false); expect(document.querySelector('.map-note')).toBeNull(); }); it('uses stored variant metadata for a custom heading and does not invent a missing observation', () => { const update = show({ ...town, name: 'Friday lobby', map_slug: 'town' }, {}, false); expect(document.querySelector('.map-note')?.textContent?.trim()).toBe( 'Current map: Town Survival' ); update({ map: null, last_map: null }); expect(document.querySelector('.map-note')).toBeNull(); }); });