# 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: 3529/dev/store-settlement-balance.spec.ts >> [3529][dev] [QA] 비스킷페이 총 정산예정금 상세 내역 확인 >> [VE] role >> 비스킷페이 거래내역 >> 비스킷페이 거래내역 합계 영역에서 총 정산금액과 세금 정보가 공제 전 기준으로 보이는지 확인
- Location: src/qa/scenarios/storeSettlementBalance.ts:304:9

# Error details

```
Error: 거래내역 세금/부가세 정보가 보여야 합니다.

expect(received).toMatch(expected)

Expected pattern: /세금|부가세|세액|VAT/i
Received string:  "빅스페이먼츠 뒤로가기 거래내역 정산내역 주문내역 조회 기간 총 8건 ~ 조회 2026-06-12 ~ 2026-06-19 총 8건 매출합계 (정산합계) 42,345원 (40,227원) 결제취소 박재민_가맹_한결데 [수기결제] 06. 12. 20:45 -1,004원 (-953원) 영수증 복사하기 한국결제데이터 • 승인번호: 20796079 신한카드 • 510737******8654 결제승인 박재민_가맹_한결데 [수기결제] 06. 12. 20:45 1,004원 (953원) 영수증 복사하기 한국결제데이터 • 승인번호: 20796079 신한카드 • 510737******8654 결제승인 박재민_가맹_한결데 [알림결제(인증)] 06. 12. 20:25 10,000원 (9,500원) 영수증 복사하기 웰컴페이먼츠 • 승인번호: 23146055 국민 • 557162******0301 거래취소 결제승인 박재민_가맹_한결데 [알림결제(인증)] 06. 12. 20:21 10,000원 (9,500원) 영수증 복사하기 웰컴페이먼츠 • 승인번호: 20173347 국민 • 557162******0301 거래취소 결제승인 박재민_가맹_한결데 [알림결제(인증)] 06. 12. 20:21 10,000원 (9,500원) 영수증 복사하기 웰컴페이먼츠 • 승인번호: 85833672 국민 • 557162******0301 거래취소 결제승인 박재민_가맹_한결데 [알림결제(인증)] 06. 12. 20:20 12,345원 (11,727원) 영수증 복사하기 웰컴페이먼츠 • 승인번호: 43577422 국민 • 557162******0301 거래취소 결제취소 박재민_가맹_한결데 [수기결제] 06. 12. 01:50 -1,004원 (-953원) 영수증 복사하기 한국결제데이터 • 승인번호: 09248676 신한카드 • 510737******8654 결제승인 박재민_가맹_한결데 [수기결제] 06. 12. 01:49 1,004원 (953원) 영수증 복사하기 한국결제데이터 • 승인번호: 09248676 신한카드 • 510737******8654 홈 지갑 결제 내역 카드"
```

# Test source

