Skip to content

Commit 427bcbd

Browse files
authored
Merge pull request team-wedding#169 from team-wedding/develop
Develop
2 parents f4f1423 + 7e8ddb9 commit 427bcbd

175 files changed

Lines changed: 8924 additions & 4237 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,10 @@ dist-ssr
2727

2828
# Sentry Config File
2929
.env.sentry-build-plugin
30+
31+
*storybook.log
32+
storybook-static
33+
34+
#Playwright test Results
35+
test-results
36+
test-value

.storybook/main.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { StorybookConfig } from '@storybook/react-vite';
2+
3+
const config: StorybookConfig = {
4+
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
5+
addons: [
6+
'@chromatic-com/storybook',
7+
'@storybook/addon-docs',
8+
'@storybook/addon-a11y',
9+
'@storybook/addon-postcss',
10+
],
11+
framework: { name: '@storybook/react-vite', options: {} },
12+
};
13+
export default config;

.storybook/preview.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { Preview } from '@storybook/react-vite';
2+
import '../src/styles/global.css';
3+
4+
const preview: Preview = {
5+
parameters: {
6+
backgrounds: {
7+
default: 'light',
8+
values: [
9+
{ name: 'light', value: '#ffffff' },
10+
{ name: 'dark', value: '#333333' },
11+
],
12+
},
13+
controls: {
14+
matchers: {
15+
color: /(background|color)$/i,
16+
date: /Date$/i,
17+
},
18+
},
19+
},
20+
};
21+
22+
export default preview;

e2e/createInvitation.spec.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// e2e/createInvitation.spec.ts
2+
import { test, expect } from '@playwright/test';
3+
4+
test.describe('CreateInvitationPage', () => {
5+
test.beforeEach(async ({ page }) => {
6+
// 로그인 후 초대장 생성 페이지로 이동
7+
await page.goto('/login');
8+
//하드 코딩 되어있는 테스트용 계정 로그인 정보
9+
await page.fill('input[name="email"]', 'testuser@example.com');
10+
await page.fill('input[name="password"]', ' TestPassword123!');
11+
await page.click('button[type="submit"]');
12+
//하드 코딩 되어있는 invitationID
13+
await page.goto('/create/129');
14+
});
15+
16+
test('초기 렌더링 및 필수 입력값 검증', async ({ page }) => {
17+
await expect(page.getByLabel('이름')).toBeVisible();
18+
await expect(page.getByLabel('날짜')).toBeVisible();
19+
// await expect(page.getByText('이름을 입력하세요')).toBeVisible();
20+
// await expect(page.getByText('날짜를 입력하세요')).toBeVisible();
21+
});
22+
23+
// test('이미지 업로드', async ({ page }) => {
24+
// const filePath = 'src/assets/image/wedding1.png';
25+
// await page.setInputFiles('input[type="file"]', filePath);
26+
// await expect(page.locator('.image-preview')).toBeVisible();
27+
// });
28+
29+
// test('음악/테마 선택', async ({ page }) => {
30+
// await page.selectOption('select[name="music"]', 'aBeautifulPlan');
31+
// await page.selectOption('select[name="theme"]', 'classic');
32+
// await expect(page.getByText('aBeautifulPlan')).toBeVisible();
33+
// await expect(page.getByText('classic')).toBeVisible();
34+
// });
35+
36+
test('초대장 미리보기', async ({ page }) => {
37+
await page.fill('input[name="name"]', '테스트 초대장');
38+
await page.fill('input[name="date"]', '2024-12-31');
39+
await page.click('button.preview');
40+
await expect(page.getByText('테스트 초대장')).toBeVisible();
41+
await expect(page.getByText('2024-12-31')).toBeVisible();
42+
});
43+
44+
// test('초대장 생성 성공', async ({ page }) => {
45+
// await page.fill('input[name="name"]', '테스트 초대장');
46+
// await page.fill('input[name="date"]', '2024-12-31');
47+
// await page.fill('input[name="location"]', '서울');
48+
// await page.click('button[type="submit"]');
49+
// await expect(page).toHaveURL('/dashboard');
50+
// await expect(page.getByText('초대장이 생성되었습니다')).toBeVisible();
51+
// });
52+
53+
// test('취소/초기화 동작', async ({ page }) => {
54+
// await page.fill('input[name="name"]', '임시 입력');
55+
// await page.click('button.cancel');
56+
// await expect(page.getByLabel('이름')).toHaveValue('');
57+
// });
58+
});

