import json import subprocess from pathlib import Path POLLER = Path(__file__).parents[1] / "frontend" / "context-poller.js" def run_node(script: str) -> dict: result = subprocess.run( ["node", "-e", script], check=True, capture_output=True, text=True ) return json.loads(result.stdout) def test_context_poller_is_single_flight_and_pauses_until_visible(): script = f""" const createContextPoller = require({json.dumps(str(POLLER))}); let calls = 0; let hidden = false; let resolveRequest; const timers = []; const poller = createContextPoller({{ fetchContext: () => {{ calls += 1; if (calls > 1) return Promise.resolve({{ repos: [] }}); return new Promise((resolve) => {{ resolveRequest = resolve; }}); }}, onSnapshot: () => {{}}, onError: () => {{}}, isHidden: () => hidden, setTimer: (callback) => {{ timers.push(callback); return timers.length; }}, clearTimer: () => {{}}, intervalMs: 8000, }}); (async () => {{ const first = poller.start(); const joined = poller.refresh(); const callsWhilePending = calls; resolveRequest({{ repos: [] }}); await Promise.all([first, joined]); hidden = true; poller.setVisible(false); const scheduled = timers.shift(); if (scheduled) scheduled(); await Promise.resolve(); const callsWhileHidden = calls; hidden = false; await poller.setVisible(true); process.stdout.write(JSON.stringify({{ callsWhilePending, callsWhileHidden, callsAfterResume: calls, }})); }})(); """ assert run_node(script) == { "callsWhilePending": 1, "callsWhileHidden": 1, "callsAfterResume": 2, } def test_context_poller_sends_revisions_and_merges_changed_sections(): script = f""" const createContextPoller = require({json.dumps(str(POLLER))}); const requested = []; const rendered = []; const responses = [ {{ context: {{ user: {{ login: 'timmy' }} }}, events: [{{ id: 1 }}], notifications: [], sections: {{ context: 'fresh', events: 'fresh', notifications: 'fresh' }}, revisions: {{ context: 1, events: 1, notifications: 1 }}, freshness: {{ age_seconds: 0 }} }}, {{ sections: {{ context: 'fresh', events: 'fresh', notifications: 'fresh' }}, revisions: {{ context: 1, events: 2, notifications: 1 }}, events: [{{ id: 2 }}], freshness: {{ age_seconds: 1 }} }}, {{ sections: {{ context: 'fresh', events: 'fresh', notifications: 'fresh' }}, revisions: {{ context: 1, events: 2, notifications: 1 }}, freshness: {{ age_seconds: 2 }} }}, ]; const poller = createContextPoller({{ fetchContext: revisions => {{ requested.push({{ ...revisions }}); return Promise.resolve(responses.shift()); }}, onSnapshot: (snapshot, changed) => rendered.push({{ context: snapshot.context.user.login, event: snapshot.events[0].id, age: snapshot.freshness.age_seconds, changed, }}), onError: error => {{ throw error; }}, setTimer: () => 1, clearTimer: () => {{}}, }}); (async () => {{ await poller.refresh(); await poller.refresh(); await poller.refresh(); process.stdout.write(JSON.stringify({{ requested, rendered }})); }})(); """ assert run_node(script) == { "requested": [ {}, {"context": 1, "events": 1, "notifications": 1}, {"context": 1, "events": 2, "notifications": 1}, ], "rendered": [ {"context": "timmy", "event": 1, "age": 0, "changed": ["context", "events", "notifications"]}, {"context": "timmy", "event": 2, "age": 1, "changed": ["events"]}, {"context": "timmy", "event": 2, "age": 2, "changed": []}, ], }