diff --git a/src/components/SettingsTab.test.tsx b/src/components/SettingsTab.test.tsx new file mode 100644 index 0000000..c48b4a9 --- /dev/null +++ b/src/components/SettingsTab.test.tsx @@ -0,0 +1,162 @@ +/** + * @vitest-environment jsdom + */ +import { render, screen, fireEvent } from "@testing-library/react"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { SettingsTab } from "./SettingsTab"; +import { MAIN_BLOCKS, DETAIL_OPTIONS } from "@/lib/cardGeneratorConstants"; +import type { CardDisplayOptions } from "@/lib/cardSettings"; + +describe("SettingsTab", () => { + const mockIsBlockVisible = vi.fn(); + const mockToggleMainBlockVisibility = vi.fn(); + const mockToggleDisplayOption = vi.fn(); + + const defaultDisplayOptions: CardDisplayOptions = { + showAvatar: true, + showBio: false, + showStats: true, + showLanguage: false, + showRepos: true, + showCompany: false, + showLocation: true, + showWebsite: false, + showTwitter: true, + showJoinedDate: false, + showTopics: true, + showContributionBreakdown: false, + showStreaks: true, + showInterests: false, + showActivityBreakdown: true, + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("renders all MAIN_BLOCKS and DETAIL_OPTIONS", () => { + render( + + ); + + MAIN_BLOCKS.forEach((block) => { + expect(screen.getByLabelText(block.label)).toBeDefined(); + }); + + DETAIL_OPTIONS.forEach((option) => { + expect(screen.getByLabelText(option.label)).toBeDefined(); + }); + }); + + it("reflects checked state for blocks and options correctly", () => { + // Let's set some specific mocks to test truthy vs falsy returns + mockIsBlockVisible.mockImplementation((id) => id === "profile" || id === "heatmap"); + + const customDisplayOptions = { + ...defaultDisplayOptions, + showAvatar: true, // Should be checked + showBio: false, // Should not be checked + }; + + render( + + ); + + const profileBlock = screen.getByLabelText( + MAIN_BLOCKS.find((b) => b.id === "profile")!.label + ) as HTMLInputElement; + expect(profileBlock.checked).toBe(true); + + const contributionsBlock = screen.getByLabelText( + MAIN_BLOCKS.find((b) => b.id === "contributions")!.label + ) as HTMLInputElement; + expect(contributionsBlock.checked).toBe(false); + + const avatarOption = screen.getByLabelText( + DETAIL_OPTIONS.find((o) => o.key === "showAvatar")!.label + ) as HTMLInputElement; + expect(avatarOption.checked).toBe(true); + + const bioOption = screen.getByLabelText( + DETAIL_OPTIONS.find((o) => o.key === "showBio")!.label + ) as HTMLInputElement; + expect(bioOption.checked).toBe(false); + }); + + it("calls toggleMainBlockVisibility when a main block checkbox is clicked", () => { + mockIsBlockVisible.mockReturnValue(false); + render( + + ); + + const profileBlock = screen.getByLabelText( + MAIN_BLOCKS.find((b) => b.id === "profile")!.label + ); + + fireEvent.click(profileBlock); + + expect(mockToggleMainBlockVisibility).toHaveBeenCalledWith("profile"); + expect(mockToggleMainBlockVisibility).toHaveBeenCalledTimes(1); + }); + + it("calls toggleDisplayOption when a detail option checkbox is clicked", () => { + mockIsBlockVisible.mockReturnValue(false); + render( + + ); + + const avatarOption = screen.getByLabelText( + DETAIL_OPTIONS.find((o) => o.key === "showAvatar")!.label + ); + + fireEvent.click(avatarOption); + + expect(mockToggleDisplayOption).toHaveBeenCalledWith("showAvatar"); + expect(mockToggleDisplayOption).toHaveBeenCalledTimes(1); + }); + + it("defaults missing displayOptions to false", () => { + const optionsWithMissingKeys = { + showAvatar: true, // Only this is present + } as CardDisplayOptions; + + render( + + ); + + const avatarOption = screen.getByLabelText( + DETAIL_OPTIONS.find((o) => o.key === "showAvatar")!.label + ) as HTMLInputElement; + expect(avatarOption.checked).toBe(true); + + const bioOption = screen.getByLabelText( + DETAIL_OPTIONS.find((o) => o.key === "showBio")!.label + ) as HTMLInputElement; + expect(bioOption.checked).toBe(false); // Defaulted to false because it's missing in the provided object + }); +}); diff --git a/vitest.config.ts b/vitest.config.ts index 9404856..6e7768d 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -21,6 +21,7 @@ export default defineConfig({ "src/components/LanguageChart.tsx", "src/components/SkillsCard.tsx", "src/components/LayoutEditor.tsx", + "src/components/SettingsTab.tsx", "src/lib/rateLimit.ts", "src/app/api/og/[username]/route.tsx" ],