e2e/dashboard.spec.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// e2e/dashboard.spec.ts
2+
import { test, expect } from '@playwright/test';
3+
4+
test.describe('DashBoardPage', () => {
5+
test.beforeEach(async ({ page }) => {
6+
// 로그인 후 대시보드로 이동 (로그인 경로/방식에 따라 수정)
7+
await page.goto('/login');
8+
//하드 코딩 되어있는 테스트용 계정 로그인 정보
9+
await page.fill('input[name="email"]', 'testuser@example.com');
10+
await page.fill('input[name="password"]', 'TestPassword123!');
11+
await page.click('button[type="submit"]');
12+
await page.waitForURL('/dashboard');
13+
});
14+
15+
test('초기 렌더링 및 주요 섹션 확인', async ({ page }) => {
16+
await expect(page.getByText('아직 저장된 청첩장이 없어요')).toBeVisible();
17+
await expect(page.getByText('청첩장 만들기')).toBeVisible();
18+
});
19+
20+
test('만들기 페이지로 이동', async ({ page }) => {
21+
await expect(page.getByText('청첩장 만들기')).toBeVisible();
22+
await page.getByText('청첩장 만들기').click();
23+
await page.fill('input[name="invitation-title"]', '친구용 청첩장');
24+
await page.getByTestId('title-submit').click();
25+
await page.waitForURL((url) => url.pathname.startsWith('/create/'));
26+
});
27+
28+
// test('초대장 목록이 보이고, 상세 진입 가능', async ({ page }) => {
29+
// const invitation = page.locator('.invitation-item').first();
30+
// await expect(invitation).toBeVisible();
31+
// await invitation.click();
32+
// await expect(page).toHaveURL(/\/invitation\/\d+/);
33+
// });
34+
35+
// test('초대장 삭제', async ({ page }) => {
36+
// const deleteButton = page.locator('.invitation-item .delete-btn').first();
37+
// await deleteButton.click();
38+
// await expect(page.getByText('정말 삭제하시겠습니까?')).toBeVisible();
39+
// await page.click('button.confirm-delete');
40+
// await expect(deleteButton).not.toBeVisible();
41+
// });
42+
43+
// test('에러/로딩 처리', async ({ page }) => {
44+
// // 네트워크 차단 등으로 에러 상황을 시뮬레이션할 수 있음
45+
// // 예시: await page.route('/api/invitations', route => route.abort());
46+
// // await page.reload();
47+
// // await expect(page.getByText('에러')).toBeVisible();
48+
// });
49+
50+
// test('로그아웃 동작', async ({ page }) => {
51+
// await page.click('button.logout');
52+
// await expect(page).toHaveURL('/login');
53+
// });
54+
});

e2e/signup.spec.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
// 회원가입 E2E 테스트
4+
5+
test('회원가입 후 /dashboard 진입', async ({ page }) => {
6+
// 1. 메인 페이지 접속
7+
await page.goto('http://localhost:5173/');
8+
9+
// 2. "시작하기" 버튼 클릭
10+
await page.getByRole('button', { name: '시작하기' }).click();
11+
12+
// 3. "회원가입" 링크 클릭
13+
await page.getByRole('link', { name: '회원가입' }).click();
14+
15+
// 4. 회원정보 입력
16+
await page.getByRole('textbox', { name: '이름' }).fill('테스트유저');
17+
// 이메일은 매번 다르게 생성 (중복 방지)
18+
const email = `testuser6@example.com`;
19+
await page.getByRole('textbox', { name: '이메일' }).fill(email);
20+
await page
21+
.getByRole('textbox', { name: '비밀번호', exact: true })
22+
.fill('TestPassword123!');
23+
await page
24+
.getByRole('textbox', { name: '비밀번호 확인' })
25+
.fill('TestPassword123!');
26+
27+
// 5. "회원가입" 버튼 클릭
28+
await page.getByRole('button', { name: '회원가입' }).click();
29+
30+
// 6. /dashboard로 이동하는지 확인 (자동 로그인 또는 리다이렉트)
31+
await page.waitForTimeout(1000); // 네트워크/애니메이션 대기
32+
await expect(page).toHaveURL(/.*login/);
33+
34+
// 7. 로그인 페이지에서 이메일과 비밀번호 입력
35+
await page.getByRole('textbox', { name: '이메일' }).fill(email);
36+
await page
37+
.getByRole('textbox', { name: '비밀번호', exact: true })
38+
.fill('TestPassword123!');
39+
40+
// 8. "로그인" 버튼 클릭
41+
await page.getByRole('button', { name: '로그인' }).click();
42+
43+
await page.waitForTimeout(1000); // 네트워크/애니메이션 대기
44+
await expect(page).toHaveURL(/.*dashboard/);
45+
await page.context().storageState({ path: 'auth.json' });
46+
});

eslint.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format
2+
import storybook from 'eslint-plugin-storybook';
3+
14
import ts from '@typescript-eslint/eslint-plugin';
25
import tsParser from '@typescript-eslint/parser';
36
import react from 'eslint-plugin-react';
@@ -32,4 +35,5 @@ export default [
3235
},
3336
},
3437
prettier,
38+
...storybook.configs['flat/recommended'],
3539
];

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
</head>
1818
<body>
1919
<div id="root"></div>
20+
<div id="modal-root"></div>
2021
<script type="module" src="/src/main.tsx"></script>
2122
</body>
2223
</html>

0 commit comments

Comments
 (0)