| 12345678910111213141516171819202122232425262728293031323334 |
- import fs from 'node:fs/promises';
- import path from 'node:path';
- import os from 'node:os';
- import test from 'node:test';
- import assert from 'node:assert/strict';
- import {spawnSync} from 'node:child_process';
- import {preflightMjsMime} from '../scripts/preflight-mime-mjs.mjs';
- async function fixture(t,{mapping='types { application/javascript js mjs; }',type='application/javascript; charset=utf-8',body='export const ready=true;'}={}){
- const root=await fs.mkdtemp(path.join(os.tmpdir(),'ksf-mjs-preflight-'));t.after(()=>fs.rm(root,{recursive:true,force:true}));
- const targetDir=await fs.realpath(root),mimeFile=path.join(root,'mime.types');await fs.writeFile(mimeFile,mapping);await fs.writeFile(path.join(root,'module.mjs'),'export const ready=true;');
- return{origin:'https://example.test',targetDir,mimeFile,files:[{path:'module.mjs'}],fetchImpl:async()=>new Response(body,{headers:{'content-type':type}})};
- }
- test('有效配置与真实模块响应均通过,预检保持只读',async t=>{
- const options=await fixture(t),before=await fs.readdir(options.targetDir),r=await preflightMjsMime(options);
- assert.equal(r.ok,true);assert.equal(r.readOnly,true);assert.equal(r.publicModulesChecked,1);assert.deepEqual(await fs.readdir(options.targetDir),before);
- });
- test('旧配置缺少mjs映射时,在请求前停止,注释不能冒充映射',async t=>{
- const options=await fixture(t,{mapping:'types { application/javascript js; }\n# application/javascript mjs;'});let requests=0;
- const r=await preflightMjsMime({...options,fetchImpl:async()=>{requests++;throw Error('should not fetch');}});
- assert.equal(r.ok,false);assert.equal(r.errorCode,'MJS_JAVASCRIPT_MAPPING_MISSING');assert.equal(requests,0);assert.ok(r.remedy.includes('nginx -t'));
- const cli=spawnSync(process.execPath,['scripts/preflight-mime-mjs.mjs','--target-dir',options.targetDir,'--mime-file',options.mimeFile],{encoding:'utf8'});
- assert.equal(cli.status,1);assert.equal(JSON.parse(cli.stdout).ok,false);
- });
- test('配置正确但响应为octet-stream时拒绝,复现白屏原因',async t=>{
- const r=await preflightMjsMime(await fixture(t,{type:'application/octet-stream'}));assert.equal(r.ok,false);assert.equal(r.errorCode,'PUBLIC_MJS_NOT_LOADABLE');
- });
- test('SPA返回HTML或内容不符不能因200和JavaScript响应头而通过',async t=>{
- const r=await preflightMjsMime(await fixture(t,{body:'<!doctype html><title>fallback</title>'}));assert.equal(r.ok,false);assert.equal(r.modules[0].bytesMatchTarget,false);
- });
- test('首次发布尚不存在的模块明确留待发布后验证',async t=>{
- const options=await fixture(t);await fs.unlink(path.join(options.targetDir,'module.mjs'));
- const r=await preflightMjsMime(options);assert.equal(r.ok,true);assert.equal(r.publicModulesChecked,0);assert.equal(r.publicVerificationDeferred,true);assert.equal(r.modules[0].reason,'not-yet-deployed');
- });
|