Files

43 lines
2.7 KiB
JavaScript

import {build} from 'esbuild';
import {mkdtemp,rm} from 'node:fs/promises';
import {tmpdir} from 'node:os';
import {join} from 'node:path';
import {pathToFileURL} from 'node:url';
import assert from 'node:assert/strict';
const dir=await mkdtemp(join(process.env.TMPDIR??tmpdir(),'framely-visibility-'));
try {
const file=join(dir,'visibility.mjs');
await build({entryPoints:['sdk/src/visibility.ts'],bundle:true,platform:'node',format:'esm',outfile:file});
const {createVisibilityApi,registerVisibility}=await import(pathToFileURL(file));
let deliver,resolve,unsubscribed=false;
const bridge={request:()=>new Promise(r=>resolve=r),subscribe:f=>{deliver=f;return()=>{unsubscribed=true;}}};
const states=[],api=createVisibilityApi(()=>bridge);
const off=api.onVisibilityChanged(s=>states.push(s));
const newer={known:true,captureObscured:true,pageVisible:true,sequence:2};
deliver({type:'ui.visibility.changed',data:newer});
resolve({known:true,captureObscured:false,pageVisible:false,sequence:1});
await new Promise(r=>setImmediate(r));
assert.deepEqual(states,[newer],'stale initial query must not overwrite a newer event');
off();deliver({type:'ui.visibility.changed',data:{...newer,sequence:3}});
assert(unsubscribed);assert.equal(states.length,1,'unsubscribe suppresses later callbacks');
let lateResolve;
const lateStates=[];
const late=createVisibilityApi(()=>({request:()=>new Promise(r=>lateResolve=r),subscribe:()=>()=>{}}));
late.onVisibilityChanged(s=>lateStates.push(s))();lateResolve(newer);
await new Promise(r=>setImmediate(r));assert.deepEqual(lateStates,[],'unmount suppresses pending initial query');
const restarted=[],epochApi=createVisibilityApi(()=>bridge);
const epochOff=epochApi.onVisibilityChanged(s=>restarted.push(s));
deliver({type:'ui.visibility.changed',data:{...newer,sequence:100,sessionId:'old'}});
deliver({type:'ui.visibility.changed',data:{...newer,sequence:1,sessionId:'new'}});
deliver({type:'ui.visibility.changed',data:{...newer,sequence:101,sessionId:'old'}});
assert.equal(restarted.length,2,'new host session resets ordering; retired sessions cannot overwrite it');epochOff();
let error;
const failed=createVisibilityApi(()=>({request:()=>Promise.reject(Error('disconnected')),subscribe:()=>()=>{}}));
failed.onVisibilityChanged(()=>{},e=>error=e);
await new Promise(r=>setImmediate(r));assert.equal(error.message,'disconnected');
const dispatch=registerVisibility(state=>state.captureObscured);
assert.equal(await dispatch('framely.ui.visibility',newer),true);
await assert.rejects(dispatch('fake',newer));
console.log('PASS SDK visibility initial query, event ordering, unsubscribe, disconnect and backend dispatcher');
} finally {await rm(dir,{recursive:true,force:true});}