# 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: settings/teams.spec.ts >> Settings: Teams >> delete button disabled when team has users
- Location: src/tests/settings/teams.spec.ts:455:7

# Error details

```
Error: expect(locator).toBeDisabled() failed

Locator:  locator('.p-dialog-mask .p-dialog').first().locator('[data-testid="delete-button"]').first()
Expected: disabled
Received: enabled
Timeout:  5000ms

Call log:
  - Expect "toBeDisabled" with timeout 5000ms
  - waiting for locator('.p-dialog-mask .p-dialog').first().locator('[data-testid="delete-button"]').first()
    9 × locator resolved to <p-button pc135="" variant="text" severity="danger" icon="pi pi-trash" data-pc-section="host" data-testid="delete-button">…</p-button>
      - unexpected value "enabled"

```

# Page snapshot

```yaml
- generic [ref=e1]:
  - generic [ref=e2]:
    - generic [ref=e3]:
      - generic [ref=e5]:
        - generic [ref=e8]:
          - link "MasterEV Home" [ref=e9] [cursor=pointer]:
            - /url: /admin
            - img [ref=e12]
          - link "MasterEV" [ref=e18] [cursor=pointer]:
            - /url: /admin
        - menubar
        - generic [ref=e24] [cursor=pointer]:
          - generic [ref=e25]: 
          - generic [ref=e28]: E2E ADMIN settings-teams-spec-ts
          - generic [ref=e29]: 
      - generic [ref=e32]:
        - generic [ref=e36]:
          - heading "Einstellungen" [level=1] [ref=e37]
          - paragraph [ref=e38]: Benutzer:innen- und Systemeinstellungen
        - generic [ref=e42]:
          - tablist [ref=e45]:
            - tab "Benutzer:innen" [ref=e47] [cursor=pointer]
            - tab "Teams" [selected] [ref=e49] [cursor=pointer]
            - tab "Vorlagen" [ref=e51] [cursor=pointer]
          - generic [ref=e54]:
            - generic [ref=e55]:
              - generic [ref=e56]:
                - heading "Teams" [level=2] [ref=e57]
                - paragraph [ref=e58]: Verwalten Sie die Teams und deren Mitglieder
              - generic [ref=e59]:
                - generic [ref=e62]:
                  - generic [ref=e63]: 
                  - textbox "Suchen" [ref=e64]
                - button " Erstellen" [ref=e66] [cursor=pointer]:
                  - generic [ref=e67]: 
                  - generic [ref=e68]: Erstellen
            - generic [ref=e69]:
              - generic [ref=e71]:
                - generic [ref=e73] [cursor=pointer]:
                  - text: Teamname
                  - generic [ref=e74]: 
                - generic [ref=e76] [cursor=pointer]:
                  - text: Kürzel
                  - generic [ref=e77]: 
                - generic [ref=e79]: Details
                - generic [ref=e81] [cursor=pointer]:
                  - text: Aktiviert
                  - generic [ref=e82]: 
              - generic [ref=e86]:
                - generic [ref=e87] [cursor=pointer]:
                  - generic [ref=e89]: E2E Active mpl9uo6jot60
                  - generic [ref=e94]: Ampl9
                  - generic [ref=e97]:
                    - generic [ref=e98]: 
                    - generic [ref=e99]: "0"
                  - generic [ref=e101]:
                    - generic:
                      - switch [disabled]
                  - button "" [ref=e104]:
                    - generic [ref=e105]: 
                - generic [ref=e106] [cursor=pointer]:
                  - generic [ref=e108]: E2E Active mplb0jx3tpwt
                  - generic [ref=e113]: Amplb
                  - generic [ref=e116]:
                    - generic [ref=e117]: 
                    - generic [ref=e118]: "0"
                  - generic [ref=e120]:
                    - generic:
                      - switch [disabled]
                  - button "" [ref=e123]:
                    - generic [ref=e124]: 
                - generic [ref=e125] [cursor=pointer]:
                  - generic [ref=e127]: E2E Create mpl9uj0h3c1q
                  - generic [ref=e132]: Cmpl9
                  - generic [ref=e135]:
                    - generic [ref=e136]: 
                    - generic [ref=e137]: "5"
                  - generic [ref=e139]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e142]:
                    - generic [ref=e143]: 
                - generic [ref=e144] [cursor=pointer]:
                  - generic [ref=e146]: E2E Create mplb0evxx71l
                  - generic [ref=e151]: Cmplb
                  - generic [ref=e154]:
                    - generic [ref=e155]: 
                    - generic [ref=e156]: "0"
                  - generic [ref=e158]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e161]:
                    - generic [ref=e162]: 
                - generic [ref=e163] [cursor=pointer]:
                  - generic [ref=e165]: E2E Edited mpl9ukhwzfjn
                  - generic [ref=e170]: Dmpl9
                  - generic [ref=e173]:
                    - generic [ref=e174]: 
                    - generic [ref=e175]: "0"
                  - generic [ref=e177]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e180]:
                    - generic [ref=e181]: 
                - generic [ref=e182] [cursor=pointer]:
                  - generic [ref=e184]: E2E Edited mplb0g4f32zd
                  - generic [ref=e189]: Dmplb
                  - generic [ref=e192]:
                    - generic [ref=e193]: 
                    - generic [ref=e194]: "0"
                  - generic [ref=e196]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e199]:
                    - generic [ref=e200]: 
                - generic [ref=e201] [cursor=pointer]:
                  - generic [ref=e203]: E2E Quota mpl9um5eupnt
                  - generic [ref=e208]: Qmpl9
                  - generic [ref=e211]:
                    - generic [ref=e212]: 
                    - generic [ref=e213]: "0"
                  - generic [ref=e215]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e218]:
                    - generic [ref=e219]: 
                - generic [ref=e220] [cursor=pointer]:
                  - generic [ref=e222]: E2E Quota mplb0i3bhw0f
                  - generic [ref=e227]: Qmplb
                  - generic [ref=e230]:
                    - generic [ref=e231]: 
                    - generic [ref=e232]: "0"
                  - generic [ref=e234]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e237]:
                    - generic [ref=e238]: 
                - generic [ref=e239] [cursor=pointer]:
                  - generic [ref=e241]: E2E Unit mpl9upf4o7us
                  - generic [ref=e246]: Umpl9
                  - generic [ref=e249]:
                    - generic [ref=e250]: 
                    - generic [ref=e251]: "0"
                  - generic [ref=e253]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e256]:
                    - generic [ref=e257]: 
                - generic [ref=e258] [cursor=pointer]:
                  - generic [ref=e260]: E2E Unit mplb0lgm03q1
                  - generic [ref=e265]: Umplb
                  - generic [ref=e268]:
                    - generic [ref=e269]: 
                    - generic [ref=e270]: "0"
                  - generic [ref=e272]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e275]:
                    - generic [ref=e276]: 
      - generic [ref=e280]:
        - link " Impressum" [ref=e283] [cursor=pointer]:
          - /url: /pages/sitenotice
          - generic [ref=e284]: 
          - generic [ref=e285]: Impressum
        - link " E2E Test Title mpl9v292dp1s" [ref=e288] [cursor=pointer]:
          - /url: /pages/privacy
          - generic [ref=e289]: 
          - generic [ref=e290]: E2E Test Title mpl9v292dp1s
        - generic [ref=e294] [cursor=pointer]: 
    - generic:
      - generic:
        - alertdialog
  - dialog "Team bearbeiten" [ref=e296]:
    - generic [ref=e299]:
      - generic [ref=e300]: Team bearbeiten
      - button "Close" [ref=e303] [cursor=pointer]:
        - img [ref=e304]
    - generic [ref=e307]:
      - generic [ref=e309]:
        - generic [ref=e310]:
          - generic [ref=e311]: Teamname
          - textbox [active] [ref=e312]: E2E Active mpl9uo6jot60
        - generic [ref=e313]:
          - generic [ref=e314]: Kürzel
          - textbox [ref=e315]: Ampl9
        - generic [ref=e316]:
          - generic [ref=e317]: Sollanteil an Bewerbungen
          - generic [ref=e318]:
            - spinbutton "optional" [ref=e320]
            - button "" [ref=e322] [cursor=pointer]:
              - generic [ref=e323]: 
          - generic [ref=e324]: Prozentualer oder gewichteter Sollanteil an der Gesamtzahl aller Bewerbungen
        - generic [ref=e325]:
          - generic [ref=e326]: Aktiviert
          - switch [ref=e328] [cursor=pointer]
      - generic [ref=e331]:
        - button " Löschen" [ref=e334] [cursor=pointer]:
          - generic [ref=e335]: 
          - generic [ref=e336]: Löschen
        - button " Abbrechen" [ref=e338] [cursor=pointer]:
          - generic [ref=e339]: 
          - generic [ref=e340]: Abbrechen
        - button " Speichern" [ref=e342] [cursor=pointer]:
          - generic [ref=e343]: 
          - generic [ref=e344]: Speichern
```

