# 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 { 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 { > 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 { 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 | ```