<3/products/browser/Tests/

transport.test.cjs

const { test } = require('node:test');
const assert = require('node:assert/strict');
const vm = require('node:vm');
const fs = require('node:fs');
const path = require('node:path');
const resources = path.join(__dirname, '../Sources/GhostBrowser/Resources');

function environment() {
  const messages = [], listeners = {};
  class XHR {
    constructor() { this.listeners = {}; this.responseType = ''; }
    open(method, url) { this.url = url; }
    addEventListener(event, callback) { this.listeners[event] = callback; }
    send() { this.status = 200; this.responseText = JSON.stringify({data:{favorite_tweet:'Done'}}); this.listeners.load?.(); }
  }
  const sandbox = {
    URL, URLSearchParams, Request, Response, XMLHttpRequest: XHR, WeakMap, Promise, Date, console,
    location: {href:'https://x.com/alex/following'},
    document: {addEventListener:(event,fn)=>listeners[event]=fn,querySelectorAll:()=>[]},
    history: {pushState(state, title, url) { sandbox.location.href = new URL(url,sandbox.location.href).href; }, replaceState(state,title,url) {sandbox.location.href=new URL(url,sandbox.location.href).href;}},
    addEventListener:(event,fn)=>listeners[event]=fn,
    webkit:{messageHandlers:{ghost:{postMessage:value=>messages.push(value)}}},
    fetch: async () => new Response(JSON.stringify({data:{favorite_tweet:'Done'}}),{status:200})
  };
  sandbox.window=sandbox; sandbox.top=sandbox;
  const context = vm.createContext(sandbox);
  for (const script of ['X.js','Capture.js']) vm.runInContext(fs.readFileSync(path.join(resources,script),'utf8'),context);
  return {context,sandbox,messages,listeners};
}
const settle = () => new Promise(resolve=>setTimeout(resolve,20));
const endpoint = 'https://x.com/i/api/graphql/test/FavoriteTweet';

test('fetch wrapper emits once and leaves original response readable', async () => {
  const {sandbox,messages}=environment();
  const result=await sandbox.fetch(endpoint,{method:'POST',body:JSON.stringify({variables:{tweet_id:'123'}})});
  assert.equal((await result.json()).data.favorite_tweet,'Done');
  await settle();
  assert.equal(messages.filter(m=>m.kind==='event').length,1);
});
test('XHR wrapper captures the response once', () => {
  const {sandbox,messages}=environment();
  const xhr=new sandbox.XMLHttpRequest(); xhr.open('POST',endpoint); xhr.send(JSON.stringify({variables:{tweet_id:'123'}}));
  assert.equal(messages.filter(m=>m.kind==='event').length,1);
});
test('pausing excludes requests and discards in-flight pre-pause observations', async () => {
  const {sandbox,messages}=environment();
  const result=sandbox.fetch(endpoint,{method:'POST',body:JSON.stringify({variables:{tweet_id:'123'}})});
  sandbox.__ghostSetPaused(true);
  await result; await settle();
  assert.equal(messages.filter(m=>m.kind==='event').length,0);
  await sandbox.fetch(endpoint,{method:'POST',body:JSON.stringify({variables:{tweet_id:'456'}})}); await settle();
  assert.equal(messages.filter(m=>m.kind==='event').length,0);
});
test('SPA links preserve discovery source and ignore automatic URL rewrites', () => {
  const {sandbox,messages,listeners}=environment();
  sandbox.history.replaceState({},'', '/alex/following?lang=en');
  assert.equal(messages.filter(m=>m.kind==='navigation').length,0);
  const link={href:'https://x.com/sam',target:''};
  listeners.click({isTrusted:true,target:{closest:selector=>selector==='a[href]'?link:null}});
  sandbox.history.pushState({},'', '/sam');
  const nav=messages.find(m=>m.kind==='navigation');
  assert.equal(nav.source_url,'https://x.com/alex/following?lang=en');
  assert.equal(nav.context,'x.profile_from_following_list');
  sandbox.history.replaceState({},'', '/sam?lang=en');
  assert.equal(messages.filter(m=>m.kind==='navigation').length,1);
});
test('opening a background tab preserves source intent without a fake same-tab arrival', () => {
  const {sandbox,messages,listeners}=environment();
  const link={href:'https://x.com/sam',target:''};
  listeners.click({isTrusted:true,metaKey:true,target:{closest:()=>link}});
  sandbox.history.replaceState({},'', '/alex/following?foo=bar');
  assert.equal(messages.filter(m=>m.kind==='link').length,1);
  assert.equal(messages.filter(m=>m.kind==='navigation').length,0);
});
test('clickable post cards can produce a deliberate SPA arrival', () => {
  const {sandbox,messages,listeners}=environment();
  listeners.click({isTrusted:true,target:{closest:()=>null}});
  sandbox.history.pushState({},'', '/sam/status/123');
  assert.equal(messages.filter(m=>m.kind==='navigation').length,1);
});