fix: GPS 기반 시나리오에 위치 권한 팝업 클릭 단계 추가

- Geolocation API 모킹을 첫 번째 단계로 이동 (팝업 방지)
- '사이트에 있는 동안 허용' 버튼 클릭 로직 추가
- 좌측 상단 권한 팝업 처리 스크립트 개선

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
김보곤
2026-02-02 09:10:38 +09:00
parent 05b24731cd
commit 08050f2af0
2 changed files with 70 additions and 48 deletions

View File

@@ -92,53 +92,46 @@
"steps": [
{
"id": "step-0",
"name": "🔐 위치 권한 사전 설정 (Playwright)",
"description": "Playwright 컨텍스트 레벨에서 위치 권한을 미리 허용하여 브라우저 팝업 방지",
"name": "🔐 Geolocation API 모킹 (권한 팝업 방지)",
"description": "페이지 로드 직후 Geolocation API를 모킹하여 브라우저 권한 팝업이 나타나지 않도록 함",
"critical": true,
"executeBeforeNavigation": true,
"playwright": {
"commands": [
{
"tool": "mcp__playwright__playwright_evaluate",
"script": "// 브라우저 시작 시 위치 권한 자동 허용 (Playwright 컨텍스트 레벨)"
}
],
"contextSetup": {
"permissions": ["geolocation"],
"geolocation": {
"latitude": 37.557358,
"longitude": 126.864414
}
}
},
"note": "이 단계는 브라우저 컨텍스트 생성 시 자동으로 처리됨"
"executeBeforeNavigation": false,
"executeImmediately": true,
"actions": [
{
"type": "evaluate",
"script": "(() => { const mockPosition = { coords: { latitude: 37.557358, longitude: 126.864414, accuracy: 100, altitude: null, altitudeAccuracy: null, heading: null, speed: null }, timestamp: Date.now() }; const mockGeolocation = { getCurrentPosition: (success, error, options) => { console.log('[E2E] Geolocation.getCurrentPosition - 모킹된 위치 반환'); setTimeout(() => success(mockPosition), 50); }, watchPosition: (success, error, options) => { console.log('[E2E] Geolocation.watchPosition - 모킹된 위치 반환'); setTimeout(() => success(mockPosition), 50); return 1; }, clearWatch: (id) => {} }; Object.defineProperty(navigator, 'geolocation', { value: mockGeolocation, writable: false, configurable: true }); console.log('[E2E] Geolocation API 모킹 완료 - 서울 영등포구 좌표'); return { success: true, coords: mockPosition.coords }; })()",
"description": "Geolocation API 모킹 (서울 영등포구 좌표: 37.557358, 126.864414)"
},
{ "type": "wait", "duration": 300, "description": "모킹 적용 대기" }
],
"note": "Geolocation API를 모킹하면 브라우저가 위치 권한을 요청하지 않음"
},
{
"id": "step-0-1",
"name": "🗺️ 위치 권한 팝업 처리 및 사이드바 메뉴 전체 펼치기",
"description": "위치 권한 요청 팝업 처리 후 모두 펼치기 버튼을 클릭하여 전체 메뉴 펼침",
"name": "🗺️ 브라우저 위치 권한 팝업 클릭 (좌측 상단)",
"description": "Chrome 브라우저 좌측 상단에 나타나는 '사이트에 있는 동안 허용' 팝업 클릭",
"critical": true,
"actions": [
{ "type": "wait", "duration": 1000, "description": "페이지 로드 및 권한 팝업 표시 대기" },
{ "type": "wait", "duration": 1500, "description": "위치 권한 팝업 표시 대기" },
{
"type": "conditionalClick",
"description": "위치 권한 팝업이 나타나면 '허용' 또는 '항상 허용' 버튼 클릭",
"selectors": [
"button:has-text('항상 허용')",
"button:has-text('허용')",
"button:has-text('Allow')",
"button:has-text('Always Allow')",
"[data-testid='allow-location']",
".permission-allow-button",
"button[aria-label*='허용']",
"button[aria-label*='위치']"
],
"fallback": {
"action": "skip",
"reason": "권한 팝업이 없으면 이미 허용된 상태"
}
"type": "evaluate",
"script": "(async function() { const permissionSelectors = [ '[class*=\"permission\"][class*=\"allow\"]', '[class*=\"infobar\"] button', '[aria-label*=\"허용\"]', '[aria-label*=\"Allow\"]', 'button:has-text(\"사이트에 있는 동안 허용\")', 'button:has-text(\"허용\")', 'button:has-text(\"Allow\")', '[data-testid*=\"permission\"]', '.permission-prompt button', '[class*=\"PermissionPrompt\"] button' ]; for (const sel of permissionSelectors) { try { const btn = document.querySelector(sel); if (btn && btn.offsetParent !== null) { btn.click(); console.log('[E2E] 위치 권한 팝업 클릭 성공:', sel); await new Promise(r => setTimeout(r, 500)); return { clicked: true, selector: sel }; } } catch(e) {} } const allButtons = Array.from(document.querySelectorAll('button, [role=\"button\"]')); const allowBtn = allButtons.find(b => { const text = b.innerText || b.textContent || ''; return text.includes('사이트에 있는 동안 허용') || text.includes('허용') || text.includes('Allow'); }); if (allowBtn && allowBtn.offsetParent !== null) { allowBtn.click(); console.log('[E2E] 위치 권한 팝업 텍스트 검색으로 클릭'); return { clicked: true, method: 'textSearch' }; } console.log('[E2E] 위치 권한 팝업 없음 (이미 허용되었거나 모킹으로 우회됨)'); return { clicked: false, reason: 'no_popup_found' }; })()",
"description": "좌측 상단 권한 팝업 찾아서 클릭"
},
{ "type": "wait", "duration": 500, "description": "권한 설정 적용 대기" },
{ "type": "wait", "duration": 500, "description": "권한 설정 적용 대기" }
],
"errorHandling": {
"onTimeout": "continue",
"onNotFound": "continue",
"reason": "팝업이 없으면 이미 허용된 상태로 간주"
}
},
{
"id": "step-0-2",
"name": "📂 사이드바 메뉴 전체 펼치기",
"description": "모두 펼치기 버튼을 클릭하여 전체 메뉴 펼침",
"actions": [
{
"type": "evaluate",
"script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})"
@@ -152,14 +145,8 @@
{ "type": "screenshot", "name": "after_permission_grant_and_menu_expanded" }
],
"verification": [
"위치 권한 팝업이 닫혔는지 확인",
"또는 팝업이 처음부터 없었는지 확인 (이미 허용된 경우)"
],
"errorHandling": {
"onTimeout": "continue",
"onNotFound": "continue",
"reason": "팝업이 없으면 권한이 이미 허용된 상태로 간주"
}
"사이드바 메뉴가 펼쳐졌는지 확인"
]
},
{
"id": 2,

View File

@@ -81,7 +81,42 @@
"steps": [
{
"id": "step-0",
"name": "사이드바 메뉴 전체 펼치기",
"name": "🔐 Geolocation API 모킹 (권한 팝업 방지)",
"description": "페이지 로드 직후 Geolocation API를 모킹하여 브라우저 권한 팝업이 나타나지 않도록 함",
"critical": true,
"actions": [
{
"type": "evaluate",
"script": "(() => { const mockPosition = { coords: { latitude: 37.5665, longitude: 126.9780, accuracy: 100, altitude: null, altitudeAccuracy: null, heading: null, speed: null }, timestamp: Date.now() }; const mockGeolocation = { getCurrentPosition: (success, error, options) => { console.log('[E2E] Geolocation.getCurrentPosition - 모킹된 위치 반환'); setTimeout(() => success(mockPosition), 50); }, watchPosition: (success, error, options) => { console.log('[E2E] Geolocation.watchPosition - 모킹된 위치 반환'); setTimeout(() => success(mockPosition), 50); return 1; }, clearWatch: (id) => {} }; Object.defineProperty(navigator, 'geolocation', { value: mockGeolocation, writable: false, configurable: true }); console.log('[E2E] Geolocation API 모킹 완료 - 서울시청 좌표'); return { success: true, coords: mockPosition.coords }; })()",
"description": "Geolocation API 모킹 (서울시청 좌표: 37.5665, 126.9780)"
},
{ "type": "wait", "duration": 300, "description": "모킹 적용 대기" }
],
"note": "Geolocation API를 모킹하면 브라우저가 위치 권한을 요청하지 않음"
},
{
"id": "step-0-1",
"name": "🗺️ 브라우저 위치 권한 팝업 클릭 (좌측 상단)",
"description": "Chrome 브라우저 좌측 상단에 나타나는 '사이트에 있는 동안 허용' 팝업 클릭",
"critical": true,
"actions": [
{ "type": "wait", "duration": 1500, "description": "위치 권한 팝업 표시 대기" },
{
"type": "evaluate",
"script": "(async function() { const permissionSelectors = [ '[class*=\"permission\"][class*=\"allow\"]', '[class*=\"infobar\"] button', '[aria-label*=\"허용\"]', '[aria-label*=\"Allow\"]', 'button:has-text(\"사이트에 있는 동안 허용\")', 'button:has-text(\"허용\")', 'button:has-text(\"Allow\")', '[data-testid*=\"permission\"]', '.permission-prompt button', '[class*=\"PermissionPrompt\"] button' ]; for (const sel of permissionSelectors) { try { const btn = document.querySelector(sel); if (btn && btn.offsetParent !== null) { btn.click(); console.log('[E2E] 위치 권한 팝업 클릭 성공:', sel); await new Promise(r => setTimeout(r, 500)); return { clicked: true, selector: sel }; } } catch(e) {} } const allButtons = Array.from(document.querySelectorAll('button, [role=\"button\"]')); const allowBtn = allButtons.find(b => { const text = b.innerText || b.textContent || ''; return text.includes('사이트에 있는 동안 허용') || text.includes('허용') || text.includes('Allow'); }); if (allowBtn && allowBtn.offsetParent !== null) { allowBtn.click(); console.log('[E2E] 위치 권한 팝업 텍스트 검색으로 클릭'); return { clicked: true, method: 'textSearch' }; } console.log('[E2E] 위치 권한 팝업 없음 (이미 허용되었거나 모킹으로 우회됨)'); return { clicked: false, reason: 'no_popup_found' }; })()",
"description": "좌측 상단 권한 팝업 찾아서 클릭"
},
{ "type": "wait", "duration": 500, "description": "권한 설정 적용 대기" }
],
"errorHandling": {
"onTimeout": "continue",
"onNotFound": "continue",
"reason": "팝업이 없으면 이미 허용된 상태로 간주"
}
},
{
"id": "step-0-2",
"name": "📂 사이드바 메뉴 전체 펼치기",
"description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비",
"actions": [
{