import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { newFixture, type Fixture } from '../helpers/fixture.js'; let fixture: Fixture; beforeEach(async () => { vi.resetModules(); fixture = await newFixture(); delete process.env.KOMODO_ADDRESS; delete process.env.RCON_PASSWORD; }); afterEach(async () => { await fixture.cleanup(); }); function request(content: string, reuse = false) { const form = new FormData(); form.append('content', new File([content], 'hud.gsc')); if (reuse) form.append('reuseExisting', 'true'); return new Request('http://localhost/api/scripts/inspect', { method: 'POST', body: form }); } async function seed() { const mod = await import('../../src/lib/server/fleet/scripts.js'); return { ...mod, ...mod.createScript({ name: 'HUD', targetRelPath: 'hud.gsc', scopeType: 'game', scopeValue: 't5', content: Buffer.from('main(){}') }) }; } describe('script upload review', () => { it('inspects content against all versions without creating records or including plugins', async () => { const { script, version, uploadNewVersion, createScript, listVersions } = await seed(); uploadNewVersion(script.id, Buffer.from('changed(){}')); createScript({ name: 'Plugin', targetRelPath: 'plugin.dll', kind: 'plugin', content: Buffer.from('main(){}') }); const { POST } = await import('../../src/routes/api/scripts/inspect/+server.js'); const res = await POST({ request: request('main(){}') }); expect(await res.json()).toEqual({ sha256: version.sha256, duplicates: [{ scriptId: script.id, versionId: version.id, version: 1 }] }); expect(listVersions(script.id)).toHaveLength(2); expect((await POST({ request: request('') })).status).toBe(400); }); it('reuses identical historical content and creates changed versions while preserving scope', async () => { const { script, version, uploadNewVersion, listVersions, getScript } = await seed(); uploadNewVersion(script.id, Buffer.from('changed(){}')); const { POST } = await import('../../src/routes/api/scripts/[id]/versions/+server.js'); const invoke = (content: string) => POST({ params: { id: String(script.id) }, request: request(content, true) }); const res = await invoke('main(){}'); expect(await res.json()).toMatchObject({ ok: true, reused: true, version: { id: version.id, version: 1 } }); expect(listVersions(script.id)).toHaveLength(2); const added = await invoke('third(){}'); expect(await added.json()).toMatchObject({ ok: true, version: { version: 3 } }); expect(listVersions(script.id)).toHaveLength(3); expect(getScript(script.id)).toMatchObject({ scope_type: 'game', scope_value: 't5' }); expect((await invoke('')).status).toBe(400); expect(listVersions(script.id)).toHaveLength(3); }); it('rejects new versions when a beta becomes active after the upload preview', async () => { const { script, version, listVersions } = await seed(); const { seedServerRegistry } = await import('../../src/lib/server/fleet/servers.js'); await seedServerRegistry(); const { openBeta } = await import('../../src/lib/server/fleet/beta.js'); await openBeta({ scripts: [{ scriptId: script.id, scriptVersionId: version.id }], servers: ['t5_zombie_theater_1'], waitForHealth: false, waitForMatch: false }); const { POST } = await import('../../src/routes/api/scripts/[id]/versions/+server.js'); const res = await POST({ params: { id: String(script.id) }, request: request('changed(){}', true) }); expect(res.status).toBe(409); expect(listVersions(script.id)).toHaveLength(1); }); it('lists promoted and latest version metadata separately without file contents', async () => { const { script, version, uploadNewVersion } = await seed(); const latest = uploadNewVersion(script.id, Buffer.from('changed(){}')); const { db } = await import('../../src/lib/server/db/index.js'); db().prepare('UPDATE scripts SET current_version_id = ? WHERE id = ?').run(version.id, script.id); const { GET } = await import('../../src/routes/api/scripts/+server.js'); const body = await (await GET({ url: new URL('http://localhost/api/scripts?kind=script') })).json(); expect(body.scripts[0]).toMatchObject({ currentVersion: { id: version.id, version: 1 }, latestVersion: { id: latest.id, version: 2 } }); expect(body.scripts[0].currentVersion).not.toHaveProperty('content'); }); });