fix(notifications): Mark all read empties a band of read rows, and a read landing mid-write cannot refill it
This commit is contained in:
@@ -97,7 +97,7 @@ function mount() {
|
||||
</QueryClientProvider>
|
||||
);
|
||||
const { rerender } = render(tree());
|
||||
return { rerender: () => rerender(tree()) };
|
||||
return { qc, rerender: () => rerender(tree()) };
|
||||
}
|
||||
// Every test has a "Ready 1" on screen once the server list has landed.
|
||||
const loaded = () => screen.findByText("Ready 1");
|
||||
@@ -211,4 +211,59 @@ describe("NotificationsPanel · order", () => {
|
||||
expect(row.isConnected).toBe(true);
|
||||
expect(document.activeElement).toBe(row);
|
||||
});
|
||||
|
||||
it("a band of rows already read still offers Mark all read, which empties it", async () => {
|
||||
// Opening the center marked this browser's notices read: the band holds them, and nothing on
|
||||
// the page is unread any more.
|
||||
h.server = [server(1, 1 * H, true)];
|
||||
h.client = [client(2, 2 * H, { read: false })];
|
||||
const { rerender } = mount();
|
||||
await loaded();
|
||||
h.client = [client(2, 2 * H, { read: true })]; // what the mount's markAllRead leaves
|
||||
await act(async () => rerender());
|
||||
expect(listUnder("inbox.sectionNeedsYou:1")).toEqual(["Activity 2"]);
|
||||
const button = screen.getByRole("button", { name: "inbox.markAllRead" });
|
||||
expect(button.hasAttribute("disabled")).toBe(false);
|
||||
fireEvent.click(button);
|
||||
await act(async () => rerender());
|
||||
expect(screen.queryByText(/inbox\.sectionNeedsYou/)).toBeNull();
|
||||
});
|
||||
|
||||
it("a read that lands before Mark all read commits does not put the rows back", async () => {
|
||||
let commit!: () => void;
|
||||
vi.spyOn(api, "markAllNotificationsRead").mockImplementation(
|
||||
() => new Promise((resolve) => (commit = () => resolve({ ok: true } as never))),
|
||||
);
|
||||
h.server = [server(1, 1 * H, false)];
|
||||
h.client = [];
|
||||
const { qc } = mount();
|
||||
await loaded();
|
||||
fireEvent.click(screen.getByRole("button", { name: "inbox.markAllRead" }));
|
||||
await waitFor(() => expect(api.markAllNotificationsRead).toHaveBeenCalled());
|
||||
// The poll (or another row's write) reads the list before the server has committed the write.
|
||||
void qc.invalidateQueries({ queryKey: ["notifications"] });
|
||||
await waitFor(() =>
|
||||
expect(qc.getQueryData<{ items: AppNotification[] }>(["notifications"])?.items[0]?.read).toBe(
|
||||
false,
|
||||
),
|
||||
);
|
||||
h.server = [server(1, 1 * H, true)];
|
||||
await act(async () => commit());
|
||||
await waitFor(() => expect(screen.queryByText(/inbox\.sectionNeedsYou/)).toBeNull());
|
||||
expect(listUnder("inbox.sectionRecent")).toEqual(["Ready 1"]);
|
||||
});
|
||||
|
||||
it("a refused Mark all read brings the rows back at once, not at the next poll", async () => {
|
||||
vi.spyOn(api, "markAllNotificationsRead").mockRejectedValue(new Error("offline"));
|
||||
h.server = [server(1, 1 * H, false)];
|
||||
h.client = [];
|
||||
mount();
|
||||
await loaded();
|
||||
const reads = vi.mocked(api.notifications).mock.calls.length;
|
||||
fireEvent.click(screen.getByRole("button", { name: "inbox.markAllRead" }));
|
||||
await waitFor(() =>
|
||||
expect(vi.mocked(api.notifications).mock.calls.length).toBeGreaterThan(reads),
|
||||
);
|
||||
await waitFor(() => expect(listUnder("inbox.sectionNeedsYou:1")).toEqual(["Ready 1"]));
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user