Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions src/components/SettingsTab.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// @vitest-environment jsdom
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
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";
import type { CardBlockId } from "@/lib/types";
import "@testing-library/jest-dom";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 冗長な @testing-library/jest-dom インポート

vitest.setup.tssetupFiles として登録されており、その中で @testing-library/jest-dom を既にグローバルにインポートしています。この行はすべてのテストファイルで自動的に有効になるため、各テストファイルで個別にインポートする必要はありません。

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/SettingsTab.test.tsx
Line: 9

Comment:
**冗長な `@testing-library/jest-dom` インポート**

`vitest.setup.ts``setupFiles` として登録されており、その中で `@testing-library/jest-dom` を既にグローバルにインポートしています。この行はすべてのテストファイルで自動的に有効になるため、各テストファイルで個別にインポートする必要はありません。

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!


describe("SettingsTab", () => {
const defaultDisplayOptions: CardDisplayOptions = {
showAvatar: true,
showBio: false,
showStats: true,
showLocation: false,
showJoinedDate: true,
showTopics: false,
showLanguage: true,
};

const defaultIsBlockVisible = vi.fn((id: CardBlockId) => id === "profile" || id === "contributions");
const toggleMainBlockVisibility = vi.fn();
const toggleDisplayOption = vi.fn();

beforeEach(() => {
vi.clearAllMocks();
});

it("renders all main block labels", () => {
render(
<SettingsTab
isBlockVisible={defaultIsBlockVisible}
toggleMainBlockVisibility={toggleMainBlockVisibility}
displayOptions={defaultDisplayOptions}
toggleDisplayOption={toggleDisplayOption}
/>
);

MAIN_BLOCKS.forEach(({ label }) => {
expect(screen.getByLabelText(label)).toBeInTheDocument();
});
});

it("renders all detail options labels", () => {
render(
<SettingsTab
isBlockVisible={defaultIsBlockVisible}
toggleMainBlockVisibility={toggleMainBlockVisibility}
displayOptions={defaultDisplayOptions}
toggleDisplayOption={toggleDisplayOption}
/>
);

DETAIL_OPTIONS.forEach(({ label }) => {
expect(screen.getByLabelText(label)).toBeInTheDocument();
});
});

it("sets correct checked state for main blocks based on isBlockVisible prop", () => {
render(
<SettingsTab
isBlockVisible={defaultIsBlockVisible}
toggleMainBlockVisibility={toggleMainBlockVisibility}
displayOptions={defaultDisplayOptions}
toggleDisplayOption={toggleDisplayOption}
/>
);

const profileCheckbox = screen.getByLabelText("Profile") as HTMLInputElement;
expect(profileCheckbox.checked).toBe(true);

const heatmapCheckbox = screen.getByLabelText("Activity Heatmap") as HTMLInputElement;
expect(heatmapCheckbox.checked).toBe(false);
Comment on lines +70 to +74

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 ラベル文字列のハードコードによるドリフトリスク

"Profile""Activity Heatmap" をハードコードしていますが、MAIN_BLOCKS の定数が変更された場合、このテストは定数とずれてしまいます。既にテスト上部でインポートしている MAIN_BLOCKS の値を使えば、ラベルが変わっても追従できます。

Suggested change
const profileCheckbox = screen.getByLabelText("Profile") as HTMLInputElement;
expect(profileCheckbox.checked).toBe(true);
const heatmapCheckbox = screen.getByLabelText("Activity Heatmap") as HTMLInputElement;
expect(heatmapCheckbox.checked).toBe(false);
const profileLabel = MAIN_BLOCKS.find((b) => b.id === "profile")!.label;
const profileCheckbox = screen.getByLabelText(profileLabel) as HTMLInputElement;
expect(profileCheckbox.checked).toBe(true);
const heatmapLabel = MAIN_BLOCKS.find((b) => b.id === "heatmap")!.label;
const heatmapCheckbox = screen.getByLabelText(heatmapLabel) as HTMLInputElement;
expect(heatmapCheckbox.checked).toBe(false);
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/SettingsTab.test.tsx
Line: 70-74

Comment:
**ラベル文字列のハードコードによるドリフトリスク**

`"Profile"``"Activity Heatmap"` をハードコードしていますが、`MAIN_BLOCKS` の定数が変更された場合、このテストは定数とずれてしまいます。既にテスト上部でインポートしている `MAIN_BLOCKS` の値を使えば、ラベルが変わっても追従できます。

```suggestion
    const profileLabel = MAIN_BLOCKS.find((b) => b.id === "profile")!.label;
    const profileCheckbox = screen.getByLabelText(profileLabel) as HTMLInputElement;
    expect(profileCheckbox.checked).toBe(true);

    const heatmapLabel = MAIN_BLOCKS.find((b) => b.id === "heatmap")!.label;
    const heatmapCheckbox = screen.getByLabelText(heatmapLabel) as HTMLInputElement;
    expect(heatmapCheckbox.checked).toBe(false);
```

How can I resolve this? If you propose a fix, please make it concise.

});

it("sets correct checked state for detail options based on displayOptions prop", () => {
const optionsWithUndefined = { ...defaultDisplayOptions, showJoinedDate: undefined };
render(
<SettingsTab
isBlockVisible={defaultIsBlockVisible}
toggleMainBlockVisibility={toggleMainBlockVisibility}
displayOptions={optionsWithUndefined}
toggleDisplayOption={toggleDisplayOption}
/>
);

const avatarCheckbox = screen.getByLabelText("Avatar") as HTMLInputElement;
expect(avatarCheckbox.checked).toBe(true);

const bioCheckbox = screen.getByLabelText("Bio") as HTMLInputElement;
expect(bioCheckbox.checked).toBe(false);

const joinedDateCheckbox = screen.getByLabelText("Joined Date") as HTMLInputElement;
expect(joinedDateCheckbox.checked).toBe(false); // Covers the ?? false fallback
});

it("calls toggleMainBlockVisibility when a main block checkbox is toggled", async () => {
const user = userEvent.setup();
render(
<SettingsTab
isBlockVisible={defaultIsBlockVisible}
toggleMainBlockVisibility={toggleMainBlockVisibility}
displayOptions={defaultDisplayOptions}
toggleDisplayOption={toggleDisplayOption}
/>
);

const profileCheckbox = screen.getByLabelText("Profile");
await user.click(profileCheckbox);
expect(toggleMainBlockVisibility).toHaveBeenCalledWith("profile");
expect(toggleMainBlockVisibility).toHaveBeenCalledTimes(1);
});

it("calls toggleDisplayOption when a detail option checkbox is toggled", async () => {
const user = userEvent.setup();
render(
<SettingsTab
isBlockVisible={defaultIsBlockVisible}
toggleMainBlockVisibility={toggleMainBlockVisibility}
displayOptions={defaultDisplayOptions}
toggleDisplayOption={toggleDisplayOption}
/>
);

const avatarCheckbox = screen.getByLabelText("Avatar");
await user.click(avatarCheckbox);
expect(toggleDisplayOption).toHaveBeenCalledWith("showAvatar");
expect(toggleDisplayOption).toHaveBeenCalledTimes(1);
});
});
1 change: 1 addition & 0 deletions vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default defineConfig({
"src/components/ReadmeCardUrlSection.tsx",
"src/components/BusinessCard.tsx",
"src/components/LanguageChart.tsx",
"src/components/SettingsTab.tsx",
"src/components/SkillsCard.tsx",
"src/components/LayoutEditor.tsx",
"src/lib/rateLimit.ts",
Expand Down
Loading