111 lines
3.1 KiB
TypeScript
111 lines
3.1 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import {
|
|
createRefreshThrottleState,
|
|
markScheduledRefreshExecuted,
|
|
planThrottledRefresh,
|
|
shouldRefreshRealtimeEvent,
|
|
} from "../src/lib/realtime-refresh";
|
|
|
|
test("shouldRefreshRealtimeEvent filters scoped conversation updates by project and note", () => {
|
|
assert.equal(
|
|
shouldRefreshRealtimeEvent({
|
|
eventType: "conversation.updated",
|
|
eventData: JSON.stringify({ projectId: "project-a", note: "project_goals.updated" }),
|
|
projectIds: ["project-a", "project-b"],
|
|
conversationUpdatedNotes: ["project_goals.updated"],
|
|
}),
|
|
true,
|
|
);
|
|
|
|
assert.equal(
|
|
shouldRefreshRealtimeEvent({
|
|
eventType: "conversation.updated",
|
|
eventData: JSON.stringify({ projectId: "project-z", note: "project_goals.updated" }),
|
|
projectIds: ["project-a", "project-b"],
|
|
conversationUpdatedNotes: ["project_goals.updated"],
|
|
}),
|
|
false,
|
|
);
|
|
|
|
assert.equal(
|
|
shouldRefreshRealtimeEvent({
|
|
eventType: "conversation.updated",
|
|
eventData: JSON.stringify({ projectId: "project-a", note: "other.note" }),
|
|
projectIds: ["project-a", "project-b"],
|
|
conversationUpdatedNotes: ["project_goals.updated"],
|
|
}),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test("shouldRefreshRealtimeEvent ignores scoped events that do not identify a project", () => {
|
|
assert.equal(
|
|
shouldRefreshRealtimeEvent({
|
|
eventType: "conversation.updated",
|
|
eventData: JSON.stringify({ deviceId: "mac-studio" }),
|
|
projectId: "project-a",
|
|
}),
|
|
false,
|
|
);
|
|
|
|
assert.equal(
|
|
shouldRefreshRealtimeEvent({
|
|
eventType: "project.context_risk.updated",
|
|
eventData: JSON.stringify({ deviceId: "mac-studio" }),
|
|
projectIds: ["project-a", "project-b"],
|
|
}),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test("shouldRefreshRealtimeEvent can match scoped device events when page opts into device scope", () => {
|
|
assert.equal(
|
|
shouldRefreshRealtimeEvent({
|
|
eventType: "conversation.updated",
|
|
eventData: JSON.stringify({ deviceId: "mac-studio" }),
|
|
projectIds: ["project-a", "project-b"],
|
|
deviceId: "mac-studio",
|
|
}),
|
|
true,
|
|
);
|
|
|
|
assert.equal(
|
|
shouldRefreshRealtimeEvent({
|
|
eventType: "conversation.updated",
|
|
eventData: JSON.stringify({ deviceId: "windows-box" }),
|
|
projectIds: ["project-a", "project-b"],
|
|
deviceId: "mac-studio",
|
|
}),
|
|
false,
|
|
);
|
|
});
|
|
|
|
test("planThrottledRefresh coalesces bursts into one delayed refresh", () => {
|
|
const state = createRefreshThrottleState();
|
|
|
|
assert.deepEqual(planThrottledRefresh(state, 1_000, 400), {
|
|
type: "refresh_now",
|
|
});
|
|
assert.equal(state.lastRefreshAt, 1_000);
|
|
assert.equal(state.pending, false);
|
|
|
|
assert.deepEqual(planThrottledRefresh(state, 1_180, 400), {
|
|
type: "schedule_refresh",
|
|
delayMs: 220,
|
|
});
|
|
assert.equal(state.pending, true);
|
|
|
|
assert.deepEqual(planThrottledRefresh(state, 1_220, 400), {
|
|
type: "skip",
|
|
});
|
|
|
|
markScheduledRefreshExecuted(state, 1_400);
|
|
assert.equal(state.pending, false);
|
|
assert.equal(state.lastRefreshAt, 1_400);
|
|
|
|
assert.deepEqual(planThrottledRefresh(state, 1_900, 400), {
|
|
type: "refresh_now",
|
|
});
|
|
});
|