stackchain-dashboard/tests/test_context_polling.py
timmy fedddb246d
All checks were successful
CI / lint (pull_request) Successful in 25s
CI / build-frontend (pull_request) Successful in 5s
perf: skip unchanged live snapshot sections (#285)
2026-08-08 09:35:48 +00:00

117 lines
3.6 KiB
Python

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": []},
],
}