# 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 7217-1852-7483-83 Cancelled
  - heading "General" [level=3]
  - table:
    - rowgroup:
      - row "Customer Isabel Wolff":
        - rowheader "Customer"
        - cell "Isabel Wolff":
          - link "Isabel Wolff":
            - /url: /customers/836900462
      - row "Location Vienna South":
        - rowheader "Location"
        - cell "Vienna South":
          - link "Vienna South":
            - /url: /locations/5000500050
      - row "Created at 21 Aug 2026":
        - rowheader "Created at"
        - cell "21 Aug 2026"
      - row "Move-in 5 Sep 2026":
        - rowheader "Move-in"
        - cell "5 Sep 2026"
      - row "Move-out 21 Aug 2026":
        - rowheader "Move-out"
        - cell "21 Aug 2026"
      - row "Cancelled at 21 Aug 2026, 04:17":
        - rowheader "Cancelled at"
        - cell "21 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 5 Sep - 5 Oct 2026":
        - rowheader "Current period"
        - cell "5 Sep - 5 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 5 Sep 2026":
        - rowheader "Next invoice"
        - cell "5 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/72171852748383/edit/notes
  - table:
    - rowgroup:
      - row "Note -":
        - rowheader "Note"
        - cell "-"
  - heading "Items" [level=3]
  - link "Licensed Box 6UhJBv":
    - /url: /unit-types/3936455
  - text: /
  - link "Unit Kn5BZO":
    - /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, unitType] = await Promise.all([
  20 |       createCustomer(getCustomerCreateData()),
  21 |       createUnitType(getUnitTypeCreateData()),
  22 |     ]);
  23 |     const unit = await createUnit(getUnitCreateData(unitType));
  24 |     const bookingData = getBookingCreateData({ customer, unitType, unit }, tc.initialOptions);
  25 |     const cancellation = getBookingCancelData(tc.cancellation);
  26 | 
  27 |     const { oldStatus, newStatus, moveOutDate } = toBookingCancellationDetails(bookingData, cancellation);
  28 | 
  29 |     const booking = await createBooking(bookingData);
  30 | 
  31 |     await bookingDetailsPage.goto(booking.id);
  32 | 
  33 |     const detailsPageAfterCancel = await test.step('cancel booking', async () => {
  34 |       const cancelDialog = await bookingDetailsPage.openBookingCancelDialog();
  35 |       return cancelDialog.cancel(cancellation);
  36 |     });
  37 | 
  38 |     await test.step('verify booking after cancel on details page', async () => {
  39 |       await expectSingleLocatorToHaveText(detailsPageAfterCancel.baseStatus, newStatus);
  40 | 
  41 |       if (oldStatus === 'scheduled') {
> 42 |         await expect(detailsPageAfterCancel.canceledBeforeStartStatus).toBeVisible();
     |                                                                        ^ Error: expect(locator).toBeVisible() failed
  43 |       } else if (oldStatus === 'active' && newStatus !== 'cancelled') {
  44 |         await expectSingleLocatorToHaveText(detailsPageAfterCancel.cancelsOnStatus, `ends on ${moveOutDate}`);
  45 |       }
  46 | 
  47 |       await expectSingleLocatorToHaveText(detailsPageAfterCancel.generalCard.moveOut, moveOutDate);
  48 |     });
  49 | 
  50 |     await test.step('verify booking after cancel on list page', async () => {
  51 |       const listPage = await detailsPageAfterCancel.returnToBookingListPage();
  52 | 
  53 |       await listPage.searchTextField.fill(formatId(booking.id));
  54 | 
  55 |       await expect(listPage.dataTable.getRows()).toHaveCount(1);
  56 |       await expectDataTableChipsColumnToHaveText(
  57 |         listPage.dataTable,
  58 |         bookingTableColumnTestIds.status,
  59 |         newStatus === 'cancelled' ? 'cancelled' : [newStatus, '']
  60 |       );
  61 |       await expectDataTableTextColumnToHaveText(listPage.dataTable, bookingTableColumnTestIds.moveOut, moveOutDate);
  62 |     });
  63 |   });
  64 | }
  65 | 
```