E2E Suite 가 200개를 넘었다
make parallel # 7-Phase 병렬 실행
나름 안정화가 돼서 CI 를 붙여봤다
CI 구조
매일 오전 6시에 돌고, Slack 으로 결과를 받는다
매일 06:00 KST (cron)
↓
GitHub Actions: Playwright headless
↓
7-Phase 병렬 실행
↓
Allure Report 생성 → gh-pages 배포
↓
Slack 알림 (카테고리별 PASS/FAIL)
수동 실행도 가능하다 — Phase 5 에서 터졌으면 5 부터만 재실행 가능
on:
workflow_dispatch:
inputs:
from_phase:
description: '시작 Phase (1-7)'
default: '1'
CI 에서 터진 것 3가지
로컬에서 잘 되던 게 CI 에 올리니까 바로 터졌다
1. CSS 파일 미존재
OSError: reports/custom_style.css not found
pytest.ini 에서 --css=reports/custom_style.css 를 참조하는데 .gitignore 에 걸려서 CI 에 없다
reports/
!reports/custom_style.css # ← 예외 추가
git add -f 로 강제 추적
2. credentials.py 미존재
ModuleNotFoundError: No module named 'test_data.credentials'
로컬에서는 .env + credentials.py 로 관리하는데 CI 에는 둘 다 없다
GitHub Secrets → .env 생성은 간단한데, credentials.py 동적 생성이 좀 까다롭다
heredoc + sed 로 하면 Python 들여쓰기가 깨진다 — textwrap.dedent 가 정답
- name: Generate credentials wrapper (gitignored)
run: |
python3 -c "
import textwrap, pathlib
code = textwrap.dedent('''
from config.settings import Settings
class TestCredentials:
EMAIL = Settings.get_env('TEST_EMAIL')
PASSWORD = Settings.get_env('TEST_PASSWORD')
OTP = '000000'
''').strip() + '\n'
pathlib.Path('test_data/credentials.py').write_text(code)
"
3. 타임아웃
Error: The operation was canceled.
timeout-minutes: 60 으로 잡았는데 2번 연속 취소됐다
CI 환경은 로컬보다 느리다 — 180분으로 올렸다
timeout-minutes: 180
concurrency:
group: e2e-parallel-${{ github.ref }}
cancel-in-progress: true # 같은 브랜치 중복 실행 시 이전 건 취소
concurrency 는 같은 워크플로우가 중복 실행될 때 이전 걸 자동 취소한다
무료 할당량 아끼는 데 필수
스피너 로그 폭발
CI 첫 실행 로그를 열었더니 수만 줄이었다
⠋ Phase 3 진행 중...
⠙ Phase 3 진행 중...
⠹ Phase 3 진행 중...
... (매 0.1초마다 새 줄)
원인: 로컬 터미널은 \r 로 같은 줄을 덮어쓰는데 GitHub Actions 는 \r 을 줄바꿈으로 처리한다
스피너 1회전 = 새 줄 1개 = 10초에 100줄
CI 감지 후 분기
IS_CI="${CI:-false}" # GitHub Actions 는 CI=true 자동 설정
start_spinner() {
if [ "$IS_CI" = "true" ]; then
echo "$message" # 한 줄만 출력
return
fi
# 기존 스피너 로직
}
모니터링은 5분 간격으로 줄였다
5분인 이유 — GitHub Actions 는 10분 동안 stdout 출력이 없으면 job 을 kill 한다
최종 워크플로우
name: E2E Parallel Test (Daily)
on:
schedule:
- cron: '0 21 * * *' # 매일 06:00 KST
workflow_dispatch: # 수동 실행
jobs:
e2e-parallel:
runs-on: ubuntu-latest
timeout-minutes: 180
steps:
- uses: actions/checkout@v4
- name: Setup Python 3.11
uses: actions/setup-python@v5
- name: Install dependencies
run: |
pip install -r requirements.txt
playwright install --with-deps chromium
- name: Create .env from secrets
run: |
echo "TEST_EMAIL=${{ secrets.TEST_EMAIL }}" >> .env
- name: Run parallel tests
run: bash scripts/test_parallel.sh
- name: Generate Allure Report
if: always()
uses: simple-elf/allure-report-action@master
with:
allure_results: reports/allure-results
allure_report: reports/allure-report
allure_history: reports/allure-history
- name: Upload test artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ github.run_number }}
path: |
reports/allure-report/
reports/screenshots/
reports/videos/
reports/traces/
retention-days: 30
if: always() — 실패해도 리포트 생성 + 아티팩트 업로드는 돌아가야 한다
정리
| 문제 | 해결 |
|---|---|
| 매일 수동 실행 | cron 자동 실행 |
| CSS 파일 미존재 | .gitignore 예외 + git add -f |
| credentials.py 미존재 | textwrap.dedent 동적 생성 |
| 60분 타임아웃 | 180분 + concurrency 중복 방지 |
| 스피너 로그 폭발 | CI=true 감지 → 비활성화 |
| 모니터 로그 폭발 | 5분 간격 출력 (10분 kill 정책 대응) |
로컬에서 잘 돌아가는 스크립트를 CI 에 그대로 올리면 안 된다
\r 동작, 파일 존재, 타임아웃 — 터미널에서 당연한 것들이 CI 에서는 전부 다르다
CI 를 붙이는 타이밍도 중요하다 — 실패가 많을 때 붙이면 매일 빨간불에 알림 피로만 쌓인다
안정화 먼저, CI 는 그 다음이다
'TIL > Playwright' 카테고리의 다른 글
| [TIL][Playwright] AI 챗봇 응답 완료를 E2E 로 감지하는 방법 (0) | 2026.06.14 |
|---|---|
| [TIL][Playwright] expect vs wait_for — disabled 버튼 때문에 30초 날린 이야기 (0) | 2026.06.07 |
| [TIL][Playwright] SVG 요소는 선택으로 검증하면 안 된다 — DOM 구조 검증 (0) | 2026.03.22 |
| 로그인 인증 상태 저장 및 재사용 방법 w/ Playwright (6) | 2025.08.12 |
| Playwright 로 API Test 해보기 w/ OpenAPI (0) | 2025.06.30 |