# 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/portal/tests/e2e/booking/booking-create.spec.ts >> creates a scheduled booking for a private customer with a move-in date in the future and card payment
- Location: src/portal/tests/e2e/booking/booking-create.spec.ts:131:7

# Error details

```
Test timeout of 120000ms exceeded.
```

```
Error: page.waitForURL: Test timeout of 120000ms exceeded.
=========================== logs ===========================
waiting for navigation to "**/checkout/step/payment?lang=en" until "load"
============================================================
```

# Page snapshot

```yaml
- generic [ref=f1e3]:
  - generic [ref=f1e8]:
    - banner [ref=f1e9]:
      - generic [ref=f1e11]:
        - img "Logo of Storeroom Innsbruck" [ref=f1e14]
        - complementary [ref=f1e15]:
          - button "English" [ref=f1e17] [cursor=pointer]
          - button "Help" [ref=f1e23] [cursor=pointer]:
            - figure [ref=f1e24]
    - main [ref=f1e30]:
      - generic [ref=f1e31]:
        - link "Back" [ref=f1e33] [cursor=pointer]:
          - /url: /5000500053/unit-type/1189370091/options/basket
          - figure [ref=f1e34]
        - heading "Your details" [level=1] [ref=f1e39]
      - generic [ref=f1e41]:
        - generic [ref=f1e46]:
          - generic [ref=f1e47]:
            - generic [ref=f1e48]: Customer type *
            - combobox "Customer type *" [ref=f1e50]:
              - option "Private" [selected]
              - option "Business"
          - generic [ref=f1e51]:
            - generic [ref=f1e52]:
              - generic [ref=f1e53]: First name *
              - textbox "First name *" [ref=f1e57]: Kenyatta
            - generic [ref=f1e58]:
              - generic [ref=f1e59]: Last name *
              - textbox "Last name *" [ref=f1e63]: Collier
          - generic [ref=f1e64]:
            - generic [ref=f1e65]:
              - generic [ref=f1e66]: Email address *
              - textbox "Email address *" [ref=f1e70]: kenyatta.collier14@hotmail.com
            - generic [ref=f1e71]:
              - generic [ref=f1e72]: Mobile phone number *
              - generic [ref=f1e76]:
                - generic [ref=f1e77]:
                  - button "Show popup" [ref=f1e80] [cursor=pointer]:
                    - img "Hungary" [ref=f1e81]
                  - generic [ref=f1e84]: "+36"
                - textbox "Mobile phone number * +36" [ref=f1e85]: "9"
              - list [ref=f1e88]:
                - listitem [ref=f1e89]: Not a valid phone number
          - generic [ref=f1e90]:
            - generic [ref=f1e91]: Street and house number *
            - textbox "Street and house number *" [ref=f1e95]: 66355 Mayert Knolls
          - generic [ref=f1e96]:
            - generic [ref=f1e97]:
              - generic [ref=f1e98]: Postcode *
              - textbox "Postcode *" [ref=f1e102]: 35833-9297
            - generic [ref=f1e103]:
              - generic [ref=f1e104]: City *
              - textbox "City *" [ref=f1e108]: Gregoriostad
          - generic [ref=f1e109]:
            - generic [ref=f1e110]: Country *
            - generic [ref=f1e114]:
              - combobox "Show popup" [ref=f1e115]: Austria
              - button [ref=f1e116] [cursor=pointer]
          - generic [ref=f1e119]:
            - generic [ref=f1e122]:
              - checkbox "I have read and understood the terms and conditions *" [checked]
              - generic [ref=f1e128] [cursor=pointer]:
                - generic [ref=f1e129]:
                  - text: I have read and understood the
                  - link "terms and conditions" [ref=f1e130]:
                    - /url: https://www.storeroom.com/gtc
                - text: "*"
            - generic [ref=f1e133]:
              - checkbox "I agree to the privacy policy guidelines *" [checked]
              - generic [ref=f1e139] [cursor=pointer]:
                - generic [ref=f1e140]:
                  - text: I agree to the
                  - link "privacy policy guidelines" [ref=f1e141]:
                    - /url: https://www.storeroom.com/privacy
                - text: "*"
            - generic [ref=f1e144]:
              - checkbox "I have read and understood the forbidden items policy *" [checked]
              - generic [ref=f1e150] [cursor=pointer]:
                - generic [ref=f1e151]:
                  - text: I have read and understood the
                  - link "forbidden items policy" [ref=f1e152]:
                    - /url: https://www.storeroom.com/forbidden-items/gtc
                - text: "*"
            - generic [ref=f1e155]:
              - checkbox "I have read and understood the cancellation policy *" [checked]
              - generic [ref=f1e161] [cursor=pointer]:
                - generic [ref=f1e162]:
                  - text: I have read and understood the
                  - link "cancellation policy" [ref=f1e163]:
                    - /url: https://www.storeroom.com/cancellation-policy
                - text: "*"
          - button "Book and pay now" [active] [ref=f1e165] [cursor=pointer]
        - complementary [ref=f1e167]:
          - generic [ref=f1e168]:
            - generic [ref=f1e170]:
              - generic [ref=f1e171]:
                - heading "Storeroom Innsbruck" [level=2] [ref=f1e172]
                - generic [ref=f1e173]: Gewerbepark 2, 6010 Innsbruck
              - img "Image of the facility named \"Storeroom Innsbruck\"" [ref=f1e176]
            - separator [ref=f1e177]
            - generic [ref=f1e178]:
              - generic [ref=f1e179]: Move-in date
              - generic [ref=f1e181]: Oct 10, 2026
            - separator [ref=f1e183]
            - generic [ref=f1e184]:
              - generic [ref=f1e185]:
                - generic [ref=f1e186]:
                  - generic [ref=f1e187]: VI 7 sqm Unit
                  - generic [ref=f1e188]: every 26 weeks
                - generic [ref=f1e189]:
                  - generic [ref=f1e190]: €5,304.00
                  - generic [ref=f1e193]: (incl. tax)
              - generic [ref=f1e194]:
                - generic [ref=f1e195]:
                  - generic [ref=f1e196]: VI - Insurance weekly - 10
                  - generic [ref=f1e197]: every 26 weeks
                - generic [ref=f1e198]:
                  - generic [ref=f1e199]: €265.20
                  - generic [ref=f1e200]: (incl. tax)
              - generic [ref=f1e201]:
                - separator [ref=f1e202]
                - generic [ref=f1e206]:
                  - generic [ref=f1e207]:
                    - generic [ref=f1e208]: Discount code
                    - generic [ref=f1e209]: €20.00 off forever
                  - button "Remove" [ref=f1e210] [cursor=pointer]
                - separator [ref=f1e212]
                - generic [ref=f1e213]:
                  - generic [ref=f1e214]:
                    - generic [ref=f1e215]: Total
                    - generic [ref=f1e216]: first invoice
                  - generic [ref=f1e217]:
                    - generic [ref=f1e219]:
                      - generic [ref=f1e220]: €5,569.20
                      - generic [ref=f1e221]: €5,545.20
                    - generic [ref=f1e222]: (incl. tax)
                - generic [ref=f1e223]:
                  - generic [ref=f1e224]:
                    - generic [ref=f1e225]: Recurring payment
                    - generic [ref=f1e226]: every 26 weeks
                  - generic [ref=f1e227]:
                    - generic [ref=f1e229]:
                      - generic [ref=f1e230]: €5,569.20
                      - generic [ref=f1e231]: €5,545.20
                    - generic [ref=f1e232]: (incl. tax)
  - contentinfo [ref=f1e233]:
    - separator [ref=f1e234]
    - generic [ref=f1e235]:
      - link "Imprint" [ref=f1e236] [cursor=pointer]:
        - /url: https://www.storeroom.com/imprint
      - generic [ref=f1e237]: •
      - link "Data privacy" [ref=f1e238] [cursor=pointer]:
        - /url: https://www.storeroom.com/privacy
      - generic [ref=f1e239]: •
      - button "Privacy settings" [ref=f1e240] [cursor=pointer]
```

