# 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/booking/booking-create.spec.ts >> should create a booking for a customer with sepa payment - Location: src/manager/tests/e2e/booking/booking-create.spec.ts:16:7 # Error details ``` Error: expect(locator).toHaveText(expected) failed Locator: getByTestId('app-page').getByTestId('app-page-content').locator('[data-test-id=app-details-card]:has([data-test-id=title]:has-text("Billing"))').locator('[data-test-id=key-value-item]:has([data-test-id=key]:text-is("Payment method"))').getByTestId('payment-method-row') Timeout: 20000ms - Expected - 1 + Received + 2 - •••• 3201 IBAN + •••• 3201 + SEPA via Stripe Call log: - Expect "toHaveText" with timeout 20000ms - waiting for getByTestId('app-page').getByTestId('app-page-content').locator('[data-test-id=app-details-card]:has([data-test-id=title]:has-text("Billing"))').locator('[data-test-id=key-value-item]:has([data-test-id=key]:text-is("Payment method"))').getByTestId('payment-method-row') 24 × locator resolved to
- unexpected value "•••• 3201 SEPA via Stripe" ``` # Page snapshot ```yaml - generic [active] [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=e149]: - link [ref=e151] [cursor=pointer]: - /url: /bookings - generic [ref=e153]: 󰁍 - generic [ref=e156]: - generic [ref=e157]: Bookings - generic [ref=e158]: - heading "Booking 1501-3211-44" [level=1] [ref=e159]: - generic [ref=e160]: Booking 1501-3211-44 - generic [ref=e164]: Active - button "Actions" [ref=e166] [cursor=pointer]: - generic [ref=e167]: - text: Actions - generic [ref=e168]: 󱨉 - generic [ref=e170]: - generic [ref=e171]: - generic [ref=e173]: - heading "General" [level=3] [ref=e177] - table [ref=e180]: - rowgroup [ref=e181]: - row "Customer Kevinio Privato" [ref=e182]: - rowheader "Customer" [ref=e183] - cell "Kevinio Privato" [ref=e184]: - link "Kevinio Privato" [ref=e187] [cursor=pointer]: - /url: /customers/2000200020 - generic [ref=e189]: Kevinio Privato - row "Location Vienna South" [ref=e190]: - rowheader "Location" [ref=e191] - cell "Vienna South" [ref=e192]: - link "Vienna South" [ref=e195] [cursor=pointer]: - /url: /locations/561465857 - generic [ref=e197]: Vienna South - row "Created at 10 Apr 2026" [ref=e198]: - rowheader "Created at" [ref=e199] - cell "10 Apr 2026" [ref=e200]: - generic [ref=e202]: 10 Apr 2026 - row "Move-in 10 Apr 2026" [ref=e203]: - rowheader "Move-in" [ref=e204] - cell "10 Apr 2026" [ref=e205]: - generic [ref=e207]: 10 Apr 2026 - row "Move-out -" [ref=e208]: - rowheader "Move-out" [ref=e209] - cell "-" [ref=e210]: - generic [ref=e212]: "-" - row "Cancelled at -" [ref=e213]: - rowheader "Cancelled at" [ref=e214] - cell "-" [ref=e215]: - generic [ref=e217]: "-" - row "Deposit excl. VAT -" [ref=e218]: - rowheader "Deposit excl. VAT" [ref=e219] - cell "-" [ref=e220]: - generic [ref=e222]: "-" - row "Discount -" [ref=e223]: - rowheader "Discount" [ref=e224] - cell "-" [ref=e225]: - generic [ref=e227]: "-" - row "Contract -" [ref=e228]: - rowheader "Contract" [ref=e229] - cell "-" [ref=e230]: - generic [ref=e232]: "-" - generic [ref=e233]: - generic [ref=e234]: - heading "Billing" [level=3] [ref=e238] - table [ref=e241]: - rowgroup [ref=e242]: - row "Booking Plan Super flex (1 week)" [ref=e243]: - rowheader "Booking Plan" [ref=e244] - cell "Super flex (1 week)" [ref=e245]: - generic [ref=e247]: Super flex (1 week) - row "Current period 10 - 17 Apr 2026" [ref=e248]: - rowheader "Current period" [ref=e249] - cell "10 - 17 Apr 2026" [ref=e250]: - generic [ref=e252]: 10 - 17 Apr 2026 - row "Amount excl. VAT €50.00" [ref=e253]: - rowheader "Amount excl. VAT" [ref=e254] - cell "€50.00" [ref=e255]: - generic [ref=e257]: €50.00 - row "Price adjustment -" [ref=e258]: - rowheader "Price adjustment" [ref=e259] - cell "-" [ref=e260]: - generic [ref=e262]: "-" - row "Next invoice 17 Apr 2026" [ref=e263]: - rowheader "Next invoice" [ref=e264] - cell "17 Apr 2026" [ref=e265]: - generic [ref=e267]: 17 Apr 2026 - row "Payment method •••• 3201 SEPA via Stripe" [ref=e268]: - rowheader "Payment method" [ref=e269] - cell "•••• 3201 SEPA via Stripe" [ref=e270]: - generic [ref=e276]: - generic [ref=e278]: •••• 3201 - generic [ref=e279]: SEPA via Stripe - row "Payment option Automatic payment through Stripe" [ref=e280]: - rowheader "Payment option" [ref=e281] - cell "Automatic payment through Stripe" [ref=e282]: - generic [ref=e284]: Automatic payment through Stripe - generic [ref=e285]: - generic [ref=e287]: - heading "Notes" [level=3] [ref=e289] - link [ref=e291] [cursor=pointer]: - /url: /bookings/1501321144/edit/notes - generic [ref=e293]: 󰲶 - table [ref=e296]: - rowgroup [ref=e297]: - row "Note -" [ref=e298]: - rowheader "Note" [ref=e299] - cell "-" [ref=e300]: - generic [ref=e302]: "-" - generic [ref=e305]: - heading "Items" [level=3] [ref=e309] - generic [ref=e312]: - generic [ref=e313]: - generic [ref=e314]: - link "VS 1 sqm Unit" [ref=e315] [cursor=pointer]: - /url: /unit-types/561465857 - generic [ref=e317]: VS 1 sqm Unit - text: / - 'link "Unit 49 #49" [ref=e318] [cursor=pointer]': - /url: /units/998976231 - generic [ref=e320]: "Unit 49 #49" - generic [ref=e321]: €40.00 - generic [ref=e322]: - link "VS - Insurance weekly - 10" [ref=e323] [cursor=pointer]: - /url: /insurances/1970483263 - generic [ref=e325]: VS - Insurance weekly - 10 - generic [ref=e326]: €10.00 - generic [ref=e327]: - generic [ref=e328]: - strong [ref=e329]: Total excl. VAT - strong [ref=e330]: €50.00 - generic [ref=e331]: - generic [ref=e332]: VAT - generic [ref=e333]: €10.00 - generic [ref=e334]: - generic [ref=e335]: Total incl. VAT - generic [ref=e336]: €60.00 - generic [ref=e339]: - generic [ref=e341]: - heading "Invoices" [level=3] [ref=e343] - progressbar [ref=e346]: - img [ref=e347] - generic [ref=e354]: - generic [ref=e356]: - generic [ref=e358]: - button "Select all" [ref=e366] [cursor=pointer]: - generic [ref=e368]: 󰄬 - generic [ref=e369]: Select all - generic [ref=e370]: - button "Mark as paid" [disabled] [ref=e373]: - generic [ref=e375]: 󰗡 - generic [ref=e376]: Mark as paid - button "SEPA XML actions" [disabled] [ref=e379]: - generic [ref=e381]: 󱨉 - generic [ref=e382]: SEPA XML actions - generic: 󰗡 󰅚 󰗖 - generic [ref=e385]: - button [ref=e386] [cursor=pointer]: - generic [ref=e388]: 󱒇 - generic: 󰄲 󰄲 󰄲 󰄲 󰄲 󰄲 󰄲 󰄲 󰄲 - table [ref=e390]: - rowgroup [ref=e391]: - row "Number Status Payment option Due date Unit Total (incl. VAT) Amount due Issue date Actions" [ref=e392]: - columnheader "Number" [ref=e393]: - button "Number" [ref=e394] [cursor=pointer]: - generic [ref=e396]: Number - generic [ref=e399]: 󰁝 - columnheader "Status" [ref=e400]: - button "Status" [ref=e401] [cursor=pointer]: - generic [ref=e403]: Status - generic [ref=e406]: 󰁝 - columnheader "Payment option" [ref=e407]: - button "Payment option" [ref=e408] [cursor=pointer]: - generic [ref=e410]: Payment option - generic [ref=e413]: 󰁝 - columnheader "Due date" [ref=e414]: - button "Due date" [ref=e415] [cursor=pointer]: - generic [ref=e417]: Due date - generic [ref=e420]: 󰁝 - columnheader "Unit" [ref=e421]: - button "Unit" [ref=e422] [cursor=pointer]: - generic [ref=e424]: Unit - generic [ref=e427]: 󰁝 - columnheader "Total (incl. VAT)" [ref=e428]: - button "Total (incl. VAT)" [ref=e429] [cursor=pointer]: - generic [ref=e430]: - generic [ref=e431]: Total (incl. VAT) - generic [ref=e433]: 󰋽 - generic [ref=e436]: 󰁝 - columnheader "Amount due" [ref=e437]: - button "Amount due" [ref=e438] [cursor=pointer]: - generic [ref=e440]: Amount due - generic [ref=e443]: 󰁝 - columnheader "Issue date" [ref=e444]: - button "Issue date" [ref=e445] [cursor=pointer]: - generic [ref=e447]: Issue date - generic [ref=e450]: 󰁝 - columnheader "Actions" [ref=e451]: - generic [ref=e454]: Actions - row [ref=e455]: - columnheader [ref=e456] - rowgroup [ref=e457]: - row "No data yet" [ref=e458]: - cell "No data yet" [ref=e459]: - generic [ref=e460]: No data yet - generic [ref=e463]: - generic [ref=e464]: - generic [ref=e465]: "Items per page:" - combobox [ref=e468] [cursor=pointer]: - generic [ref=e470]: - generic [ref=e472]: "10" - combobox "Items per page:": "10" - generic [ref=e474]: 󰍝 - generic [ref=e475]: 0-0 of 0 - generic [ref=e476]: - button [disabled]: - generic: - generic: 󰘀 - button [disabled]: - generic: - generic: 󰅁 - button [disabled]: - generic: - generic: 󰅂 - button [disabled]: - generic: - generic: 󰘁 - generic [ref=e479]: - generic [ref=e481]: - heading "Payments" [level=3] [ref=e483] - progressbar [ref=e486]: - img [ref=e487] - generic [ref=e494]: - table [ref=e498]: - rowgroup [ref=e499]: - row "Total Status Invoice no. Date Payment method" [ref=e500]: - columnheader "Total" [ref=e501]: - button "Total" [ref=e502] [cursor=pointer]: - generic [ref=e504]: Total - generic [ref=e507]: 󰁝 - columnheader "Status" [ref=e508]: - button "Status" [ref=e509] [cursor=pointer]: - generic [ref=e511]: Status - generic [ref=e514]: 󰁝 - columnheader "Invoice no." [ref=e515]: - button "Invoice no." [ref=e516] [cursor=pointer]: - generic [ref=e518]: Invoice no. - generic [ref=e521]: 󰁝 - columnheader "Date" [ref=e522]: - button "Date" [ref=e523] [cursor=pointer]: - generic [ref=e525]: Date - generic [ref=e528]: 󰁝 - columnheader "Payment method" [ref=e529]: - button "Payment method" [ref=e530] [cursor=pointer]: - generic [ref=e532]: Payment method - generic [ref=e535]: 󰁝 - row [ref=e536]: - columnheader [ref=e537] - rowgroup [ref=e538]: - row "No data yet" [ref=e539]: - cell "No data yet" [ref=e540]: - generic [ref=e541]: No data yet - generic [ref=e544]: - generic [ref=e545]: - generic [ref=e546]: "Items per page:" - combobox [ref=e549] [cursor=pointer]: - generic [ref=e551]: - generic [ref=e553]: "10" - combobox "Items per page:": "10" - generic [ref=e555]: 󰍝 - generic [ref=e556]: 0-0 of 0 - generic [ref=e557]: - button [disabled]: - generic: - generic: 󰘀 - button [disabled]: - generic: - generic: 󰅁 - button [disabled]: - generic: - generic: 󰅂 - button [disabled]: - generic: - generic: 󰘁 - contentinfo [ref=e558]: - generic [ref=e559]: - generic [ref=e560]: - text: Kinnovis GmbH - generic [ref=e561]: 󰗦 - text: "2026" - generic [ref=e562]: v2026.04.08 - generic: - 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 { expect, Locator } from '@playwright/test'; 2 | 3 | export async function expectMultiLocatorToHaveText(locator: Locator, text: string[] | undefined): Promise { 4 | if (!text) { 5 | await expectLocatorToBeEmpty(locator); 6 | return; 7 | } 8 | 9 | const expectedValue = RegExp(text.join('|')); 10 | 11 | for (const element of await locator.all()) { 12 | await expectSingleLocatorToHaveText(element, expectedValue); 13 | } 14 | } 15 | 16 | export async function expectSingleLocatorToHaveText( 17 | locator: Locator, 18 | text: string | RegExp | undefined 19 | ): Promise { 20 | text > 21 | ? await expect(locator).toHaveText(text, { ignoreCase: true, useInnerText: true }) | ^ Error: expect(locator).toHaveText(expected) failed 22 | : await expectLocatorToBeEmpty(locator); 23 | } 24 | 25 | export async function expectLocatorToBeEmpty(locator: Locator): Promise { 26 | await expect(locator).toHaveText(/^(\s*-?\s*)$/); 27 | } 28 | ```