# 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/invoice/invoice-bulk-mark-as-paid.spec.ts >> marks multiple selected invoices as paid at once - Location: src/manager/tests/e2e/invoice/invoice-bulk-mark-as-paid.spec.ts:145:5 # Error details ``` Test timeout of 120000ms exceeded. ``` ``` Error: locator.click: Test timeout of 120000ms exceeded. Call log: - waiting for getByTestId('app-page').getByTestId('app-page-content').locator('.ui-data-grid').locator('[data-test-id=ui-data-grid-table]:not(.disabled):not(.loading):not(.fetching)').locator('button[data-test-id="invoice-bulk-mark-as-paid-action"]') ``` # Page snapshot ```yaml - generic [ref=e1]: - generic [ref=e6]: - navigation [ref=e7]: - generic [ref=e9]: - link [ref=e10] [cursor=pointer]: - /url: / - generic [ref=e11]: - generic [ref=e12]: KINNOVIS - generic [ref=e13]: Manager - button [ref=e15] [cursor=pointer] - list [ref=e19]: - generic [ref=e21]: Dashboard - link "Tasks" [ref=e23] [cursor=pointer]: - /url: /tasks - link "Facility maps" [ref=e30] [cursor=pointer]: - /url: /facility-map - generic [ref=e31]: 󰧾 - link "Analytics" [ref=e35] [cursor=pointer]: - /url: /dashboard - generic [ref=e36]: 󱖶 - generic [ref=e40]: Sales - link "Bookings" [ref=e42] [cursor=pointer]: - /url: /bookings - generic [ref=e43]: 󰇡 - link "Customers" [ref=e47] [cursor=pointer]: - /url: /customers - generic [ref=e48]: 󰀏 - link "Invoices" [ref=e52] [cursor=pointer]: - /url: /invoices - generic [ref=e53]: 󰷉 - link "Credit notes" [ref=e57] [cursor=pointer]: - /url: /credit-notes - link "Units" [ref=e64] [cursor=pointer]: - /url: /units - generic [ref=e65]: 󰍀 - generic [ref=e69]: Site management - link "Locations" [ref=e71] [cursor=pointer]: - /url: /locations - generic [ref=e72]: 󰟙 - link "Unit types" [ref=e76] [cursor=pointer]: - /url: /unit-types - generic [ref=e77]: 󰆧 - link "Protection Plans" [ref=e81] [cursor=pointer]: - /url: /insurances - generic [ref=e82]: 󰳌 - link "Deposits" [ref=e86] [cursor=pointer]: - /url: /deposits - generic [ref=e87]: 󱙆 - link "Products" [ref=e91] [cursor=pointer]: - /url: /products - generic [ref=e92]: 󰄑 - link "Discounts" [ref=e96] [cursor=pointer]: - /url: /discounts - generic [ref=e97]: 󰓼 - generic [ref=e101]: - option "Emails" [ref=e102] [cursor=pointer]: - generic [ref=e103]: 󰻨 - generic [ref=e107]: 󰅀 - text: 󱡰 󰁥 - generic [ref=e111]: Admin - link "Integrations" [ref=e113] [cursor=pointer]: - /url: /connected-apps - generic [ref=e114]: 󱘖 - link "User & Roles" [ref=e118] [cursor=pointer]: - /url: /users - generic [ref=e119]: 󰭘 - generic [ref=e123]: - option "Booking Portal" [ref=e124] [cursor=pointer]: - generic [ref=e125]: 󱃁 - generic [ref=e129]: 󰅀 - text: 󰖟 󰟙 - generic [ref=e133]: - option "JaneAI" [ref=e134] [cursor=pointer]: - generic [ref=e135]: 󱙺 - generic [ref=e139]: 󰅀 - text: 󱜹 - generic [ref=e143]: Feedback - link "Voting Portal" [ref=e145] [cursor=pointer]: - /url: /voting-portal - generic [ref=e146]: 󰔔 - generic [ref=e152]: - button "AS Andreas Stadler andreas.stadler@storeroom.at" [ref=e155] [cursor=pointer]: - generic [ref=e156]: AS - generic [ref=e159]: - generic [ref=e160]: Andreas Stadler - generic "andreas.stadler@storeroom.at" [ref=e161] - generic [ref=e162]: 󰇙 - generic: 󰗊 󰅀 󰷖 󰍃 - button [ref=e163] [cursor=pointer]: - generic [ref=e164]: 󰋽 - main [ref=e166]: - generic [ref=e168]: - generic [ref=e170]: - generic [ref=e171]: Invoices - generic [ref=e174]: - link [ref=e175] [cursor=pointer]: - /url: /invoices/create - generic [ref=e176]: - generic [ref=e177]: 󰐕 - text: Create Invoice - button [ref=e178] [cursor=pointer]: - generic [ref=e179]: 󰍝 - generic [ref=e184]: - generic [ref=e186]: - button [ref=e187] [cursor=pointer]: - generic [ref=e188]: - heading "Filters" [level=3] [ref=e191] - generic [ref=e193]: - button [ref=e195]: - generic [ref=e196]: - generic [ref=e197]: 󰑐 - text: Reset filters - generic [ref=e199]: 󰅀 - generic [ref=e207]: - generic [ref=e212]: - generic [ref=e213]: 󰍉 - textbox "Search" [ref=e216]: Debra YundtHGzNSR - button "Clear Search" [ref=e218] [cursor=pointer]: 󰅙 - generic: Search - combobox [ref=e222]: - generic [ref=e223]: - generic: Location - combobox "Location" [ref=e225] - button [ref=e227] [cursor=pointer]: 󰍝 - combobox [ref=e231]: - generic [ref=e232]: - generic: Status - combobox "Status" [ref=e234] - button [ref=e236] [cursor=pointer]: 󰍝 - combobox [ref=e240]: - generic [ref=e241]: - generic: Payment option - combobox "Payment option" [ref=e243] - button [ref=e245] [cursor=pointer]: 󰍝 - combobox [ref=e249]: - generic [ref=e250]: - generic: Type - combobox "Type" [ref=e252] - button [ref=e254] [cursor=pointer]: 󰍝 - generic [ref=e259]: - generic [ref=e260]: 󰸗 - generic [ref=e262]: - generic: Created at - textbox "Created at" [ref=e263]: - generic: 󰅁 󰍝 󰅂 󰅁 󰍝 󰅂 - text: 󰅙 - generic [ref=e265]: - generic [ref=e267]: - generic [ref=e269]: - generic [ref=e271]: - generic [ref=e272]: 2 selected - generic [ref=e277]: - button "Deselect all" [ref=e282] [cursor=pointer]: - generic [ref=e283]: 󰅖 - button "Select all" [ref=e290] [cursor=pointer]: - generic [ref=e291]: 󰄬 - generic [ref=e294]: - button "Mark as paid" [ref=e297] [cursor=pointer]: - generic [ref=e298]: 󰗡 - button "SEPA XML actions" [disabled] [ref=e303]: - generic [ref=e304]: 󱨉 - generic: 󰗡 󰅚 󰗖 - generic [ref=e309]: - button [ref=e310] [cursor=pointer] - generic: 󰄲 󰄲 󰄲 󰄲 󰄲 󰄲 󰄲 󰄲 󰄲 󰄲 󰄲 - table [ref=e316]: - rowgroup [ref=e317]: - row [ref=e318]: - columnheader [ref=e319]: - generic [ref=e320]: - checkbox [ref=e321] - generic [ref=e322] [cursor=pointer]: 󰄱 - columnheader [ref=e324]: - button "Number" [ref=e325] [cursor=pointer]: - generic [ref=e328]: 󰁝 - columnheader [ref=e331]: - button "Location" [ref=e332] [cursor=pointer]: - generic [ref=e335]: 󰁝 - columnheader [ref=e338]: - button "Status" [ref=e339] [cursor=pointer]: - generic [ref=e342]: 󰁝 - columnheader [ref=e345]: - button "Payment option" [ref=e346] [cursor=pointer]: - generic [ref=e349]: 󰁝 - columnheader [ref=e352]: - button "Due date" [ref=e353] [cursor=pointer]: - generic [ref=e356]: 󰁝 - columnheader [ref=e359]: - button "Customer" [ref=e360] [cursor=pointer]: - generic [ref=e363]: 󰁝 - columnheader [ref=e366]: - button "Unit" [ref=e367] [cursor=pointer]: - generic [ref=e370]: 󰁝 - columnheader "Discount" [ref=e373] - columnheader [ref=e377]: - button "Total (incl. VAT)" [ref=e378] [cursor=pointer]: - generic [ref=e379]: - generic [ref=e380]: Total (incl. VAT) - generic [ref=e381]: 󰋽 - generic [ref=e383]: 󰁝 - columnheader [ref=e386]: - button "Amount due" [ref=e387] [cursor=pointer]: - generic [ref=e390]: 󰁝 - columnheader [ref=e393]: - button "Issue date" [ref=e394] [cursor=pointer]: - generic [ref=e397]: 󰁝 - columnheader "Actions" [ref=e400] - row [ref=e404]: - columnheader [ref=e405] - rowgroup [ref=e406]: - row [ref=e407]: - cell [ref=e408]: - generic [ref=e409]: - checkbox [checked] [ref=e410] - generic [ref=e411] [cursor=pointer]: 󰄲 - cell [ref=e413]: - link "INV-2110619" [ref=e414] [cursor=pointer]: - /url: /invoices/1562527908 - cell [ref=e416]: - link "Vienna South" [ref=e417] [cursor=pointer]: - /url: /invoices/1562527908 - cell [ref=e419]: - link "Open" [ref=e420] [cursor=pointer]: - /url: /invoices/1562527908 - cell [ref=e425]: - link "Manual" [ref=e426] [cursor=pointer]: - /url: /invoices/1562527908 - cell [ref=e428]: - link "23 Aug 2026" [ref=e429] [cursor=pointer]: - /url: /invoices/1562527908 - cell [ref=e431]: - link "Debra YundtHGzNSR" [ref=e432] [cursor=pointer]: - /url: /invoices/1562527908 - cell [ref=e435]: - link [ref=e436] [cursor=pointer]: - /url: /invoices/1562527908 - cell "-" [ref=e437] - cell [ref=e439]: - link "€640.80" [ref=e440] [cursor=pointer]: - /url: /invoices/1562527908 - cell [ref=e442]: - link "€640.80" [ref=e443] [cursor=pointer]: - /url: /invoices/1562527908 - cell [ref=e445]: - link "21 Aug 2026" [ref=e446] [cursor=pointer]: - /url: /invoices/1562527908 - cell [ref=e448]: - button [ref=e451] [cursor=pointer]: - generic [ref=e452]: 󰇘 - generic: 󰇚 󰯝 - row [ref=e454]: - cell [ref=e455]: - generic [ref=e456]: - checkbox [checked] [active] [ref=e457] - generic [ref=e458] [cursor=pointer]: 󰄲 - cell [ref=e460]: - link "INV-2110620" [ref=e461] [cursor=pointer]: - /url: /invoices/765278480 - cell [ref=e463]: - link "Vienna South" [ref=e464] [cursor=pointer]: - /url: /invoices/765278480 - cell [ref=e466]: - link "Open" [ref=e467] [cursor=pointer]: - /url: /invoices/765278480 - cell [ref=e472]: - link "Manual" [ref=e473] [cursor=pointer]: - /url: /invoices/765278480 - cell [ref=e475]: - link "23 Aug 2026" [ref=e476] [cursor=pointer]: - /url: /invoices/765278480 - cell [ref=e478]: - link "Debra YundtHGzNSR" [ref=e479] [cursor=pointer]: - /url: /invoices/765278480 - cell [ref=e482]: - link [ref=e483] [cursor=pointer]: - /url: /invoices/765278480 - cell "-" [ref=e484] - cell [ref=e486]: - link "€640.80" [ref=e487] [cursor=pointer]: - /url: /invoices/765278480 - cell [ref=e489]: - link "€640.80" [ref=e490] [cursor=pointer]: - /url: /invoices/765278480 - cell [ref=e492]: - link "21 Aug 2026" [ref=e493] [cursor=pointer]: - /url: /invoices/765278480 - cell [ref=e495]: - button [ref=e498] [cursor=pointer]: - generic [ref=e499]: 󰇘 - generic: 󰇚 󰯝 - row [ref=e501]: - cell [ref=e502]: - generic [ref=e503]: - checkbox [ref=e504] - generic [ref=e505] [cursor=pointer]: 󰄱 - cell [ref=e507]: - link "INV-2110618" [ref=e508] [cursor=pointer]: - /url: /invoices/1299524162 - cell [ref=e510]: - link "Vienna South" [ref=e511] [cursor=pointer]: - /url: /invoices/1299524162 - cell [ref=e513]: - link "Open" [ref=e514] [cursor=pointer]: - /url: /invoices/1299524162 - cell [ref=e519]: - link "Manual" [ref=e520] [cursor=pointer]: - /url: /invoices/1299524162 - cell [ref=e522]: - link "23 Aug 2026" [ref=e523] [cursor=pointer]: - /url: /invoices/1299524162 - cell [ref=e525]: - link "Debra YundtHGzNSR" [ref=e526] [cursor=pointer]: - /url: /invoices/1299524162 - cell [ref=e529]: - link [ref=e530] [cursor=pointer]: - /url: /invoices/1299524162 - cell "-" [ref=e531] - cell [ref=e533]: - link "€640.80" [ref=e534] [cursor=pointer]: - /url: /invoices/1299524162 - cell [ref=e536]: - link "€640.80" [ref=e537] [cursor=pointer]: - /url: /invoices/1299524162 - cell [ref=e539]: - link "21 Aug 2026" [ref=e540] [cursor=pointer]: - /url: /invoices/1299524162 - cell [ref=e542]: - button [ref=e545] [cursor=pointer]: - generic [ref=e546]: 󰇘 - generic: 󰇚 󰯝 - generic [ref=e550]: - generic [ref=e551]: - generic [ref=e552]: "Items per page:" - combobox [ref=e555]: - generic [ref=e557] [cursor=pointer]: - generic [ref=e558]: "10" - combobox "Items per page:": "10" - generic [ref=e560]: 󰍝 - generic [ref=e562]: 1-3 of 3 - generic [ref=e563]: - button [disabled]: - generic: 󰘀 - button [disabled]: - generic: 󰅁 - button [disabled]: - generic: 󰅂 - button [disabled]: - generic: 󰘁 - generic: - 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 - tooltip - tooltip - tooltip - tooltip - tooltip - tooltip - tooltip - tooltip ``` # Test source ```ts 1 | import { BasePage } from '@/manager/shared/base/BasePage'; 2 | import { InvoiceBulkMarkAsPaidDialog } from '@/manager/modules/invoice/views/InvoiceBulkMarkAsPaidDialog'; 3 | import { InvoiceCreateDialog } from '@/manager/modules/invoice/views/InvoiceCreateDialog'; 4 | import { InvoiceDetailsPage } from '@/manager/modules/invoice/views/InvoiceDetailsPage'; 5 | import { DataTable } from '@/manager/modules/ui/data-table/components/DataTable'; 6 | import { DebouncedTextField } from '@/manager/shared/components/DebouncedTextField'; 7 | import { MultiAutocomplete } from '@/manager/shared/components/MultiAutocomplete'; 8 | import { RangeDatePicker } from '@/manager/shared/components/RangeDatePicker'; 9 | import { getFilterHost } from '@/manager/shared/utils/locator-utils'; 10 | 11 | export class InvoiceListPage extends BasePage { 12 | readonly actionButton = this.header.getByTestId('invoice-list-action-button'); 13 | readonly searchTextField = new DebouncedTextField(getFilterHost(this.body, 'Search')); 14 | readonly locationAutocomplete = new MultiAutocomplete(getFilterHost(this.body, 'Location')); 15 | readonly statusAutocomplete = new MultiAutocomplete(getFilterHost(this.body, 'Status')); 16 | readonly createdAtDatePicker = new RangeDatePicker(getFilterHost(this.body, 'Created at')); 17 | readonly dataTable = new DataTable(this.body); 18 | readonly bulkMarkAsPaidActionButton = this.dataTable.rowSelector.getAction('invoice-bulk-mark-as-paid-action'); 19 | 20 | async goto(): Promise { 21 | await this.host.goto('/invoices'); 22 | } 23 | 24 | selectInvoices(indexes: number | number[]): Promise { 25 | return this.dataTable.rowSelector.select(indexes); 26 | } 27 | 28 | async openInvoiceBulkMarkAsPaidDialog(): Promise { > 29 | await this.bulkMarkAsPaidActionButton.click(); | ^ Error: locator.click: Test timeout of 120000ms exceeded. 30 | return new InvoiceBulkMarkAsPaidDialog(this.host); 31 | } 32 | 33 | async openInvoiceCreateDialog(): Promise { 34 | await this.dataTable.waitForLoading(); 35 | await Promise.all([this.host.waitForURL('/invoices/create'), this.actionButton.click()]); 36 | return new InvoiceCreateDialog(this.host); 37 | } 38 | 39 | async goToInvoiceDetailsPage(index: number): Promise { 40 | await Promise.all([this.host.waitForURL('**/invoices/*'), this.dataTable.clickRow(index)]); 41 | return new InvoiceDetailsPage(this.host); 42 | } 43 | } 44 | ```