# Test source

```ts
  385 |   test('quota unit toggle switches between count and percentage', async ({ adminPage }) => {
  386 |     const id = unique();
  387 |     const teamName = `E2E Unit ${id}`;
  388 |     await adminPage.goto('/admin/settings/teams');
  389 | 
  390 |     // Step 1: Create team
  391 |     const createButton = adminPage.locator('[data-testid="create-button"]').first();
  392 |     await expect(createButton).toBeVisible({ timeout: 10_000 });
  393 |     await createButton.click();
  394 | 
  395 |     const dialog = adminPage.locator(DIALOG).first();
  396 |     await expect(dialog).toBeVisible({ timeout: 5_000 });
  397 | 
  398 |     const inputs = dialog.locator('input');
  399 |     await inputs.first().fill(teamName);
  400 |     await inputs.nth(1).fill(`U${id.slice(0, 4)}`);
  401 | 
  402 |     // The quota unit toggle button is next to the InputNumber
  403 |     const unitToggle = dialog.locator('p-inputgroup p-button').first();
  404 |     await expect(unitToggle).toBeVisible({ timeout: 3_000 });
  405 | 
  406 |     // Click toggle to switch unit — the suffix on the input should change
  407 |     const quotaInput = dialog.locator('p-inputnumber input').first();
  408 |     await quotaInput.fill('50');
  409 | 
  410 |     // Click the unit toggle
  411 |     await unitToggle.click();
  412 | 
  413 |     // Fill a value after toggle to verify input still works
  414 |     await quotaInput.fill('25');
  415 | 
  416 |     const saveButton2 = dialog.locator('[data-testid="save-button"]').first();
  417 |     await expect(saveButton2).toBeEnabled({ timeout: 3_000 });
  418 |     await saveButton2.click();
  419 |     const closed2 = await expect(dialog).not.toBeVisible({ timeout: 15_000 }).then(() => true).catch(() => false);
  420 |     if (!closed2) {
  421 |       await adminPage.keyboard.press('Escape');
  422 |       test.skip(true, 'Save dialog did not close — server may have rejected the mutation');
  423 |       return;
  424 |     }
  425 | 
  426 |     // Step 2: Re-open and verify quota was saved.
  427 |     // Scope the edit-button click to the team's row (search filter
  428 |     // may not have settled when `.first()` reads the DOM).
  429 |     const foundUnit = await searchAndFind(adminPage, teamName);
  430 |     test.skip(!foundUnit, 'Created team not found in search — Convex sync delay');
  431 |     const rowsWithTeam = adminPage
  432 |       .locator('[data-testid="data-table"] [class*="border-b"]')
  433 |       .filter({ hasText: teamName });
  434 |     await expect
  435 |       .poll(() => rowsWithTeam.count(), { timeout: 10_000 })
  436 |       .toBeGreaterThan(0);
  437 |     await rowsWithTeam.first().locator('[data-testid="edit-button"]').first().click();
  438 |     const editDialog = adminPage.locator(DIALOG).first();
  439 |     await expect(editDialog).toBeVisible({ timeout: 5_000 });
  440 |     // Wait for the dialog to hydrate before reading the quota.
  441 |     await expect(editDialog.locator('input').first()).toHaveValue(teamName, {
  442 |       timeout: 5_000,
  443 |     });
  444 | 
  445 |     const savedQuota = editDialog.locator('p-inputnumber input').first();
  446 |     await expect(savedQuota).toBeVisible({ timeout: 3_000 });
  447 |     // Value should have been saved (either as percentage or count)
  448 |     const savedValue = await savedQuota.inputValue();
  449 |     expect(savedValue).toBeTruthy();
  450 | 
  451 |     await editDialog.locator('[data-testid="cancel-button"]').first().click();
  452 |     await expect(editDialog).not.toBeVisible({ timeout: 5_000 });
  453 |   });
  454 | 
  455 |   test('delete button disabled when team has users', async ({ adminPage }) => {
  456 |     await adminPage.goto('/admin/settings/teams');
  457 |     await expect(adminPage.locator('masterev-infinite-data-table').first()).toBeVisible({ timeout: 10_000 });
  458 | 
  459 |     // Find a team that has users (user count tag with pi-user icon showing > 0)
  460 |     const userCountTags = adminPage.locator('masterev-infinite-data-table p-tag[icon="pi pi-user"], masterev-infinite-data-table .p-tag:has(.pi-user)');
  461 |     const tagCount = await userCountTags.count();
  462 |     test.skip(tagCount === 0, 'No teams with user count tags found');
  463 | 
  464 |     // Find a team with at least 1 user
  465 |     let teamWithUsers = false;
  466 |     for (let i = 0; i < Math.min(tagCount, 5); i++) {
  467 |       const tag = userCountTags.nth(i);
  468 |       const text = await tag.textContent();
  469 |       const count = parseInt(text?.trim() ?? '0', 10);
  470 |       if (count > 0) {
  471 |         // Click the row's edit button
  472 |         const row = tag.locator('xpath=ancestor::div[contains(@class,"row") or contains(@class,"flex")]').first();
  473 |         const editButton = row.locator('[data-testid="edit-button"]').first();
  474 |         const hasEdit = await editButton.isVisible({ timeout: 2_000 }).catch(() => false);
  475 |         if (!hasEdit) continue;
  476 | 
  477 |         await editButton.click();
  478 |         const dialog = adminPage.locator(DIALOG).first();
  479 |         await expect(dialog).toBeVisible({ timeout: 5_000 });
  480 | 
  481 |         // Verify delete button is disabled
  482 |         const deleteButton = dialog.locator('[data-testid="delete-button"]').first();
  483 |         const hasDelete = await deleteButton.isVisible({ timeout: 3_000 }).catch(() => false);
  484 |         if (hasDelete) {
> 485 |           await expect(deleteButton).toBeDisabled();
      |                                      ^ Error: expect(locator).toBeDisabled() failed
  486 |           teamWithUsers = true;
  487 |         }
  488 | 
  489 |         await dialog.locator('[data-testid="cancel-button"]').first().click();
  490 |         await expect(dialog).not.toBeVisible({ timeout: 5_000 });
  491 |         break;
  492 |       }
  493 |     }
  494 |     test.skip(!teamWithUsers, 'No team with users found to verify disabled delete button');
  495 |   });
  496 | 
  497 |   test('team users dialog opens on user count click', async ({ adminPage }) => {
  498 |     await adminPage.goto('/admin/settings/teams');
  499 |     await expect(adminPage.locator('masterev-infinite-data-table').first()).toBeVisible({ timeout: 10_000 });
  500 | 
  501 |     // Find the user count p-tag with user icon (not the team short tag)
  502 |     const userCountTag = adminPage.locator('masterev-infinite-data-table p-tag[icon="pi pi-user"], masterev-infinite-data-table .p-tag:has(.pi-user)').first();
  503 |     const tagVisible = await userCountTag.waitFor({ state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false);
  504 |     test.skip(!tagVisible, 'No user count tags found in teams table');
  505 |     await userCountTag.click();
  506 | 
  507 |     // Verify the team users dialog opens and shows a data table
  508 |     const dialog = adminPage.locator(DIALOG).first();
  509 |     const dialogOpened = await dialog.waitFor({ state: 'visible', timeout: 5_000 }).then(() => true).catch(() => false);
  510 |     test.skip(!dialogOpened, 'User count click did not open dialog — may require non-zero user count');
  511 | 
  512 |     const usersTable = dialog.locator('masterev-infinite-data-table').first();
  513 |     await expect(usersTable).toBeVisible({ timeout: 10_000 });
  514 | 
  515 |     // Close the dialog via the header close button
  516 |     const closeButton = dialog.locator('.p-dialog-header button, [data-testid="cancel-button"]').first();
  517 |     await closeButton.click();
  518 |     await expect(dialog).not.toBeVisible({ timeout: 5_000 });
  519 |   });
  520 | });
  521 | 
```