Fix observer not seeing messages sent while they were away from the page

This commit is contained in:
Kalle
2026-08-29 20:32:37 +03:00
parent 9d8cfcd1f6
commit f1e6f51d69
4 changed files with 84 additions and 2 deletions

View File

@@ -590,6 +590,32 @@ describe("createChatClient", () => {
expect(client.getSnapshot().messagesByRoomId.has(50)).toBe(true);
});
test("reopening an observed room refetches its history", async () => {
const observed = room({ id: 50 });
const harness = createHarness({
observedRoom: observed,
messages: [message({ id: 1, roomId: 50 })],
});
const client = await startedClient(harness);
client.ensureRoomKnown(50);
await flush();
client.ensureMessagesLoaded(50);
await flush();
harness.fetchMessages.mockResolvedValue({
messages: [
message({ id: 1, roomId: 50 }),
message({ id: 2, roomId: 50 }),
],
});
client.ensureMessagesLoaded(50);
await flush();
// nothing was pushed to the observer while the room's page was not open
expect(harness.fetchMessages).toHaveBeenCalledTimes(2);
expect(client.getSnapshot().messagesByRoomId.get(50)).toHaveLength(2);
});
test("an observed room the user's list later carries is superseded by the list version", async () => {
const observed = room({ id: 50 });
const harness = createHarness({ observedRoom: observed });

View File

@@ -67,7 +67,7 @@ export interface ChatClient {
refreshRooms: () => Promise<void>;
/** Fetches a room's info as an observed room when the user's own room list does not carry it (observer access via a route's `chatRooms`). */
ensureRoomKnown: (roomId: number) => void;
/** Fetches the room's history unless it is already loaded or loading. */
/** Fetches the room's history unless it is already loaded or loading. An observed room's held history is refetched instead of trusted: messages only reach an observer while the route surfacing the room keeps its subscription. */
ensureMessagesLoaded: (roomId: number) => void;
/** Reconnect catch-up: refetches the room list and every loaded history. */
catchUp: () => void;
@@ -455,7 +455,8 @@ export function createChatClient(deps: ChatClientDeps): ChatClient {
void loadObservedRoom(roomId);
},
ensureMessagesLoaded: (roomId) => {
if (messagesByRoomId.has(roomId)) return;
const canHaveMissedMessages = roomById(roomId)?.observed ?? false;
if (messagesByRoomId.has(roomId) && !canHaveMissedMessages) return;
void loadMessages(roomId);
},
catchUp: () => {

View File

@@ -0,0 +1,4 @@
---
type: bug
---
Fix tournament staff not seeing chat messages sent while they were on another page

View File

@@ -25,6 +25,7 @@ import { MobileNav } from "./pages/layout/mobile-nav";
import { SideNav } from "./pages/layout/side-nav";
import { SendouQLookingPage } from "./pages/sendouq/sendouq-looking-page";
import { SendouQMatchPage } from "./pages/sendouq/sendouq-match-page";
import { TournamentBracketsPage } from "./pages/tournament/tournament-brackets-page";
import { TournamentMatchPage } from "./pages/tournament/tournament-match-page";
test.describe("Chat", () => {
@@ -383,6 +384,56 @@ test.describe("Chat", () => {
}
});
test("An observer coming back to a match chat sees what was said while they were away", async ({
page,
browser,
workerBaseURL,
factories,
}) => {
const { tournament, matchId } = await createInProgressMatch(factories, {
name: "Chat Cup",
friendId: NZAP_TEST_ID,
});
const participant = await openSecondUser(
browser,
workerBaseURL,
NZAP_TEST_ID,
);
try {
await new TournamentMatchPage(participant.page).goto({
tournamentId: tournament.id,
matchId,
});
const participantChat = new ChatSidebar(participant.page).chat();
// the tournament's author, and so an observer of the match chat
await impersonate(page);
const brackets = new TournamentBracketsPage(page);
await brackets.goto(tournament.id);
const matchPage = await brackets.openMatch(matchId);
const chat = new ChatSidebar(page);
await expect(chat.locators.openChats).toHaveCount(1);
// an observer is only pushed the room's messages while on the page that
// surfaced it, so what is said from here on never reaches their history
await matchPage.backToBracket();
await participantChat.send("said while you were on the bracket");
await expect(participantChat.locators.pendingMessages).toHaveCount(0);
await brackets.openMatch(matchId);
await expect(
chat.chat().message("said while you were on the bracket"),
).toBeVisible();
} finally {
await participant.close();
}
});
test("A closed room is readable by staff and denied to its participants", async ({
page,
browser,