# Instructions

- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.

# Test info

- Name: 3522/dev/settlement-button-permission.spec.ts >> [3522][dev] [QA] 거래내역 정산내역 버튼 권한별 노출 재검증 >> admin도 동일하게 권한 유무 기준으로 버튼/메뉴 접근이 달라지는지 확인
- Location: src/qa/scenarios/settlementButtonPermission.ts:242:5

# Error details

```
Error: ADMIN 정산 조회 권한 부여 시 거래내역 본문 정산내역 버튼이 보여야 합니다.

expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false
```

# Page snapshot

```yaml
- generic [ref=e2]:
  - generic [ref=e4]:
    - button "공지 배너 닫기" [ref=e5] [cursor=pointer]
    - generic [ref=e10] [cursor=pointer]: 테스트
  - generic [ref=e12]:
    - generic:
      - generic:
        - generic:
          - generic:
            - generic:
              - generic:
                - main:
                  - generic:
                    - generic:
                      - generic:
                        - generic: 2026년 06월 11일
                        - generic: 요약
                      - generic:
                        - generic:
                          - generic:
                            - generic: 일일 거래액
                            - button: 더보기
                          - generic:
                            - generic: ₩0
                        - generic:
                          - generic:
                            - generic: 일일 거래건수
                            - button: 더보기
                          - generic:
                            - generic: 0건
                        - generic:
                          - generic:
                            - generic: 지갑 잔액
                            - button: 더보기
                          - generic:
                            - generic: ₩11,068,424
                    - generic:
                      - generic:
                        - generic:
                          - generic: 영업점 잠금 예약
                          - button: 더보기
                        - generic: 잠금 예약된 영업점이 없습니다
                      - generic:
                        - generic:
                          - generic: 가맹점 잠금 예약
                          - button: 더보기
                        - generic: 잠금 예약된 가맹점이 없습니다
                    - generic:
                      - generic:
                        - generic: 미수금 관리
                        - generic:
                          - button: 전체
                          - button: 일수금
                          - button: 채권
                          - button: 통신비
                      - generic:
                        - generic:
                          - generic:
                            - generic: 일수금
                            - generic: 4건
                          - paragraph: 남은금액
                          - generic:
                            - generic: 11,200,000
                            - generic: / 11,200,000
                        - generic:
                          - generic:
                            - generic: 채권
                            - generic: 14건
                          - paragraph: 남은금액
                          - generic:
                            - generic: 2,012,179
                            - generic: / 3,382,585
                        - generic:
                          - generic:
                            - generic: 통신비
                            - generic: 52건
                          - paragraph: 남은금액
                          - generic:
                            - generic: 814,000
                            - generic: / 814,000
                      - generic:
                        - generic:
                          - generic: "#"
                          - generic: 유형
                          - generic: 부서유형
                          - generic: 부서명
                          - generic: 회수실패
                          - generic: 남은횟수
                          - generic: 남은금액
                          - generic: 총액
                          - generic: 상환금액
                        - generic:
                          - generic: "1"
                          - generic: 일수금
                          - generic: 가맹점
                          - generic: 반길현_가맹12
                          - generic: "50"
                          - generic: "100"
                          - generic: 10,000,000
                          - generic: 10,000,000
                          - generic: "0"
                        - generic:
                          - generic: "2"
                          - generic: 일수금
                          - generic: 가맹점
                          - generic: 주홍석_가맹1
                          - generic: "50"
                          - generic: "100"
                          - generic: 100,000
                          - generic: 100,000
                          - generic: "0"
                        - generic:
                          - generic: "3"
                          - generic: 일수금
                          - generic: 가맹점
                          - generic: 박재민_가맹
                          - generic: "49"
                          - generic: "200"
                          - generic: 1,000,000
                          - generic: 1,000,000
                          - generic: "0"
                        - generic:
                          - generic: "4"
                          - generic: 일수금
                          - generic: 가맹점
                          - generic: 박재민_가맹
                          - generic: "41"
                          - generic: "100"
                          - generic: 100,000
                          - generic: 100,000
                          - generic: "0"
                        - generic:
                          - generic: "5"
                          - generic: 채권
                          - generic: 법인
                          - generic: A_주홍석_법인
                          - generic: 10,040
                          - generic: 10,000
                          - generic: "-40"
                        - generic:
                          - generic: "6"
                          - generic: 채권
                          - generic: 가맹점
                          - generic: A_주홍석_가맹4_루시페이먼츠
                          - generic: 34,287
                          - generic: 30,000
                          - generic: "-4,287"
                        - generic:
                          - generic: "7"
                          - generic: 채권
                          - generic: 법인
                          - generic: 박재민_법인
                          - generic: 116,377
                          - generic: 116,377
                          - generic: "0"
                        - generic:
                          - generic: "8"
                          - generic: 채권
                          - generic: 가맹점
                          - generic: A_주홍석_가맹1
                          - generic: "-13,500"
                          - generic: "0"
                          - generic: 13,500
                        - generic:
                          - generic: "9"
                          - generic: 채권
                          - generic: 가맹점
                          - generic: 두바이소금빵가맹
                          - generic: 6,000
                          - generic: 6,000
                          - generic: "0"
                        - generic:
                          - generic: "10"
                          - generic: 채권
                          - generic: 가맹점
                          - generic: 박재민_가맹3
                          - generic: "0"
                          - generic: 3,166
                          - generic: 3,166
                        - generic:
                          - generic: "11"
                          - generic: 채권
                          - generic: 법인
                          - generic: 안법인
                          - generic: 27,029
                          - generic: 40,000
                          - generic: 12,971
                        - generic:
                          - generic: "12"
                          - generic: 채권
                          - generic: 법인
                          - generic: 최인석 법인
                          - generic: 61,991
                          - generic: 35,956
                          - generic: "-26,035"
                        - generic:
                          - generic: "13"
                          - generic: 채권
                          - generic: 법인
                          - generic: 반길현_법인
                          - generic: "-334"
                          - generic: 1,000
                          - generic: 1,334
                        - generic:
                          - generic: "14"
                          - generic: 채권
                          - generic: 가맹점
                          - generic: 반길현_코페이_가맹2
                          - generic: "-79,550"
                          - generic: 10,450
                          - generic: 90,000
                        - generic:
                          - generic: "15"
                          - generic: 채권
                          - generic: 가맹점
                          - generic: 박재민_가맹8
                          - generic: 190,000
                          - generic: 190,000
                          - generic: "0"
                        - generic:
                          - generic: "16"
                          - generic: 채권
                          - generic: 가맹점
                          - generic: 안가맹
                          - generic: "-1,236,368"
                          - generic: 55,282
                          - generic: 1,291,650
                        - generic:
                          - generic: "17"
                          - generic: 채권
                          - generic: 가맹점
                          - generic: 최인석 가맹
                          - generic: 99,494
                          - generic: 65,782
                          - generic: "-33,712"
                        - generic:
                          - generic: "18"
                          - generic: 채권
                          - generic: 가맹점
                          - generic: 박재민_가맹
                          - generic: 2,796,713
                          - generic: 2,818,572
                          - generic: 21,859
                        - generic:
                          - generic: "19"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 가맹 엑셀 테스트
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "20"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹14
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "21"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹15
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "22"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹16
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "23"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹17
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "24"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 안승현 가맹1
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "25"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 안승현 가맹2
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "26"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 안승현 가맹3
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "27"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 안승현 가맹4
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "28"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 안승현 가맹5
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "29"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹5
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "30"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹3
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "31"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹2
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "32"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 박재민_가맹8
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "33"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 박재민_가맹7
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "34"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 박재민_가맹6
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "35"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹6
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "36"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹7
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "37"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹8
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "38"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹9
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "39"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹10
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "40"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹11
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "41"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹12
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "42"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹13
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "43"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 박재민_가맹5
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "44"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 박재민_가맹_한결데
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "45"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 박재민_가맹3
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "46"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 최인석 가맹4
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "47"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 박재민_가맹2
                          - generic: 11,000
                          - generic: 11,000
                          - generic: "0"
                        - generic:
                          - generic: "48"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 김경주_가맹_테스트7
                          - generic: 22,000
                          - generic: 22,000
                          - generic: "0"
                        - generic:
                          - generic: "49"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 김경주_가맹_테스트6
                          - generic: 22,000
                          - generic: 22,000
                          - generic: "0"
                        - generic:
                          - generic: "50"
                          - generic: 통신비
                          - generic: 가맹점
                          - generic: 김경주_가맹_테스트5
                          - generic: 22,000
                          - generic: 22,000
                          - generic: "0"
                    - generic:
                      - generic:
                        - generic: 공지사항
                        - button: 더보기
                      - generic:
                        - generic:
                          - generic: 테스트
                          - generic: 2026.06.09
                        - generic:
                          - generic: 공지 테스트 0512
                          - generic: 2026.05.12
                        - generic:
                          - generic: 패치노트 링크연결테스트
                          - generic: 2026.04.17
                        - generic:
                          - generic: 테스트
                          - generic: 2026.04.17
                        - generic:
                          - generic: 권한 테스트
                          - generic: 2026.04.17
                        - generic:
                          - generic: co 테스트
                          - generic: 2026.04.17
    - generic [ref=e14]:
      - generic [ref=e15]:
        - generic [ref=e16]:
          - link "logo 빅스페이먼츠" [ref=e18] [cursor=pointer]:
            - /url: /
            - img "logo" [ref=e19]
            - generic [ref=e20]: 빅스페이먼츠
          - button "사이드바 접기" [ref=e21] [cursor=pointer]:
            - img [ref=e24]
            - generic:
              - img "메뉴 열기"
        - generic [ref=e27]:
          - navigation "열린 페이지 탭" [ref=e28]:
            - generic [ref=e29]:
              - generic "홈" [ref=e30]:
                - generic [ref=e32] [cursor=pointer]:
                  - img [ref=e33]
                  - generic [ref=e36]: 홈
              - button "홈" [disabled] [ref=e38] [cursor=pointer]:
                - generic [ref=e39]:
                  - img
                  - generic [ref=e41]:
                    - generic [ref=e43]: 홈
                    - generic "홈 고정 탭" [ref=e44]:
                      - img [ref=e45]
              - button "새 탭 열기" [ref=e49] [cursor=pointer]:
                - img [ref=e50]
            - status [ref=e51]
          - generic [ref=e52]:
            - button "다운로드 이력" [ref=e53] [cursor=pointer]:
              - img [ref=e54]
            - generic [ref=e58]:
              - img [ref=e59]
              - generic [ref=e62]: 167:55:49
              - button "연장" [ref=e63] [cursor=pointer]
            - button "secret-redacted" [ref=e64] [cursor=pointer]:
              - generic [ref=e66]: secret-redacted
      - main [ref=e76]:
        - generic [ref=e77]:
          - generic [ref=e78]:
            - generic [ref=e79]:
              - generic [ref=e80]: 2026년 06월 11일
              - generic [ref=e81]: 요약
            - generic [ref=e82]:
              - generic [ref=e83]:
                - generic [ref=e84]:
                  - generic [ref=e85]: 일일 거래액
                  - button "더보기" [ref=e86] [cursor=pointer]
                - generic [ref=e88]: ₩0
              - generic [ref=e89]:
                - generic [ref=e90]:
                  - generic [ref=e91]: 일일 거래건수
                  - button "더보기" [ref=e92] [cursor=pointer]
                - generic [ref=e94]: 0건
              - generic [ref=e95]:
                - generic [ref=e96]:
                  - generic [ref=e97]: 지갑 잔액
                  - button "더보기" [ref=e98] [cursor=pointer]
                - generic [ref=e100]: ₩11,068,424
          - generic [ref=e101]:
            - generic [ref=e102]:
              - generic [ref=e103]:
                - generic [ref=e104]: 영업점 잠금 예약
                - button "더보기" [ref=e105] [cursor=pointer]
              - generic [ref=e106]: 잠금 예약된 영업점이 없습니다
            - generic [ref=e107]:
              - generic [ref=e108]:
                - generic [ref=e109]: 가맹점 잠금 예약
                - button "더보기" [ref=e110] [cursor=pointer]
              - generic [ref=e111]: 잠금 예약된 가맹점이 없습니다
          - generic [ref=e112]:
            - generic [ref=e113]:
              - generic [ref=e114]: 미수금 관리
              - generic [ref=e115]:
                - button "전체" [ref=e116] [cursor=pointer]
                - button "일수금" [ref=e117] [cursor=pointer]
                - button "채권" [ref=e118] [cursor=pointer]
                - button "통신비" [ref=e119] [cursor=pointer]
            - generic [ref=e120]:
              - generic [ref=e121]:
                - generic [ref=e122]:
                  - generic [ref=e123]: 일수금
                  - generic [ref=e124]: 4건
                - paragraph [ref=e125]: 남은금액
                - generic [ref=e126]:
                  - generic [ref=e127]: 11,200,000
                  - generic [ref=e128]: / 11,200,000
              - generic [ref=e129]:
                - generic [ref=e130]:
                  - generic [ref=e131]: 채권
                  - generic [ref=e132]: 14건
                - paragraph [ref=e133]: 남은금액
                - generic [ref=e134]:
                  - generic [ref=e135]: 2,012,179
                  - generic [ref=e136]: / 3,382,585
              - generic [ref=e137]:
                - generic [ref=e138]:
                  - generic [ref=e139]: 통신비
                  - generic [ref=e140]: 52건
                - paragraph [ref=e141]: 남은금액
                - generic [ref=e142]:
                  - generic [ref=e143]: 814,000
                  - generic [ref=e144]: / 814,000
            - generic [ref=e145]:
              - generic [ref=e146]:
                - generic [ref=e147]: "#"
                - generic [ref=e148]: 유형
                - generic [ref=e149]: 부서유형
                - generic [ref=e150]: 부서명
                - generic [ref=e151]: 회수실패
                - generic [ref=e152]: 남은횟수
                - generic [ref=e153]: 남은금액
                - generic [ref=e154]: 총액
                - generic [ref=e155]: 상환금액
              - generic [ref=e156] [cursor=pointer]:
                - generic [ref=e157]: "1"
                - generic [ref=e158]: 일수금
                - generic [ref=e159]: 가맹점
                - generic [ref=e160]: 반길현_가맹12
                - generic [ref=e161]: "50"
                - generic [ref=e162]: "100"
                - generic [ref=e163]: 10,000,000
                - generic [ref=e164]: 10,000,000
                - generic [ref=e165]: "0"
              - generic [ref=e166] [cursor=pointer]:
                - generic [ref=e167]: "2"
                - generic [ref=e168]: 일수금
                - generic [ref=e169]: 가맹점
                - generic [ref=e170]: 주홍석_가맹1
                - generic [ref=e171]: "50"
                - generic [ref=e172]: "100"
                - generic [ref=e173]: 100,000
                - generic [ref=e174]: 100,000
                - generic [ref=e175]: "0"
              - generic [ref=e176] [cursor=pointer]:
                - generic [ref=e177]: "3"
                - generic [ref=e178]: 일수금
                - generic [ref=e179]: 가맹점
                - generic [ref=e180]: 박재민_가맹
                - generic [ref=e181]: "49"
                - generic [ref=e182]: "200"
                - generic [ref=e183]: 1,000,000
                - generic [ref=e184]: 1,000,000
                - generic [ref=e185]: "0"
              - generic [ref=e186] [cursor=pointer]:
                - generic [ref=e187]: "4"
                - generic [ref=e188]: 일수금
                - generic [ref=e189]: 가맹점
                - generic [ref=e190]: 박재민_가맹
                - generic [ref=e191]: "41"
                - generic [ref=e192]: "100"
                - generic [ref=e193]: 100,000
                - generic [ref=e194]: 100,000
                - generic [ref=e195]: "0"
              - generic [ref=e196] [cursor=pointer]:
                - generic [ref=e197]: "5"
                - generic [ref=e198]: 채권
                - generic [ref=e199]: 법인
                - generic [ref=e200]: A_주홍석_법인
                - generic [ref=e201]: 10,040
                - generic [ref=e202]: 10,000
                - generic [ref=e203]: "-40"
              - generic [ref=e204] [cursor=pointer]:
                - generic [ref=e205]: "6"
                - generic [ref=e206]: 채권
                - generic [ref=e207]: 가맹점
                - generic [ref=e208]: A_주홍석_가맹4_루시페이먼츠
                - generic [ref=e209]: 34,287
                - generic [ref=e210]: 30,000
                - generic [ref=e211]: "-4,287"
              - generic [ref=e212] [cursor=pointer]:
                - generic [ref=e213]: "7"
                - generic [ref=e214]: 채권
                - generic [ref=e215]: 법인
                - generic [ref=e216]: 박재민_법인
                - generic [ref=e217]: 116,377
                - generic [ref=e218]: 116,377
                - generic [ref=e219]: "0"
              - generic [ref=e220] [cursor=pointer]:
                - generic [ref=e221]: "8"
                - generic [ref=e222]: 채권
                - generic [ref=e223]: 가맹점
                - generic [ref=e224]: A_주홍석_가맹1
                - generic [ref=e225]: "-13,500"
                - generic [ref=e226]: "0"
                - generic [ref=e227]: 13,500
              - generic [ref=e228] [cursor=pointer]:
                - generic [ref=e229]: "9"
                - generic [ref=e230]: 채권
                - generic [ref=e231]: 가맹점
                - generic [ref=e232]: 두바이소금빵가맹
                - generic [ref=e233]: 6,000
                - generic [ref=e234]: 6,000
                - generic [ref=e235]: "0"
              - generic [ref=e236] [cursor=pointer]:
                - generic [ref=e237]: "10"
                - generic [ref=e238]: 채권
                - generic [ref=e239]: 가맹점
                - generic [ref=e240]: 박재민_가맹3
                - generic [ref=e241]: "0"
                - generic [ref=e242]: 3,166
                - generic [ref=e243]: 3,166
              - generic [ref=e244] [cursor=pointer]:
                - generic [ref=e245]: "11"
                - generic [ref=e246]: 채권
                - generic [ref=e247]: 법인
                - generic [ref=e248]: 안법인
                - generic [ref=e249]: 27,029
                - generic [ref=e250]: 40,000
                - generic [ref=e251]: 12,971
              - generic [ref=e252] [cursor=pointer]:
                - generic [ref=e253]: "12"
                - generic [ref=e254]: 채권
                - generic [ref=e255]: 법인
                - generic [ref=e256]: 최인석 법인
                - generic [ref=e257]: 61,991
                - generic [ref=e258]: 35,956
                - generic [ref=e259]: "-26,035"
              - generic [ref=e260] [cursor=pointer]:
                - generic [ref=e261]: "13"
                - generic [ref=e262]: 채권
                - generic [ref=e263]: 법인
                - generic [ref=e264]: 반길현_법인
                - generic [ref=e265]: "-334"
                - generic [ref=e266]: 1,000
                - generic [ref=e267]: 1,334
              - generic [ref=e268] [cursor=pointer]:
                - generic [ref=e269]: "14"
                - generic [ref=e270]: 채권
                - generic [ref=e271]: 가맹점
                - generic [ref=e272]: 반길현_코페이_가맹2
                - generic [ref=e273]: "-79,550"
                - generic [ref=e274]: 10,450
                - generic [ref=e275]: 90,000
              - generic [ref=e276] [cursor=pointer]:
                - generic [ref=e277]: "15"
                - generic [ref=e278]: 채권
                - generic [ref=e279]: 가맹점
                - generic [ref=e280]: 박재민_가맹8
                - generic [ref=e281]: 190,000
                - generic [ref=e282]: 190,000
                - generic [ref=e283]: "0"
              - generic [ref=e284] [cursor=pointer]:
                - generic [ref=e285]: "16"
                - generic [ref=e286]: 채권
                - generic [ref=e287]: 가맹점
                - generic [ref=e288]: 안가맹
                - generic [ref=e289]: "-1,236,368"
                - generic [ref=e290]: 55,282
                - generic [ref=e291]: 1,291,650
              - generic [ref=e292] [cursor=pointer]:
                - generic [ref=e293]: "17"
                - generic [ref=e294]: 채권
                - generic [ref=e295]: 가맹점
                - generic [ref=e296]: 최인석 가맹
                - generic [ref=e297]: 99,494
                - generic [ref=e298]: 65,782
                - generic [ref=e299]: "-33,712"
              - generic [ref=e300] [cursor=pointer]:
                - generic [ref=e301]: "18"
                - generic [ref=e302]: 채권
                - generic [ref=e303]: 가맹점
                - generic [ref=e304]: 박재민_가맹
                - generic [ref=e305]: 2,796,713
                - generic [ref=e306]: 2,818,572
                - generic [ref=e307]: 21,859
              - generic [ref=e308] [cursor=pointer]:
                - generic [ref=e309]: "19"
                - generic [ref=e310]: 통신비
                - generic [ref=e311]: 가맹점
                - generic [ref=e312]: 가맹 엑셀 테스트
                - generic [ref=e313]: 11,000
                - generic [ref=e314]: 11,000
                - generic [ref=e315]: "0"
              - generic [ref=e316] [cursor=pointer]:
                - generic [ref=e317]: "20"
                - generic [ref=e318]: 통신비
                - generic [ref=e319]: 가맹점
                - generic [ref=e320]: 최인석 가맹14
                - generic [ref=e321]: 11,000
                - generic [ref=e322]: 11,000
                - generic [ref=e323]: "0"
              - generic [ref=e324] [cursor=pointer]:
                - generic [ref=e325]: "21"
                - generic [ref=e326]: 통신비
                - generic [ref=e327]: 가맹점
                - generic [ref=e328]: 최인석 가맹15
                - generic [ref=e329]: 11,000
                - generic [ref=e330]: 11,000
                - generic [ref=e331]: "0"
              - generic [ref=e332] [cursor=pointer]:
                - generic [ref=e333]: "22"
                - generic [ref=e334]: 통신비
                - generic [ref=e335]: 가맹점
                - generic [ref=e336]: 최인석 가맹16
                - generic [ref=e337]: 11,000
                - generic [ref=e338]: 11,000
                - generic [ref=e339]: "0"
              - generic [ref=e340] [cursor=pointer]:
                - generic [ref=e341]: "23"
                - generic [ref=e342]: 통신비
                - generic [ref=e343]: 가맹점
                - generic [ref=e344]: 최인석 가맹17
                - generic [ref=e345]: 11,000
                - generic [ref=e346]: 11,000
                - generic [ref=e347]: "0"
              - generic [ref=e348] [cursor=pointer]:
                - generic [ref=e349]: "24"
                - generic [ref=e350]: 통신비
                - generic [ref=e351]: 가맹점
                - generic [ref=e352]: 안승현 가맹1
                - generic [ref=e353]: 11,000
                - generic [ref=e354]: 11,000
                - generic [ref=e355]: "0"
              - generic [ref=e356] [cursor=pointer]:
                - generic [ref=e357]: "25"
                - generic [ref=e358]: 통신비
                - generic [ref=e359]: 가맹점
                - generic [ref=e360]: 안승현 가맹2
                - generic [ref=e361]: 11,000
                - generic [ref=e362]: 11,000
                - generic [ref=e363]: "0"
              - generic [ref=e364] [cursor=pointer]:
                - generic [ref=e365]: "26"
                - generic [ref=e366]: 통신비
                - generic [ref=e367]: 가맹점
                - generic [ref=e368]: 안승현 가맹3
                - generic [ref=e369]: 11,000
                - generic [ref=e370]: 11,000
                - generic [ref=e371]: "0"
              - generic [ref=e372] [cursor=pointer]:
                - generic [ref=e373]: "27"
                - generic [ref=e374]: 통신비
                - generic [ref=e375]: 가맹점
                - generic [ref=e376]: 안승현 가맹4
                - generic [ref=e377]: 11,000
                - generic [ref=e378]: 11,000
                - generic [ref=e379]: "0"
              - generic [ref=e380] [cursor=pointer]:
                - generic [ref=e381]: "28"
                - generic [ref=e382]: 통신비
                - generic [ref=e383]: 가맹점
                - generic [ref=e384]: 안승현 가맹5
                - generic [ref=e385]: 11,000
                - generic [ref=e386]: 11,000
                - generic [ref=e387]: "0"
              - generic [ref=e388] [cursor=pointer]:
                - generic [ref=e389]: "29"
                - generic [ref=e390]: 통신비
                - generic [ref=e391]: 가맹점
                - generic [ref=e392]: 최인석 가맹5
                - generic [ref=e393]: 11,000
                - generic [ref=e394]: 11,000
                - generic [ref=e395]: "0"
              - generic [ref=e396] [cursor=pointer]:
                - generic [ref=e397]: "30"
                - generic [ref=e398]: 통신비
                - generic [ref=e399]: 가맹점
                - generic [ref=e400]: 최인석 가맹3
                - generic [ref=e401]: 11,000
                - generic [ref=e402]: 11,000
                - generic [ref=e403]: "0"
              - generic [ref=e404] [cursor=pointer]:
                - generic [ref=e405]: "31"
                - generic [ref=e406]: 통신비
                - generic [ref=e407]: 가맹점
                - generic [ref=e408]: 최인석 가맹2
                - generic [ref=e409]: 11,000
                - generic [ref=e410]: 11,000
                - generic [ref=e411]: "0"
              - generic [ref=e412] [cursor=pointer]:
                - generic [ref=e413]: "32"
                - generic [ref=e414]: 통신비
                - generic [ref=e415]: 가맹점
                - generic [ref=e416]: 박재민_가맹8
                - generic [ref=e417]: 11,000
                - generic [ref=e418]: 11,000
                - generic [ref=e419]: "0"
              - generic [ref=e420] [cursor=pointer]:
                - generic [ref=e421]: "33"
                - generic [ref=e422]: 통신비
                - generic [ref=e423]: 가맹점
                - generic [ref=e424]: 박재민_가맹7
                - generic [ref=e425]: 11,000
                - generic [ref=e426]: 11,000
                - generic [ref=e427]: "0"
              - generic [ref=e428] [cursor=pointer]:
                - generic [ref=e429]: "34"
                - generic [ref=e430]: 통신비
                - generic [ref=e431]: 가맹점
                - generic [ref=e432]: 박재민_가맹6
                - generic [ref=e433]: 11,000
                - generic [ref=e434]: 11,000
                - generic [ref=e435]: "0"
              - generic [ref=e436] [cursor=pointer]:
                - generic [ref=e437]: "35"
                - generic [ref=e438]: 통신비
                - generic [ref=e439]: 가맹점
                - generic [ref=e440]: 최인석 가맹6
                - generic [ref=e441]: 11,000
                - generic [ref=e442]: 11,000
                - generic [ref=e443]: "0"
              - generic [ref=e444] [cursor=pointer]:
                - generic [ref=e445]: "36"
                - generic [ref=e446]: 통신비
                - generic [ref=e447]: 가맹점
                - generic [ref=e448]: 최인석 가맹7
                - generic [ref=e449]: 11,000
                - generic [ref=e450]: 11,000
                - generic [ref=e451]: "0"
              - generic [ref=e452] [cursor=pointer]:
                - generic [ref=e453]: "37"
                - generic [ref=e454]: 통신비
                - generic [ref=e455]: 가맹점
                - generic [ref=e456]: 최인석 가맹8
                - generic [ref=e457]: 11,000
                - generic [ref=e458]: 11,000
                - generic [ref=e459]: "0"
              - generic [ref=e460] [cursor=pointer]:
                - generic [ref=e461]: "38"
                - generic [ref=e462]: 통신비
                - generic [ref=e463]: 가맹점
                - generic [ref=e464]: 최인석 가맹9
                - generic [ref=e465]: 11,000
                - generic [ref=e466]: 11,000
                - generic [ref=e467]: "0"
              - generic [ref=e468] [cursor=pointer]:
                - generic [ref=e469]: "39"
                - generic [ref=e470]: 통신비
                - generic [ref=e471]: 가맹점
                - generic [ref=e472]: 최인석 가맹10
                - generic [ref=e473]: 11,000
                - generic [ref=e474]: 11,000
                - generic [ref=e475]: "0"
              - generic [ref=e476] [cursor=pointer]:
                - generic [ref=e477]: "40"
                - generic [ref=e478]: 통신비
                - generic [ref=e479]: 가맹점
                - generic [ref=e480]: 최인석 가맹11
                - generic [ref=e481]: 11,000
                - generic [ref=e482]: 11,000
                - generic [ref=e483]: "0"
              - generic [ref=e484] [cursor=pointer]:
                - generic [ref=e485]: "41"
                - generic [ref=e486]: 통신비
                - generic [ref=e487]: 가맹점
                - generic [ref=e488]: 최인석 가맹12
                - generic [ref=e489]: 11,000
                - generic [ref=e490]: 11,000
                - generic [ref=e491]: "0"
              - generic [ref=e492] [cursor=pointer]:
                - generic [ref=e493]: "42"
                - generic [ref=e494]: 통신비
                - generic [ref=e495]: 가맹점
                - generic [ref=e496]: 최인석 가맹13
                - generic [ref=e497]: 11,000
                - generic [ref=e498]: 11,000
                - generic [ref=e499]: "0"
              - generic [ref=e500] [cursor=pointer]:
                - generic [ref=e501]: "43"
                - generic [ref=e502]: 통신비
                - generic [ref=e503]: 가맹점
                - generic [ref=e504]: 박재민_가맹5
                - generic [ref=e505]: 11,000
                - generic [ref=e506]: 11,000
                - generic [ref=e507]: "0"
              - generic [ref=e508] [cursor=pointer]:
                - generic [ref=e509]: "44"
                - generic [ref=e510]: 통신비
                - generic [ref=e511]: 가맹점
                - generic [ref=e512]: 박재민_가맹_한결데
                - generic [ref=e513]: 11,000
                - generic [ref=e514]: 11,000
                - generic [ref=e515]: "0"
              - generic [ref=e516] [cursor=pointer]:
                - generic [ref=e517]: "45"
                - generic [ref=e518]: 통신비
                - generic [ref=e519]: 가맹점
                - generic [ref=e520]: 박재민_가맹3
                - generic [ref=e521]: 11,000
                - generic [ref=e522]: 11,000
                - generic [ref=e523]: "0"
              - generic [ref=e524] [cursor=pointer]:
                - generic [ref=e525]: "46"
                - generic [ref=e526]: 통신비
                - generic [ref=e527]: 가맹점
                - generic [ref=e528]: 최인석 가맹4
                - generic [ref=e529]: 11,000
                - generic [ref=e530]: 11,000
                - generic [ref=e531]: "0"
              - generic [ref=e532] [cursor=pointer]:
                - generic [ref=e533]: "47"
                - generic [ref=e534]: 통신비
                - generic [ref=e535]: 가맹점
                - generic [ref=e536]: 박재민_가맹2
                - generic [ref=e537]: 11,000
                - generic [ref=e538]: 11,000
                - generic [ref=e539]: "0"
              - generic [ref=e540] [cursor=pointer]:
                - generic [ref=e541]: "48"
                - generic [ref=e542]: 통신비
                - generic [ref=e543]: 가맹점
                - generic [ref=e544]: 김경주_가맹_테스트7
                - generic [ref=e545]: 22,000
                - generic [ref=e546]: 22,000
                - generic [ref=e547]: "0"
              - generic [ref=e548] [cursor=pointer]:
                - generic [ref=e549]: "49"
                - generic [ref=e550]: 통신비
                - generic [ref=e551]: 가맹점
                - generic [ref=e552]: 김경주_가맹_테스트6
                - generic [ref=e553]: 22,000
                - generic [ref=e554]: 22,000
                - generic [ref=e555]: "0"
              - generic [ref=e556] [cursor=pointer]:
                - generic [ref=e557]: "50"
                - generic [ref=e558]: 통신비
                - generic [ref=e559]: 가맹점
                - generic [ref=e560]: 김경주_가맹_테스트5
                - generic [ref=e561]: 22,000
                - generic [ref=e562]: 22,000
                - generic [ref=e563]: "0"
          - generic [ref=e564]:
            - generic [ref=e565]:
              - generic [ref=e566]: 공지사항
              - button "더보기" [ref=e567] [cursor=pointer]
            - generic [ref=e568]:
              - generic [ref=e569] [cursor=pointer]:
                - generic [ref=e570]: 테스트
                - generic [ref=e571]: 2026.06.09
              - generic [ref=e572] [cursor=pointer]:
                - generic [ref=e573]: 공지 테스트 0512
                - generic [ref=e574]: 2026.05.12
              - generic [ref=e575] [cursor=pointer]:
                - generic [ref=e576]: 패치노트 링크연결테스트
                - generic [ref=e577]: 2026.04.17
              - generic [ref=e578] [cursor=pointer]:
                - generic [ref=e579]: 테스트
                - generic [ref=e580]: 2026.04.17
              - generic [ref=e581] [cursor=pointer]:
                - generic [ref=e582]: 권한 테스트
                - generic [ref=e583]: 2026.04.17
              - generic [ref=e584] [cursor=pointer]:
                - generic [ref=e585]: co 테스트
                - generic [ref=e586]: 2026.04.17
```

