# 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/customer/customer-create.spec.ts >> should create a business German customer with one location - Location: src/manager/tests/e2e/customer/customer-create.spec.ts:13:7 # Error details ``` Test timeout of 60000ms exceeded. ``` ``` Error: locator.focus: Test timeout of 60000ms exceeded. Call log: - waiting for locator('.v-dialog:has([data-test-id="customer-create-dialog"]):has(.v-overlay__content:not(.dialog-bottom-transition-enter-active))').locator('fieldset:has(legend:has-text("General"))').locator('.v-input:has(label:has-text("Customer type"))').locator('.v-field:not(.v-field--loading)').locator('input[type=text]') ``` # Page snapshot ```yaml - generic [ref=e1]: - generic [ref=e6]: - banner [ref=e7]: - generic [ref=e8]: - button [ref=e9] [cursor=pointer]: - generic [ref=e11]: 󰍜 - link [ref=e12] [cursor=pointer]: - /url: / - button "AS" [ref=e14] [cursor=pointer]: - generic [ref=e18]: AS - generic: - text: 󰗊 󰅀 - text: 󰷖 󰍃 - navigation [ref=e19]: - list [ref=e21]: - generic [ref=e23]: Dashboard - link "Tasks" [ref=e24] [cursor=pointer]: - /url: /tasks - img [ref=e27] - generic [ref=e30]: Tasks - link "Facility maps" [ref=e31] [cursor=pointer]: - /url: /facility-map - generic [ref=e33]: 󰧾 - generic [ref=e35]: Facility maps - link "Analytics" [ref=e36] [cursor=pointer]: - /url: /dashboard - generic [ref=e38]: 󱖶 - generic [ref=e40]: Analytics - generic [ref=e42]: Sales - link "Bookings" [ref=e43] [cursor=pointer]: - /url: /bookings - generic [ref=e45]: 󰇡 - generic [ref=e47]: Bookings - link "Customers" [ref=e48] [cursor=pointer]: - /url: /customers - generic [ref=e50]: 󰀏 - generic [ref=e52]: Customers - link "Invoices" [ref=e53] [cursor=pointer]: - /url: /invoices - generic [ref=e55]: 󰷉 - generic [ref=e57]: Invoices - link "Credit notes" [ref=e58] [cursor=pointer]: - /url: /credit-notes - img [ref=e61] - generic [ref=e64]: Credit notes - link "Units" [ref=e65] [cursor=pointer]: - /url: /units - generic [ref=e67]: 󰍀 - generic [ref=e69]: Units - generic [ref=e71]: Site Management - link "Locations" [ref=e72] [cursor=pointer]: - /url: /locations - generic [ref=e74]: 󰟙 - generic [ref=e76]: Locations - link "Unit types" [ref=e77] [cursor=pointer]: - /url: /unit-types - generic [ref=e79]: 󰆧 - generic [ref=e81]: Unit types - link "Protection Plans" [ref=e82] [cursor=pointer]: - /url: /insurances - generic [ref=e84]: 󰳌 - generic [ref=e86]: Protection Plans - link "Deposits" [ref=e87] [cursor=pointer]: - /url: /deposits - generic [ref=e89]: 󱙆 - generic [ref=e91]: Deposits - link "Products" [ref=e92] [cursor=pointer]: - /url: /products - generic [ref=e94]: 󰄑 - generic [ref=e96]: Products - link "Discounts" [ref=e97] [cursor=pointer]: - /url: /discounts - generic [ref=e99]: 󰓼 - generic [ref=e101]: Discounts - generic [ref=e102]: - option "Emails" [ref=e103] [cursor=pointer]: - generic [ref=e105]: 󰻨 - generic [ref=e107]: Emails - generic [ref=e109]: 󰅀 - text: 󱡰 󰁥 - generic [ref=e111]: Admin - link "Integrations" [ref=e112] [cursor=pointer]: - /url: /connected-apps - generic [ref=e114]: 󱘖 - generic [ref=e116]: Integrations - link "User & Roles" [ref=e117] [cursor=pointer]: - /url: /users - generic [ref=e119]: 󰭘 - generic [ref=e121]: User & Roles - generic [ref=e122]: - option "Booking Portal" [ref=e123] [cursor=pointer]: - generic [ref=e125]: 󱃁 - generic [ref=e127]: Booking Portal - generic [ref=e129]: 󰅀 - text: 󰖟 󰟙 - generic [ref=e130]: - option "JaneAI" [ref=e131] [cursor=pointer]: - generic [ref=e133]: 󱙺 - generic [ref=e135]: JaneAI - generic [ref=e137]: 󰅀 - text: 󱜹 - generic [ref=e139]: Feedback - link "Voting Portal" [ref=e140] [cursor=pointer]: - /url: /voting-portal - generic [ref=e142]: 󰔔 - generic [ref=e144]: Voting Portal - main [ref=e145]: - generic [ref=e146]: - generic [ref=e148]: - generic [ref=e152]: - generic [ref=e153]: Customers - heading "Overview" [level=1] [ref=e155]: - generic [ref=e156]: Overview - button "Actions" [ref=e158] [cursor=pointer]: - generic [ref=e159]: - text: Actions - generic [ref=e160]: 󱨉 - generic: 󰐕 - generic [ref=e162]: - generic [ref=e164]: - generic [ref=e166]: - heading "Filters" [level=3] [ref=e168] - button "Reset filters" [ref=e170] [cursor=pointer]: - generic [ref=e171]: Reset filters - generic [ref=e175]: - generic [ref=e180]: - textbox "Search" [ref=e182]: Abdullah_Kock@yahoo.com - button "Clear Search" [ref=e184] [cursor=pointer]: 󰅙 - generic [ref=e186]: 󰍉 - generic: - generic: Search - combobox [ref=e190]: - generic [ref=e191]: - generic: Location - combobox "Location" [ref=e193] - button [ref=e195] [cursor=pointer]: 󰍝 - combobox [ref=e199]: - generic [ref=e200]: - generic: Has past due invoice(s) - combobox "Has past due invoice(s)" [ref=e202] - button [ref=e204] [cursor=pointer]: 󰍝 - combobox [ref=e208]: - generic [ref=e209]: - generic: Status - combobox "Status" [ref=e211] - button [ref=e213] [cursor=pointer]: 󰍝 - generic [ref=e215]: - table [ref=e219]: - rowgroup [ref=e220]: - row "Customer no. Name Location(s) Email address Phone number Status Past due invoice(s) Created at" [ref=e221]: - columnheader "Customer no." [ref=e222]: - button "Customer no." [ref=e223] [cursor=pointer]: - generic [ref=e225]: Customer no. - generic [ref=e228]: 󰁝 - columnheader "Name" [ref=e229]: - button "Name" [ref=e230] [cursor=pointer]: - generic [ref=e232]: Name - generic [ref=e235]: 󰁝 - columnheader "Location(s)" [ref=e236]: - button "Location(s)" [ref=e237] [cursor=pointer]: - generic [ref=e239]: Location(s) - generic [ref=e242]: 󰁝 - columnheader "Email address" [ref=e243]: - button "Email address" [ref=e244] [cursor=pointer]: - generic [ref=e246]: Email address - generic [ref=e249]: 󰁝 - columnheader "Phone number" [ref=e250]: - generic [ref=e253]: Phone number - columnheader "Status" [ref=e254]: - button "Status" [ref=e255] [cursor=pointer]: - generic [ref=e257]: Status - generic [ref=e260]: 󰁝 - columnheader "Past due invoice(s)" [ref=e261]: - button "Past due invoice(s)" [ref=e262] [cursor=pointer]: - generic [ref=e264]: Past due invoice(s) - generic [ref=e267]: 󰁝 - columnheader "Created at" [ref=e268]: - button "Created at" [ref=e269] [cursor=pointer]: - generic [ref=e271]: Created at - generic [ref=e274]: 󰁝 - row [ref=e275]: - columnheader [ref=e276] - rowgroup [ref=e277]: - row "No data yet" [ref=e278]: - cell "No data yet" [ref=e279]: - generic [ref=e280]: No data yet - generic [ref=e283]: - generic [ref=e284]: - generic [ref=e285]: "Items per page:" - combobox [ref=e288] [cursor=pointer]: - generic [ref=e290]: - generic [ref=e292]: "10" - combobox "Items per page:": "10" - generic [ref=e294]: 󰍝 - generic [ref=e295]: 0-0 of 0 - generic [ref=e296]: - button [disabled]: - generic: - generic: 󰘀 - button [disabled]: - generic: - generic: 󰅁 - button [disabled]: - generic: - generic: 󰅂 - button [disabled]: - generic: - generic: 󰘁 - contentinfo [ref=e297]: - generic [ref=e298]: - generic [ref=e299]: - text: Kinnovis GmbH - generic [ref=e300]: 󰗦 - text: "2026" - generic [ref=e301]: v2026.04.03 - generic: - tooltip - tooltip - tooltip - tooltip - dialog: - generic [ref=e304]: - generic [ref=e305]: - generic [ref=e306]: - generic [ref=e307]: - button [ref=e308] [cursor=pointer]: - generic [ref=e310]: 󰅖 - heading "Create Customer" [level=2] [ref=e312] - button "Save" [ref=e314] [cursor=pointer]: - generic [ref=e315]: Save - separator [ref=e316] - generic [ref=e318]: - group "General" [ref=e319]: - heading "General" [level=3] [ref=e321]: - generic [ref=e323]: General - generic [ref=e324]: - generic [ref=e326]: - combobox [ref=e328]: - generic [ref=e330]: - generic [ref=e332]: Private - combobox "Customer type *" [ref=e333] - button [ref=e335] [cursor=pointer]: 󰍝 - generic: - generic: Customer type * - alert [ref=e336] - generic [ref=e339]: - combobox [ref=e341]: - generic [ref=e342]: - generic: Location(s) * - combobox "Location(s) *" [ref=e344] - button [ref=e346] [cursor=pointer]: 󰍝 - alert [ref=e347] - generic [ref=e349]: - generic [ref=e351]: - generic [ref=e354]: - generic: First name * - textbox "First name *" [ref=e355] - alert [ref=e356] - generic [ref=e359]: - generic [ref=e362]: - generic: Last name * - textbox "Last name *" [ref=e363] - alert [ref=e364] - generic [ref=e367]: - generic [ref=e370]: - generic: Email address * - textbox "Email address *" [ref=e371] - alert [ref=e372] - generic [ref=e376]: - generic [ref=e380]: - button [ref=e383] [cursor=pointer]: - generic [ref=e386]: 󰍝 - generic [ref=e387]: - generic: Phone number * - textbox "Phone number *" [ref=e388] - alert [ref=e389] - generic [ref=e392]: - combobox [ref=e394]: - generic [ref=e395]: - generic: Language * - combobox "Language *" [ref=e397] - button [ref=e399] [cursor=pointer]: 󰍝 - alert [ref=e400] - generic [ref=e403]: - generic [ref=e406]: - generic: Note - textbox "Note" [ref=e407] - alert [ref=e408] - group "Accounting" [ref=e410]: - heading "Accounting" [level=3] [ref=e412]: - generic [ref=e414]: Accounting - generic [ref=e417]: - generic [ref=e420]: - generic: Accounts receivable number - textbox "Accounts receivable number" [ref=e421] - alert [ref=e422] - group "Address" [ref=e424]: - heading "Address" [level=3] [ref=e426]: - generic [ref=e428]: Address - generic [ref=e429]: - generic [ref=e431]: - generic [ref=e434]: - generic: Street / House Number / Building * - textbox "Street / House Number / Building *" [ref=e435] - alert [ref=e436] - generic [ref=e439]: - generic [ref=e442]: - generic: Postal code * - textbox "Postal code *" [ref=e443] - alert [ref=e444] - generic [ref=e447]: - generic [ref=e450]: - generic: City * - textbox "City *" [ref=e451] - alert [ref=e452] - generic [ref=e455]: - combobox [ref=e457]: - generic [ref=e458]: - generic: Country * - combobox "Country *" [ref=e460] - button [ref=e462] [cursor=pointer]: 󰍝 - alert [ref=e463] - tooltip ``` # Test source ```ts 1 | import { OptionMenu } from '@/manager/shared/components/OptionMenu'; 2 | import { BaseComponent } from '@/shared/base/BaseComponent'; 3 | import { sleep } from '@/shared/utils/timeout-utils'; 4 | 5 | export class SingleAutocomplete extends BaseComponent { 6 | private readonly body = this.host.locator('.v-field:not(.v-field--loading)'); 7 | private readonly input = this.body.locator('input[type=text]'); 8 | private readonly closeButton = this.body.locator('.v-field__clearable'); 9 | readonly menu = new OptionMenu(this.input); 10 | 11 | async select(value: string): Promise { 12 | await this.input.focus(); 13 | await this.input.clear(); 14 | await this.input.clear(); 15 | await this.input.fill(value); 16 | await this.menu.select(value); 17 | } 18 | 19 | async fill(value: string): Promise { > 20 | await this.input.focus(); | ^ Error: locator.focus: Test timeout of 60000ms exceeded. 21 | await this.input.clear(); 22 | await this.input.clear(); 23 | // TODO: temporary fix for when the autocomplete is not fully loaded yet e.g. due to currently opening a root dialog 24 | await sleep(75); 25 | await this.input.fill(value); 26 | 27 | if (value) { 28 | const menuBody = await this.menu.getBody(); 29 | await menuBody.waitFor(); 30 | } 31 | 32 | await this.input.press('Enter'); 33 | } 34 | 35 | async fillWithoutEnter(value: string): Promise { 36 | await this.input.focus(); 37 | await this.input.fill(''); 38 | await this.input.fill(value); 39 | } 40 | 41 | async clear(): Promise { 42 | await this.closeButton.hover(); 43 | await this.closeButton.click(); 44 | } 45 | } 46 | ```