LogoSkills

Selector Policy (flutter-skill → Patrol)

| 주제 | 권위 있는 문서 |

이 문서는 cc-e2e-authoring 전용 — flutter-skill 의 semantic ref 를 K 통합 Key 로 승격하는 매핑 규약만 담당합니다. K 클래스 네이밍, 파일 위치, build.yaml, 일반 Widget Key 규약은 cc-flutter-dev/rules/bdd-test-patterns.md 가 조직 표준입니다. (중복 금지)

1. 역할 분담#

주제권위 있는 문서
TestDriver / WidgetTestDriver / PatrolTestDriver 추상화 cc-flutter-dev/rules/bdd-test-patterns.md
K 클래스 위치 ( package/test_driver/lib/src/key/k.dart ), package/test_driver 구조 cc-flutter-dev/rules/bdd-test-patterns.md
.feature 파일 포맷, @both/@widget-only/@patrol-only 태그 cc-uiux/skills/bdd-testing
bdd_test_gen / build.yaml cc-uiux/skills/bdd-testing
flutter-skill semantic ref ↔ K 매핑본 문서

본 문서는 상위 문서와 충돌하지 않아야 합니다. 상위 문서가 변경되면 본 문서도 갱신.

2. flutter-skill semantic ref → K 매핑 규칙#

flutter-skill 의 inspect_interactive 가 반환하는 semantic ref (button:Login[1] 등) 는 런타임 계산 ID 입니다. key-hardening 스킬은 이것을 package/test_driver/lib/src/key/k.dartK 상수로 승격시킵니다.

Key 형식 규약 (kobic 권위): K 상수는 flat snake_case Key('...') 입니다. ValueKey 금지, screen 접두 금지, 점-네임스페이스(screen.label) 금지. 정의는 abstract final class K 내부 static const.

semantic ref 패턴제안 K 상수실제 Key 문자열
button:{Label} K.{label}Button {label_snake}_button
input:{Label} K.{label}Field {label_snake}_field
toggle:{Label} K.{label}Toggle {label_snake}_toggle
select:{Label} K.{label}Select {label_snake}_select
slider:{Label} K.{label}Slider {label_snake}_slider
link:{Label} K.{label}Link {label_snake}_link
item:{Label} (동적) K.{singular}Item + 도메인 id 결합 {singular}_item

예:

  • button:LoginK.loginButton = Key('login_button')
  • input:EmailK.emailField = Key('email_field')
  • item:Book Title (스토어 리스트) → Key('book_item:${book.id}') 를 런타임에 생성

Key 문자열은 .feature 의 flat key 참조({'login_button'})와 1:1 로 매칭됩니다. 위젯 할당은 key: K.loginButton.

3. [index] 접미사 처리#

semantic ref 의 [0], [1] 등 인덱스는 Key 에 포함하지 않습니다 — 인덱스 기반 셀렉터는 리스트 순서 변경에 취약.

  • 동일 타입 위젯이 화면에 여럿이면 domain id 결합 (book_item:${book.id}) 패턴 사용
  • 그 외 중복은 사람 검토 필요 (자동 매핑 거부 + 사용자 확인)

4. K 상수 추가 절차#

key-hardening 스킬이 자동 수행하는 절차:

  1. package/test_driver/lib/src/key/k.dart 에 상수 추가:
    // 기존에 이어붙이기 (알파벳순 정렬 유지)
    // flat snake_case Key — ValueKey/screen 접두/점-네임스페이스 금지
    abstract final class K {
      static const loginButton = Key('login_button');
      static const emailField = Key('email_field');
    }
    
  2. 대상 위젯 파일에 key: K.xxx 주입 (최소 diff)
  3. 기존 widget/unit test 에서 해당 위젯을 find.byType 등으로 찾고 있었는지 확인 — 파괴적 변경 아니면 기존 테스트 유지

5. Patrol step 에서 셀렉터 금지 목록#

integration_test/step/test/src/bdd/step/ 의 TestDriver step 에서 금지:

금지대신
$('Login') 또는 $(find.text('Login')) driver.tap(K.loginButton)
$(ElevatedButton)driver.tap(K.loginButton)
find.byWidgetPredicate(...)driver.tap(K.xxx)
flutter-skill semantic ref (button:Login) 반드시 K 로 치환 후 사용
좌표 기반 $.native.tap(x, y)semantic Key + PatrolTester

예외: Patrol native_automator 의 OS 다이얼로그(퍼미션 등) 는 시스템 ID 사용 허용.

6. 규약 위반 자동 탐지#

scenario-lock 의 Pre-lock 검증에서 다음을 스캔:

  • integration_test/**/*.dart, **/test/src/bdd/step/**/*.dartbutton:, input:, ref:, elem_ 잔존
  • .feature 파일에 semantic ref 잔존
  • K 클래스 외부의 Key('...') 문자열 리터럴 (위젯 파일 내부 허용, 테스트 코드 금지)
  • find.text(...)assertion 이 아닌 tap 대상 으로 사용됨

하나라도 잔존하면 lock 거부.

7. 예외: assertion 에서의 find.text#

표시 내용 자체를 검증할 때는 find.text 허용:

// ✅ 허용: 텍스트 표시 내용 검증
await driver.expectTextVisible('환영합니다');

// ❌ 금지: 버튼을 지목하는 용도
await driver.tapText('로그인');  // K 로 대체 필요

참고#

  • 조직 K 규약 전체: cc-flutter-dev/rules/bdd-test-patterns.md
  • .feature 포맷: cc-uiux/skills/bdd-testing/SKILL.md
  • 본 문서는 flutter-skill 도입 시에만 필요한 얇은 매핑 레이어