# Test source

```ts
  1  | import { BookingBasketContent } from '@/portal/modules/booking/components/BookingBasketContent';
  2  | import { BookingCreateCustomer } from '@/portal/modules/booking/booking-types';
  3  | import { BookingPaymentView } from '@/portal/modules/booking/views/BookingPaymentView';
  4  | import { Checkbox } from '@/portal/shared/components/Checkbox';
  5  | import { PhoneField } from '@/portal/shared/components/PhoneField';
  6  | import { SingleAutocomplete } from '@/portal/shared/components/SingleAutocomplete';
  7  | import { SingleSelect } from '@/portal/shared/components/SingleSelect';
  8  | import { TextField } from '@/portal/shared/components/TextField';
  9  | import { BaseView } from '@/shared/base/BaseView';
  10 | import { Locator } from '@playwright/test';
  11 | 
  12 | export class BookingCustomerView extends BaseView {
  13 |   readonly customerTypeSelect = new SingleSelect(this.host.getByTestId('customer-type-select'));
  14 |   readonly companyNameInput = new TextField(this.host.getByTestId('company-name-input'));
  15 |   readonly vatNumberInput = new TextField(this.host.getByTestId('vat-number-input'));
  16 |   readonly firstNameInput = new TextField(this.host.getByTestId('first-name-input'));
  17 |   readonly lastNameInput = new TextField(this.host.getByTestId('last-name-input'));
  18 |   readonly emailInput = new TextField(this.host.getByTestId('email-input'));
  19 |   readonly phoneInput = new PhoneField(this.host.getByTestId('phone-input'));
  20 |   readonly streetInput = new TextField(this.host.getByTestId('street-input'));
  21 |   readonly zipInput = new TextField(this.host.getByTestId('zip-input'));
  22 |   readonly cityInput = new TextField(this.host.getByTestId('city-input'));
  23 |   readonly countryAutocomplete = new SingleAutocomplete(this.host.getByTestId('country-combobox'));
  24 |   readonly termsCheckboxes = this.host.getByTestId('terms-checkbox');
  25 |   readonly acceptChangesButton = this.host.getByTestId('accept-basket-changes-button');
  26 |   isMobile = false;
  27 | 
  28 |   async fill(customer: BookingCreateCustomer): Promise<void> {
  29 |     await this.customerTypeSelect.select(customer.type);
  30 | 
  31 |     if (customer.type === 'business') {
  32 |       if (this.isMobile) {
  33 |         await this.acceptChangesButton.click();
  34 |       }
  35 | 
  36 |       await this.companyNameInput.fill(customer.companyName ?? '');
  37 | 
  38 |       if (customer.vatNumber) {
  39 |         await this.vatNumberInput.fill(customer.vatNumber);
  40 |       }
  41 |     }
  42 | 
  43 |     await this.firstNameInput.fill(customer.firstName);
  44 |     await this.lastNameInput.fill(customer.lastName);
  45 |     await this.emailInput.fill(customer.email);
  46 |     await this.phoneInput.fill(customer.phone, customer.country.name);
  47 |     await this.streetInput.fill(customer.street);
  48 |     await this.zipInput.fill(customer.postalCode);
  49 |     await this.cityInput.fill(customer.city);
  50 |     await this.countryAutocomplete.fill(customer.country.name);
  51 | 
  52 |     for (const locator of await this.termsCheckboxes.all()) {
  53 |       const checkbox = new Checkbox(locator);
  54 |       await checkbox.check();
  55 |     }
  56 |   }
  57 | 
  58 |   async confirm(): Promise<BookingPaymentView> {
> 59 |     await Promise.all([this.host.waitForURL('**/checkout/step/payment?lang=en'), this.getSubmitButton().click()]);
     |                                  ^ Error: page.waitForURL: Test timeout of 120000ms exceeded.
  60 |     return new BookingPaymentView(this.host);
  61 |   }
  62 | 
  63 |   async openDrawer(): Promise<void> {
  64 |     await this.host.getByTestId('drawer-drag-handle').click();
  65 |   }
  66 | 
  67 |   getSubmitButton(): Locator {
  68 |     return this.isMobile
  69 |       ? this.host.getByTestId('drawer-submit-button')
  70 |       : this.host.getByTestId('standalone-submit-button');
  71 |   }
  72 | 
  73 |   getBasketContent(): BookingBasketContent {
  74 |     return new BookingBasketContent(
  75 |       this.isMobile ? this.host.getByTestId('basket-content-drawer') : this.host.getByTestId('basket-content-card')
  76 |     );
  77 |   }
  78 | }
  79 | 
```