fix : reaible vistor count
CI / Verify (push) Successful in 1m28s
CI / Build immutable images and deploy (push) Successful in 2m2s

This commit is contained in:
2026-09-22 21:34:18 +07:00 Unverified
parent 95f491b862
commit b5e6588958
4 changed files with 54 additions and 9 deletions
+21 -2
View File
@@ -54,14 +54,33 @@ describeWithRedis("shared Redis security paths", () => {
});
it("tracks visitor counts without a separate Redis round trip per visitor", async () => {
const first = await updateVisitorPresence({ tabId: `${runId}:1`, guideId: "guide-a", active: true });
const first = await updateVisitorPresence({ tabId: `${runId}:1`, browserId: `${runId}:browser-1`, guideId: "guide-a", active: true });
expect(first.global).toBe(1);
expect(first.guide).toBe(1);
await updateVisitorPresence({ tabId: `${runId}:2`, guideId: "guide-a", active: true });
const second = await updateVisitorPresence({ tabId: `${runId}:2`, browserId: `${runId}:browser-2`, guideId: "guide-a", active: true });
expect(second.global).toBe(2);
expect(second.guide).toBe(2);
const count = await publisher.zcard(`${process.env.REDIS_PRESENCE_PREFIX}:visitors`);
expect(count).toBe(2);
});
it("counts a browser once across tabs without losing either guide", async () => {
const browserId = `${runId}:browser-3`;
const firstTab = `${runId}:3`;
const secondTab = `${runId}:4`;
const firstGuide = await updateVisitorPresence({ tabId: firstTab, browserId, guideId: "guide-c", active: true });
const secondGuide = await updateVisitorPresence({ tabId: secondTab, browserId, guideId: "guide-d", active: true });
expect(secondGuide.global).toBe(firstGuide.global);
expect(secondGuide.guide).toBe(1);
expect(secondGuide.byGuide["guide-c"]).toBe(1);
const sameGuide = await updateVisitorPresence({ tabId: secondTab, browserId, guideId: "guide-c", active: true });
expect(sameGuide.guide).toBe(1);
expect(sameGuide.byGuide["guide-d"]).toBeUndefined();
const afterLeave = await updateVisitorPresence({ tabId: secondTab, browserId, guideId: "guide-d", active: false });
expect(afterLeave.byGuide["guide-c"]).toBe(1);
expect(afterLeave.byGuide["guide-d"]).toBeUndefined();
});
it("fans one subscribed topic out to two SSE clients", async () => {
const topic = `page:${runId}`;
const first = new AbortController();