# 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-edit-general.spec.ts >> edits the phone number
- Location: src/manager/tests/e2e/customer/customer-edit-general.spec.ts:125:5

# Error details

```
Error: expect(locator).toHaveCount(expected) failed

Locator:  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)').getByTestId('ui-data-grid-table-with-data').locator('tr')
Expected: 1
Received: 0
Timeout:  20000ms

Call log:
  - Expect "toHaveCount" with timeout 20000ms
  - 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)').getByTestId('ui-data-grid-table-with-data').locator('tr')
    24 × locator resolved to 0 elements
       - unexpected value "0"

```

# 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=e15] [cursor=pointer]:
          - generic [ref=e19]: AS
          - generic:
            - text: 󰗊 󰅀
            - text: 󰷖 󰍃
    - navigation [ref=e20]:
      - list [ref=e22]:
        - generic [ref=e24]: Dashboard
        - link "Tasks" [ref=e25] [cursor=pointer]:
          - /url: /tasks
          - img [ref=e28]
          - generic [ref=e31]: Tasks
        - link "Facility maps" [ref=e32] [cursor=pointer]:
          - /url: /facility-map
          - generic [ref=e34]: 󰧾
          - generic [ref=e36]: Facility maps
        - link "Analytics" [ref=e37] [cursor=pointer]:
          - /url: /dashboard
          - generic [ref=e39]: 󱖶
          - generic [ref=e41]: Analytics
        - generic [ref=e43]: Sales
        - link "Bookings" [ref=e44] [cursor=pointer]:
          - /url: /bookings
          - generic [ref=e46]: 󰇡
          - generic [ref=e48]: Bookings
        - link "Customers" [ref=e49] [cursor=pointer]:
          - /url: /customers
          - generic [ref=e51]: 󰀏
          - generic [ref=e53]: Customers
        - link "Invoices" [ref=e54] [cursor=pointer]:
          - /url: /invoices
          - generic [ref=e56]: 󰷉
          - generic [ref=e58]: Invoices
        - link "Credit notes" [ref=e59] [cursor=pointer]:
          - /url: /credit-notes
          - img [ref=e62]
          - generic [ref=e65]: Credit notes
        - link "Units" [ref=e66] [cursor=pointer]:
          - /url: /units
          - generic [ref=e68]: 󰍀
          - generic [ref=e70]: Units
        - generic [ref=e72]: Site management
        - link "Locations" [ref=e73] [cursor=pointer]:
          - /url: /locations
          - generic [ref=e75]: 󰟙
          - generic [ref=e77]: Locations
        - link "Unit types" [ref=e78] [cursor=pointer]:
          - /url: /unit-types
          - generic [ref=e80]: 󰆧
          - generic [ref=e82]: Unit types
        - link "Protection Plans" [ref=e83] [cursor=pointer]:
          - /url: /insurances
          - generic [ref=e85]: 󰳌
          - generic [ref=e87]: Protection Plans
        - link "Deposits" [ref=e88] [cursor=pointer]:
          - /url: /deposits
          - generic [ref=e90]: 󱙆
          - generic [ref=e92]: Deposits
        - link "Products" [ref=e93] [cursor=pointer]:
          - /url: /products
          - generic [ref=e95]: 󰄑
          - generic [ref=e97]: Products
        - link "Discounts" [ref=e98] [cursor=pointer]:
          - /url: /discounts
          - generic [ref=e100]: 󰓼
          - generic [ref=e102]: Discounts
        - generic [ref=e103]:
          - option "Emails" [ref=e104] [cursor=pointer]:
            - generic [ref=e106]: 󰻨
            - generic [ref=e108]: Emails
            - generic [ref=e112]: 󰅀
          - text: 󱡰 󰁥
        - generic [ref=e114]: Admin
        - link "Integrations" [ref=e115] [cursor=pointer]:
          - /url: /connected-apps
          - generic [ref=e117]: 󱘖
          - generic [ref=e119]: Integrations
        - link "User & Roles" [ref=e120] [cursor=pointer]:
          - /url: /users
          - generic [ref=e122]: 󰭘
          - generic [ref=e124]: User & Roles
        - generic [ref=e125]:
          - option "Booking Portal" [ref=e126] [cursor=pointer]:
            - generic [ref=e128]: 󱃁
            - generic [ref=e130]: Booking Portal
            - generic [ref=e134]: 󰅀
          - text: 󰖟 󰟙
        - generic [ref=e135]:
          - option "JaneAI" [ref=e136] [cursor=pointer]:
            - generic [ref=e138]: 󱙺
            - generic [ref=e140]: JaneAI
            - generic [ref=e144]: 󰅀
          - text: 󱜹
        - generic [ref=e146]: Feedback
        - link "Voting Portal" [ref=e147] [cursor=pointer]:
          - /url: /voting-portal
          - generic [ref=e149]: 󰔔
          - generic [ref=e151]: Voting Portal
      - generic [ref=e153]:
        - generic [ref=e154]: Kinnovis GmbH © 2026
        - generic [ref=e155]: v2026.05.19
    - main [ref=e156]:
      - generic [ref=e158]:
        - generic [ref=e160]:
          - generic [ref=e163]:
            - generic [ref=e164]: Sales
            - heading "Customers" [level=1] [ref=e166]:
              - generic [ref=e167]: Customers
          - generic [ref=e169]:
            - link "Create customer" [ref=e170] [cursor=pointer]:
              - /url: /customers/create
              - generic [ref=e171]:
                - generic [ref=e172]: 󰐕
                - text: Create customer
            - button [ref=e173] [cursor=pointer]:
              - generic [ref=e177]: 󰍝
        - generic [ref=e179]:
          - generic [ref=e181]:
            - button "Filters Reset filters" [ref=e182] [cursor=pointer]:
              - generic [ref=e183]:
                - heading "Filters" [level=3] [ref=e186]
                - generic [ref=e188]:
                  - button "Reset filters" [ref=e190]:
                    - generic [ref=e191]:
                      - generic [ref=e192]: 󰑐
                      - text: Reset filters
                  - generic [ref=e196]: 󰅀
            - generic [ref=e202]:
              - generic [ref=e207]:
                - generic [ref=e209]: 󰍉
                - textbox "Search" [active] [ref=e211]: +55 51 5982 5770
                - button "Clear Search" [ref=e213] [cursor=pointer]: 󰅙
                - generic:
                  - generic: Search
              - combobox [ref=e217]:
                - generic [ref=e218]:
                  - generic: Location
                  - combobox "Location" [ref=e220]
                - button [ref=e222] [cursor=pointer]: 󰍝
              - combobox [ref=e226]:
                - generic [ref=e227]:
                  - generic: Has past due invoice(s)
                  - combobox "Has past due invoice(s)" [ref=e229]
                - button [ref=e231] [cursor=pointer]: 󰍝
              - combobox [ref=e235]:
                - generic [ref=e236]:
                  - generic: Status
                  - combobox "Status" [ref=e238]
                - button [ref=e240] [cursor=pointer]: 󰍝
          - generic [ref=e242]:
            - table [ref=e246]:
              - rowgroup [ref=e247]:
                - row "Customer no. Name Location(s) Email address Phone number Status Past due invoice(s) Created at" [ref=e248]:
                  - columnheader "Customer no." [ref=e249]:
                    - button "Customer no." [ref=e250] [cursor=pointer]:
                      - generic [ref=e252]: Customer no.
                      - generic [ref=e255]: 󰁝
                  - columnheader "Name" [ref=e256]:
                    - button "Name" [ref=e257] [cursor=pointer]:
                      - generic [ref=e259]: Name
                      - generic [ref=e262]: 󰁝
                  - columnheader "Location(s)" [ref=e263]:
                    - button "Location(s)" [ref=e264] [cursor=pointer]:
                      - generic [ref=e266]: Location(s)
                      - generic [ref=e269]: 󰁝
                  - columnheader "Email address" [ref=e270]:
                    - button "Email address" [ref=e271] [cursor=pointer]:
                      - generic [ref=e273]: Email address
                      - generic [ref=e276]: 󰁝
                  - columnheader "Phone number" [ref=e277]:
                    - generic [ref=e280]: Phone number
                  - columnheader "Status" [ref=e281]:
                    - button "Status" [ref=e282] [cursor=pointer]:
                      - generic [ref=e284]: Status
                      - generic [ref=e287]: 󰁝
                  - columnheader "Past due invoice(s)" [ref=e288]:
                    - button "Past due invoice(s)" [ref=e289] [cursor=pointer]:
                      - generic [ref=e291]: Past due invoice(s)
                      - generic [ref=e294]: 󰁝
                  - columnheader "Created at" [ref=e295]:
                    - button "Created at" [ref=e296] [cursor=pointer]:
                      - generic [ref=e298]: Created at
                      - generic [ref=e301]: 󰁝
                - row [ref=e302]:
                  - columnheader [ref=e303]
              - rowgroup [ref=e304]:
                - row "No data yet" [ref=e305]:
                  - cell "No data yet" [ref=e306]:
                    - generic [ref=e307]: No data yet
            - generic [ref=e310]:
              - generic [ref=e311]:
                - generic [ref=e312]: "Items per page:"
                - combobox [ref=e315]:
                  - generic [ref=e317] [cursor=pointer]:
                    - generic [ref=e319]: "10"
                    - combobox "Items per page:": "10"
                  - generic [ref=e321]: 󰍝
              - generic [ref=e322]: 0-0 of 0
              - generic [ref=e323]:
                - button [disabled]:
                  - generic:
                    - generic: 󰘀
                - button [disabled]:
                  - generic:
                    - generic: 󰅁
                - button [disabled]:
                  - generic:
                    - generic: 󰅂
                - button [disabled]:
                  - generic:
                    - generic: 󰘁
  - generic:
    - tooltip
    - tooltip
    - tooltip
    - tooltip
