e2e-test
星标11
分支0
更新时间2026年3月4日 17:10
Prowl 앱을 격리 환경에서 실행하고 UI 동작을 E2E 검증. 작업 완료 후 회귀 확인용.
安装
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
SKILL.md
readonly菜单
Prowl 앱을 격리 환경에서 실행하고 UI 동작을 E2E 검증. 작업 완료 후 회귀 확인용.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
| name | e2e-test |
| description | Prowl 앱을 격리 환경에서 실행하고 UI 동작을 E2E 검증. 작업 완료 후 회귀 확인용. |
| argument-hint | [검증할 시나리오 설명 (선택)] |
현재 변경 사항을 기반으로 Playwright E2E 테스트를 실행하고 결과를 분석합니다.
사용법:
/e2e-test — git diff로 시나리오 자동 추론 후 기존 스펙 실행/e2e-test 태스크 생성 후 목록에 표시되어야 함 — 명시적 요구사항으로 신규 스펙 작성A. 명시적 요구사항 (인자가 있는 경우 우선 사용):
$ARGUMENTS
B. git diff 분석 (항상 실행):
git diff main...HEAD --stat
git diff main...HEAD
변경된 파일을 보고 어떤 사용자 플로우를 검증할지 결정. 기존 스펙(e2e/specs/)으로 커버되는지 먼저 확인.
ls dist/main/index.js 2>/dev/null || bun run build
# 전체 스펙
bun run e2e:test
# 특정 스펙만
bun run e2e:test --grep "시나리오 설명"
# UI 모드 (디버깅용)
bun run e2e:test:ui
실패 시 리포트 확인:
open e2e/report/index.html
기존 스펙으로 커버되지 않으면 e2e/specs/{기능명}.spec.ts를 추가.
/** E2E — {기능 설명} */
import { expect, test } from "@playwright/test";
import { getTodayDateString } from "../helpers";
import { DashboardPage } from "../pages/DashboardPage";
import { launchApp } from "../runner";
test("{시나리오 설명}", async () => {
const { page, cleanup } = await launchApp();
const dashboard = new DashboardPage(page);
try {
// 데이터 준비: IPC로 직접 주입 (UI보다 빠르고 안정적)
await dashboard.createTask(getTodayDateString(), {
id: `e2e-${Date.now()}`,
title: `테스트 태스크 ${Date.now()}`, // Date.now()로 충돌 방지
completed: false,
createdAt: new Date().toISOString(),
});
// 검증: POM 메서드만 사용, 스펙 파일에서 셀렉터 직접 사용 금지
await dashboard.clickTodayCell();
await expect(dashboard.taskLocator("테스트 태스크")).toBeVisible({ timeout: 5000 });
} finally {
await cleanup(); // 임시 디렉터리 자동 삭제, 실패해도 반드시 실행
}
});
app 레퍼런스가 있어야 두 번째 창을 열 수 있다.
test("{시나리오 설명}", async () => {
const { app, page: rawPage, cleanup } = await launchApp();
const dashboard = new DashboardPage(rawPage, app); // app 전달
try {
await dashboard.createTask(/* ... */);
const compactRawPage = await dashboard.openCompactView(); // 두 번째 창
const compact = new CompactPage(compactRawPage);
await compact.waitForLoad();
await compact.toggleTask("태스크 제목");
// rawPage(Dashboard)로 돌아와 검증
await dashboard.clickTodayCell();
await expect(dashboard.completedTaskLocator("태스크 제목")).toBeVisible();
} finally {
await cleanup();
}
});
| 파일 | 담당 |
|---|---|
e2e/pages/DashboardPage.ts | 대시보드 — 태스크 생성/편집/삭제/완료, 캘린더, 네비게이션, Compact 창 열기 |
e2e/pages/CompactPage.ts | Compact 창 — 태스크 완료, 완료 목록 펼치기 |
e2e/pages/PersonalizePage.ts | Personalize 탭 — Memory CRUD, System Prompt 저장/초기화, Tone 저장 |
새 POM이 필요하면 e2e/pages/에 추가. 스펙에서 셀렉터를 직접 쓰면 안 된다.
dashboard.createTask()처럼 page.evaluate(electronAPI.xxx)를 통해 직접 주입. UI로 입력하는 것보다 빠르고 안정적page.locator(), page.click() 직접 호출 금지. 모든 인터랙션은 POM 메서드cleanup()이 반드시 실행돼야 임시 디렉터리가 남지 않음Date.now() 접미사로 병렬 실행 시 충돌 예방 (현재 workers=1이지만 습관으로)app을 destructurePROWL_DATA_HOME이 자동 설정되므로 실제 ~/.prowl 데이터는 변경되지 않음workers: 1 — 앱 인스턴스 격리를 위해 직렬 실행에이전트 간 상호작용 구조와 워크플로우 정의
컨벤션에 맞춰 커밋 생성
PR 템플릿에 맞춰 Pull Request 생성
TanStack Query 기반 데이터 페칭 패턴
Prowl 앱의 디자인 시스템 (Liquid Glass + 골드 액센트)
IPC 채널 추가/수정 시 안전 규칙과 절차