mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-08 20:26:08 -05:00
Fix observer not seeing messages sent while they were away from the page
This commit is contained in:
@@ -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 });
|
||||
|
||||
@@ -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: () => {
|
||||
|
||||
4
changelog/2026-08-29-observer-chat-history.md
Normal file
4
changelog/2026-08-29-observer-chat-history.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
type: bug
|
||||
---
|
||||
Fix tournament staff not seeing chat messages sent while they were on another page
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user