# 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-cancel.spec.ts >> cancels a scheduled booking immediately
- Location: src/manager/tests/e2e/booking/booking-cancel.spec.ts:18:7

# Error details

```
Error: expect(locator).toBeVisible() failed

Locator: getByTestId('app-page').getByTestId('app-page-header').getByTestId('base-view-header-status-canceled-before-start')
Expected: visible
Timeout: 30000ms
Error: element(s) not found

Call log:
  - Expect "toBeVisible" with timeout 30000ms
  - waiting for getByTestId('app-page').getByTestId('app-page-header').getByTestId('base-view-header-status-canceled-before-start')

```

```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 6586-8493-4461-521 Cancelled
  - heading "General" [level=3]
  - table:
    - rowgroup:
      - row "Customer Phillip Kub":
        - rowheader "Customer"
        - cell "Phillip Kub":
          - link "Phillip Kub":
            - /url: /customers/836900462
      - row "Location Vienna South":
        - rowheader "Location"
        - cell "Vienna South":
          - link "Vienna South":
            - /url: /locations/5000500050
      - row "Created at 18 Aug 2026":
        - rowheader "Created at"
        - cell "18 Aug 2026"
      - row "Move-in 2 Sep 2026":
        - rowheader "Move-in"
        - cell "2 Sep 2026"
      - row "Move-out 18 Aug 2026":
        - rowheader "Move-out"
        - cell "18 Aug 2026"
      - row "Cancelled at 18 Aug 2026, 04:17":
        - rowheader "Cancelled at"
        - cell "18 Aug 2026, 04:17"
      - 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 month)":
        - rowheader "Booking Plan"
        - cell "Basic (1 month)"
      - row "Current period 2 Sep - 2 Oct 2026":
        - rowheader "Current period"
        - cell "2 Sep - 2 Oct 2026"
      - row "Amount excl. VAT €50.00":
        - rowheader "Amount excl. VAT"
        - cell "€50.00"
      - row "Price adjustment -":
        - rowheader "Price adjustment"
        - cell "-"
      - row "Next invoice 2 Sep 2026":
        - rowheader "Next invoice"
        - cell "2 Sep 2026"
      - 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/658684934461521/edit/notes
  - table:
    - rowgroup:
      - row "Note -":
        - rowheader "Note"
        - cell "-"
  - heading "Items" [level=3]
  - link "Tasty Box iXeV2s":
    - /url: /unit-types/3936455
  - text: /
  - link "Unit vze5k2":
    - /url: /units/506494111
  - 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]
  - progressbar:
    - img
  - 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 "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 "No data yet":
        - cell "No data yet"
  - text: "Items per page:"
  - combobox:
    - text: "10"
    - combobox "Items per page:": "10"
  - text: 0-0 of 0
  - button [disabled]
  - button [disabled]
  - button [disabled]
  - button [disabled]
  - heading "Payments" [level=3]
  - progressbar:
    - img
  - 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 "No data yet":
        - cell "No data yet"
  - text: "Items per page:"
  - combobox:
    - text: "10"
    - combobox "Items per page:": "10"
  - text: 0-0 of 0
  - 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
```

# Test source

```ts
  1  | import { getBookingCancelData, getBookingCreateData } from '@/manager/modules/booking/booking-factories';
  2  | import { test } from '@/manager/modules/booking/booking-fixtures';
  3  | import { toBookingCancellationDetails } from '@/manager/modules/booking/booking-mappers';
  4  | import { bookingCancelHappyTestCases } from '@/manager/modules/booking/test-cases/booking-cancel-happy-test-cases';
  5  | import { getCustomerCreateData } from '@/manager/modules/customer/customer-factories';
  6  | import {
  7  |   expectDataTableChipsColumnToHaveText,
  8  |   expectDataTableTextColumnToHaveText,
  9  | } from '@/manager/modules/ui/data-table/data-table-assertions';
  10 | import { bookingTableColumnTestIds } from '@/manager/modules/ui/data-table/data/data-table-column-test-ids';
  11 | import { getUnitCreateData } from '@/manager/modules/unit/unit-factories';
  12 | import { getUnitTypeCreateData } from '@/manager/modules/unit-type/unit-type-factories';
  13 | import { expectSingleLocatorToHaveText } from '@/manager/shared/utils/expect-utils';
  14 | import { formatId } from '@/shared/utils/formatters';
  15 | import { expect } from '@/shared/utils/matchers';
  16 | 
  17 | for (const tc of bookingCancelHappyTestCases) {
  18 |   test(tc.description, async ({ createCustomer, createUnitType, createUnit, createBooking, bookingDetailsPage }) => {
  19 |     const customer = await createCustomer(getCustomerCreateData());
  20 |     const unitType = await createUnitType(getUnitTypeCreateData());
  21 |     const unit = await createUnit(getUnitCreateData(unitType));
  22 |     const bookingData = getBookingCreateData({ customer, unitType, unit }, tc.initialOptions);
  23 |     const cancellation = getBookingCancelData(tc.cancellation);
  24 | 
  25 |     const { oldStatus, newStatus, moveOutDate } = toBookingCancellationDetails(bookingData, cancellation);
  26 | 
  27 |     const booking = await createBooking(bookingData);
  28 | 
  29 |     await bookingDetailsPage.goto(booking.id);
  30 | 
  31 |     const detailsPageAfterCancel = await test.step('cancel booking', async () => {
  32 |       const cancelDialog = await bookingDetailsPage.openBookingCancelDialog();
  33 |       return cancelDialog.cancel(cancellation);
  34 |     });
  35 | 
  36 |     await test.step('verify booking after cancel on details page', async () => {
  37 |       await expectSingleLocatorToHaveText(detailsPageAfterCancel.baseStatus, newStatus);
  38 | 
  39 |       if (oldStatus === 'scheduled') {
> 40 |         await expect(detailsPageAfterCancel.canceledBeforeStartStatus).toBeVisible();
     |                                                                        ^ Error: expect(locator).toBeVisible() failed
  41 |       } else if (oldStatus === 'active' && newStatus !== 'cancelled') {
  42 |         await expectSingleLocatorToHaveText(detailsPageAfterCancel.cancelsOnStatus, `ends on ${moveOutDate}`);
  43 |       }
  44 | 
  45 |       await expectSingleLocatorToHaveText(detailsPageAfterCancel.generalCard.moveOut, moveOutDate);
  46 |     });
  47 | 
  48 |     await test.step('verify booking after cancel on list page', async () => {
  49 |       const listPage = await detailsPageAfterCancel.returnToBookingListPage();
  50 | 
  51 |       await listPage.searchTextField.fill(formatId(booking.id));
  52 | 
  53 |       await expect(listPage.dataTable.getRows()).toHaveCount(1);
  54 |       await expectDataTableChipsColumnToHaveText(
  55 |         listPage.dataTable,
  56 |         bookingTableColumnTestIds.status,
  57 |         newStatus === 'cancelled' ? 'cancelled' : [newStatus, '']
  58 |       );
  59 |       await expectDataTableTextColumnToHaveText(listPage.dataTable, bookingTableColumnTestIds.moveOut, moveOutDate);
  60 |     });
  61 |   });
  62 | }
  63 | 
```