import test from 'node:test'; import assert from 'node:assert/strict'; import { normalizeBubbleRef, assertSessionFresh, mergeCapturedRecord, selectTargetArticles, rankSpaceLinks, pendingCaptureReferences, ingestCapturedBody, boundedCaptureBody } from '../bubble-corpus-utils.mjs'; test('typed lookup references normalize to the same space identifier', () => { const id = '1700000000000x1234567890'; assert.equal(normalizeBubbleRef(`LOOKUP__custom.space__${id}`), id); assert.equal(normalizeBubbleRef(`LOOKUP__${id}`), id); assert.equal(normalizeBubbleRef(`1234567890__LOOKUP__${id}`), id); assert.equal(normalizeBubbleRef(id), id); }); test('expired signature blocks capture; an expired analytics cookie does not', () => { assert.throws(() => assertSessionFresh({cookies:[{name:'app.sig',expires:9}]},10), /bubble_session_expired/); assert.doesNotThrow(() => assertSessionFresh({cookies:[ {name:'analytics',expires:9},{name:'app.sig',expires:11}]},10)); }); test('partial network responses retain full notes captured in this run', () => { const first = mergeCapturedRecord(null,{content_text:'synthetic full notes'},'root'); assert.equal(mergeCapturedRecord(first,{nomer_text:'Synthetic call'},'root').content_text, 'synthetic full notes'); }); test('explicit target selection never substitutes the largest space', () => { const records = {root:{space_custom_space:'target',content_text:'synthetic index'}, call:{space_custom_space:'target',content_text:'synthetic protocol'}, a:{space_custom_space:'other'},b:{space_custom_space:'other'},c:{space_custom_space:'other'}}; const [id, selected] = selectTargetArticles(records,'root'); assert.equal(id,'target'); assert.equal(selected.length,2); delete records.call.content_text; assert.throws(() => selectTargetArticles(records,'root'), /target_protocol_bodies_incomplete/); records.call.content_text = 'synthetic protocol'; delete records.call; assert.throws(() => selectTargetArticles(records,'root'), /target_protocols_not_captured/); }); test('all-space capture ranks by space creation, keeps unknowns and deduplicates roots', () => { const links = ['old', 'new', 'unknown', 'new'].map(id => ({ href: `/pg_chunk/${id}`, label: id })); const spaces = {a:{'Created Date':1,'Modified Date':99},b:{'Created Date':2}}; const articles = {old:{space_custom_space:'a','Created Date':100}, new:{space_custom_space:'b','Created Date':0,nomer_text:'New space title'}}; const ranked = rankSpaceLinks(links, spaces, articles); assert.deepEqual(ranked.map(r => r.rootId), ['new', 'old', 'unknown']); assert.equal(ranked[2].createdMs, null); assert.equal(ranked[0].label, 'New space title'); assert.deepEqual(ranked, rankSpaceLinks([...links].reverse(), spaces, articles)); }); test('reference continuation follows missing chunks, parents, bodies and unrefreshed space roots', () => { const root='1700000000000x1', child='1700000000000x2', parent='1700000000000x3'; const inventory={space:{_chunk_custom_article:root}}; const articles={[root]:{content_text:'Synthetic', 'Created Date':1, chunks_list_custom_article:[`12__LOOKUP__${child}`], context_custom_article:parent}}; assert.deepEqual(pendingCaptureReferences({},articles,inventory),[root,child,parent]); articles[child]={content_text:'Child','Created Date':2}; articles[parent]={content_text:'Parent','Created Date':3}; assert.deepEqual(pendingCaptureReferences({space:{'Created Date':1}},articles,inventory),[]); delete articles[child].content_text; assert.deepEqual(pendingCaptureReferences({space:{'Created Date':1}},articles,inventory),[child]); }); test('shared response ingestion normalizes prefixed references and preserves already captured body', () => { const spaces={},articles={}; const id='1700000000000x1', space='1700000000000x2'; ingestCapturedBody(JSON.stringify({_type:'custom.article',_id:id, _source:{content_text:'Synthetic only',space_custom_space:`12__LOOKUP__${space}`}}),spaces,articles); ingestCapturedBody(JSON.stringify({_type:'custom.article',_id:id, _source:{nomer_text:'Synthetic title'}}),spaces,articles); assert.equal(articles[id].space_custom_space,space); assert.equal(articles[id].content_text,'Synthetic only'); }); test('reference continuation also retains uncaptured contents relations', () => { const id='1700000000000x1', related='1700000000000x2'; const articles={[id]:{content_text:'Synthetic', 'Created Date':1, contents_list_custom_article:[`12__LOOKUP__${related}`]}}; assert.deepEqual(pendingCaptureReferences({},articles),[related]); articles[related]={content_text:'Related', 'Created Date':2}; assert.deepEqual(pendingCaptureReferences({},articles),[]); }); test('unfinished source responses cannot stall the capture drain or leak diagnostics', async () => { assert.deepEqual(await boundedCaptureBody({text:()=>Promise.resolve('synthetic')}), {status:'read',text:'synthetic'}); assert.deepEqual(await boundedCaptureBody({text:()=>new Promise(()=>{})},1),{status:'timeout'}); assert.deepEqual(await boundedCaptureBody({text:()=>Promise.reject(new Error('synthetic detail'))}), {status:'failed'}); });