Skip to content

Commit

Permalink
Merge pull request #32 from DaleStudy/25-button-component
Browse files Browse the repository at this point in the history
25 button component
  • Loading branch information
nhistory authored Feb 20, 2025
2 parents fe0d235 + a84896b commit b901810
Show file tree
Hide file tree
Showing 6 changed files with 437 additions and 87 deletions.
Binary file added bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function App() {
</section>
<section>
<Heading level={2}>์„น์…˜ 2</Heading>
<Button>ํด๋ฆญ</Button>
<Button variant={"solid"}>ํด๋ฆญ</Button>
</section>
</main>
<footer>
Expand Down
40 changes: 0 additions & 40 deletions src/components/Button/Button.stories.ts

This file was deleted.

115 changes: 115 additions & 0 deletions src/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "./Button";
import { vstack } from "../../../styled-system/patterns";

export default {
component: Button,
parameters: {
layout: "centered",
},
args: {
children: "์‹œ์ž‘ํ•˜๊ธฐ",
variant: "solid",
},
} satisfies Meta<typeof Button>;

export const Basic: StoryObj<typeof Button> = {};

export const Variants: StoryObj<typeof Button> = {
render: (args) => {
return (
<div className={vstack({ gap: "4" })}>
<Button {...args} variant="solid">
์†”๋ฆฌ๋“œ ๋ฒ„ํŠผ
</Button>
<Button {...args} variant="outline">
์•„์›ƒ๋ผ์ธ ๋ฒ„ํŠผ
</Button>
</div>
);
},
argTypes: {
children: {
control: false,
},
variant: {
control: false,
},
},
};

export const Tones: StoryObj<typeof Button> = {
render: (args) => {
return (
<div className={vstack({ gap: "4" })}>
<Button {...args} tone="neutral">
์ค‘๋ฆฝ ์ƒ‰์กฐ
</Button>
<Button {...args} tone="accent">
๊ฐ•์กฐ ์ƒ‰์กฐ
</Button>
<Button {...args} tone="danger">
์œ„ํ—˜ ์ƒ‰์กฐ
</Button>
<Button {...args} tone="warning">
๊ฒฝ๊ณ  ์ƒ‰์กฐ
</Button>
</div>
);
},
argTypes: {
children: {
control: false,
},
tone: {
control: false,
},
},
};

export const Sizes: StoryObj<typeof Button> = {
render: (args) => {
return (
<div className={vstack({ gap: "4" })}>
<Button {...args} size="sm">
์ž‘์€ ๋ฒ„ํŠผ
</Button>
<Button {...args} size="md">
์ค‘๊ฐ„ ๋ฒ„ํŠผ
</Button>
<Button {...args} size="lg">
ํฐ ๋ฒ„ํŠผ
</Button>
</div>
);
},
argTypes: {
children: {
control: false,
},
size: {
control: false,
},
},
};

export const Disabled: StoryObj<typeof Button> = {
render: (args) => {
return (
<div className={vstack({ gap: "4" })}>
<Button {...args} disabled>
๋น„ํ™œ์„ฑํ™” ๋ฒ„ํŠผ
</Button>
<Button {...args}>ํ™œ์„ฑํ™” ๋ฒ„ํŠผ</Button>
</div>
);
},
argTypes: {
children: {
control: false,
},
disabled: {
control: false,
},
},
};
115 changes: 100 additions & 15 deletions src/components/Button/Button.test.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,108 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { expect, describe, it, vi } from "vitest";
import { composeStories } from "@storybook/react";
import { render, screen, fireEvent } from "@testing-library/react";
import { expect, test, vi } from "vitest";
import * as stories from "./Button.stories";
import { Button } from "./Button";

describe("<Button>", () => {
it("renders a button with text", () => {
render(<Button>Click</Button>);
const { Basic, Variants, Tones, Sizes, Disabled } = composeStories(stories);

expect(screen.getByRole("button")).toHaveTextContent("Click");
});
test("renders the button with the correct text content", () => {
render(<Basic>ํ…Œ์ŠคํŠธ</Basic>);

it("calls onClick handler when clicked", async () => {
const user = userEvent.setup();
const handleClick = vi.fn();
expect(screen.getByText("ํ…Œ์ŠคํŠธ")).toBeInTheDocument();
});

test("applies the correct variant styles", () => {
render(<Variants />);

expect(screen.getByText("์†”๋ฆฌ๋“œ ๋ฒ„ํŠผ")).toHaveClass("bg_bg");
expect(screen.getByText("์•„์›ƒ๋ผ์ธ ๋ฒ„ํŠผ")).toHaveClass("bd_3px_solid");
});

test("applies the correct tone styles", () => {
render(<Tones />);

expect(screen.getByText("์ค‘๋ฆฝ ์ƒ‰์กฐ")).toHaveClass("bg_bg");
expect(screen.getByText("๊ฐ•์กฐ ์ƒ‰์กฐ")).toHaveClass("bg_bg.accent");
expect(screen.getByText("์œ„ํ—˜ ์ƒ‰์กฐ")).toHaveClass("bg_bg.danger");
expect(screen.getByText("๊ฒฝ๊ณ  ์ƒ‰์กฐ")).toHaveClass("bg_bg.warning");
});

test("applies the correct font size based on the size prop", () => {
render(<Sizes />);

expect(screen.getByText("์ž‘์€ ๋ฒ„ํŠผ")).toHaveClass("fs_sm");
expect(screen.getByText("์ค‘๊ฐ„ ๋ฒ„ํŠผ")).toHaveClass("fs_md");
expect(screen.getByText("ํฐ ๋ฒ„ํŠผ")).toHaveClass("fs_lg");
});

test("applies the correct disabled styles", () => {
render(<Disabled />);

render(<Button onClick={handleClick}>Click</Button>);
expect(screen.getByText("๋น„ํ™œ์„ฑํ™” ๋ฒ„ํŠผ")).toBeDisabled();
expect(screen.getByText("ํ™œ์„ฑํ™” ๋ฒ„ํŠผ")).toBeEnabled();
expect(screen.getByText("๋น„ํ™œ์„ฑํ™” ๋ฒ„ํŠผ")).toHaveClass("[&:disabled]:op_0.5");
});

test("renders a button with type='button' by default", () => {
render(<Basic>Default Button</Basic>);
const button = screen.getByText("Default Button");
expect(button).toHaveAttribute("type", "button");
});

await user.click(screen.getByRole("button"));
test("renders a button with type='button' by default", () => {
render(<Basic variant="solid">Default Button</Basic>);
const button = screen.getByText("Default Button");
expect(button).toHaveAttribute("type", "button");
});

test("renders a button with type='button' when specified", () => {
render(
<Button type="button" variant="solid">
Button Type Button
</Button>
);
const button = screen.getByText("Button Type Button");
expect(button).toHaveAttribute("type", "button");
});

test("renders a button with type='submit' when specified", () => {
render(
<form>
<Button type="submit" variant="solid">
Submit Type Button
</Button>
</form>
);
const button = screen.getByText("Submit Type Button");
expect(button).toHaveAttribute("type", "submit");
});

test("submits the form when type='submit' button is clicked", () => {
const handleSubmit = vi.fn();
render(
<form onSubmit={handleSubmit}>
<Button type="submit" variant="solid">
Submit Button
</Button>
</form>
);

const submitButton = screen.getByText("Submit Button");
fireEvent.click(submitButton);
expect(handleSubmit).toHaveBeenCalledTimes(1);
});

expect(handleClick).toHaveBeenCalledTimes(1);
});
test("does not submit the form when type='button' button is clicked", () => {
const handleSubmit = vi.fn();
render(
<form onSubmit={handleSubmit}>
<Button type="button" variant="solid">
Button Type Button
</Button>
</form>
);
const buttonTypeButton = screen.getByText("Button Type Button");
fireEvent.click(buttonTypeButton);
expect(handleSubmit).toHaveBeenCalledTimes(0);
});
Loading

0 comments on commit b901810

Please sign in to comment.