51 lines
3.9 KiB
JavaScript
51 lines
3.9 KiB
JavaScript
'use strict';
|
|
|
|
const {assert,read,functionSource}=require('./helpers/app-source');
|
|
const {createHttpRouter}=require('../server/http-router');
|
|
const {createAuthenticator}=require('../server/auth');
|
|
const {createJsonRepository}=require('../server/json-repository');
|
|
const {createCursorModel}=require('../client/ui/cursor');
|
|
|
|
(async()=>{
|
|
const calls=[],router=createHttpRouter({notFound:()=>calls.push('missing')});
|
|
router.add('GET','/ok',(_req,_res,url)=>calls.push(url.pathname));
|
|
await router.dispatch({method:'GET'},null,{pathname:'/ok'});
|
|
await router.dispatch({method:'POST'},null,{pathname:'/ok'});
|
|
assert(calls.join(',')==='/ok,missing'&&router.routes().length===1,'HTTP route dispatch does not isolate method/path selection');
|
|
|
|
const auth=createAuthenticator({
|
|
playerPattern:/^[a-f0-9]{16,64}$/i,
|
|
tokenPattern:/^[a-f0-9]{32,128}$/i,
|
|
readPlayer:async()=>({tokenHash:'aa'}),
|
|
hashToken:()=> 'aa',
|
|
safeEqual:(a,b)=>a===b
|
|
});
|
|
const request={headers:{authorization:`Bearer ${'a'.repeat(16)}.${'b'.repeat(32)}`}};
|
|
assert((await auth.player(request)).playerId==='a'.repeat(16),'Authentication middleware rejected a valid injected repository result');
|
|
let unauthorized=false;try{auth.parse({headers:{}})}catch(error){unauthorized=error.status===401}
|
|
assert(unauthorized,'Authentication middleware did not reject a missing bearer token');
|
|
|
|
const files=new Map(),fsp={
|
|
async readFile(file){const value=files.get(file);if(value==null)throw Object.assign(new Error('missing'),{code:'ENOENT'});return value},
|
|
async writeFile(file,value){files.set(file,value)},
|
|
async rename(from,to){files.set(to,files.get(from));files.delete(from)},
|
|
async unlink(file){if(!files.delete(file))throw Object.assign(new Error('missing'),{code:'ENOENT'})}
|
|
};
|
|
const repository=createJsonRepository({fsp,crypto:{randomBytes:()=>Buffer.from('abcdef','hex')},processId:1});
|
|
await repository.write('world.json',{revision:3});
|
|
assert((await repository.read('world.json')).revision===3,'JSON repository did not publish an atomic record');
|
|
await repository.remove('world.json');assert(await repository.read('world.json',{missing:null})===null,'JSON repository missing-value behavior is incorrect');
|
|
|
|
const cursor=createCursorModel([{cursorStyle:'smile',cursorEmoji:'🙂'},{cursorStyle:'flag',flagAsset:'flag.svg'}]);
|
|
assert(cursor.presentation('smile').mode==='dom'&&cursor.presentation('smile').pickup.kind==='glyph','Cursor model did not map glyph presentation');
|
|
assert(cursor.presentation('flag').pickup.asset==='flag.svg'&&cursor.presentation('missing').mode==='default','Cursor model did not map flag or default presentation');
|
|
|
|
const server=read('server.js'),style=read('style.css'),html=read('index.html');
|
|
assert(functionSource('handleApi',server).includes('apiRouter.dispatch')&&functionSource('handleApi',server).length<120,'Server route selection is still coupled to domain behavior');
|
|
assert(server.includes("require('./server/player-service')")&&server.includes("require('./server/json-repository')"),'Server services or repositories are not wired through explicit boundaries');
|
|
assert(style.startsWith('@import url("client/styles/tokens.css") layer(tokens);')&&style.includes('@import url("client/styles/base.css") layer(base);')&&style.includes('@import url("client/ui/cursor.css") layer(cursor);')&&style.includes('@layer tokens,base,layout,board,interactions,hud,dialogs,cursor,responsive,accessibility,legacy;'),'CSS cascade ownership is not explicit');
|
|
assert(!style.includes('.board-card.claimed-other:not(.solved) .board-card.claimed-other'),'Unmatchable nested claimed-board selector remains');
|
|
assert(html.indexOf('client/ui/cursor.js')<html.indexOf('app.js'),'Cursor model is not loaded before the application');
|
|
|
|
console.log('HTTP, authentication, repository, cursor, and CSS ownership boundaries passed');
|
|
})().catch(error=>{console.error(error);process.exitCode=1});
|