# 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: src/manager/tests/e2e/booking/booking-create.spec.ts >> creates a card auto-charged booking
- Location: src/manager/tests/e2e/booking/booking-create.spec.ts:84:7

# Error details

```
Error: expect(locator).toHaveText(expected) failed

Locator: getByTestId('app-page').getByTestId('app-page-content').locator('[data-test-id=app-details-card]:has([data-test-id=title]:has-text("Billing"))').locator('[data-test-id=key-value-item]:has([data-test-id=key]:text-is("Payment method"))').getByTestId('payment-method-row')
Expected: "•••• 4444 Card"
Timeout: 30000ms
Error: element(s) not found

Call log:
  - Expect "toHaveText" with timeout 30000ms
  - waiting for getByTestId('app-page').getByTestId('app-page-content').locator('[data-test-id=app-details-card]:has([data-test-id=title]:has-text("Billing"))').locator('[data-test-id=key-value-item]:has([data-test-id=key]:text-is("Payment method"))').getByTestId('payment-method-row')

```

```yaml
- navigation:
  - link:
    - /url: /
  - text: KINNOVIS Manager
  - button:
    - img
  - list:
    - text: Dashboard
    - link "Tasks":
      - /url: /tasks
      - img
      - text: Tasks
    - link "Facility maps":
      - /url: /facility-map
    - link "Analytics":
      - /url: /dashboard
    - text: Sales
    - link "Bookings":
      - /url: /bookings
    - link "Customers":
      - /url: /customers
    - link "Invoices":
      - /url: /invoices
    - link "Credit notes":
      - /url: /credit-notes
      - img
      - text: Credit notes
    - link "Units":
      - /url: /units
    - text: Site management
    - link "Locations":
      - /url: /locations
    - link "Unit types":
      - /url: /unit-types
    - link "Protection Plans":
      - /url: /insurances
    - link "Deposits":
      - /url: /deposits
    - link "Products":
      - /url: /products
    - link "Discounts":
      - /url: /discounts
    - option "Emails"
    - link "Document templates":
      - /url: /document-templates
    - text: Admin
    - link "Integrations":
      - /url: /connected-apps
    - link "User & Roles":
      - /url: /users
    - option "Booking Portal"
    - option "JaneAI"
    - text: Feedback
    - link "Voting Portal":
      - /url: /voting-portal
  - button "AS Andreas Stadler andreas.stadler@storeroom.at"
  - button
- main:
  - link "Bookings":
    - /url: /bookings
  - text: Booking 3163-6288-6682-261 Active
  - button "Actions"
  - tablist:
    - tab "Details" [selected]
    - tab "Timeline"
  - separator
  - heading "General" [level=3]
  - table:
    - rowgroup:
      - row "Customer Alfredo Weissnat":
        - rowheader "Customer"
        - cell "Alfredo Weissnat":
          - link "Alfredo Weissnat":
            - /url: /customers/465050282
      - row "Location Vienna South":
        - rowheader "Location"
        - cell "Vienna South":
          - link "Vienna South":
            - /url: /locations/5000500050
      - row "Created at 19 Aug 2026":
        - rowheader "Created at"
        - cell "19 Aug 2026"
      - row "Move-in 19 Aug 2026":
        - rowheader "Move-in"
        - cell "19 Aug 2026"
      - row "Move-out -":
        - rowheader "Move-out"
        - cell "-"
      - row "Cancelled at -":
        - rowheader "Cancelled at"
        - cell "-"
      - row "Deposit excl. VAT -":
        - rowheader "Deposit excl. VAT"
        - cell "-"
      - row "Discount -":
        - rowheader "Discount"
        - cell "-"
      - row "Contract -":
        - rowheader "Contract"
        - cell "-"
  - heading "Billing" [level=3]
  - table:
    - rowgroup:
      - row "Booking Plan Basic (1 week)":
        - rowheader "Booking Plan"
        - cell "Basic (1 week)"
      - row "Current period 19 - 26 Aug 2026":
        - rowheader "Current period"
        - cell "19 - 26 Aug 2026"
      - row "Amount excl. VAT €50.00":
        - rowheader "Amount excl. VAT"
        - cell "€50.00"
      - row "Price adjustment -":
        - rowheader "Price adjustment"
        - cell "-"
      - row "Next invoice 26 Aug 2026 Show preview":
        - rowheader "Next invoice"
        - cell "26 Aug 2026 Show preview":
          - text: 26 Aug 2026
          - link "Show preview":
            - /url: /bookings/316362886682261/upcoming-invoice
      - row "Payment method -":
        - rowheader "Payment method"
        - cell "-"
      - row "Payment option Automatic payment through Stripe":
        - rowheader "Payment option"
        - cell "Automatic payment through Stripe"
  - heading "Notes" [level=3]
  - link:
    - /url: /bookings/316362886682261/edit/notes
  - table:
    - rowgroup:
      - row "Note -":
        - rowheader "Note"
        - cell "-"
  - heading "Items" [level=3]
  - link "Electronic Box YDosMb":
    - /url: /unit-types/2107525124
  - text: /
  - link "Unit djpozz":
    - /url: /units/654719874
  - text: €50.00
  - strong: Total excl. VAT
  - strong: €50.00
  - text: VAT €8.50
  - strong: Total incl. VAT
  - strong: €58.50
  - heading "Invoices" [level=3]
  - button "Select all"
  - button "Mark as paid" [disabled]
  - button "SEPA XML actions" [disabled]
  - button:
    - img
  - table:
    - rowgroup:
      - row "Number Status Payment option Due date Unit Discount Total (incl. VAT) Amount due Issue date Actions":
        - columnheader:
          - checkbox
        - columnheader "Number":
          - button "Number"
        - columnheader "Status":
          - button "Status"
        - columnheader "Payment option":
          - button "Payment option"
        - columnheader "Due date":
          - button "Due date"
        - columnheader "Unit":
          - button "Unit"
        - columnheader "Discount"
        - columnheader "Total (incl. VAT)":
          - button "Total (incl. VAT)"
        - columnheader "Amount due":
          - button "Amount due"
        - columnheader "Issue date":
          - button "Issue date"
        - columnheader "Actions"
      - row:
        - columnheader
    - rowgroup:
      - row "INV-2106673 Open Auto charge 21 Aug 2026 - €58.50 €58.50 19 Aug 2026":
        - cell:
          - checkbox
        - cell "INV-2106673":
          - link "INV-2106673":
            - /url: /invoices/71728323
        - cell "Open":
          - link "Open":
            - /url: /invoices/71728323
        - cell "Auto charge":
          - link "Auto charge":
            - /url: /invoices/71728323
        - cell "21 Aug 2026":
          - link "21 Aug 2026":
            - /url: /invoices/71728323
        - cell:
          - link:
            - /url: /invoices/71728323
        - cell "-"
        - cell "€58.50":
          - link "€58.50":
            - /url: /invoices/71728323
        - cell "€58.50":
          - link "€58.50":
            - /url: /invoices/71728323
        - cell "19 Aug 2026":
          - link "19 Aug 2026":
            - /url: /invoices/71728323
        - cell:
          - button
  - text: "Items per page:"
  - combobox:
    - text: "10"
    - combobox "Items per page:": "10"
  - text: 1-1 of 1
  - button [disabled]
  - button [disabled]
  - button [disabled]
  - button [disabled]
  - heading "Payments" [level=3]
  - table:
    - rowgroup:
      - row "Total Status Invoice no. Date Payment method":
        - columnheader "Total":
          - button "Total"
        - columnheader "Status":
          - button "Status"
        - columnheader "Invoice no.":
          - button "Invoice no."
        - columnheader "Date":
          - button "Date"
        - columnheader "Payment method":
          - button "Payment method"
      - row:
        - columnheader
    - rowgroup:
      - row "€58.50 Not paid yet INV-2106673 19 Aug 2026":
        - cell "€58.50"
        - cell "Not paid yet"
        - cell "INV-2106673"
        - cell "19 Aug 2026"
        - cell
  - text: "Items per page:"
  - combobox:
    - text: "10"
    - combobox "Items per page:": "10"
  - text: 1-1 of 1
  - button [disabled]
  - button [disabled]
  - button [disabled]
  - button [disabled]
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
- tooltip
```

# Test source

```ts
  1  | import { expect, Locator } from '@playwright/test';
  2  | 
  3  | export async function expectMultiLocatorToHaveText(locator: Locator, text: string[] | undefined): Promise<void> {
  4  |   if (!text) {
  5  |     await expectLocatorToBeEmpty(locator);
  6  |     return;
  7  |   }
  8  | 
  9  |   const expectedValue = RegExp(text.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'));
  10 | 
  11 |   for (const element of await locator.all()) {
  12 |     await expectSingleLocatorToHaveText(element, expectedValue);
  13 |   }
  14 | }
  15 | 
  16 | export async function expectSingleLocatorToHaveText(
  17 |   locator: Locator,
  18 |   text: string | RegExp | undefined
  19 | ): Promise<void> {
  20 |   text
> 21 |     ? await expect(locator).toHaveText(text, { ignoreCase: true, useInnerText: true })
     |                             ^ Error: expect(locator).toHaveText(expected) failed
  22 |     : await expectLocatorToBeEmpty(locator);
  23 | }
  24 | 
  25 | export async function expectLocatorToBeEmpty(locator: Locator): Promise<void> {
  26 |   await expect(locator).toHaveText(/^(\s*-?\s*)$/);
  27 | }
  28 | 
```