fix(A05 가이드 캡처): 위험 단추 검사가 선택자 글자만 봄(text= · :has-text) · class · id 이름 제외 · 시험 덧

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 09:39:57 +09:00
co-authored by Claude Sonnet 5.5
parent 08cf07290a
commit d6137b362d
2 changed files with 26 additions and 7 deletions
+16 -4
View File
@@ -49,8 +49,9 @@
frame 은 callouts 항목에도 씀
지킴
- [저장] · [확정] · [초기화] · [적용] · [삭제] · 메일 보내기 등 위험 단추 누름은 거절 — 선택자 · eval 글(목록
읽을 때) · 실제 요소 글자(누르기 직전) 둘 다 검사 · [취소] · [닫기] 는 통과
- [저장] · [확정] · [초기화] · [적용] · [삭제] · 메일 보내기 등 위험 단추 누름은 거절 — 선택자 속 글자
(`text=` · `:has-text("…")`만 · class · id 이름은 안 봄) · eval 글 · 실제 요소 글자(누르기 직전) 검사 ·
[취소] · [닫기] 는 통과
- 확인창을 찍을 때만 `"confirm": true` 로 그 단추를 누름 — 그 장면은 after 에 누름 단계가 있어야 함([취소])
- 페이지의 /api 쓰기 요청(PUT · PATCH · DELETE · allow_post 밖 POST)은 모두 끊음 · 끊은 요청은 표에 적음
- 브라우저 확인창(window.confirm)은 늘 취소 · 새 컨텍스트라 사용자 브라우저 · 저장소와 안 섞임
@@ -132,6 +133,17 @@ def is_danger(text: str) -> bool:
return bool(text) and bool(DANGER_RE.search(text)) and not SAFE_RE.search(text)
SEL_TEXT_RE = re.compile(
r"""text\s*=\s*(?:"[^"]*"|'[^']*'|[^>]+)|:(?:has-)?text(?:-is|-matches)?\(\s*(?:"[^"]*"|'[^']*')""",
re.I,
)
def sel_text(sel: str) -> str:
"""선택자 속 글자 부분만(`text=` · `:has-text("…")`) — class · id 이름은 뺌."""
return " ".join(SEL_TEXT_RE.findall(sel or ""))
def _check_steps(steps: Any, where: str) -> tuple[list[str], bool]:
"""단계 목록 검사 → (잘못, confirm 단계 있음)."""
if steps is None:
@@ -166,11 +178,11 @@ def _check_steps(steps: Any, where: str) -> tuple[list[str], bool]:
if kind != "click":
errs.append(f"{at} confirm 은 click 에만")
confirm = True
elif kind in ("click", "eval") and is_danger(val):
elif is_danger(val if kind == "eval" else sel_text(val)) and kind in ("click", "eval"):
errs.append(
f"{at} 위험 단추 거절({kind}: {val[:40]}) — 확인창만이면 confirm + after [취소]"
)
if kind == "press" and is_danger(st.get("sel", "")):
if kind == "press" and is_danger(sel_text(st.get("sel", ""))):
errs.append(f"{at} 위험 요소에서 키 거절")
return errs, confirm
+10 -3
View File
@@ -80,11 +80,9 @@ def test_bad_fields(bad):
[
"button:has-text('저장')",
"text=확정",
".reset-btn",
"button:has-text('초기화')",
"button:has-text('적용')",
"button:has-text('메일 보내기')",
"#save",
"button:has-text('삭제')",
],
)
@@ -101,7 +99,16 @@ def test_danger_eval_rejected():
@pytest.mark.parametrize(
"sel", ["button:has-text('취소')", "text=닫기", ".cancel", "button:has-text('내보내기')"]
"sel",
[
"button:has-text('취소')",
"text=닫기",
".cancel",
"button:has-text('내보내기')",
".d04-confirm__list",
".ui-confirm__cancel",
"#save-btn button:has-text('닫기')",
],
)
def test_safe_click_passes(sel):
assert G.check_scene(_scene(before=[{"click": sel}]), "B05") == []