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"
],