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();