40 lines
3.1 KiB
JavaScript
40 lines
3.1 KiB
JavaScript
const test=require('node:test');const assert=require('node:assert/strict');const fs=require('node:fs');const vm=require('node:vm');
|
|
const source=fs.readFileSync('../browser_gateway/platform/notice_signal.py','utf8');
|
|
const install=source.match(/INSTALL = r"""([\s\S]*?)"""/)[1];const wait=source.match(/WAIT = r"""([\s\S]*?)"""/)[1];
|
|
function browser(){
|
|
const listeners=new Map(),timers=new Map();let counter=0;
|
|
const f={_options:{deviceID:'123'},OPEN:1,readyState:1,addEventListener(k,fn){if(!listeners.has(k))listeners.set(k,new Set());listeners.get(k).add(fn);},removeEventListener(k,fn){listeners.get(k)?.delete(fn);}};
|
|
const C={frontierInstance:f};const modules={sdk:{NoticeFrontier:C},codec:{decodedFrame:data=>({service:20313,payload:data})}};
|
|
const req=id=>modules[id];req.m={sdk:function(){/*NOTICE_PUSH_EVENT_NAMES:function*/},codec:function(){/* .decodedFrame= .encodeFrame= */}};
|
|
const chunks=[];chunks.push=function(v){v[2](req);return Array.prototype.push.call(this,v)};
|
|
const window={webpackChunkdouyin_web:chunks};
|
|
const context=vm.createContext({window,location:{origin:'https://www.douyin.com'},Uint8Array,TextDecoder,JSON,Date,Error,
|
|
setTimeout(fn){const id=++counter;timers.set(id,fn);return id;},clearTimeout(id){timers.delete(id);}});
|
|
const evaluate=s=>vm.runInContext(s.replaceAll('KEY','"bridge"').replaceAll('UID','"123"').replaceAll('ALIAS','"account"'),context);
|
|
return{window,f,C,timers,evaluate,emit(k,value){for(const fn of listeners.get(k)||[])fn(value)},listeners};
|
|
}
|
|
test('native notification wakes a pending receiver without waiting for heartbeat',async()=>{
|
|
const b=browser();assert.equal(JSON.parse(await b.evaluate(install)).connected,true);
|
|
const pending=b.evaluate(wait);assert.equal(b.timers.size,1);
|
|
const payload='{"notices":[{"notice_id_str":"9007199254740993123","effect_groups":[700]}]}';
|
|
b.emit('message',{data:Buffer.from(payload)});
|
|
const result=JSON.parse(await pending);assert.equal(result[0].payload,payload);assert.equal(b.timers.size,0);
|
|
});
|
|
test('connection replacement and identity change fail explicitly',async()=>{
|
|
const b=browser();await b.evaluate(install);b.C.frontierInstance={};await assert.rejects(b.evaluate(wait),/identity or page changed/);
|
|
const c=browser();await c.evaluate(install);c.f._options.deviceID='456';await assert.rejects(c.evaluate(wait),/identity or page changed/);
|
|
});
|
|
test('signal overload reports an error rather than silently dropping notifications',async()=>{
|
|
const b=browser();await b.evaluate(install);
|
|
for(let i=0;i<1001;i++)b.emit('message',{data:Buffer.from('{}')});
|
|
await assert.rejects(b.evaluate(wait),/queue full/);
|
|
});
|
|
test('reinstall removes stale callbacks instead of accumulating page listeners',async()=>{
|
|
const b=browser();await b.evaluate(install);await b.evaluate(install);
|
|
assert.equal(b.listeners.get('message').size,1);assert.equal(b.listeners.get('close').size,1);
|
|
});
|
|
test('disposal removes page listeners and wakes an idle receiver',async()=>{
|
|
const b=browser();await b.evaluate(install);const pending=b.evaluate(wait);b.window.bridge.dispose();await pending;
|
|
assert.equal(b.listeners.get('message').size,0);assert.equal(b.listeners.get('close').size,0);
|
|
});
|