import fs from 'node:fs';
import {deepEqual,equal,run,test} from './harness.js';
const root=new URL('../',import.meta.url);
const pageNames=[
'index.html',
'guide/index.html',
'api/index.html',
'patterns/index.html',
'browser/index.html',
'examples/index.html',
'playground/index.html',
'performance/index.html',
'stack/index.html',
'migration/index.html',
'testing/index.html',
'testing/unit/index.html',
'testing/functional/index.html',
'testing/behavioral/index.html',
'testing/integration/index.html',
'testing/regression/index.html'
];
function read(relativePath){
return fs.readFileSync(new URL(relativePath,root),'utf8');
}
function testCaseNames(relativePaths,layer){
const names=[];
const prefix=`${layer}: `;
for(const relativePath of relativePaths){
const source=read(relativePath);
const pattern=/test\('([^']+)'/g;
let match;
while((match=pattern.exec(source))){
if(match[1].startsWith(prefix)){
names.push(match[1].slice(prefix.length));
}
}
}
return names;
}
function localTargets(source){
const targets=[];
const pattern=/(?:href|src)="([^"]+)"/g;
let match;
while((match=pattern.exec(source))){
const target=match[1];
if(/^(?:https?:|mailto:|data:)/i.test(target)){
continue;
}
targets.push(target);
}
return targets;
}
function targetExists(pageName,target){
const base=new URL(pageName,root);
const [pathPart,fragment]=target.split('#');
let resolved=new URL(pathPart || base.href,base);
if(resolved.pathname.endsWith('/')){
resolved=new URL('index.html',resolved);
}
if(!fs.existsSync(resolved)){
return false;
}
if(!fragment){
return true;
}
return fs.readFileSync(resolved,'utf8').includes(`id="${decodeURIComponent(fragment)}"`);
}
test('regression: documentation remains split into sixteen focused pages',()=>{
const missing=pageNames.filter(name=>!fs.existsSync(new URL(name,root)));
deepEqual(missing,[]);
equal(pageNames.length,16);
equal(read('index.html').includes('16focused documentation pages'),true);
});
test('regression: documentation pages retain their required short contracts',()=>{
const required={
'index.html':['overview','guarantees','routes'],
'guide/index.html':['start','install','first-queue','model'],
'api/index.html':['api','methods','state'],
'patterns/index.html':['patterns','async','gates','errors'],
'browser/index.html':['browser','esm','classic','serve'],
'examples/index.html':['examples','live-demo','recipes'],
'playground/index.html':['playground','controls','pending','code','trace'],
'performance/index.html':['performance','benchmarks','method'],
'stack/index.html':['stack','entry','comparison'],
'migration/index.html':['migration','changes','checklist'],
'testing/index.html':['testing','suites','coverage','ci'],
'testing/unit/index.html':['unit','cases','run'],
'testing/functional/index.html':['functional','cases','run'],
'testing/behavioral/index.html':['behavioral','cases','run'],
'testing/integration/index.html':['integration','cases','run'],
'testing/regression/index.html':['regression','cases','run']
};
for(const [name,ids] of Object.entries(required)){
const source=read(name);
const missing=ids.filter(id=>!source.includes(`id="${id}"`));
deepEqual(missing,[],`${name} is missing required sections.`);
}
const browserClaim='works with bundlers and without a bundler.';
for(const pageName of pageNames){
equal(read(pageName).includes(browserClaim),true,`${pageName} omits the browser contract.`);
}
for(const documentName of ['README.md','MIGRATION.md','CHANGELOG.md']){
equal(read(documentName).includes(browserClaim),true,`${documentName} omits the browser contract.`);
}
const readme=read('README.md');
const browserGuide=read('browser/index.html');
for(const source of [readme,browserGuide]){
for(const mapping of [
'./node_modules/js-queue/queue.js',
'./node_modules/js-queue/',
'./node_modules/js-queue/stack.js',
'./node_modules/easy-stack/stack.js',
'./node_modules/js-queue/node_modules/easy-stack/stack.js'
]){
equal(source.includes(mapping),true,`Browser documentation omits ${mapping}.`);
}
equal(source.includes('"scopes"'),true,'Browser documentation omits the nested dependency scope.');
equal(source.includes('file://'),true,'Browser documentation omits the unsupported file URL boundary.');
equal(source.includes('HTTP(S)'),true,'Browser documentation omits the HTTP(S) requirement.');
}
equal((readme.match(/'),true);
equal(page.includes('data-playground-code'),true);
equal(source.startsWith("import Queue from 'js-queue';"),true);
equal(source.includes("\"import Queue from 'js-queue';\""),true);
equal(exampleSource.startsWith("import Queue from 'js-queue';"),true);
equal(/\beval\s*\(|new\s+Function\b|\.innerHTML\s*=|set(?:Timeout|Interval)\s*\(/.test(source),false);
});
test('regression: CI and Pages retain all delivery gates and curated assets',()=>{
const ci=read('.github/workflows/ci.yml');
const pages=read('.github/workflows/pages.yml');
const publisher=read('.github/workflows/npm-publish.yml');
equal(ci.includes('npm test'),true);
equal(ci.includes('npm audit --audit-level=high'),true);
equal(ci.includes('npm run test:consumer'),true);
equal(ci.includes('npm run coverage'),true);
equal(ci.includes('npm run benchmark --silent'),true);
equal(ci.includes("VANILLA_TEST_CHROME_NO_SANDBOX: '1'"),true);
equal(ci.includes("'22.13.0'"),true);
equal(ci.includes("'12.22.12'"),false);
equal(pages.includes('workflow_run:'),true);
equal(pages.includes("github.event.workflow_run.conclusion == 'success'"),true);
equal(pages.includes('actions/deploy-pages'),true);
equal(pages.includes('_site/assets/playground.js'),true);
equal(pages.includes('_site/assets/vanilla-test-header.png'),true);
equal(pages.includes('_site/assets/benchmark-construct.svg'),true);
equal(pages.includes('_site/assets/benchmark-tasks.svg'),true);
equal(pages.includes('_site/performance/index.html'),true);
equal(pages.includes('_site/benchmarks/results.json'),true);
equal(pages.includes('_site/stack.js'),true);
equal(pages.includes('_site/node_modules/easy-stack/stack.js'),true);
equal(pages.includes('IMPORT_MAP_PAGE'),true);
equal(pages.includes("import Queue from 'js-queue';"),true);
equal(pages.includes("import Stack from 'easy-stack';"),true);
equal(pages.includes('_site/reports/node/index.html'),true);
equal(pages.includes('_site/reports/chrome/index.html'),true);
for(const layer of ['unit','functional','behavioral','integration','regression']){
equal(pages.includes(`_site/testing/${layer}/index.html`),true,`Pages workflow omits testing/${layer}.`);
}
for(const pageName of pageNames){
equal(pages.includes(pageName.split('/')[0]),true,`Pages workflow omits ${pageName}.`);
}
equal(publisher.includes('workflow_dispatch:'),true);
equal(publisher.includes('EXPECTED_COMMIT'),true);
equal(publisher.includes('test "$ACTUAL_COMMIT" = "$EXPECTED_COMMIT"'),true);
equal(publisher.includes('npm audit --audit-level=high'),true);
equal(publisher.includes('npm publish --access public'),true);
equal(publisher.includes('REGISTRY_GIT_HEAD'),true);
});
test('regression: modern queue runtimes do not restore WeakMap state',()=>{
for(const file of ['queue.js','queue-vanilla.js']){
equal(read(file).includes('WeakMap'),false,`${file} restored WeakMap state.`);
}
});
test('regression: project remains JavaScript-only',()=>{
const forbidden=[];
function inspect(directory){
for(const entry of fs.readdirSync(directory,{withFileTypes:true})){
if(['.git','coverage','node_modules'].includes(entry.name)){
continue;
}
const target=new URL(`${entry.name}${entry.isDirectory() ? '/' : ''}`,directory);
if(entry.isDirectory()){
inspect(target);
}else if(/\.(?:ts|tsx)$/i.test(entry.name)){
forbidden.push(target.href);
}
}
}
inspect(root);
deepEqual(forbidden,[]);
});
await run();