diff --git a/src/components/atoms/action-dropdown/ActionDropdown.test.tsx b/src/components/atoms/action-dropdown/ActionDropdown.test.tsx
new file mode 100644
index 00000000..1ff4f2c6
--- /dev/null
+++ b/src/components/atoms/action-dropdown/ActionDropdown.test.tsx
@@ -0,0 +1,71 @@
+import "@testing-library/jest-dom";
+
+import { fireEvent, render, screen } from "@testing-library/react";
+
+import ActionDropdown from "./ActionDropdown";
+
+describe("ActionDropdown Component", () => {
+ let mockItems: { label: string; onClick: jest.Mock }[];
+
+ beforeEach(() => {
+ mockItems = [
+ { label: "Option 1", onClick: jest.fn() },
+ { label: "Option 2", onClick: jest.fn() },
+ ];
+ });
+
+ test("드롭다운이 열려 있을 때 메뉴가 렌더링 되는지 확인", () => {
+ render(
+ ,
+ );
+
+ expect(screen.getByText("Option 1")).toBeInTheDocument();
+ expect(screen.getByText("Option 2")).toBeInTheDocument();
+ });
+
+ test("드롭다운이 닫혀 있을 때 메뉴가 보이지 않는지 확인", () => {
+ render(
+ ,
+ );
+
+ expect(screen.queryByText("Option 1")).not.toBeInTheDocument();
+ expect(screen.queryByText("Option 2")).not.toBeInTheDocument();
+ });
+
+ test("메뉴 아이템을 클릭하면 onClick 핸들러가 호출되고 드롭다운이 닫힘", () => {
+ const setIsOpenMock = jest.fn(); // 드롭다운 상태를 변경하는 Mock 함수 생성
+
+ render(
+ ,
+ );
+
+ const option1 = screen.getByText("Option 1");
+ fireEvent.click(option1);
+
+ // Option 1의 onClick 핸들러가 정상적으로 실행되었는지 확인
+ expect(mockItems[0].onClick).toHaveBeenCalledTimes(1);
+
+ // 클릭 후 드롭다운이 닫혔는지 확인
+ expect(setIsOpenMock).toHaveBeenCalledWith(false);
+ });
+
+ test("드롭다운 외부 클릭 시 닫힘", () => {
+ const setIsOpenMock = jest.fn();
+ render(
+ ,
+ );
+
+ const overlay = screen.getByTestId("dropdown-overlay");
+ fireEvent.click(overlay);
+
+ expect(setIsOpenMock).toHaveBeenCalledWith(false);
+ });
+});
diff --git a/src/components/atoms/action-dropdown/ActionDropdown.tsx b/src/components/atoms/action-dropdown/ActionDropdown.tsx
index 6d0d3fa7..4f8ffcdf 100644
--- a/src/components/atoms/action-dropdown/ActionDropdown.tsx
+++ b/src/components/atoms/action-dropdown/ActionDropdown.tsx
@@ -88,6 +88,7 @@ export default function ActionDropdown({
{/* dropdown 외부를 덮고있는 레이어 (드롭다운 외부 클릭 시 닫혀야 함) */}
diff --git a/src/components/atoms/button/Button.test.tsx b/src/components/atoms/button/Button.test.tsx
new file mode 100644
index 00000000..dabcc74b
--- /dev/null
+++ b/src/components/atoms/button/Button.test.tsx
@@ -0,0 +1,64 @@
+import "@testing-library/jest-dom";
+
+import { fireEvent, render, screen } from "@testing-library/react";
+
+import Button from "./Button";
+
+describe("Button Component", () => {
+ test("버튼이 기본 스타일로 렌더링 되는지 확인", () => {
+ render();
+
+ const button = screen.getByRole("button", { name: "버튼" });
+
+ expect(button).toBeInTheDocument();
+ expect(button).toHaveClass("bg-blue-500 text-white");
+ });
+
+ test("variant props에 따라 스타일이 변경되는지 확인", () => {
+ render();
+
+ const button = screen.getByRole("button", { name: "버튼" });
+
+ expect(button).toHaveClass("bg-white text-blue-500 border");
+ });
+
+ test("size props에 따라 크기가 변경되는지 확인", () => {
+ render();
+
+ const button = screen.getByRole("button", { name: "버튼" });
+
+ expect(button).toHaveClass("w-[291px] h-[48px] text-base");
+ });
+
+ test("rounded props가 true일 때, 둥근 스타일이 적용되는지 확인", () => {
+ render();
+
+ const button = screen.getByRole("button", { name: "버튼" });
+
+ expect(button).toHaveClass("rounded-[24px]");
+ });
+
+ test("disabled 상태일 때 클릭 이벤트가 발생하지 않는지 확인", () => {
+ const handleClick = jest.fn();
+ render(
+ ,
+ );
+
+ const button = screen.getByRole("button", { name: "버튼" });
+ fireEvent.click(button);
+
+ expect(handleClick).not.toHaveBeenCalled();
+ });
+
+ test("버튼 클릭 시 onClick 핸들러가 호출되는지 확인", () => {
+ const handleClick = jest.fn();
+ render();
+
+ const button = screen.getByRole("button", { name: "버튼" });
+ fireEvent.click(button);
+
+ expect(handleClick).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/src/components/atoms/exit-btn/ExitBtn.test.tsx b/src/components/atoms/exit-btn/ExitBtn.test.tsx
new file mode 100644
index 00000000..52a8bd15
--- /dev/null
+++ b/src/components/atoms/exit-btn/ExitBtn.test.tsx
@@ -0,0 +1,33 @@
+import "@testing-library/jest-dom";
+
+import { fireEvent, render, screen } from "@testing-library/react";
+
+import ExitBtn from "./ExitBtn";
+
+describe("ExitBtn Component", () => {
+ test("이미지가 올바르게 렌더링되는지 확인", () => {
+ render();
+
+ const button = screen.getByRole("img", { name: /exit-button/i });
+
+ expect(button).toBeInTheDocument();
+ });
+
+ test("props로 넘겨준 클래스가 정상적으로 적용되는지 확인", () => {
+ render();
+
+ const button = screen.getByRole("img", { name: /exit-button/i });
+
+ expect(button).toHaveClass("custom-class");
+ });
+
+ test("클릭 시 onClick 핸들러가 호출되는지 확인", () => {
+ const handleClick = jest.fn();
+ render();
+
+ const button = screen.getByRole("img", { name: /exit-button/i });
+ fireEvent.click(button);
+
+ expect(handleClick).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/src/components/atoms/exit-btn/ExitBtn.tsx b/src/components/atoms/exit-btn/ExitBtn.tsx
index e9d78a19..05005ee7 100644
--- a/src/components/atoms/exit-btn/ExitBtn.tsx
+++ b/src/components/atoms/exit-btn/ExitBtn.tsx
@@ -13,7 +13,6 @@ export default function ExitBtn({ onClick, className }: ExitBtnProps) {
alt="exit-button"
width={24}
height={24}
- layout="fixed"
className={cn("cursor-pointer hover:brightness-50", className)}
onClick={onClick}
/>
diff --git a/src/components/atoms/goal-item/GoalItem.test.tsx b/src/components/atoms/goal-item/GoalItem.test.tsx
new file mode 100644
index 00000000..73bdf3da
--- /dev/null
+++ b/src/components/atoms/goal-item/GoalItem.test.tsx
@@ -0,0 +1,63 @@
+import "@testing-library/jest-dom";
+
+import { render, screen } from "@testing-library/react";
+
+import GoalItem from "./GoalItem";
+
+describe("GoalItem Component", () => {
+ test("아이콘과 텍스트가 정상적으로 렌더링 되는지 확인", () => {
+ render(
+ ,
+ );
+
+ const icon = screen.getByRole("img", { name: "flag-goal" });
+ const text = screen.getByText("목표제목");
+
+ expect(icon).toBeInTheDocument();
+ expect(text).toBeInTheDocument();
+ });
+
+ test("아이콘 크기가 lg일 때 size가 올바르게 렌더링 되는지 확인", () => {
+ render(
+ ,
+ );
+
+ const icon = screen.getByRole("img", { name: "flag-goal" });
+
+ expect(icon).toHaveAttribute("width", "40");
+ expect(icon).toHaveAttribute("height", "40");
+ });
+
+ test("goal 값이 없을 때, span 태그가 렌더링되지 않는지 확인", () => {
+ render();
+
+ const text = screen.queryByText(/.+/); // 아무 텍스트나 있는지 확인
+
+ expect(text).not.toBeInTheDocument();
+ });
+
+ test("gap 값이 올바르게 적용되는지 확인", () => {
+ const { container } = render(
+ ,
+ );
+
+ const wrapper = container.firstChild;
+ expect(wrapper).toHaveStyle("gap: 10px");
+ });
+});
diff --git a/src/components/atoms/goal-item/GoalItem.tsx b/src/components/atoms/goal-item/GoalItem.tsx
index fc0a8881..07367786 100644
--- a/src/components/atoms/goal-item/GoalItem.tsx
+++ b/src/components/atoms/goal-item/GoalItem.tsx
@@ -33,7 +33,6 @@ export default function GoalItem({
width: iconSize === "lg" ? 40 : 24,
height: iconSize === "lg" ? 40 : 24,
alt: "flag-goal",
- layout: "fixed",
};
return (
diff --git a/src/components/atoms/input/Input.test.tsx b/src/components/atoms/input/Input.test.tsx
new file mode 100644
index 00000000..a18710bb
--- /dev/null
+++ b/src/components/atoms/input/Input.test.tsx
@@ -0,0 +1,46 @@
+import "@testing-library/jest-dom";
+
+import { fireEvent, render, screen } from "@testing-library/react";
+
+import RefInput from "./Input";
+
+describe("RefInput Component", () => {
+ test("기본 렌더링 확인", () => {
+ render();
+
+ const input = screen.getByPlaceholderText("Enter text");
+
+ expect(input).toBeInTheDocument();
+ });
+
+ test("size props에 따라 클래스가 적용되는지 확인", () => {
+ render();
+ const input = screen.getByPlaceholderText("Large input");
+
+ expect(input).toHaveClass("w-[612px] h-[48px] text-base");
+ });
+
+ test("사용자 정의 className이 올바르게 적용되는지 확인", () => {
+ render();
+ const input = screen.getByPlaceholderText("text");
+
+ expect(input).toHaveClass("custom-class");
+ });
+
+ test("placeholder가 올바르게 표시되는지 확인", () => {
+ render();
+ const input = screen.getByPlaceholderText("Test Placeholder");
+
+ expect(input).toBeInTheDocument();
+ });
+
+ test("입력값이 정상적으로 반영되는지 확인", () => {
+ render();
+ const input = screen.getByRole("textbox");
+
+ // 값 입력
+ fireEvent.change(input, { target: { value: "Hello, World!" } });
+
+ expect(input).toHaveValue("Hello, World!");
+ });
+});
diff --git a/src/components/atoms/input/Input.tsx b/src/components/atoms/input/Input.tsx
index 986a293b..1a9f5c39 100644
--- a/src/components/atoms/input/Input.tsx
+++ b/src/components/atoms/input/Input.tsx
@@ -32,18 +32,15 @@ type InputElementProps = Omit<
const RefInput = forwardRef(
({ className, size, ...props }, ref) => {
- const sizeProps = typeof size === "number" ? { size } : {};
-
return (
);
diff --git a/src/components/atoms/spinner/Spinner.tsx b/src/components/atoms/spinner/Spinner.tsx
index f842b793..17c878bd 100644
--- a/src/components/atoms/spinner/Spinner.tsx
+++ b/src/components/atoms/spinner/Spinner.tsx
@@ -12,7 +12,6 @@ export default function Spinner({ size }: SpinnerProps) {
alt="spinner"
width={size}
height={size}
- layout="fixed"
/>
);
diff --git a/src/components/atoms/title-with-icon/TitleWithIcon.tsx.tsx b/src/components/atoms/title-with-icon/TitleWithIcon.tsx.tsx
index 0375f9f6..a2dbf7ff 100644
--- a/src/components/atoms/title-with-icon/TitleWithIcon.tsx.tsx
+++ b/src/components/atoms/title-with-icon/TitleWithIcon.tsx.tsx
@@ -22,7 +22,6 @@ export default function TitleWithIcon({
width: iconSize === "lg" ? 40 : 24,
height: iconSize === "lg" ? 40 : 24,
alt: `${imgUrl}`,
- layout: "fixed",
};
return (
diff --git a/src/utils/formatDate/formatDate.test.ts b/src/utils/formatDate/formatDate.test.ts
index d626f68a..c4fde667 100644
--- a/src/utils/formatDate/formatDate.test.ts
+++ b/src/utils/formatDate/formatDate.test.ts
@@ -35,6 +35,19 @@ describe("formatDate 함수 테스트", () => {
);
});
+ test("빈 값 입력 시 빈 문자열 반환", () => {
+ expect(formatDate(undefined)).toBe("");
+ });
+
+ test("지원되지 않는 타입 입력 시 예외 발생", () => {
+ const invalidInputs = [{}, [], true];
+ invalidInputs.forEach((input) => {
+ expect(() => formatDate(input as never)).toThrow(
+ "유효하지 않은 날짜 형식입니다.",
+ );
+ });
+ });
+
test("숫자 범위를 초과하는 타임스탬프를 입력하면 예외를 발생", () => {
expect(() => formatDate(9999999999999999)).toThrow(
"유효하지 않은 날짜 형식입니다.",
diff --git a/src/views/dashboard/goal-based-todo/components/GoalItem.tsx b/src/views/dashboard/goal-based-todo/components/GoalItem.tsx
index 844631bd..92b05a87 100644
--- a/src/views/dashboard/goal-based-todo/components/GoalItem.tsx
+++ b/src/views/dashboard/goal-based-todo/components/GoalItem.tsx
@@ -64,7 +64,6 @@ export default function GoalItem({ goal }: GoalItemProps) {
alt={"arrow_right"}
width={20}
height={20}
- layout="fixed"
/>
diff --git a/src/views/note/note-detail/components/LinkItem.tsx b/src/views/note/note-detail/components/LinkItem.tsx
index e1defb56..41c79199 100644
--- a/src/views/note/note-detail/components/LinkItem.tsx
+++ b/src/views/note/note-detail/components/LinkItem.tsx
@@ -17,13 +17,7 @@ export default function LinkItem({ linkUrl, setIsEmbedOpen }: LinkItemProps) {
onClick={toggleEmbed}
className="flex cursor-pointer items-center gap-2 rounded-[20px] bg-slate-200 px-[6px] py-1 hover:brightness-95"
>
-
+
{linkUrl}