Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: storybook 테스트 초기 셋팅 및 예제 코드 추가 #227

Merged
merged 10 commits into from
Nov 27, 2024

Conversation

aquaman122
Copy link
Contributor

@aquaman122 aquaman122 commented Nov 26, 2024

💡 작업 내용

  • storybook 테스트 초기 셋팅 및 예제 코드 추가
  • 경매목록 찜 테스트 오류 수정
  • storybook 초기 세팅

💡 자세한 설명

스토리북의 장점

시각적 테스트

각각의 스토리를 통해 컴포넌트들의 props를 직접 조각하며 시각적으로 확인할 수 있는 환경을 제공한다.
다양한 상태에서 컴포넌트가 어떻게 보이는지 미리 확인하여 디자인의 일관성을 유지할 수 있도록 돕는다.
두 눈으로 확인시켜 주는게 가장 큰 장점이다.

독립적인 분리

대규모작업에서 공통적으로 사용하는 컴포넌트들을 정의해 스토리북에 등록하려 한다면, 도메인에 상관없이 어떠한 프로젝트에서도 사용할 수 있어야한다.
그러기 위해선 컴포넌트는 특정 관심사와 의존성들을 모두 제거해 범용성이 높고 독립적이어야 한다.

유지보수

컴포넌트가 독립적이라는 것은 코드를 집중화해, 한 곳에서 관리할 수 있다는 엄청난 장점이 있다.
이에 집중화 된 코드를 배포 후 철저한 버전관리를 함으로써 일관성 있는 유지보수가 가능해진다.

문서화

스토리북은 컴포넌트에 대한 문서를 자동으로 생성하며, 사용자에게 컴포넌트의 Props와 사용법, 예제를 쉽게 제공할 수 있다.
그렇기에 내가 만들거나 다른 사람이 만든 컴포넌트들을 더 쉽게 확인하고 사용할 수 있다.

🛠️ 예제 컴포넌트 테스트 ProductItem.stoires.tsx 추가

// components/product/ui/productItem.stories.tsx
import { Meta, StoryObj } from '@storybook/react';
import ProductItem from './ProductItem';
import { Price, LikeCount } from '@/shared/ui';

const meta: Meta<typeof ProductItem> = {
  title: 'Components/ProductItem',
  component: ProductItem,
  argTypes: {
    onClick: { action: 'clicked' },
  },
};

export default meta;

type Story = StoryObj<typeof ProductItem>;

export const Default: Story = {
  args: {
    product: {
      id: 1,
      productName: '테스트 상품',
      minPrice: 50000,
      timeRemaining: 3600,
      participantCount: 10,
      likeCount: 5,
      isLiked: false,
      status: 'active',
      createdAt: '2024-01-01T00:00:00',
      imageUrl: 'https://via.placeholder.com/150',
    },
    children: (
      <>
        <Price title="시작가" price={50000} />
        <LikeCount count={5} />
      </>
    ),
  },
};

export const Liked: Story = {
  args: {
    product: {
      id: 2,
      productName: '좋아요 상품',
      minPrice: 100000,
      timeRemaining: 3600,
      participantCount: 15,
      likeCount: 10,
      isLiked: true,
      status: 'active',
      createdAt: '2024-01-01T00:00:00',
      imageUrl: 'https://via.placeholder.com/150',
    },
    children: (
      <>
        <Price title="시작가" price={100000} />
        <LikeCount count={10} />
      </>
    ),
  },
};

🛠️ 컴포넌트 테스트 코드 추가

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { MemoryRouter } from "react-router-dom";
import { describe, expect, test, vi } from "vitest";
import ProductItem from "../ui/ProductItem";

// scrollIntoView 메서드가 jsdom에 지원되지 않아서 오류 발생
Object.defineProperty(Element.prototype, 'hasPointerCapture', {
  value: () => false,
});

Object.defineProperty(Element.prototype, 'setPointerCapture', {
  value: () => {},
});

Object.defineProperty(Element.prototype, 'scrollIntoView', {
  value: () => {},
})


const mockProduct = {
  id: 1,
  productName: "테스트 상품",
  minPrice: 30000,
  timeRemaining: 3600,
  likeCount: 10,
  isLiked: false,
  imageUrl: "https://via.placeholder.com/150",
};

describe("ProductItem 컴포넌트 테스트", () => {
  const setup = (overrides = {}) => {
    const props = {
      product: { ...mockProduct, ...overrides },
      onClick: vi.fn(),
      children: <p>추가 정보</p>,
    };

    const user = userEvent.setup();
    render(
      <MemoryRouter>
        <ProductItem {...props} />
      </MemoryRouter>
    );

    return { props, user };
  };

  test("기본 렌더링 확인", () => {
    setup();

    const productImage = screen.getByAltText("테스트 상품");
    expect(productImage).toBeInTheDocument();
    expect(productImage).toHaveAttribute("src", "https://via.placeholder.com/150");

    const productName = screen.getByText("테스트 상품");
    expect(productName).toBeInTheDocument();

    // 금액 확인 테스트코드 추가해야 함

    // 좋아요 카운터 테스트코드 추가해야 함

    const additionalInfo = screen.getByText("추가 정보");
    expect(additionalInfo).toBeInTheDocument();
  });

  test("onClick 이벤트 확인", async () => {
    const { props, user } = setup();

    const productItem = screen.getByRole("img", { name: "테스트 상품" });
    await user.click(productItem);

    expect(props.onClick).toHaveBeenCalled();
  });

  // 좋아요 버튼 상태 확인 테스트 코드 추가해야함

  test("남은 시간이 표시되는지 확인", () => {
    setup();

    const timeLabel = screen.getByText((content, element) => {
      return content.includes("1시간 남음") && element?.tagName === "P";
    });
    expect(timeLabel).toBeInTheDocument();
  });

  test("이미지 대체 텍스트가 없는 경우 기본값 표시", () => {
    setup({ productName: undefined });

    const productImage = screen.getByAltText("제품 사진");
    expect(productImage).toBeInTheDocument();
  });
});

📗 참고 자료 (선택)

✅ 셀프 체크리스트

  • PR 제목을 형식에 맞게 작성했나요?
  • 브랜치 전략에 맞는 브랜치에 PR을 올리고 있나요? (master/main이 아닙니다.)
  • 이슈는 close 했나요?
  • Reviewers, Labels, Projects를 등록했나요?
  • 작업 도중 문서 수정이 필요한 경우 잘 수정했나요?
  • 테스트는 잘 통과했나요?
  • 불필요한 코드는 제거했나요?

closes #이슈번호

@aquaman122 aquaman122 added ✨feature 구현, 개선 사항 관련 부분 👩🏻‍💻frontend 프론트엔드 작업 labels Nov 26, 2024
@aquaman122 aquaman122 self-assigned this Nov 26, 2024
Copy link
Contributor

@CLOUDoort CLOUDoort left a comment

Choose a reason for hiding this comment

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

확인했습니다!

Object.defineProperty(Element.prototype, 'scrollIntoView', {
value: () => {},
})

Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분은 Register.test.tsxAddress.test.tsx랑 겹치네요!
setupTest.tsx에서 설정해도 좋을 것 같습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

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

오 넵! 두개 다 수정하고 병합하겠습니다!

@aquaman122 aquaman122 merged commit 9a43a86 into dev Nov 27, 2024
@aquaman122 aquaman122 deleted the fix/payment-success branch November 27, 2024 03:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨feature 구현, 개선 사항 관련 부분 👩🏻‍💻frontend 프론트엔드 작업
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants