반응형

TIL 145

[TIL][Shell] pytest 좀비 프로세스를 잡는 Watchdog 스크립트

출근해서 노트북을 켜는데, 노트북에서 비행기가 날아가면서 금세 뜨거워졌다2026-04-04(금) 새벽부터 2026-04-06(월) 오후까지, pytest 프로세스 4개가 49시간 동안 종료되지 않고 실행 중이었다PID 58852 test_login_steps 금 05AM~ 누적 CPU 594분 91.5%PID 68916 test_login_steps 금 08AM~ 누적 CPU 405분 91.5%PID 65872 test_bench_steps 금 08AM~ 누적 CPU 411분 93.6%PID 89532 omics-horizon-backend 금 03AM~ 누적 CPU 468분 90.9%Load Average 9.15, 메모리 15G/1..

TIL/Claude Code 2026.04.16

[TIL][Playwright] pages/ 전체 210개 wait_for_timeout을 0개로 제거한 4단계 과정

pages/ 디렉토리에 wait_for_timeout 호출이 263개 있었다대부분은 "혹시 느릴 수 있으니까"라는 이유로 들어간 것들이었다이 글은 4일에 걸쳐 210개를 이벤트 기반 대기로 전환하고, 재발 방지 Hook까지 구축한 과정을 기록한다wait_for_timeout이 왜 문제인가wait_for_timeout(1000)은 1초를 고정으로 기다린다버튼이 100ms 만에 활성화되어도 1초를 기다린다반대로 네트워크가 느린 날에는 1초 안에 준비가 안 되어 검증이 실패한다두 문제가 동시에 존재한다: 빠를 때는 낭비, 느릴 때는 불안정263개의 wait_for_timeout 호출을 분류해보니 네 가지 카테고리로 나뉘었다카테고리내용건수A이벤트 기반으로 완전 교체 가능25BMCP 실측 기반으로 값 단축 가능1..

TIL/Claude Code 2026.04.14

[TIL][Python] except Exception이 코드 버그를 "요소를 못 찾았다"로 위장시킨다

Page Object에서 이런 코드를 발견했다def click_save_button(self): try: button = self.page.locator(self.locators.SAVE_BUTTON) button.clikc() # ← 오타! click이 아니라 clikc except Exception: logger.warning("저장 버튼을 찾을 수 없음") return Nonebutton.clikc()은 AttributeError를 발생시킨다except Exception이 이걸 잡아서 "저장 버튼을 찾을 수 없음"으로 로깅한다로그만 보면 로케이터 문제 같다실제로는 오타다이 문제가 왜 오래 숨어 있었는가except Exception은 Py..

TIL/Claude Code 2026.04.12

[TIL][Playwright] E2E 검증에서 가장 위험한 코드는 "항상 통과하는 검증"이다

Bench에서 분자를 삭제하는 시나리오가 있다Scenario: 분자를 삭제한다 Given Bench 페이지에 진입한다 When 첫 번째 분자를 삭제한다 Then 분자가 삭제되었음을 확인한다검증이 매번 PASS였다그런데 Then Step 코드를 열어보니 이랬다@then("분자가 삭제되었음을 확인한다")def verify_molecule_removed(bench_page, bench_context): bench_page.take_screenshot("molecule_deleted") logger.info("✓ 분자 삭제 완료")스크린샷 찍고, 로그에 체크마크 출력하고, pytest는 PASS를 반환한다실제로 분자가 삭제되었는지는 아무도 확인하지 않는다삭제 API가 500을 반환해도..

TIL/Claude Code 2026.04.12

[TIL][Playwright] 모달이 버튼 인덱스를 밀어낸다 — nth() 로케이터의 함정

언어 전환 버튼을 선택하는 코드가 있다로컬에서는 잘 돌았는데, CI 에서 터졌다원인을 찾는데 2시간 걸렸다문제: 버튼 인덱스가 밀린다기존 코드는 전체 button 목록에서 인덱스로 언어 버튼을 찾았다# ❌ 기존 코드 — 글로벌 button 인덱스 기반user_btn_idx = page.evaluate(""" () => { const btns = Array.from(document.querySelectorAll('button')); return btns.findIndex(b => b.querySelector('p')); }""")# 언어 버튼 = 아바타 바로 앞 버튼lang_button = page.locator("button").nth(user_btn_idx - 1)l..

TIL/Claude Code 2026.04.04

[TIL][Claude Code] Playwright MCP 로 E2E 디버깅하기 — browser_snapshot 워크플로우

"저장" 버튼을 못 찾는다FAILED - playwright._impl._errors.TimeoutError: Timeout 30000ms exceeded. Locator: get_by_role("button", name="저장")로케이터가 틀렸나? 텍스트가 바뀌었나? 아니면 버튼이 아예 안 나오나?에러 로그만 보고는 모른다에러 로그만 보고 추측하면 생기는 일에러: "저장" 버튼 Timeout ↓추측: "텍스트가 바뀌었겠지" → name="Save" 로 변경 ↓실행 → 또 실패 ↓추측: "버튼이 아니라 link 겠지" → get_by_role("link") 로 변경 ↓실행 → 또 실패 ↓추측: "로딩이 느린가봐" → timeout 60초로 증가 ↓실행 → 또 실패 (6..

TIL/Claude Code 2026.04.02

[TIL][Claude Code] "이게 최선이야?" 를 자동으로 묻게 만들기

Claude Code 로 코드를 짜면 빠르다근데 빠른 만큼 대충 끝내는 경우도 있다"완료했습니다" 하고 보여주는데 보면 에러 처리가 빠져있거나, 실행도 안 해봤거나,.그래서 "이게 최선이야?" 를 매번 물어봐야 했다이걸 자동화했다구조: 3중 게이트코드 편집 (Edit/Write) ↓[자동] post-edit-quality-check.sh → 파일별 셀프 리뷰 체크리스트 ↓"/quality_gate" 커맨드 실행 ↓[수동] quality_gate.md → 5단계 체계적 검증 ↓"완료했습니다" 보고 시도 ↓[자동] notification-quality-gate.sh → 최종 게이트1차는 편집할 때마다 자동으로, 2차는 내가 직접 부를 때, 3차는 완료 보고할 때 자동으로 발동한다1..

TIL/Claude Code 2026.03.30

[TIL][Claude Code] CLAUDE.md 가 500줄이 된 이유

2025년 12월에 Claude Code 를 처음 접했다CLAUDE.md 는 10줄이었다# CLAUDE.md- Python 프로젝트- 한국어로 대답해줘- pytest-bdd 사용3개월 뒤, 506줄이 되었다왜 늘어나는가같은 실수가 반복되기 때문이다Claude Code 는 대화가 끝나면 컨텍스트를 잊는다"Step 파일에 locator 직접 쓰지 마" 라고 말해도 다음 대화에서 또 쓴다그래서 CLAUDE.md 에 적는다❌ 금지: Step 안에 UI 탐색 로직, 폴백 전략, 대기 코드 직접 작성✅ 필수: Page Object 메서드 호출 + context 관리 + 로깅만한 번 적으면 매 대화 시작 시 자동으로 읽는다더 이상 말로 반복할 필요가 없다규칙이 추가된 실제 과정Phase 1: 기본 설정 (12월)- ..

TIL/Claude Code 2026.03.24

[TIL][Playwright] SVG 요소는 선택으로 검증하면 안 된다 — DOM 구조 검증

HyperDesign 에서 Warhead 원자가 선택 보호되어 있는지 검증해야 했다처음엔 선택해서 반응이 없으면 보호가 정상이라고 판단했다틀렸다force=True 가 보호를 우회하기 때문이다상황: Covalent HyperDesign 의 Warhead 보호약물 설계 도구에서 분자 구조를 수정할 수 있다그런데 Warhead (반응기) 부분은 수정하면 안 된다UI 에서 Warhead 원자를 선택해도 반응되지 않아야 한다이걸 E2E 자동화로 검증해야 한다첫 번째 시도: 선택 기반 검증 (실패)# ❌ Bad — 선택해서 반응 없으면 보호 정상이라고 판단def test_warhead_protection(page): warhead_atom = page.locator(".warhead-atom").first ..

TIL/Playwright 2026.03.22
반응형