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
13 changes: 12 additions & 1 deletion e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ npm run e2e:ui # 에뮬레이터를 켜고 Playwright UI 창을 연

케이스를 골라 돌리기, ID·태그로 거르기, 반복 실행은 UI 창 안에서 한다.

### 클릭으로 테스트 만들기

```bash
npm run e2e:record
```

새 테스트 사용자로 로그인하고 예시 데이터(카테고리·할 일·루틴)를 넣은 홈 화면에서 멈춘다.
함께 뜨는 Playwright Inspector 에서 **Record** 를 누르고 화면을 조작하면 그 조작이 코드로 쌓인다.
코드를 복사해 케이스 설명(`cases/*.md` 형식)과 함께 넘기거나 spec 에 붙인다. 창을 닫으면 끝난다.
녹화한 코드는 `getByRole` 같은 셀렉터를 고르지만 확인(`expect`)은 넣지 않으므로, spec 으로 옮길 때 기대 결과를 더한다.

## CI

`.github/workflows/test.yml` 이 PR 과 main 푸시마다 `npm run check` 와 `npm run e2e` 를 돌린다.
Expand Down Expand Up @@ -78,7 +89,7 @@ test("TC-ROUTINE-001 ...", { tag: "@regression" }, async ({ page, signIn }) => {
역할도 이름도 없는 요소(끌기 미리보기 같은 그림)에만 `data-testid` 를 단다.
- `signIn()` 은 로그인 전용 화면을 새로 열어 로그인한다. 같은 탭에서 계정을 바꾸는 흐름처럼 새로고침 없이 이어져야 하면 `signIn({ inPlace: true })` 를 쓴다.
- 헤더 메뉴로 화면을 옮긴 직후에는 새 화면이 뜬 것을 먼저 확인한다. 다음 화면 코드를 받는 동안 이전 화면이 그대로 남아 있어, 같은 이름의 요소를 잘못 잡는다.
- 고정 대기(`waitForTimeout`)는 쓰지 않는다. `expect(...).toBeVisible()` 처럼 상태를 기다린다. 예외는 `drag.ts` 의 누르고 있기뿐이다.
- 고정 대기(`waitForTimeout`)는 쓰지 않는다. `expect(...).toBeVisible()` 처럼 상태를 기다린다.
- 화면은 저장을 기다리지 않고 먼저 바뀐다. 새로고침이나 다른 화면에서 저장을 확인하려면 먼저 `waitForSaved(page)` 를 부른다.
- 일부러 실패를 일으켜 콘솔 에러가 나는 테스트는 `test.use({ expectedError: /.../ })` 로 그 에러만 허용한다.
- 회귀 케이스를 만들면 고친 코드를 잠시 되돌려 테스트가 실제로 실패하는지 확인한다. 통과만 확인한 테스트는 아무것도 지켜 주지 않을 수 있다.
Expand Down
26 changes: 3 additions & 23 deletions e2e/TODO.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,8 @@
# 케이스 구현 전에 필요한 것
# 남은 확인 거리

케이스 후보를 뽑으며 찾은, 테스트를 막는 지점이다. 해결하면 지운다.

## 마크업에 이름 붙이기

역할이나 이름이 없어 테스트가 사람처럼 찾을 수 없는 요소. 스크린 리더 사용자도 같은 이유로 쓰기 어렵다.
P1 케이스가 거치는 요소는 이름을 붙였다. 남은 것은 P2·P3 케이스용이다.

| 위치 | 문제 | 제안 |
| --- | --- | --- |
| src/pages/HomePage/components/TitleSection.tsx:56, 59 | ◀▶ 가 `div` onClick | `button` + `aria-label="이전"`/`"다음"` |
| 같은 파일 | 섹션 제목이 heading 이 아니라 "오늘"·"새로고침" 을 섹션별로 좁혀 잡을 수 없다 | `section aria-labelledby` 로 감싸기 |
| src/pages/HomePage/components/TaskReport/modals/TaskSettingModal.tsx:101 | 선택 버튼이 빈 `button` | `role="radio"` + `aria-checked` |
| src/pages/RoutinePage/.../EndDateField.tsx:31-35 | "추가"/"삭제" 가 다른 버튼과 이름이 겹침 | `aria-label="종료 날짜 추가"` |
| src/shared/ui/notices/components/NoticeList.tsx:27 | 공지 항목이 클릭만 되는 `div` | `button` |

## seed 확장

- `category` 의 `status: "ENDED"` 와 `endedAt`
- `routine` 의 `endDate`, 여러 구간의 `scheduleHistory`
- `task` 의 `time`
- `monthlyStats`: 마이 화면 달성률과 월간 통계 회귀 케이스용
- `notice`: 최상위 `notices` 컬렉션 (모든 사용자가 함께 본다)
테스트를 만들며 찾았지만 아직 결론을 내지 못한 것이다. 해결하면 지운다.

## 확인이 필요한 앱 동작

- **다시 받아 온 집계가 진행 중인 체크 표시를 덮는다**: 체크하면 캘린더 숫자를 먼저 고쳐 두는데, 그사이 다른 곳(첫 문서 생성 뒤 재계산 등)이 월간 통계를 다시 받아 오면 고쳐 둔 값이 덮여 새로고침 전까지 옛 숫자가 보인다. 저장된 값은 맞다. 부하가 클 때 TC-HOME-004 에서 한 번 관찰했다. 체크가 끝났을 때 그사이 통계를 다시 받아 왔으면 한 번 더 받아 오는 식으로 막을 수 있으나, 재현을 고정하는 테스트를 먼저 만들어야 한다.
- 재현 시도: CPU 를 6배·10배로 늦추고 같은 조작(문서 생성 확인 → 할 일 추가 → 루틴 체크)을 56번 돌렸으나 끝까지 진행된 실행에서는 한 번도 나오지 않았다. 다시 관찰되면 그 실행의 trace(월간 통계 요청 순서)를 남겨 원인을 좁힌다.
20 changes: 10 additions & 10 deletions e2e/cases/category.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- 근거: src/shared/api/category/crud.ts:48-69

### TC-CATEGORY-002 가운데를 종료한 뒤 새로 만든 카테고리는 맨 뒤에 붙는다
- 우선순위: P2 / 태그: @regression / 상태: 제안
- 우선순위: P2 / 태그: @regression / 상태: 구현됨
- 전제: A(0), B(1), C(2)
- 절차: B 종료(확인 창에서 "종료") → D 생성
- 기대: 진행중 목록이 A, C, D
Expand Down Expand Up @@ -40,46 +40,46 @@
- 근거: CategoryModal.tsx:188, 198-215

### TC-CATEGORY-006 복구하면 진행중 목록 맨 뒤로 돌아온다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: 진행중 A, B. 종료된 C (seed 확장 필요)
- 기대: A, B, C. 종료 섹션이 비면 섹션째 사라진다
- 근거: crud.ts:119-134

### TC-CATEGORY-007 이름이 비었거나 공백뿐이면 저장되지 않는다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 기대: 공백만이면 "저장" 비활성, Enter 는 "카테고리 이름을 입력해 주세요." 21자는 20자까지만
- 근거: CategoryModal.tsx:26, 32-38, 101-106

### TC-CATEGORY-008 저장에 실패하면 토스트가 뜨고 모달이 남는다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: 쓰기 실패
- 절차: 생성 / 수정 / 종료(확인 창에서 "종료")
- 기대: 각각의 실패 토스트, 모달 유지, 목록 그대로
- 근거: CategoryModal.tsx:85-99

### TC-CATEGORY-009 순서 저장에 실패하면 원래 순서로 돌아간다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 기대: "순서 저장에 실패했습니다…" 토스트, A, B, C 로 원복
- 근거: CategorySection.tsx:94-98

### TC-CATEGORY-010 저장을 연달아 눌러도 하나만 만들어진다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: 쓰기 응답을 1초 늦춘다
- 기대: "저장 중...", 같은 이름이 1개만
- 근거: CategoryModal.tsx:67-68, 89

### TC-CATEGORY-011 수정 중에 닫으려 하면 확인을 묻는다
- 우선순위: P3 / 태그: @feature / 상태: 제안
- 기대: "수정 중인 내용이 있습니다". 공백만 덧붙였으면 묻지 않는다
- 우선순위: P3 / 태그: @feature / 상태: 구현됨
- 기대: "수정 중인 내용이 있습니다". 버리면 상세로 돌아가 이름이 그대로다. 공백만 덧붙였으면 묻지 않는다. "취소" 버튼은 묻지 않고 돌아간다
- 근거: 3100b2c, CategoryModal.tsx:73-82

### TC-CATEGORY-012 첫 사용자에게 빈 화면 안내가 보인다
- 우선순위: P3 / 태그: @feature / 상태: 제안
- 우선순위: P3 / 태그: @feature / 상태: 구현됨
- 기대: "진행중인 카테고리가 없습니다." 와 "카테고리 추가". "종료된 카테고리" 제목은 없다
- 근거: f801b9e, CategorySection.tsx:142-161

### TC-CATEGORY-013 목록을 읽지 못하면 다시 시도할 수 있다
- 우선순위: P3 / 태그: @feature / 상태: 제안
- 우선순위: P3 / 태그: @feature / 상태: 구현됨
- 전제: 첫 조회만 실패
- 기대: "카테고리를 불러오지 못했습니다." → "다시 시도" 로 목록
- 근거: CategorySection.tsx:130-139
7 changes: 4 additions & 3 deletions e2e/cases/common.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@
- 근거: src/shared/stores/authStore.ts:95-101, firestore.rules:83-87, de153af

### TC-COMMON-002 로그인한 사용자가 / 나 /login 에 가면 /home 으로 간다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 기대: 두 경우 모두 /home, "달성 현황" 이 보인다
- 근거: src/pages/LandingPage/LandingPage.tsx:22, src/pages/LoginPage/LoginPage.tsx:19
- 발견: 모바일에서 소개 화면이 자리 잡기 전이나 떠나는 순간 애니메이션 시점이 0/0 = NaN 이 되어 콘솔 에러가 나던 문제를 찾아 고쳤다(useFilmEngine.ts)

### TC-COMMON-003 공지는 고정 공지가 먼저, 상세에서 이전·다음으로 오간다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: 고정 1건, 일반 2건 (seed 확장 필요. 공지는 모든 사용자가 같이 보므로 제목에 고유값을 넣는다)
- 절차: 헤더 "공지" → 두 번째 공지 → "다음 공지" → 목록으로 → "닫기"
- 기대: 고정 공지 → 최신순. 상세 제목이 바뀌고 모달이 닫힌다
- 근거: src/shared/api/notice/queries.ts:14, src/shared/ui/notices/index.tsx:23-30

### TC-COMMON-004 푸터에서 약관으로 가고, 인스타그램은 새 창으로 열린다
- 우선순위: P3 / 태그: @feature / 상태: 제안
- 우선순위: P3 / 태그: @feature / 상태: 구현됨
- 기대: /terms 로 이동. "checky 인스타그램 (새 창)" 은 target=_blank
- 근거: src/shared/ui/Footer.tsx:21-32, 10d7c86
30 changes: 19 additions & 11 deletions e2e/cases/home.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,60 +44,60 @@
- 근거: src/pages/HomePage/components/TaskReport/hooks/useTaskModalHandlers.ts:113, :175, TaskModal.tsx (삭제 확인)

### TC-HOME-007 "이동" 으로 완료한 할 일을 다른 날로 옮긴다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: 10-21 에 완료한 할 일. today 2026-10-21
- 절차: ⋯ → "이동" → 10-23 → 확인 → 캘린더 23일 클릭
- 기대: 21일에서 사라지고 23일에 완료 상태로 보인다. 캘린더 숫자가 맞게 바뀐다
- 근거: src/pages/HomePage/components/TaskReport/hooks/useTaskDateMove.ts:42-96

### TC-HOME-008 리스트 메뉴 "미완료 할 일을 오늘 하기"
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: 10-20 에 미완료 1개, 완료 1개. today 2026-10-21
- 절차: ◀ 로 20일 → 리스트 메뉴 → 항목 선택 → "완료" → "오늘"
- 절차: ◀ 로 20일 → 리스트 메뉴 → "미완료 할 일을 오늘 하기" → "완료" → 할 일 목록 "오늘"
- 기대: 20일엔 완료만 남고 21일에 미완료 1개. 오늘 날짜에서 하면 "이미 오늘 목록입니다."
- 근거: src/pages/HomePage/components/TaskReport/sections/TaskSetting.tsx:86-130

### TC-HOME-009 "모든 할 일 삭제" 확인과 빈 대상 안내
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: (a) 할 일 2개 (b) 할 일 없음
- 절차: 리스트 메뉴 → "모든 할 일 삭제" → "완료" → 확인에서 "삭제" / "취소"
- 기대: (a) 삭제하면 목록이 비고, 취소하면 그대로 (b) "삭제할 할 일이 없습니다."
- 근거: TaskSetting.tsx:93, :243

### TC-HOME-010 한 주 보기에서 끌어 옮기면 개수와 하루 보기에 반영된다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: 10-21 에 미완료 할 일 1개. today 2026-10-21
- 절차: "한 주" → 할 일을 "10월 23일" 로 끈다 → "10월 23일 하루 보기"
- 기대: 21일 칸 "할 일 0", 23일 칸 "할 일 1", 하루 보기 23일에 보인다
- 근거: src/pages/HomePage/components/TaskReport/hooks/useTaskWeek.ts:167-215 (두 날짜 캐시를 손으로 고침)

### TC-HOME-011 끌어 옮기기에 실패하면 원래 날로 돌아간다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: TC-HOME-010 과 같고 쓰기를 실패시킨다
- 기대: "할 일 이동에 실패했습니다…" 토스트, 21일 칸으로 돌아간다
- 근거: useTaskWeek.ts:202-208

### TC-HOME-012 루틴 표 체크가 합계·캘린더에 반영된다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: 10-01 부터 매일 루틴 1개. today 2026-10-21
- 절차: 21일 칸 체크 → 새로고침
- 기대: 행 합계 "1 / 7", 합계 행 21일 "1/1", 22일 이후 "–", 캘린더 21일 완료 색. 새로고침해도 유지
- 근거: src/pages/HomePage/components/RoutineReport/hooks/useRoutineToggle.ts:43-123

### TC-HOME-013 캘린더 날짜를 누르면 모든 섹션이 그 날을 따라간다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: 10-14 에 할 일 "지난주 일". today 2026-10-21
- 절차: 캘린더 14일 → 할 일 목록 "오늘"
- 기대: 할 일·루틴 주·달성 현황이 14일 기준으로 바뀌고, "오늘" 을 누르면 21일로 돌아온다
- 기대: 할 일·루틴 주(10/11~17, 일요일 시작)·달성 현황이 14일 기준으로 바뀌고, "오늘" 을 누르면 21일로 돌아온다
- 근거: src/pages/HomePage/components/MonthlyReport/components/CalendarCell.tsx:49

### TC-HOME-014 새 사용자의 빈 상태
- 우선순위: P3 / 태그: @feature / 상태: 제안
- 우선순위: P3 / 태그: @feature / 상태: 구현됨
- 기대: "아직 카테고리가 없어요." 와 "카테고리 만들기" 링크(→ /category), 달성 현황 빈 안내
- 근거: src/pages/HomePage/components/TaskReport/sections/TaskList.tsx:35

### TC-HOME-015 루틴 목록을 불러오지 못하면 다시 시도할 수 있다
- 우선순위: P3 / 태그: @feature / 상태: 제안
- 우선순위: P3 / 태그: @feature / 상태: 구현됨
- 전제: 루틴 조회를 첫 번째만 실패시킨다
- 기대: "루틴 목록을 불러오지 못했습니다." → "다시 시도" 로 표가 보인다
- 근거: src/pages/HomePage/components/RoutineReport/index.tsx:60-66
Expand All @@ -110,3 +110,11 @@
- 발견: 문서가 없을 때의 집계 반영은 건너뛰고 곧이어 저장되는 문서는 조작 전에 센 값이라, 조작이 영구히 빠졌다. 건너뛴 조작을 세어 두고, 첫 문서를 만든 쪽이 그 수가 바뀌었으면 원본에서 다시 세도록 고쳤다
- 근거: src/shared/hooks/calendar/monthlyStats/useMonthlyData.ts (첫 문서 저장), src/shared/api/monthlyStats/queries.ts (patchMonthlyStatsByDayDeltas 의 missing-doc)
- 재현: 첫 monthlyStats 커밋을 page.route 로 2초 붙잡고 그 사이에 할 일을 추가한다

### TC-HOME-017 리스트 메뉴로 미완료 할 일을 다른 날(다음 날)로 옮긴다
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: 10-21 에 미완료 1개, 완료 1개. today 2026-10-21
- 절차: 리스트 메뉴 → "미완료 할 일을 다른 날 하기" → "완료" → 날짜 선택(기본값 다음 날) → "이동"
- 기대: 21일에는 완료한 것만 남고, 22일에 미완료가 보인다. 캘린더 21일 남은 일 0개, 22일 1개. 옮길 것이 없으면 "옮길 미완료 할 일이 없습니다."
- 근거: src/pages/HomePage/components/TaskReport/sections/TaskSetting.tsx ("after" 동작)
- 출처: 녹화 모드로 직접 추가 (`npm run e2e:record`)
6 changes: 3 additions & 3 deletions e2e/cases/my.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@
- 메모: 새로고침하면 메모리 캐시가 사라져 버그가 가려지므로 같은 탭에서 계정을 바꾼다. 캐시 키가 사용자 ID 를 품고 있어, 로그아웃 때 캐시를 비우는 코드만 빼서는 이 케이스가 실패하지 않는다. 두 장치 중 하나라도 남아 있는지를 지킨다

### TC-MY-005 다크 테마를 고르면 바로 바뀌고 새로고침해도 유지된다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 기대: "다크" 가 눌린 상태, html 에 dark 클래스. 새로고침 후에도 같다
- 근거: src/pages/MyPage/components/ThemeSection.tsx:31-37, 40d07b7

### TC-MY-006 프로필과 최근 6개월 달성률을 보여 준다
- 우선순위: P2 / 태그: @feature / 상태: 제안
- 우선순위: P2 / 태그: @feature / 상태: 구현됨
- 전제: today 2026-10-21. 9월 월간 통계(10건 중 7건 완료) (seed 확장 필요)
- 기대: 이름 "E2E 사용자", 5월~10월, 9월 70%, 기록 없는 달은 "기록 없음"
- 근거: src/pages/MyPage/components/MonthlyHistorySection.tsx:89-104, 1fce43f, 9a95573

### TC-MY-007 탈퇴 확인에서 취소하면 아무것도 바뀌지 않는다
- 우선순위: P3 / 태그: @feature / 상태: 제안
- 우선순위: P3 / 태그: @feature / 상태: 구현됨
- 기대: 모달이 닫히고 팝업이 열리지 않는다
- 근거: src/pages/MyPage/MyPage.tsx:138-147
Loading
Loading