perf(web): hydrate empty message favorites once (#2025)

This commit is contained in:
Carlos Florêncio
2026-07-28 23:04:55 +01:00
committed by GitHub
parent 60040a71f1
commit 2f6079fe0b
3 changed files with 25 additions and 6 deletions
@@ -8,7 +8,7 @@ import { SessionPage } from "../../pages/session-page";
const SEEDED_MESSAGE = "Favorite toggle regression fixture message";
test.describe("Chat message favorite toggle", () => {
test("stars a message, tints its background yellow, and un-stars it back", async ({
test("keeps a starred message highlighted after reload and un-stars it", async ({
testPage,
apiClient,
seedData,
@@ -48,6 +48,13 @@ test.describe("Chat message favorite toggle", () => {
await expect(unstar).toBeVisible();
await expect.poll(async () => highlight.getAttribute("class")).toMatch(/yellow/);
await testPage.reload();
await session.waitForLoad();
await expect(chat.getByText(SEEDED_MESSAGE)).toBeVisible();
await expect(unstar).toBeVisible();
await expect.poll(async () => highlight.getAttribute("class")).toMatch(/yellow/);
await unstar.click();
await expect(star).toBeVisible();
@@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { useMessageFavoritesStore } from "./favorites-store";
import { MESSAGE_FAVORITES_STORAGE_PREFIX, loadSessionFavorites } from "./persistence";
@@ -11,6 +11,10 @@ describe("message favorites store", () => {
useMessageFavoritesStore.setState({ bySession: {} });
});
afterEach(() => {
vi.restoreAllMocks();
});
it("starts with no favorites for an unhydrated session", () => {
const state = useMessageFavoritesStore.getState();
expect(state.bySession[SESSION_ID]).toBeUndefined();
@@ -60,6 +64,15 @@ describe("message favorites store", () => {
expect(state.bySession[SESSION_ID]).toEqual({ "msg-1": true, "msg-2": true });
});
it("hydrates an empty session from storage only once", () => {
const getItem = vi.spyOn(window.sessionStorage, "getItem");
useMessageFavoritesStore.getState().hydrateSession(SESSION_ID);
useMessageFavoritesStore.getState().hydrateSession(SESSION_ID);
expect(getItem).toHaveBeenCalledTimes(1);
});
it("ignores malformed persisted favorites", () => {
window.sessionStorage.setItem(
`${MESSAGE_FAVORITES_STORAGE_PREFIX}${SESSION_ID}`,
@@ -88,7 +101,7 @@ describe("message favorites store", () => {
);
expect(() => useMessageFavoritesStore.getState().hydrateSession(SESSION_ID)).not.toThrow();
expect(useMessageFavoritesStore.getState().bySession[SESSION_ID]).toBeUndefined();
expect(useMessageFavoritesStore.getState().bySession[SESSION_ID]).toEqual({});
});
it("ignores a persisted array containing non-string entries", () => {
@@ -98,6 +111,6 @@ describe("message favorites store", () => {
);
expect(() => useMessageFavoritesStore.getState().hydrateSession(SESSION_ID)).not.toThrow();
expect(useMessageFavoritesStore.getState().bySession[SESSION_ID]).toBeUndefined();
expect(useMessageFavoritesStore.getState().bySession[SESSION_ID]).toEqual({});
});
});
@@ -21,9 +21,8 @@ export const useMessageFavoritesStore = create<MessageFavoritesSlice>()(
hydrateSession: (sessionId: string) =>
set((state) => {
const existing = state.bySession[sessionId];
if (existing && Object.keys(existing).length > 0) return;
if (existing) return;
const ids = loadSessionFavorites(sessionId);
if (ids.length === 0) return;
state.bySession[sessionId] = Object.fromEntries(ids.map((id) => [id, true as const]));
}),