import {test} from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import {spawnSync} from 'node:child_process'; import {fileURLToPath} from 'node:url'; import {patchWordClassroomRead} from '../prepare-word-classroom-performance.mjs'; const original=fs.readFileSync(new URL('./fixtures/word-classroom-before.js',import.meta.url),'utf8').trimEnd(); test('词库发布只替换经过审查的读取函数,保留其他线上修复且支持重复准备',()=>{ const prefix='const onlineOnly = "keep";\n',suffix='\nasync function unrelatedFix(){return "preserve newer work";}'; const patched=patchWordClassroomRead(prefix+original+suffix); assert.ok(patched.startsWith(prefix));assert.ok(patched.endsWith(suffix)); assert.notEqual(patched,prefix+original+suffix);assert.equal(patchWordClassroomRead(patched),patched); new Function(patched); }); test('同一读取函数被其他任务改动时拒绝覆盖',()=>{ assert.throws(()=>patchWordClassroomRead(original.replace('const paging = pageInput(input);','const paging = pageInput(input); const newerFix = true;')),/differs from the reviewed predecessor/); }); test('缺少发布凭据时明确停止,不能宣称已上线',()=>{ const env={...process.env};delete env.XIAOSHU_MASTER_KEY; const run=spawnSync(process.execPath,[fileURLToPath(new URL('../prepare-word-classroom-performance.mjs',import.meta.url)),'--prepare'],{env,encoding:'utf8'}); assert.notEqual(run.status,0);assert.match(run.stderr,/Missing XIAOSHU_MASTER_KEY; no production changes made/); }); test('重复准备不能覆盖回滚原件,准备流程不向服务器写入',async t=>{ const {createServer}=await import('node:http'),{tmpdir}=await import('node:os'),{join}=await import('node:path'),{spawn}=await import('node:child_process'); const dir=fs.mkdtempSync(join(tmpdir(),'xiaoshu-word-release-'));t.after(()=>fs.rmSync(dir,{recursive:true,force:true})); const methods=[]; const server=createServer((req,res)=>{methods.push(req.method);res.setHeader('Content-Type','application/json');res.end(JSON.stringify({results:[{objectId:'fixture-gateway',code:original}]}));}); await new Promise(done=>server.listen(0,'127.0.0.1',done));t.after(()=>new Promise(done=>server.close(done))); const run=()=>new Promise(done=>{ const child=spawn(process.execPath,[fileURLToPath(new URL('../prepare-word-classroom-performance.mjs',import.meta.url)),'--prepare'],{env:{...process.env,XIAOSHU_MASTER_KEY:'fixture-only',XIAOSHU_PARSE_URL:'http://127.0.0.1:'+server.address().port,XIAOSHU_WORD_RELEASE_DIR:dir}}); let stderr='';child.stderr.on('data',chunk=>stderr+=chunk);child.on('close',status=>done({status,stderr})); }); assert.equal((await run()).status,0); const saved=fs.readFileSync(join(dir,'original.json'),'utf8'); const repeat=await run();assert.notEqual(repeat.status,0);assert.match(repeat.stderr,/already exist/); assert.equal(fs.readFileSync(join(dir,'original.json'),'utf8'),saved); assert.deepEqual(methods,['GET']); });