Skip to content
Merged
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
9 changes: 6 additions & 3 deletions src/app/message/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,22 @@ const FOLLOWING_LIST = [
{
id: 1,
name: '신짱구',
profileImage: '',
profileImage:
'https://images.unsplash.com/photo-1714635218254-740bad86a0e8?q=80&w=765&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
profileMessage: '안녕하세요 신짱구입니다',
},
{
id: 2,
name: '신짱구',
profileImage: '',
profileImage:
'https://images.unsplash.com/photo-1714635218254-740bad86a0e8?q=80&w=765&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
profileMessage: '안녕하세요 신짱구입니다',
},
{
id: 3,
name: '신짱구',
profileImage: '',
profileImage:
'https://images.unsplash.com/photo-1714635218254-740bad86a0e8?q=80&w=765&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
profileMessage: '안녕하세요 신짱구입니다',
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,29 @@ const meta = {
component: FollowingCard,
parameters: {
layout: 'padded',
nextjs: {
appDirectory: true,
navigation: {
pathname: '/',
},
},
},
tags: ['autodocs'],
} satisfies Meta<typeof FollowingCard>;

export default meta;
type Story = StoryObj<typeof meta>;

const baseArgs = {
id: 0,
name: '신짱구',
profileImage:
'https://images.unsplash.com/photo-1714635218254-740bad86a0e8?q=80&w=765&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
};

export const FollowingCardTable: Story = {
args: {
id: 0,
name: '',
profileImage: '',
profileMessage: '',
Expand All @@ -36,8 +50,7 @@ export const FollowingCardTable: Story = {
<td className='p-4 align-top text-sm text-gray-600'>기본 팔로잉 카드</td>
<td className='p-4'>
<FollowingCard
name='얼룩말'
profileImage='https://cdn.pixabay.com/photo/2025/11/28/15/29/zebras-9983175_1280.jpg'
{...baseArgs}
profileMessage='안녕하세요! 반갑습니다 😊'
type='following'
/>
Expand All @@ -50,8 +63,7 @@ export const FollowingCardTable: Story = {
</td>
<td className='p-4'>
<FollowingCard
name='얼룩말'
profileImage='https://cdn.pixabay.com/photo/2025/11/28/15/29/zebras-9983175_1280.jpg'
{...baseArgs}
profileMessage='안녕하세요 안녕하세요 안녕하세요 안녕하세요 안녕하세요 안녕하세요 안녕하세요 안녕하세요'
type='following'
/>
Expand All @@ -62,9 +74,8 @@ export const FollowingCardTable: Story = {
<td className='p-4 align-top text-sm text-gray-600'>읽지 않은 메시지 없음</td>
<td className='p-4'>
<FollowingCard
{...baseArgs}
count={0}
name='얼룩말'
profileImage='https://cdn.pixabay.com/photo/2025/11/28/15/29/zebras-9983175_1280.jpg'
profileMessage='알림 0개 테스트'
type='message'
/>
Expand All @@ -75,9 +86,8 @@ export const FollowingCardTable: Story = {
<td className='p-4 align-top text-sm text-gray-600'>읽지 않은 메시지 1개</td>
<td className='p-4'>
<FollowingCard
{...baseArgs}
count={1}
name='얼룩말'
profileImage='https://cdn.pixabay.com/photo/2025/11/28/15/29/zebras-9983175_1280.jpg'
profileMessage='알림 1개 테스트'
type='message'
/>
Expand All @@ -88,9 +98,8 @@ export const FollowingCardTable: Story = {
<td className='p-4 align-top text-sm text-gray-600'>읽지 않은 메시지 10개</td>
<td className='p-4'>
<FollowingCard
{...baseArgs}
count={10}
name='얼룩말'
profileImage='https://cdn.pixabay.com/photo/2025/11/28/15/29/zebras-9983175_1280.jpg'
profileMessage='알림 10개 테스트'
type='message'
/>
Expand All @@ -101,9 +110,8 @@ export const FollowingCardTable: Story = {
<td className='p-4 align-top text-sm text-gray-600'>읽지 않은 메시지 99개 이상</td>
<td className='p-4'>
<FollowingCard
{...baseArgs}
count={100}
name='얼룩말'
profileImage='https://cdn.pixabay.com/photo/2025/11/28/15/29/zebras-9983175_1280.jpg'
profileMessage='알림 100개 테스트'
type='message'
/>
Expand Down
43 changes: 26 additions & 17 deletions src/components/pages/message/message-following-card/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
import { useRouter } from 'next/navigation';

import { fireEvent, render, screen } from '@testing-library/react';

import { FollowingCard } from '.';

jest.mock('next/navigation', () => ({
useRouter: jest.fn(),
}));
const defaultProps = {
id: 0,
name: '얼룩말',
profileImage: '/test.png',
profileMessage: '안녕하세요!',
};
const routerPush = jest.fn();

describe('FollowingCard 컴포넌트 테스트', () => {
const defaultProps = {
name: '얼룩말',
profileImage: '/test.png',
profileMessage: '안녕하세요!',
};
beforeEach(() => {
// 각 테스트 전에 mock 초기화
jest.clearAllMocks();
(useRouter as jest.Mock).mockReturnValue({
push: routerPush,
});
});

test('type=following 일 때 테스트', () => {
render(<FollowingCard {...defaultProps} type='following' />);
Expand Down Expand Up @@ -40,33 +55,27 @@ describe('FollowingCard 컴포넌트 테스트', () => {
expect(screen.getByText('99+')).toBeInTheDocument();
});

test('팔로잉 카드 클릭 시 onClick 호출되는지 테스트.', () => {
const handleClick = jest.fn();
render(<FollowingCard {...defaultProps} type='following' onClick={handleClick} />);
test('팔로잉 카드 클릭 시 router.push() 호출되는지 테스트.', () => {
render(<FollowingCard {...defaultProps} type='following' />);

const card = screen.getByTestId('following-card');

fireEvent.click(card);
expect(handleClick).toHaveBeenCalledTimes(1);
expect(routerPush).toHaveBeenCalledTimes(1);
expect(routerPush).toHaveBeenCalledWith('/profile/0');
});

test('팔로잉 카드의 메시지 버튼 클릭 시 onMessageClick만 호출되는지 테스트.', () => {
const handleClick = jest.fn();
const handleMessageClick = jest.fn();

render(
<FollowingCard
{...defaultProps}
type='following'
onClick={handleClick}
onMessageClick={handleMessageClick}
/>,
<FollowingCard {...defaultProps} type='following' onMessageClick={handleMessageClick} />,
);

const button = screen.getByText('메세지');
fireEvent.click(button);

expect(handleMessageClick).toHaveBeenCalledTimes(1);
expect(handleClick).not.toHaveBeenCalled(); // 이벤트 버블 막힘 확인
expect(routerPush).not.toHaveBeenCalled(); // 이벤트 버블 막힘 확인
});
});
11 changes: 8 additions & 3 deletions src/components/pages/message/message-following-card/index.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
import Image from 'next/image';
import { useRouter } from 'next/navigation';

import { cn } from '@/lib/utils';

interface FollowingCardProps {
id: number;
name: string;
profileImage: string;
profileMessage: string;
type: 'following' | 'message';
count?: number;
onClick?: () => void;
onMessageClick?: () => void;
}

export const FollowingCard = ({
id,
name,
profileImage,
profileMessage,
type,
count = 0,
onClick,
onMessageClick,
}: FollowingCardProps) => {
const router = useRouter();
const handleClick = () => {
router.push(`/profile/${id}`);
};
return (
<div
Copy link
Member

Choose a reason for hiding this comment

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

지금 카드가 div로 되어 있는데, 스크린리더에서는 텍스트 콘텐츠만 알리고 클릭 가능한 요소로 인식이 안되거나, 키보드(Tab, Enter, Space 등)으로 접근이 어려울 수 있어요.
지금 당장 필요하거나 중요한 사항은 아니니 나중에 리팩토링 할 때 고려해 보는 것도 좋을 거 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

좋은 지적 감사합니다!!

data-testid='following-card'
className='flex cursor-pointer items-center gap-3 bg-white p-5'
onClick={onClick}
onClick={handleClick}
>
<Image
width={48}
Expand Down
16 changes: 16 additions & 0 deletions src/components/pages/message/message-following-list/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,43 @@
import { useRouter } from 'next/navigation';

import { render, screen } from '@testing-library/react';

import { FollowingList } from '.';

const TEST_ITEMS = [
{
id: 0,
name: '신짱구',
profileImage: 'http://test.com',
profileMessage: '안녕하세요 신짱구입니다',
},
{
id: 1,
name: '김맹구',
profileImage: 'http://test.com',
profileMessage: '안녕하세요 김맹구입니다',
},

{
id: 2,
name: '흰둥이',
profileImage: 'http://test.com',
profileMessage: '안녕하세요 흰둥이입니다',
},
];
jest.mock('next/navigation', () => ({
useRouter: jest.fn(),
}));

describe('Following List 컴포넌트 테스트', () => {
beforeEach(() => {
// 각 테스트 전에 mock 초기화
jest.clearAllMocks();
(useRouter as jest.Mock).mockReturnValue({
push: jest.fn(),
});
});

test('모든 아이템이 렌더링 되는지 테스트', () => {
render(<FollowingList items={TEST_ITEMS} />);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const FollowingList = ({ items }: FollowingListProps) => {
{items.map((item) => (
<FollowingCard
key={item.id}
id={item.id}
name={item.name}
profileImage={item.profileImage}
profileMessage={item.profileMessage}
Expand Down