diff --git a/src/certificate.tsx b/src/certificate.tsx index a14700c4..69c4c53d 100644 --- a/src/certificate.tsx +++ b/src/certificate.tsx @@ -1,10 +1,13 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import Certificate from "./components/Certificate/Certificate"; +import Layout from "./components/Layout/Layout"; import "./index.css"; createRoot(document.getElementById("root")!).render( - + + + , ); diff --git a/src/components/Certificate/Certificate.test.tsx b/src/components/Certificate/Certificate.test.tsx index e290f4b7..9f42932f 100644 --- a/src/components/Certificate/Certificate.test.tsx +++ b/src/components/Certificate/Certificate.test.tsx @@ -1,12 +1,11 @@ -import { afterAll, expect, test, vi } from "vitest"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; +import { afterAll, expect, test, vi } from "vitest"; import { mock } from "vitest-mock-extended"; +import { Member } from "../../api/services/types"; import useMembers from "../../hooks/useMembers"; - import Certificate from "./Certificate"; -import { Member } from "../../api/services/types"; vi.mock("../../hooks/useMembers"); @@ -48,24 +47,6 @@ test("render the error message while fetching members", () => { expect(screen.getByText(/error/i)).toBeInTheDocument(); }); -test("renders the page header", () => { - vi.mocked(useMembers).mockReturnValue( - mock({ - isLoading: false, - error: null, - members: [], - totalCohorts: 0, - filter: { name: "", cohort: null }, - setFilter: vi.fn(), - }), - ); - - render(); - - const header = screen.getByRole("banner"); - expect(header).toBeInTheDocument(); -}); - test("render page title", () => { vi.mocked(useMembers).mockReturnValue( mock({ @@ -233,19 +214,3 @@ test("render LinkedIn link", () => { `https://www.linkedin.com/profile/add?startTask=CERTIFICATION_NAME&name=${members[0].name}&organizationId=104834174&certUrl=${location.href}`, ); }); - -test("render footer", () => { - vi.mocked(useMembers).mockReturnValue( - mock({ - isLoading: false, - error: null, - members: [mock()], - totalCohorts: 0, - filter: { name: "", cohort: null }, - setFilter: vi.fn(), - }), - ); - render(); - - expect(screen.getByRole("contentinfo", { name: "Site Footer" })); -}); diff --git a/src/components/Certificate/Certificate.tsx b/src/components/Certificate/Certificate.tsx index 79f330cd..39581276 100644 --- a/src/components/Certificate/Certificate.tsx +++ b/src/components/Certificate/Certificate.tsx @@ -2,8 +2,6 @@ import { getMembers } from "../../api/getMembers"; import useMembers from "../../hooks/useMembers"; import Signature from "../../assets/signature.png"; -import Footer from "../Footer/Footer"; -import Header from "../Header/Header"; import Link from "../Link/Link"; import Button from "../Button/Button"; @@ -25,7 +23,6 @@ export default function Certificate() { return (
-

수료증

@@ -350,7 +347,6 @@ export default function Certificate() {
-
); } diff --git a/src/components/Layout/Layout.module.css b/src/components/Layout/Layout.module.css new file mode 100644 index 00000000..585ebfdc --- /dev/null +++ b/src/components/Layout/Layout.module.css @@ -0,0 +1,4 @@ +.layout { + display: flex; + flex-direction: column; +} diff --git a/src/components/Layout/Layout.stories.tsx b/src/components/Layout/Layout.stories.tsx new file mode 100644 index 00000000..2574b63e --- /dev/null +++ b/src/components/Layout/Layout.stories.tsx @@ -0,0 +1,19 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import Layout from "./Layout"; + +const meta = { + component: Layout, +} satisfies Meta; + +export default meta; + +export const Default: StoryObj = { + args: { + children: ( +
+

👋 Welcome to the Layout component!

+

This is the main content area.

+
+ ), + }, +}; diff --git a/src/components/Layout/Layout.test.tsx b/src/components/Layout/Layout.test.tsx new file mode 100644 index 00000000..9bdcc884 --- /dev/null +++ b/src/components/Layout/Layout.test.tsx @@ -0,0 +1,36 @@ +import { render, screen } from "@testing-library/react"; +import { expect, test } from "vitest"; +import Layout from "./Layout"; + +test("renders the Header component", () => { + render( + +
Main Content
+
, + ); + + const header = screen.getByRole("banner"); + expect(header).toBeInTheDocument(); +}); + +test("renders the Footer component", () => { + render( + +
Main Content
+
, + ); + + expect(screen.getByRole("contentinfo", { name: "Site Footer" })); +}); + +test("renders children passed to the Layout component", () => { + render( + +
Main Content
+
, + ); + + const content = screen.getByTestId("content"); + expect(content).toBeInTheDocument(); + expect(content).toHaveTextContent("Main Content"); +}); diff --git a/src/components/Layout/Layout.tsx b/src/components/Layout/Layout.tsx new file mode 100644 index 00000000..fe06b043 --- /dev/null +++ b/src/components/Layout/Layout.tsx @@ -0,0 +1,18 @@ +import type { ReactNode } from "react"; + +import Footer from "../Footer/Footer"; +import Header from "../Header/Header"; + +interface LayoutProps { + children: ReactNode; +} + +export default function Layout({ children }: LayoutProps) { + return ( + <> +
+ {children} +