import {afterEach, expect, it} from 'vitest'; import {spawnSync} from 'node:child_process'; import {existsSync, mkdtempSync, mkdirSync, readFileSync, readlinkSync, rmSync, writeFileSync} from 'node:fs'; import {tmpdir} from 'node:os'; import {join, resolve} from 'node:path'; import {MOONLIGHT_STAY_PAYLOAD} from './fixtures/moonlight-stay'; const scratch: string[] = []; afterEach(() => scratch.splice(0).forEach((dir) => rmSync(dir, {recursive: true, force: true}))); it('검수 전 비공개·버전 전환·롤백·실패 격리·목업 보존', () => { const root = mkdtempSync(join(tmpdir(), 'web4ai-version-test-')); scratch.push(root); const out = join(root, 'out'); const payloadFile = join(root, 'test-pension.json'); const run = (...args: string[]) => spawnSync(process.execPath, [ resolve('dist/prerender/prerender.js'), `--out=${out}`, ...args, ], {encoding: 'utf8', timeout: 20000}); const payload = structuredClone(MOONLIGHT_STAY_PAYLOAD); payload.site.slug = 'test-pension'; payload.site.basePath = '/s/test-pension'; payload.site.publish = true; payload.site.version = 1; payload.media.forEach((media) => {media.url = `/test/${media.mediaId}.jpg`;}); const save = () => writeFileSync(payloadFile, JSON.stringify(payload)); const stage = () => run(`--payload=${payloadFile}`, '--stage-only'); mkdirSync(join(out, 's/stay'), {recursive: true}); mkdirSync(join(out, 'assets'), {recursive: true}); writeFileSync(join(out, 's/stay/index.html'), 'protected'); writeFileSync(join(out, 'assets/mock.css'), 'mock css'); save(); let result = stage(); expect(result.status, result.stderr).toBe(0); expect(existsSync(join(out, 's/test-pension'))).toBe(false); result = run('--activate=test-pension:1'); expect(result.status, result.stderr).toBe(0); const v1 = readFileSync(join(out, 's/test-pension/index.html'), 'utf8'); expect(readlinkSync(join(out, 's/test-pension'))).toBe('../versions/test-pension/1'); expect(readFileSync(join(out, 'sitemap.xml'), 'utf8')).toContain('/s/test-pension'); payload.site.version = 2; payload.place.name = '새 이름 테스트 펜션'; save(); result = stage(); expect(result.status, result.stderr).toBe(0); expect(readFileSync(join(out, 's/test-pension/index.html'), 'utf8')).toBe(v1); expect(run('--activate=test-pension:2').status).toBe(0); expect(readFileSync(join(out, 's/test-pension/index.html'), 'utf8')).toContain('새 이름 테스트 펜션'); payload.site.version = 1; save(); expect(stage().status).toBe(0); expect(run('--activate=test-pension:1').status).toBe(0); expect(readFileSync(join(out, 's/test-pension/index.html'), 'utf8')).toBe(v1); payload.site.version = 3; payload.schemaVersion = 99 as 1; save(); expect(stage().status).not.toBe(0); expect(run('--activate=test-pension:3').status).not.toBe(0); expect(readFileSync(join(out, 's/test-pension/index.html'), 'utf8')).toBe(v1); expect(run('--activate=stay:1').status).not.toBe(0); expect(run('--seed-assets').status).toBe(0); expect(readFileSync(join(out, 's/stay/index.html'), 'utf8')).toBe('protected'); expect(readFileSync(join(out, 'assets/mock.css'), 'utf8')).toBe('mock css'); }, 60000);