```

# Test source

```ts
  45  |       await expectMultiLocatorToHaveText(newDetailsPage.generalCard.locations, customerLocationNames);
  46  |       await expectSingleLocatorToHaveText(newDetailsPage.generalCard.type, newCustomer.type);
  47  | 
  48  |       if (newCustomer.type === 'business') {
  49  |         await expectSingleLocatorToHaveText(newDetailsPage.generalCard.companyName, newCustomer.companyName);
  50  |         await expectSingleLocatorToHaveText(newDetailsPage.generalCard.vatType, newCustomer.vatType?.name);
  51  |         await expectSingleLocatorToHaveText(newDetailsPage.generalCard.vatNumber, newCustomer.vatNumber);
  52  |       } else {
  53  |         await expect(newDetailsPage.generalCard.companyName).toBeHidden();
  54  |         await expect(newDetailsPage.generalCard.vatType).toBeHidden();
  55  |         await expect(newDetailsPage.generalCard.vatNumber).toBeHidden();
  56  |       }
  57  | 
  58  |       await expectSingleLocatorToHaveText(newDetailsPage.generalCard.name, customerFullName);
  59  |       await expectSingleLocatorToHaveText(newDetailsPage.generalCard.email, newCustomer.email);
  60  |       await expectSingleLocatorToHaveText(newDetailsPage.generalCard.phoneNumber, customerPhone);
  61  |       await expectSingleLocatorToHaveText(newDetailsPage.generalCard.language, newCustomer.language.id);
  62  |       await expectSingleLocatorToHaveText(newDetailsPage.generalCard.address, customerAddress);
  63  |       await expectSingleLocatorToHaveText(newDetailsPage.generalCard.note, newCustomer.note);
  64  |     });
  65  | 
  66  |     await test.step('verify new customer on list page', async () => {
  67  |       const listPage = await newDetailsPage.returnToCustomerListPage();
  68  | 
  69  |       await listPage.searchTextField.fill(newCustomer.email);
  70  | 
  71  |       await expect(listPage.dataTable.getRows()).toHaveCount(1);
  72  |       await expectDataTableTextColumnToHaveText(listPage.dataTable, customerTableColumnTestIds.id, customerId);
  73  |       await expectDataTableTextColumnToHaveText(listPage.dataTable, customerTableColumnTestIds.name, customerTitle);
  74  |       await expectDataTableChipsColumnToHaveText(
  75  |         listPage.dataTable,
  76  |         customerTableColumnTestIds.locations,
  77  |         customerLocationNames
  78  |       );
  79  |       await expectDataTableTextColumnToHaveText(
  80  |         listPage.dataTable,
  81  |         customerTableColumnTestIds.email,
  82  |         newCustomer.email
  83  |       );
  84  |       await expectDataTableTextColumnToHaveText(
  85  |         listPage.dataTable,
  86  |         customerTableColumnTestIds.phoneNumber,
  87  |         customerPhone
  88  |       );
  89  |       await expectDataTableChipsColumnToHaveText(
  90  |         listPage.dataTable,
  91  |         customerTableColumnTestIds.status,
  92  |         newCustomer.status
  93  |       );
  94  |       await expectDataTableTextColumnToHaveText(
  95  |         listPage.dataTable,
  96  |         customerTableColumnTestIds.createdAt,
  97  |         customerCreatedAt
  98  |       );
  99  |     });
  100 |   });
  101 | }
  102 | 
  103 | test('edits the email', async ({ createCustomer, customerDetailsPage }) => {
  104 |   const customer = await createCustomer(getCustomerCreateData());
  105 |   const newEmail = faker.internet.email();
  106 | 
  107 |   await customerDetailsPage.goto(customer.id);
  108 | 
  109 |   const newDetailsPage = await test.step('edit customer email', async () => {
  110 |     const dialog = await customerDetailsPage.openCustomerEditGeneralDialog();
  111 |     return dialog.edit({ email: newEmail });
  112 |   });
  113 | 
  114 |   await test.step('verify new email on details page', async () => {
  115 |     await expectSingleLocatorToHaveText(newDetailsPage.generalCard.email, newEmail);
  116 |   });
  117 | 
  118 |   await test.step('verify new email on list page', async () => {
  119 |     const listPage = await newDetailsPage.returnToCustomerListPage();
  120 |     await listPage.searchTextField.fill(newEmail);
  121 |     await expect(listPage.dataTable.getRows()).toHaveCount(1);
  122 |   });
  123 | });
  124 | 
  125 | test('edits the phone number', async ({ createCustomer, customerDetailsPage }) => {
  126 |   const customer = await createCustomer(getCustomerCreateData());
  127 |   const newCountry = countries.BR;
  128 |   const newPhone = getCustomerPhone(newCountry);
  129 |   const formattedNewPhone = formatPhone(newPhone);
  130 | 
  131 |   await customerDetailsPage.goto(customer.id);
  132 | 
  133 |   const newDetailsPage = await test.step('edit customer phone number', async () => {
  134 |     const dialog = await customerDetailsPage.openCustomerEditGeneralDialog();
  135 |     return dialog.edit({ phone: newPhone, country: newCountry });
  136 |   });
  137 | 
  138 |   await test.step('verify new phone number on details page', async () => {
  139 |     await expectSingleLocatorToHaveText(newDetailsPage.generalCard.phoneNumber, formattedNewPhone);
  140 |   });
  141 | 
  142 |   await test.step('verify new phone number on list page', async () => {
  143 |     const listPage = await newDetailsPage.returnToCustomerListPage();
  144 |     await listPage.searchTextField.fill(formattedNewPhone);
> 145 |     await expect(listPage.dataTable.getRows()).toHaveCount(1);
      |                                                ^ Error: expect(locator).toHaveCount(expected) failed
  146 |   });
  147 | });
  148 | 
  149 | test('rejects an edit with a duplicate email', async ({ createCustomer, customerDetailsPage }) => {
  150 |   const existing = await createCustomer(getCustomerCreateData());
  151 |   const editing = await createCustomer(getCustomerCreateData());
  152 | 
  153 |   await customerDetailsPage.goto(editing.id);
  154 | 
  155 |   const dialog = await test.step('submit edit with duplicate email', async () => {
  156 |     const editDialog = await customerDetailsPage.openCustomerEditGeneralDialog();
  157 |     await editDialog.fill({ email: existing.email });
  158 |     await editDialog.submit();
  159 |     return editDialog;
  160 |   });
  161 | 
  162 |   await test.step('verify errors on form', async () => {
  163 |     await expect(dialog.errors).toHaveCountGreaterThan(0);
  164 |   });
  165 | });
  166 | 
  167 | test('rejects an edit with a duplicate phone number', async ({ createCustomer, customerDetailsPage }) => {
  168 |   const existing = await createCustomer(getCustomerCreateData());
  169 |   const editing = await createCustomer(getCustomerCreateData());
  170 | 
  171 |   await customerDetailsPage.goto(editing.id);
  172 | 
  173 |   const dialog = await test.step('submit edit with duplicate phone number', async () => {
  174 |     const editDialog = await customerDetailsPage.openCustomerEditGeneralDialog();
  175 |     await editDialog.fill({ phone: existing.phone, country: existing.country });
  176 |     await editDialog.submit();
  177 |     return editDialog;
  178 |   });
  179 | 
  180 |   await test.step('verify errors on form', async () => {
  181 |     await expect(dialog.errors).toHaveCountGreaterThan(0);
  182 |   });
  183 | });
  184 | 
  185 | test('rejects an edit with a vat number that does not match the vat type', async ({
  186 |   createCustomer,
  187 |   customerDetailsPage,
  188 | }) => {
  189 |   const customer = await createCustomer(getCustomerCreateData({ type: 'business' }));
  190 | 
  191 |   await customerDetailsPage.goto(customer.id);
  192 | 
  193 |   const dialog = await test.step('submit edit with mismatched vat type and number', async () => {
  194 |     const editDialog = await customerDetailsPage.openCustomerEditGeneralDialog();
  195 |     await editDialog.fill({ vatType: vatTypes.eu_vat, vatNumber: 'INVALID-VAT-1234' });
  196 |     await editDialog.submit();
  197 |     return editDialog;
  198 |   });
  199 | 
  200 |   await test.step('verify errors on form', async () => {
  201 |     await expect(dialog.errors).toHaveCountGreaterThan(0);
  202 |   });
  203 | });
  204 | 
  205 | test('rejects an edit without all required fields', async ({ createCustomer, customerDetailsPage }) => {
  206 |   const customer = await createCustomer(getCustomerCreateData({ type: 'private' }));
  207 | 
  208 |   await customerDetailsPage.goto(customer.id);
  209 | 
  210 |   const dialog = await test.step('submit edit clearing required fields', async () => {
  211 |     const editDialog = await customerDetailsPage.openCustomerEditGeneralDialog();
  212 |     await editDialog.fill({ firstName: '', lastName: '' });
  213 |     await editDialog.submit();
  214 |     return editDialog;
  215 |   });
  216 | 
  217 |   await test.step('verify errors on form', async () => {
  218 |     await expect(dialog.errors).toHaveCountGreaterThan(0);
  219 |   });
  220 | });
  221 | 
```