word-classroom-release.test.mjs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839
  1. import {test} from 'node:test';
  2. import assert from 'node:assert/strict';
  3. import fs from 'node:fs';
  4. import {spawnSync} from 'node:child_process';
  5. import {fileURLToPath} from 'node:url';
  6. import {patchWordClassroomRead} from '../prepare-word-classroom-performance.mjs';
  7. const original=fs.readFileSync(new URL('./fixtures/word-classroom-before.js',import.meta.url),'utf8').trimEnd();
  8. test('词库发布只替换经过审查的读取函数,保留其他线上修复且支持重复准备',()=>{
  9. const prefix='const onlineOnly = "keep";\n',suffix='\nasync function unrelatedFix(){return "preserve newer work";}';
  10. const patched=patchWordClassroomRead(prefix+original+suffix);
  11. assert.ok(patched.startsWith(prefix));assert.ok(patched.endsWith(suffix));
  12. assert.notEqual(patched,prefix+original+suffix);assert.equal(patchWordClassroomRead(patched),patched);
  13. new Function(patched);
  14. });
  15. test('同一读取函数被其他任务改动时拒绝覆盖',()=>{
  16. assert.throws(()=>patchWordClassroomRead(original.replace('const paging = pageInput(input);','const paging = pageInput(input); const newerFix = true;')),/differs from the reviewed predecessor/);
  17. });
  18. test('缺少发布凭据时明确停止,不能宣称已上线',()=>{
  19. const env={...process.env};delete env.XIAOSHU_MASTER_KEY;
  20. const run=spawnSync(process.execPath,[fileURLToPath(new URL('../prepare-word-classroom-performance.mjs',import.meta.url)),'--prepare'],{env,encoding:'utf8'});
  21. assert.notEqual(run.status,0);assert.match(run.stderr,/Missing XIAOSHU_MASTER_KEY; no production changes made/);
  22. });
  23. test('重复准备不能覆盖回滚原件,准备流程不向服务器写入',async t=>{
  24. const {createServer}=await import('node:http'),{tmpdir}=await import('node:os'),{join}=await import('node:path'),{spawn}=await import('node:child_process');
  25. const dir=fs.mkdtempSync(join(tmpdir(),'xiaoshu-word-release-'));t.after(()=>fs.rmSync(dir,{recursive:true,force:true}));
  26. const methods=[];
  27. 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}]}));});
  28. await new Promise(done=>server.listen(0,'127.0.0.1',done));t.after(()=>new Promise(done=>server.close(done)));
  29. const run=()=>new Promise(done=>{
  30. 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}});
  31. let stderr='';child.stderr.on('data',chunk=>stderr+=chunk);child.on('close',status=>done({status,stderr}));
  32. });
  33. assert.equal((await run()).status,0);
  34. const saved=fs.readFileSync(join(dir,'original.json'),'utf8');
  35. const repeat=await run();assert.notEqual(repeat.status,0);assert.match(repeat.stderr,/already exist/);
  36. assert.equal(fs.readFileSync(join(dir,'original.json'),'utf8'),saved);
  37. assert.deepEqual(methods,['GET']);
  38. });