diff --git a/src/components/competitions/save-button.test.tsx b/src/components/competitions/save-button.test.tsx
index 896d71a..aa99a62 100644
--- a/src/components/competitions/save-button.test.tsx
+++ b/src/components/competitions/save-button.test.tsx
@@ -24,12 +24,10 @@ vi.mock("sonner", () => ({
}));
let mockUser: { id: string } | null = { id: "user-1" };
-let mockSupabaseClient: unknown = {
- auth: {
- getUser: () => Promise.resolve({ data: { user: mockUser } }),
- onAuthStateChange: () => ({ data: { subscription: { unsubscribe: vi.fn() } } }),
- },
-};
+// The component loads the user asynchronously; tests that interact with the
+// button must wait for this to resolve or the click lands before auth settles.
+let getUser = vi.fn();
+let mockSupabaseClient: unknown;
vi.mock("@/lib/supabase/client", () => ({
createClient: () => mockSupabaseClient,
}));
@@ -44,9 +42,10 @@ afterEach(() => {
describe("SaveButton", () => {
beforeEach(() => {
mockUser = { id: "user-1" };
+ getUser = vi.fn().mockResolvedValue({ data: { user: mockUser } });
mockSupabaseClient = {
auth: {
- getUser: () => Promise.resolve({ data: { user: mockUser } }),
+ getUser,
onAuthStateChange: () => ({ data: { subscription: { unsubscribe: vi.fn() } } }),
},
};
@@ -77,6 +76,8 @@ describe("SaveButton", () => {
it("saves optimistically and calls saveCompetition", async () => {
render();
const button = await screen.findByRole("button");
+ // Wait for the async auth load before asserting on optimistic state.
+ await waitFor(() => expect(getUser).toHaveBeenCalled());
fireEvent.click(button);
@@ -87,6 +88,7 @@ describe("SaveButton", () => {
it("unsaves and decrements the count", async () => {
render();
const button = await screen.findByRole("button");
+ await waitFor(() => expect(getUser).toHaveBeenCalled());
fireEvent.click(button);
@@ -99,6 +101,7 @@ describe("SaveButton", () => {
saveCompetition.mockRejectedValue(new Error("network error"));
render();
const button = await screen.findByRole("button");
+ await waitFor(() => expect(getUser).toHaveBeenCalled());
fireEvent.click(button);
expect(button.getAttribute("aria-pressed")).toBe("true");
@@ -107,16 +110,18 @@ describe("SaveButton", () => {
expect(toastError).toHaveBeenCalled();
});
- it("prompts sign-in when clicked while signed out, without throwing", () => {
+ it("prompts sign-in when clicked while signed out, without throwing", async () => {
mockUser = null;
+ getUser = vi.fn().mockResolvedValue({ data: { user: null } });
mockSupabaseClient = {
auth: {
- getUser: () => Promise.resolve({ data: { user: null } }),
+ getUser,
onAuthStateChange: () => ({ data: { subscription: { unsubscribe: vi.fn() } } }),
},
};
render();
const button = screen.getByRole("button");
+ await waitFor(() => expect(getUser).toHaveBeenCalled());
expect(() => fireEvent.click(button)).not.toThrow();
expect(push).toHaveBeenCalledWith(expect.stringContaining("/login?next="));