# 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/apps/portal/tests/e2e/booking/booking-create.spec.ts >> should create a booking for a private customer with move-in date today, monthly plan, insurance, and card payment - Location: src/apps/portal/tests/e2e/booking/booking-create.spec.ts:18:7 # Error details ``` Test timeout of 60000ms exceeded. ``` ``` Error: page.waitForURL: Test timeout of 60000ms exceeded. =========================== logs =========================== waiting for navigation to "**/checkout/step/payment?lang=en" until "load" ============================================================ ``` # Page snapshot ```yaml - generic [ref=e3]: - generic [ref=e10]: - banner [ref=e11]: - generic [ref=e13]: - img "Logo of Storeroom Innsbruck" [ref=e16] - complementary [ref=e17]: - button "English" [ref=e19] [cursor=pointer]: - text: English - img [ref=e20] - button "Help" [ref=e25] [cursor=pointer]: - figure [ref=e26]: - img [ref=e28] - main [ref=e32]: - generic [ref=e33]: - link "Back" [ref=e35] [cursor=pointer]: - /url: /5000500050/unit-type/836900462/options/basket - figure [ref=e36]: - img [ref=e38] - heading "Your details" [level=1] [ref=e41] - generic [ref=e43]: - generic [ref=e44]: - generic [ref=e46]: - generic [ref=e47]: - generic [ref=e48]: Customer type * - generic [ref=e49]: - generic: - generic: - generic: - img - combobox "Customer type *" [ref=e50]: - option "Private" [selected] - option "Business" - generic [ref=e51]: - generic [ref=e52]: - generic [ref=e53]: First name * - textbox "First name *" [ref=e57]: Bookini - generic [ref=e58]: - generic [ref=e59]: Last name * - textbox "Last name *" [ref=e63]: Portalio - generic [ref=e64]: - generic [ref=e65]: - generic [ref=e66]: Email address * - textbox "Email address *" [ref=e70]: bookini.portalio@gmail.com - generic [ref=e71]: - generic [ref=e72]: Mobile phone number * - generic [ref=e76]: - generic [ref=e77]: - button "Show popup" [ref=e80] [cursor=pointer]: - img "Austria" [ref=e81] - img [ref=e82] - generic [ref=e84]: "+43" - textbox "Mobile phone number * +43" [ref=e85]: "69912345678" - generic [ref=e86]: - generic [ref=e87]: Street and house number * - textbox "Street and house number *" [ref=e91]: Innsbrucker Straße 1 - generic [ref=e92]: - generic [ref=e93]: - generic [ref=e94]: Postcode * - textbox "Postcode *" [ref=e98]: "6020" - generic [ref=e99]: - generic [ref=e100]: City * - textbox "City *" [ref=e104]: Innsbruck - generic [ref=e105]: - generic [ref=e106]: Country * - generic [ref=e110]: - combobox "Show popup" [ref=e111]: Austria - button [ref=e112] [cursor=pointer]: - img [ref=e113] - generic [ref=e115]: - generic [ref=e118]: - checkbox "I have read and understood the terms and conditions *" [checked] - generic [ref=e119] [cursor=pointer]: - img [ref=e122] - generic [ref=e124]: - generic [ref=e125]: - text: I have read and understood the - link "terms and conditions" [ref=e126]: - /url: https://www.storeroom.com/gtc - text: "*" - generic [ref=e129]: - checkbox "I agree to the privacy policy guidelines *" [checked] - generic [ref=e130] [cursor=pointer]: - img [ref=e133] - generic [ref=e135]: - generic [ref=e136]: - text: I agree to the - link "privacy policy guidelines" [ref=e137]: - /url: https://www.storeroom.com/privacy - text: "*" - generic [ref=e140]: - checkbox "I have read and understood the forbidden items policy *" [checked] - generic [ref=e141] [cursor=pointer]: - img [ref=e144] - generic [ref=e146]: - generic [ref=e147]: - text: I have read and understood the - link "forbidden items policy" [ref=e148]: - /url: https://www.storeroom.com/forbidden-items/gtc - text: "*" - generic [ref=e151]: - checkbox "I have read and understood the cancellation policy *" [checked] - generic [ref=e152] [cursor=pointer]: - img [ref=e155] - generic [ref=e157]: - generic [ref=e158]: - text: I have read and understood the - link "cancellation policy" [ref=e159]: - /url: https://www.storeroom.com/cancellation-policy - text: "*" - generic [ref=e162]: "AxiosError: Request failed with status code 500" - button "Book and pay now" [ref=e164] [cursor=pointer]: - generic [ref=e165]: Book and pay now - complementary [ref=e166]: - generic [ref=e167]: - generic [ref=e169]: - generic [ref=e170]: - heading "Storeroom Innsbruck" [level=2] [ref=e171] - generic [ref=e172]: Gewerbepark 2, 6010 Innsbruck - img "Image of the facility named \"Storeroom Innsbruck\"" [ref=e175] - separator [ref=e176] - generic [ref=e177]: - generic [ref=e179]: Move-in date - generic [ref=e181]: Apr 4, 2026 - separator [ref=e182] - generic [ref=e183]: - generic [ref=e184]: - generic [ref=e185]: - generic [ref=e186]: VI 30 sqm Unit - generic [ref=e187]: every 12 months - generic [ref=e188]: - generic [ref=e189]: €7,560.00 - generic [ref=e190]: (incl. tax) - generic [ref=e191]: - generic [ref=e192]: - generic [ref=e193]: VI - Insurance monthly - 10 - generic [ref=e194]: every 12 months - generic [ref=e195]: - generic [ref=e196]: €108.00 - generic [ref=e197]: (incl. tax) - generic [ref=e198]: - separator [ref=e199] - generic [ref=e203]: - generic [ref=e204]: Discount code - button "Add code" [ref=e205] [cursor=pointer]: - generic [ref=e206]: Add code - separator [ref=e207] - generic [ref=e208]: - generic [ref=e209]: - generic [ref=e210]: Total - generic [ref=e211]: first invoice - generic [ref=e212]: - generic [ref=e215]: €7,668.00 - generic [ref=e216]: (incl. tax) - generic [ref=e217]: - generic [ref=e218]: - generic [ref=e219]: Recurring payment - generic [ref=e220]: every 12 months - generic [ref=e221]: - generic [ref=e224]: €7,668.00 - generic [ref=e225]: (incl. tax) - contentinfo [ref=e226]: - separator [ref=e227] - generic [ref=e228]: - link "Imprint" [ref=e229] [cursor=pointer]: - /url: https://www.storeroom.com/imprint - generic [ref=e230]: "|" - link "Data privacy" [ref=e231] [cursor=pointer]: - /url: https://www.storeroom.com/privacy ``` # Test source ```ts 1 | import { BookingBasketContent } from '@/apps/portal/modules/booking/components/BookingBasketContent'; 2 | import { IBookingCreateCustomer } from '@/apps/portal/modules/booking/types/booking-entity-types'; 3 | import { BookingPaymentView } from '@/apps/portal/modules/booking/views/BookingPaymentView'; 4 | import { Checkbox } from '@/apps/portal/shared/components/inputs/Checkbox'; 5 | import { PhoneField } from '@/apps/portal/shared/components/inputs/PhoneField'; 6 | import { SingleAutocomplete } from '@/apps/portal/shared/components/inputs/SingleAutocomplete'; 7 | import { SingleSelect } from '@/apps/portal/shared/components/inputs/SingleSelect'; 8 | import { TextField } from '@/apps/portal/shared/components/inputs/TextField'; 9 | import { BaseView } from '@/shared/modules/base/views/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: IBookingCreateCustomer): Promise { 29 | await this.customerTypeSelect.select(customer.type); 30 | 31 | if (customer.type === 'business') { 32 | this.isMobile && (await this.acceptChangesButton.click()); 33 | await this.companyNameInput.fill(customer.companyName ?? ''); 34 | customer.vatNumber && (await this.vatNumberInput.fill(customer.vatNumber)); 35 | } 36 | 37 | await this.firstNameInput.fill(customer.firstName); 38 | await this.lastNameInput.fill(customer.lastName); 39 | await this.emailInput.fill(customer.email); 40 | await this.phoneInput.fill(customer.phone, customer.country.name); 41 | await this.streetInput.fill(customer.street); 42 | await this.zipInput.fill(customer.postalCode); 43 | await this.cityInput.fill(customer.city); 44 | await this.countryAutocomplete.fill(customer.country.name); 45 | 46 | for (const locator of await this.termsCheckboxes.all()) { 47 | const checkbox = new Checkbox(locator); 48 | await checkbox.check(); 49 | } 50 | } 51 | 52 | async confirm(): Promise { > 53 | await Promise.all([this.host.waitForURL('**/checkout/step/payment?lang=en'), this.getSubmitButton().click()]); | ^ Error: page.waitForURL: Test timeout of 60000ms exceeded. 54 | return new BookingPaymentView(this.host); 55 | } 56 | 57 | async openDrawer(): Promise { 58 | await this.host.getByTestId('drawer-drag-handle').click(); 59 | } 60 | 61 | getSubmitButton(): Locator { 62 | return this.isMobile 63 | ? this.host.getByTestId('drawer-submit-button') 64 | : this.host.getByTestId('standalone-submit-button'); 65 | } 66 | 67 | getBasketContent(): BookingBasketContent { 68 | return new BookingBasketContent( 69 | this.isMobile ? this.host.getByTestId('basket-content-drawer') : this.host.getByTestId('basket-content-card') 70 | ); 71 | } 72 | } 73 | ```