fix(web): clear the query cache when signing out from the avatar menu

This commit is contained in:
Amruth Pillai
2026-09-29 12:28:49 +02:00
parent 3c71b4e7c3
commit 741b080296
2 changed files with 71 additions and 0 deletions
@@ -0,0 +1,68 @@
// @vitest-environment happy-dom
import type { ReactNode } from "react";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { i18n } from "@lingui/core";
import { I18nProvider } from "@lingui/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
type SignOutOptions = { fetchOptions: { onSuccess: () => void } };
const router = vi.hoisted(() => ({ invalidate: vi.fn(), navigate: vi.fn() }));
const signOut = vi.hoisted(() =>
vi.fn(({ fetchOptions }: SignOutOptions) => {
fetchOptions.onSuccess();
}),
);
vi.mock("@tanstack/react-router", () => ({ useRouter: () => router }));
vi.mock("@/libs/auth/client", () => ({
authClient: { signOut, useSession: () => ({ data: { user: { id: "user-1" } } }) },
}));
vi.mock("@/features/theme/provider", () => ({ useTheme: () => ({ theme: "light", setTheme: vi.fn() }) }));
vi.mock("@reactive-resume/ui/components/toast", () => ({ toast: { add: vi.fn(), close: vi.fn() } }));
vi.mock("@reactive-resume/ui/components/dropdown-menu", () => {
const Passthrough = ({ children }: { children?: ReactNode }) => <>{children}</>;
return {
DropdownMenu: Passthrough,
DropdownMenuContent: Passthrough,
DropdownMenuGroup: Passthrough,
DropdownMenuRadioGroup: Passthrough,
DropdownMenuRadioItem: Passthrough,
DropdownMenuSeparator: () => null,
DropdownMenuSub: Passthrough,
DropdownMenuSubContent: Passthrough,
DropdownMenuSubTrigger: Passthrough,
DropdownMenuTrigger: () => null,
DropdownMenuItem: ({ children, onClick }: { children?: ReactNode; onClick?: () => void }) => (
<button type="button" onClick={onClick}>
{children}
</button>
),
};
});
i18n.loadAndActivate({ locale: "en", messages: {} });
const { UserDropdownMenu } = await import("./dropdown-menu");
describe("UserDropdownMenu", () => {
it("clears the previous user's cached queries when signing out", async () => {
const queryClient = new QueryClient();
queryClient.setQueryData(["resumes"], [{ id: "resume-1" }]);
render(
<I18nProvider i18n={i18n}>
<QueryClientProvider client={queryClient}>
<UserDropdownMenu>{() => <button type="button" />}</UserDropdownMenu>
</QueryClientProvider>
</I18nProvider>,
);
fireEvent.click(screen.getByRole("button", { name: "Sign out" }));
await waitFor(() => expect(router.invalidate).toHaveBeenCalled());
expect(queryClient.getQueryCache().getAll()).toHaveLength(0);
});
});
@@ -2,6 +2,7 @@ import type { AuthSession } from "@reactive-resume/auth/types";
import { t } from "@lingui/core/macro";
import { useLingui } from "@lingui/react";
import { Trans } from "@lingui/react/macro";
import { useQueryClient } from "@tanstack/react-query";
import { useRouter } from "@tanstack/react-router";
import {
DropdownMenu,
@@ -30,6 +31,7 @@ type Props = {
export function UserDropdownMenu({ children }: Props) {
const router = useRouter();
const queryClient = useQueryClient();
const { i18n } = useLingui();
const { theme, setTheme } = useTheme();
const { data: session } = authClient.useSession();
@@ -46,6 +48,7 @@ export function UserDropdownMenu({ children }: Props) {
fetchOptions: {
onSuccess: () => {
toast.close(toastId);
queryClient.clear();
void router.invalidate();
},
onError: ({ error }) => {