# Test source

```ts
  153 |         await attachEvidenceLog(testInfo, userPresetPage, "ADMIN", "preset-selection", [
  154 |           "시스템메뉴 이동 > 사용자 프리셋 관리 > 사용자 프리셋 관리 화면에 접근해 QA 대상 프리셋을 확인했습니다.",
  155 |           `요청 프리셋: ${Object.entries(PRESET_BY_ROLE).map(([role, preset]) => `${role}=${preset}`).join(", ")}`,
  156 |           `API 확인 프리셋: ${resolvedPresets.map((preset) => `${preset.role}/${preset.name}(id=${preset.id}, users=${preset.userCount ?? "-"})`).join(" / ")}`,
  157 |           `현재 화면에서 감지한 프리셋명: ${visiblePresetNames.join(" / ") || "-"}`,
  158 |           `프리셋 권한 설정 카드 감지: ${/프리셋\s*권한\s*설정/.test(bodyText) ? "yes" : "no"}`,
  159 |           `기능권한 탭 감지: ${/기능\s*권한|기능권한/.test(bodyText) ? "yes" : "no"}`,
  160 |           `현재 URL: ${page.url()}`
  161 |         ]);
  162 |         await attachPageScreenshot(page, testInfo, userPresetPage, "ADMIN", "preset-selection");
  163 |
  164 |         expect(resolvedPresets, "admin/ta/co/bo 대상 프리셋이 API 목록에서 모두 확인되어야 합니다.").toHaveLength(TARGET_PRESETS.length);
  165 |         expect(bodyText, "사용자 프리셋 관리 화면에 프리셋 권한 설정 카드가 보여야 합니다.").toMatch(/사용자\s*프리셋|프리셋\s*권한\s*설정/);
  166 |       });
  167 |     });
  168 |
  169 |     test(items[1], async ({ browser }, testInfo) => {
  170 |       await withRolePage(browser, adminRuntime, async (page) => {
  171 |         await openQaPage(page, userPresetPage, adminRuntime, /사용자\s*프리셋|프리셋\s*권한|기능\s*권한/);
  172 |         const apiBase = apiBaseFromRuntime(adminRuntime);
  173 |         const resolvedPresets = await resolveTargetPresets(page.context().request, apiBase, adminRuntime.tenantId!);
  174 |         const beforeStates = await readPresetStates(page.context().request, apiBase, adminRuntime.tenantId!, resolvedPresets);
  175 |         rememberOriginalStates(originalPresetStates, beforeStates);
  176 |         const lines = [
  177 |           "사용자 프리셋 관리 > 프리셋 권한 설정 카드 > 기능권한 탭의 정산내역 > 정산 조회(READ_SETTLEMENT) 권한을 API로 확인했습니다.",
  178 |           `권한 변경 guard: ${process.env[PERMISSION_MUTATION_GUARD] === "1" ? "enabled" : "disabled"}`,
  179 |           ...beforeStates.map((state) => `${state.role}/${state.name}: 시작 상태 READ_SETTLEMENT=${state.permissionIds.includes(READ_SETTLEMENT_PERMISSION) ? "ON" : "OFF"} / permissionIds=${state.permissionIds.length}`)
  180 |         ];
  181 |
  182 |         if (process.env[PERMISSION_MUTATION_GUARD] !== "1") {
  183 |           await attachEvidenceLog(testInfo, userPresetPage, "ADMIN", "settlement-permission-toggle", lines);
  184 |           await attachPageScreenshot(page, testInfo, userPresetPage, "ADMIN", "settlement-permission-toggle");
  185 |           test.skip(true, `BLOCKED: 공유 프리셋 권한 변경은 ${PERMISSION_MUTATION_GUARD}=1 설정이 필요합니다.`);
  186 |         }
  187 |
  188 |         for (const state of beforeStates) {
  189 |           await setReadSettlementPermission(page.context().request, apiBase, adminRuntime.tenantId!, state, true);
  190 |           const grantedState = await readPresetState(page.context().request, apiBase, adminRuntime.tenantId!, state);
  191 |           await setReadSettlementPermission(page.context().request, apiBase, adminRuntime.tenantId!, grantedState, false);
  192 |           const revokedState = await readPresetState(page.context().request, apiBase, adminRuntime.tenantId!, state);
  193 |           await setReadSettlementPermission(page.context().request, apiBase, adminRuntime.tenantId!, revokedState, true);
  194 |           const regrantedState = await readPresetState(page.context().request, apiBase, adminRuntime.tenantId!, state);
  195 |           lines.push(`${state.role}/${state.name}: 부여 후=${grantedState.permissionIds.includes(READ_SETTLEMENT_PERMISSION) ? "ON" : "OFF"}, 회수 후=${revokedState.permissionIds.includes(READ_SETTLEMENT_PERMISSION) ? "ON" : "OFF"}, 재부여 후=${regrantedState.permissionIds.includes(READ_SETTLEMENT_PERMISSION) ? "ON" : "OFF"}`);
  196 |           expect(grantedState.permissionIds, `${state.role}/${state.name} 정산 조회 권한 부여가 반영되어야 합니다.`).toContain(READ_SETTLEMENT_PERMISSION);
  197 |           expect(revokedState.permissionIds, `${state.role}/${state.name} 정산 조회 권한 회수가 반영되어야 합니다.`).not.toContain(READ_SETTLEMENT_PERMISSION);
  198 |           expect(regrantedState.permissionIds, `${state.role}/${state.name} 정산 조회 권한 재부여가 반영되어야 합니다.`).toContain(READ_SETTLEMENT_PERMISSION);
  199 |         }
  200 |
  201 |         await attachEvidenceLog(testInfo, userPresetPage, "ADMIN", "settlement-permission-toggle", lines);
  202 |         await attachPageScreenshot(page, testInfo, userPresetPage, "ADMIN", "settlement-permission-toggle");
  203 |       });
  204 |     });
  205 |
  206 |     test(items[2], async ({ browser }, testInfo) => {
  207 |       await ensureAllTargetPresets(browser, adminRuntime, originalPresetStates, true);
  208 |       const snapshots = await collectAllRoleSnapshots(browser, options, transactionPage, settlementPage, testInfo, "granted-button-visible");
  209 |       await attachRoleMatrixLog(testInfo, transactionPage, "ADMIN", "granted-button-visible", snapshots);
  210 |
  211 |       for (const snapshot of snapshots) {
  212 |         expect(snapshot.settlementPageAccessible, `${snapshot.role} 정산 조회 권한 보유 시 정산내역 메뉴 접근이 가능해야 합니다.`).toBe(true);
  213 |         expect(snapshot.transactionPageAccessible, `${snapshot.role} 거래내역 화면 접근이 가능해야 합니다.`).toBe(true);
  214 |         expect(snapshot.settlementButtonVisible, `${snapshot.role} 정산 조회 권한 보유 시 거래내역 본문 정산내역 버튼이 보여야 합니다.`).toBe(true);
  215 |         expect(snapshot.modalOpened, `${snapshot.role} 정산내역 버튼 클릭 시 모달이 열려야 합니다.`).toBe(true);
  216 |         expect(snapshot.modalText, `${snapshot.role} 정산내역 모달에 정산 정보가 보여야 합니다.`).toMatch(/정산|금액|상태|일시|합계/);
  217 |       }
  218 |     });
  219 |
  220 |     test(items[3], async ({ browser }, testInfo) => {
  221 |       await ensureAllTargetPresets(browser, adminRuntime, originalPresetStates, false);
  222 |       const snapshots = await collectAllRoleSnapshots(browser, options, transactionPage, settlementPage, testInfo, "revoked-button-hidden");
  223 |       await attachRoleMatrixLog(testInfo, transactionPage, "ADMIN", "revoked-button-hidden", snapshots);
  224 |
  225 |       for (const snapshot of snapshots) {
  226 |         expect(snapshot.transactionPageAccessible, `${snapshot.role} 거래내역 접근 권한은 유지되어야 합니다.`).toBe(true);
  227 |         expect(snapshot.settlementButtonVisible, `${snapshot.role} 정산 조회 권한 회수 시 거래내역 본문 정산내역 버튼이 보이면 안 됩니다.`).toBe(false);
  228 |       }
  229 |     });
  230 |
  231 |     test(items[4], async ({ browser }, testInfo) => {
  232 |       await ensureAllTargetPresets(browser, adminRuntime, originalPresetStates, false);
  233 |       const snapshots = await collectAllRoleSnapshots(browser, options, transactionPage, settlementPage, testInfo, "revoked-settlement-denied");
  234 |       await attachRoleMatrixLog(testInfo, settlementPage, "ADMIN", "revoked-settlement-denied", snapshots);
  235 |
  236 |       for (const snapshot of snapshots) {
  237 |         expect(snapshot.settlementDenied, `${snapshot.role} 정산내역 권한 회수 시 권한 없음 문구가 보여야 합니다.`).toBe(true);
  238 |         expect(snapshot.settlementPageAccessible, `${snapshot.role} 정산 조회 권한 회수 시 정산내역 본문 접근이 가능하면 안 됩니다.`).toBe(false);
  239 |       }
  240 |     });
  241 |
  242 |     test(items[5], async ({ browser }, testInfo) => {
  243 |       await ensureAllTargetPresets(browser, adminRuntime, originalPresetStates, false, ["ADMIN"]);
  244 |       const revokedSnapshot = await collectRoleSnapshot(browser, options, "ADMIN", transactionPage, settlementPage, testInfo, "admin-revoked-correlation");
  245 |       await attachRoleMatrixLog(testInfo, transactionPage, "ADMIN", "admin-revoked-correlation", [revokedSnapshot]);
  246 |       expect(revokedSnapshot.settlementDenied, "ADMIN 정산 조회 권한 미보유 시 정산내역 메뉴에서 권한 없음 문구가 보여야 합니다.").toBe(true);
  247 |       expect(revokedSnapshot.settlementButtonVisible, "ADMIN 정산 조회 권한 미보유 시 거래내역 본문 정산내역 버튼이 보이면 안 됩니다.").toBe(false);
  248 |
  249 |       await ensureAllTargetPresets(browser, adminRuntime, originalPresetStates, true, ["ADMIN"]);
  250 |       const grantedSnapshot = await collectRoleSnapshot(browser, options, "ADMIN", transactionPage, settlementPage, testInfo, "admin-granted-correlation");
  251 |       await attachRoleMatrixLog(testInfo, transactionPage, "ADMIN", "admin-granted-correlation", [grantedSnapshot]);
  252 |       expect(grantedSnapshot.settlementPageAccessible, "ADMIN 정산 조회 권한 부여 시 정산내역 메뉴 접근이 가능해야 합니다.").toBe(true);
> 253 |       expect(grantedSnapshot.settlementButtonVisible, "ADMIN 정산 조회 권한 부여 시 거래내역 본문 정산내역 버튼이 보여야 합니다.").toBe(true);
      |                                                                                                        ^ Error: ADMIN 정산 조회 권한 부여 시 거래내역 본문 정산내역 버튼이 보여야 합니다.
  254 |     });
  255 |   });
  256 |
  257 |   function requirePage(name: string): QaPageDefinition {
  258 |     const pageDefinition = checklist.pages.find((page) => page.name === name);
  259 |     if (!pageDefinition) {
  260 |       throw new Error(`checklist.json pages에 '${name}' 정의가 필요합니다.`);
  261 |     }
  262 |     return pageDefinition;
  263 |   }
  264 | }
  265 |
  266 | async function ensureAllTargetPresets(
  267 |   browser: Browser,
  268 |   adminRuntime: RuntimeQaEnv,
  269 |   originalPresetStates: Map<string, PresetPermissionState>,
  270 |   enabled: boolean,
  271 |   onlyRoles?: string[]
  272 | ): Promise<void> {
  273 |   if (process.env[PERMISSION_MUTATION_GUARD] !== "1") {
  274 |     test.skip(true, `BLOCKED: 공유 프리셋 권한 변경은 ${PERMISSION_MUTATION_GUARD}=1 설정이 필요합니다.`);
  275 |   }
  276 |
  277 |   await withRolePage(browser, adminRuntime, async (page) => {
  278 |     await ensureAuthenticatedPage(page, adminRuntime);
  279 |     const apiBase = apiBaseFromRuntime(adminRuntime);
  280 |     const targetPresets = await resolveTargetPresets(page.context().request, apiBase, adminRuntime.tenantId!);
  281 |     const states = await readPresetStates(page.context().request, apiBase, adminRuntime.tenantId!, targetPresets);
  282 |     rememberOriginalStates(originalPresetStates, states);
  283 |
  284 |     for (const state of states) {
  285 |       if (onlyRoles && !onlyRoles.includes(state.role)) {
  286 |         continue;
  287 |       }
  288 |       await setReadSettlementPermission(page.context().request, apiBase, adminRuntime.tenantId!, state, enabled);
  289 |     }
  290 |
  291 |     await page.waitForTimeout(3_000);
  292 |   });
  293 | }
  294 |
  295 | function rememberOriginalStates(
  296 |   originalPresetStates: Map<string, PresetPermissionState>,
  297 |   states: PresetPermissionState[]
  298 | ): void {
  299 |   for (const state of states) {
  300 |     const key = presetKey(state);
  301 |     if (!originalPresetStates.has(key)) {
  302 |       originalPresetStates.set(key, {
  303 |         ...state,
  304 |         permissionIds: [...state.permissionIds]
  305 |       });
  306 |     }
  307 |   }
  308 | }
  309 |
  310 | async function resolveTargetPresets(
  311 |   request: APIRequestContext,
  312 |   apiBase: string,
  313 |   tenantId: string
  314 | ): Promise<ResolvedPreset[]> {
  315 |   const resolved: ResolvedPreset[] = [];
  316 |   const missing: string[] = [];
  317 |
  318 |   for (const target of TARGET_PRESETS) {
  319 |     const listUrl = new URL(`${apiBase}/api/v1/admin/role-permission-presets`);
  320 |     listUrl.searchParams.set("tenantId", tenantId);
  321 |     listUrl.searchParams.set("role", target.role);
  322 |     const response = await request.get(listUrl.toString());
  323 |     if (!response.ok()) {
  324 |       throw new Error(`BLOCKED: ${target.role} 프리셋 목록 조회 실패 status=${response.status()}`);
  325 |     }
  326 |     const body = await response.json() as { payload?: PresetListItem[] };
  327 |     const preset = body.payload?.find((item) => item.name === target.name);
  328 |     if (!preset) {
  329 |       missing.push(`${target.role}/${target.name}`);
  330 |       continue;
  331 |     }
  332 |     resolved.push({
  333 |       role: target.role,
  334 |       name: preset.name,
  335 |       id: preset.id,
  336 |       description: preset.description ?? "",
  337 |       departments: preset.departments ?? [],
  338 |       userCount: preset.userCount,
  339 |       isDefault: preset.isDefault
  340 |     });
  341 |   }
  342 |
  343 |   if (missing.length > 0) {
  344 |     throw new Error(`BLOCKED: 대상 사용자 프리셋을 찾지 못했습니다. missing=${missing.join(", ")}`);
  345 |   }
  346 |
  347 |   return resolved;
  348 | }
  349 |
  350 | async function readPresetStates(
  351 |   request: APIRequestContext,
  352 |   apiBase: string,
  353 |   tenantId: string,
```