```ts
  216 |               `기준 금액: ${formatKrw(target.expectedTotal)}`,
  217 |               "결론: 홈 총 정산예정금이 기준 금액과 일치합니다."
  218 |             ]);
  219 |           });
  220 |
  221 |           test(`${target.accountLabel} 홈 정산예정금 상세 팝업 분리 금액 및 슬라이드 닫힘 확인`, async ({ browser }, testInfo) => {
  222 |             test.skip(isRuntimeRoleSkipped(target.envRole), `${target.envRole} 로그인 갱신 실패로 스토어 홈 팝업 QA를 건너뜁니다.`);
  223 |             test.setTimeout(110_000);
  224 |
  225 |             const snapshot = await inspectHomeSettlementPopup(browser, options, target, homePage, testInfo);
  226 |             expect(snapshot.breakdown?.totalSettlementAmount, "팝업 총 정산예정금은 기준 금액과 일치해야 합니다.").toBe(target.expectedTotal);
  227 |           });
  228 |         });
  229 |
  230 |         test.describe(walletPage.name, () => {
  231 |           test(`${target.accountLabel} 지갑잔고 정산예정금 및 새로고침 유지 확인`, async ({ browser }, testInfo) => {
  232 |             test.skip(isRuntimeRoleSkipped(target.envRole), `${target.envRole} 로그인 갱신 실패로 지갑잔고 QA를 건너뜁니다.`);
  233 |             test.setTimeout(90_000);
  234 |
  235 |             const snapshot = await collectStoreSnapshot(browser, options, target, walletPage, testInfo, `wallet-total-${target.role}`, {
  236 |               requireWallet: true,
  237 |               attachScreenshot: true
  238 |             });
  239 |             expect(snapshot.walletPendingAmount, "스토어 지갑잔고 정산예정금 금액을 읽어야 합니다.").toBe(target.expectedTotal);
  240 |
  241 |             const refreshedAmount = await reloadAndReadWalletAmount(browser, options, target, walletPage, testInfo);
  242 |             expect(refreshedAmount, "새로고침 후 지갑잔고 정산예정금이 유지되어야 합니다.").toBe(target.expectedTotal);
  243 |
  244 |             await attachEvidenceLog(testInfo, walletPage.name, target.role, `wallet-total-${target.role}`, [
  245 |               `${target.accountLabel}(${target.departmentName}) 계정으로 스토어 지갑잔고 화면을 확인했습니다.`,
  246 |               `지갑잔고 화면 정산예정금: ${formatKrw(snapshot.walletPendingAmount ?? 0)}`,
  247 |               `wallet API processingSettlement: ${
  248 |                 snapshot.walletProcessingSettlement === undefined ? "-" : formatKrw(snapshot.walletProcessingSettlement)
  249 |               }`,
  250 |               `새로고침 후 정산예정금: ${formatKrw(refreshedAmount)}`,
  251 |               `기준 금액: ${formatKrw(target.expectedTotal)}`,
  252 |               "결론: 지갑잔고 화면 정산예정금과 새로고침 후 금액이 기준 금액과 일치합니다."
  253 |             ]);
  254 |           });
  255 |         });
  256 |       });
  257 |     }
  258 |   });
  259 | }
  260 |
  261 | function runIssue3529Suite(
  262 |   options: ScenarioOptions,
  263 |   subject: string,
  264 |   checklistItems: string[],
  265 |   pages: QaPageDefinition[]
  266 | ): void {
  267 |   const storeTransactionsPage = findPage(pages, "비스킷페이 거래내역");
  268 |   const storeSettlementsPage = findPage(pages, "비스킷페이 정산내역");
  269 |   const storeWalletPage = findPage(pages, "비스킷페이 지갑");
  270 |   const adminSettlementsPage = findPage(pages, "비스킷링크 정산내역");
  271 |   const storeRuntime = getRuntimeQaEnv(options.environment, "store", ISSUE_3529_STORE_ENV_ROLE);
  272 |   const adminRuntime = getRuntimeQaEnv(options.environment, "admin", ADMIN_ROLE);
  273 |   let transactionSnapshot: Issue3529Snapshot | undefined;
  274 |   const settlementSnapshots = new Map<string, Issue3529Snapshot>();
  275 |   let adminSettlementSnapshot: Issue3529Snapshot | undefined;
  276 |
  277 |   test.describe(`[${options.issueId}][${options.environment}] ${subject}`, () => {
  278 |     test.describe(`[${ISSUE_3529_STORE_ROLE}] role`, () => {
  279 |       test.describe(storeTransactionsPage.name, () => {
  280 |         test(checklistItems[0] ?? "BP100060 거래 정산금액 공제 전 기준 확인", async ({ browser }, testInfo) => {
  281 |           test.setTimeout(90_000);
  282 |           transactionSnapshot = await collectIssue3529StoreSnapshot(
  283 |             browser,
  284 |             storeRuntime,
  285 |             storeTransactionsPage,
  286 |             testInfo,
  287 |             "store-transaction-merchant",
  288 |             { expectedText: /거래|정산|결제/, statusText: undefined }
  289 |           );
  290 |
  291 |           expect(transactionSnapshot.bodyText, "거래내역에서 BP100060 또는 검색 조건이 확인되어야 합니다.").toMatch(/BP100060|거래|결제/);
  292 |           expect(transactionSnapshot.bodyText, "거래내역에서 정산금액 관련 문구가 보여야 합니다.").toMatch(/정산\s*금액|정산금액|정산/);
  293 |           expect(transactionSnapshot.amounts.length, "거래내역 금액 근거가 있어야 합니다.").toBeGreaterThan(0);
  294 |
  295 |           await attachEvidenceLog(testInfo, storeTransactionsPage.name, ISSUE_3529_STORE_ROLE, "store-transaction-merchant", [
  296 |             `${ISSUE_3529_STORE_ACCOUNT_LABEL} 계정으로 스토어 거래내역을 조회했습니다.`,
  297 |             `검색 기준: 가맹점 고유번호 ${ISSUE_3529_MERCHANT_CODE}, 기간 ${ISSUE_3529_PERIOD.from} ~ ${ISSUE_3529_PERIOD.to}`,
  298 |             `화면 금액 후보: ${formatAmounts(transactionSnapshot.amounts)}`,
  299 |             `수집한 요청: ${transactionSnapshot.requestUrls.slice(0, 8).join(" / ") || "-"}`,
  300 |             "결론: BP100060 조건의 거래내역 화면에서 정산금액 표시 근거를 확인했습니다."
  301 |           ]);
  302 |         });
  303 |
  304 |         test(checklistItems[1] ?? "거래내역 합계 영역 총 정산금액과 세금 정보 확인", async ({ browser }, testInfo) => {
  305 |           test.setTimeout(90_000);
  306 |           const snapshot = await collectIssue3529StoreSnapshot(
  307 |             browser,
  308 |             storeRuntime,
  309 |             storeTransactionsPage,
  310 |             testInfo,
  311 |             "store-transaction-summary",
  312 |             { expectedText: /거래|정산|합계/ }
  313 |           );
  314 |
  315 |           expect(snapshot.bodyText, "거래내역 합계/총액 영역이 보여야 합니다.").toMatch(/합계|총\s*정산|총정산|총액|정산금액/);
> 316 |           expect(snapshot.bodyText, "거래내역 세금/부가세 정보가 보여야 합니다.").toMatch(/세금|부가세|세액|VAT/i);
      |                                                                 ^ Error: 거래내역 세금/부가세 정보가 보여야 합니다.
  317 |           expect(snapshot.amounts.length, "거래내역 합계 금액 근거가 있어야 합니다.").toBeGreaterThan(0);
  318 |
  319 |           await attachEvidenceLog(testInfo, storeTransactionsPage.name, ISSUE_3529_STORE_ROLE, "store-transaction-summary", [
  320 |             "거래내역 합계 영역에서 총 정산금액 및 세금 문구를 확인했습니다.",
  321 |             `화면 금액 후보: ${formatAmounts(snapshot.amounts)}`,
  322 |             "결론: 총 정산금액/세금 정보가 화면에서 확인 가능한 형태로 표시됩니다."
  323 |           ]);
  324 |         });
  325 |       });
  326 |
  327 |       test.describe(storeSettlementsPage.name, () => {
  328 |         for (const statusText of ["정산예정", "정산대기", "정산완료"]) {
  329 |           const checklistIndex = statusText === "정산예정" ? 2 : statusText === "정산대기" ? 3 : 4;
  330 |           test(checklistItems[checklistIndex] ?? `${statusText} 정산 금액 확인`, async ({ browser }, testInfo) => {
  331 |             test.setTimeout(100_000);
  332 |             const snapshot = await collectIssue3529StoreSnapshot(
  333 |               browser,
  334 |               storeRuntime,
  335 |               storeSettlementsPage,
  336 |               testInfo,
  337 |               `store-settlement-${statusText}`,
  338 |               { expectedText: /정산|거래|결제/, statusText }
  339 |             );
  340 |             settlementSnapshots.set(statusText, snapshot);
  341 |
  342 |             expect(snapshot.bodyText, `${statusText} 상태 문구가 화면에 보여야 합니다.`).toContain(statusText);
  343 |             expect(snapshot.amounts.length, `${statusText} 금액 근거가 있어야 합니다.`).toBeGreaterThan(0);
  344 |             if (statusText === "정산완료") {
  345 |               expect(snapshot.bodyText, "정산완료 건은 세금/공제/최종 금액 근거가 보여야 합니다.").toMatch(/세금|부가세|공제|최종|실\s*정산|실정산/);
  346 |             }
  347 |
  348 |             await attachEvidenceLog(testInfo, storeSettlementsPage.name, ISSUE_3529_STORE_ROLE, `store-settlement-${statusText}`, [
  349 |               `${statusText} 조건으로 스토어 정산내역을 조회했습니다.`,
  350 |               `조회 기간: ${ISSUE_3529_PERIOD.from} ~ ${ISSUE_3529_PERIOD.to}`,
  351 |               `화면 금액 후보: ${formatAmounts(snapshot.amounts)}`,
  352 |               `정산예정금 상세 API: ${snapshot.settlementBreakdown ? formatBreakdown(snapshot.settlementBreakdown) : "-"}`,
  353 |               `수집한 요청: ${snapshot.requestUrls.slice(0, 8).join(" / ") || "-"}`,
  354 |               `결론: ${statusText} 정산 금액 표시 근거를 확인했습니다.`
  355 |             ]);
  356 |           });
  357 |         }
  358 |       });
  359 |
  360 |       test.describe(storeWalletPage.name, () => {
  361 |         test(checklistItems[6] ?? "지갑 정산예정금/정산대기금과 정산내역 합계 일치 확인", async ({ browser }, testInfo) => {
  362 |           test.setTimeout(100_000);
  363 |           const walletSnapshot = await collectIssue3529StoreSnapshot(
  364 |             browser,
  365 |             storeRuntime,
  366 |             storeWalletPage,
  367 |             testInfo,
  368 |             "store-wallet-settlement-total",
  369 |             { expectedText: /정산예정금|정산대기금|지갑/ }
  370 |           );
  371 |
  372 |           const pending = extractOptionalAmountAfterLabel(walletSnapshot.bodyText, "정산예정금");
  373 |           const waiting = extractOptionalAmountAfterLabel(walletSnapshot.bodyText, "정산대기금");
  374 |           expect(walletSnapshot.bodyText, "지갑 화면에서 정산예정금 또는 정산대기금 문구가 보여야 합니다.").toMatch(/정산예정금|정산대기금/);
  375 |           expect(walletSnapshot.amounts.length, "지갑 화면 금액 근거가 있어야 합니다.").toBeGreaterThan(0);
  376 |
  377 |           const pendingSnapshot = settlementSnapshots.get("정산예정");
  378 |           const waitingSnapshot = settlementSnapshots.get("정산대기");
  379 |           if (pending !== undefined && pendingSnapshot?.settlementBreakdown) {
  380 |             expect(pending, "지갑 정산예정금은 정산내역 정산예정 상세 금액과 일치해야 합니다.").toBe(
  381 |               pendingSnapshot.settlementBreakdown.pendingSettlementAmount
  382 |             );
  383 |           }
  384 |           if (waiting !== undefined && waitingSnapshot?.settlementBreakdown) {
  385 |             expect(waiting, "지갑 정산대기금은 정산내역 정산대기 상세 금액과 일치해야 합니다.").toBe(
  386 |               waitingSnapshot.settlementBreakdown.settlementWaitingAmount
  387 |             );
  388 |           }
  389 |
  390 |           await attachEvidenceLog(testInfo, storeWalletPage.name, ISSUE_3529_STORE_ROLE, "store-wallet-settlement-total", [
  391 |             "스토어 지갑 화면의 정산예정금/정산대기금 영역을 확인했습니다.",
  392 |             `지갑 정산예정금: ${pending === undefined ? "-" : formatKrw(pending)}`,
  393 |             `지갑 정산대기금: ${waiting === undefined ? "-" : formatKrw(waiting)}`,
  394 |             `화면 금액 후보: ${formatAmounts(walletSnapshot.amounts)}`,
  395 |             `정산예정 상세 API: ${pendingSnapshot?.settlementBreakdown ? formatBreakdown(pendingSnapshot.settlementBreakdown) : "-"}`,
  396 |             `정산대기 상세 API: ${waitingSnapshot?.settlementBreakdown ? formatBreakdown(waitingSnapshot.settlementBreakdown) : "-"}`,
  397 |             "결론: 지갑 화면과 정산내역 상세 금액 비교 근거를 수집했습니다."
  398 |           ]);
  399 |         });
  400 |       });
  401 |     });
  402 |
  403 |     test.describe(`[${ADMIN_ROLE}] role`, () => {
  404 |       test.describe(adminSettlementsPage.name, () => {
  405 |         test(checklistItems[5] ?? "비스킷링크 정산내역과 비스킷페이 정산내역 금액 비교", async ({ browser }, testInfo) => {
  406 |           test.setTimeout(100_000);
  407 |           const storeSnapshot = settlementSnapshots.get("정산예정") ?? await collectIssue3529StoreSnapshot(
  408 |             browser,
  409 |             storeRuntime,
  410 |             storeSettlementsPage,
  411 |             testInfo,
  412 |             "store-settlement-admin-source",
  413 |             { expectedText: /정산예정|정산내역/, statusText: "정산예정", attachScreenshot: false }
  414 |           );
  415 |
  416 |           adminSettlementSnapshot = await collectIssue3529AdminSettlementSnapshot(
```