Files
pbakaus_impeccable/ui/component-review/model.test.ts
T
Paul Bakaus 6a93a35293 Add human component review and prepare Impeccable 4.4.0
Carry native comp capture and completion integrity fixes into the reviewed component workflow. Bump the skill to 4.4.0 and engine/platform pins to 0.1.6; keep publication separate from this release candidate.

AI assistance: implemented and validated with OpenAI Codex.
2026-09-13 20:41:09 -07:00

48 lines
4.5 KiB
TypeScript

import { describe, expect, test } from 'bun:test';
import { approveRemaining, newDraft, submission, summarize, validBox, type ReviewPacket } from './model';
const packet: ReviewPacket = { id:'review-1', revision:'packet-1', title:'Test', round:1, comp:{url:'/comp.png',width:100,height:100}, components:[{id:'art',revision:'art-1',name:'Art',medium:'Raster',note:'',box:{x:0,y:0,w:1,h:1},preview:{kind:'image',url:'/art.png'}},{id:'control',revision:'control-1',name:'Button',medium:'HTML',note:'',box:{x:0,y:0,w:.1,h:.1},preview:{kind:'page',url:'/page.html'}}] };
describe('component review drafts',()=>{
test('bulk approval still requires explicit inventory confirmation',()=>{const draft=approveRemaining(packet,newDraft(packet));expect(summarize(packet,draft).canSubmit).toBe(false);draft.inventoryConfirmed=true;expect(submission(packet,draft).requestId).toBe(packet.id);});
test('approve remaining preserves requests for repair and their feedback',()=>{const draft=newDraft(packet);draft.decisions.art={revision:'art-1',action:'revise',feedback:'Keep the original motif',split:true};const bulk=approveRemaining(packet,draft);expect(bulk.decisions.art).toEqual(draft.decisions.art);expect(summarize(packet,bulk)).toMatchObject({approved:1,revisions:1,canSubmit:true});});
test('stale packet cannot submit',()=>{const draft=approveRemaining(packet,newDraft(packet));draft.inventoryConfirmed=true;expect(()=>submission({...packet,revision:'packet-2'},draft)).toThrow('stale');});
test('changed component version invalidates only that decision',()=>{const draft=approveRemaining(packet,newDraft(packet));draft.inventoryConfirmed=true;const changed={...packet,components:packet.components.map(c=>c.id==='art'?{...c,revision:'art-2'}:c)};expect(summarize(changed,draft)).toMatchObject({approved:1,pending:1,canSubmit:false});});
test('a missing item can be submitted without approving unrelated components',()=>{const draft=newDraft(packet);draft.missing.push({id:'missing-1',name:'Brushwork',box:{x:.2,y:.3,w:.2,h:.2},feedback:'Missing texture'});expect(summarize(packet,draft)).toMatchObject({pending:2,hasFeedback:true,canSubmit:true});draft.missing[0].name=' ';expect(summarize(packet,draft).canSubmit).toBe(false);});
test('rejects invalid regions and does not share mutable submission state',()=>{expect(validBox({x:0,y:0,w:0,h:1})).toBe(false);expect(validBox({x:.9,y:0,w:.5,h:1})).toBe(false);expect(validBox({x:NaN,y:0,w:1,h:1})).toBe(false);const draft=approveRemaining(packet,newDraft(packet));draft.inventoryConfirmed=true;const receipt=submission(packet,draft);draft.decisions.art.feedback='Changed';expect(receipt.decisions.art.feedback).toBe('');});
});
test('draft-only or changed prior decisions never count as carried approval', async () => {
const { repairStatus } = await import('./model');
const history: any = {
submitted: false, packet: { round: 1 },
draft: { decisions: { art: { action: 'approve' } } },
changes: { art: { kind: 'unchanged', files: [], reasons: [] } },
};
expect(repairStatus('art', history).carried).toBe(false);
history.submitted = true;
history.changes.art.carried = true;
expect(repairStatus('art', history).carried).toBe(true);
history.changes.art.kind = 'changed';
expect(repairStatus('art', history).carried).toBe(false);
expect(repairStatus('art', history).label).toBe('Review again');
});
test('attention states cannot hide a component behind a stale approval', async () => {
const { componentState } = await import('./model');
const draft=approveRemaining(packet,newDraft(packet));
expect(componentState(packet.components[0],draft).kind).toBe('approved');
expect(componentState({...packet.components[0],revision:'new'},draft).kind).toBe('pending');
draft.decisions.art.action='revise';
expect(componentState(packet.components[0],draft)).toMatchObject({kind:'feedback',label:'Feedback ready'});
});
test('captured code keeps its implementation identity without trusting medium as proof', async () => {
const { componentPresentation } = await import('./model');
const image = packet.components[0];
expect(componentPresentation({...image, medium:'SVG'}).code).toBe(false);
const captured = {...packet.components[1], preview:{kind:'image' as const, sourceKind:'page' as const, url:'/capture.png'}};
expect(componentPresentation(captured)).toMatchObject({code:true,captured:true,label:'HTML',caption:'Rendered component',fileLabel:'Open captured preview'});
expect(componentPresentation(packet.components[1]).caption).toBe('Live component');
});