# 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 "Tags" [ref=e51] [cursor=pointer]
            - tab "Vorlagen" [ref=e53] [cursor=pointer]
          - generic [ref=e56]:
            - generic [ref=e57]:
              - generic [ref=e58]:
                - heading "Teams" [level=2] [ref=e59]
                - paragraph [ref=e60]: Verwalten Sie die Teams und deren Mitglieder
              - generic [ref=e61]:
                - generic [ref=e64]:
                  - generic [ref=e65]: 
                  - textbox "Suchen" [ref=e66]
                - button " Erstellen" [ref=e68] [cursor=pointer]:
                  - generic [ref=e69]: 
                  - generic [ref=e70]: Erstellen
            - generic [ref=e71]:
              - generic [ref=e73]:
                - generic [ref=e75] [cursor=pointer]:
                  - text: Teamname
                  - generic [ref=e76]: 
                - generic [ref=e78] [cursor=pointer]:
                  - text: Kürzel
                  - generic [ref=e79]: 
                - generic [ref=e81]: Details
                - generic [ref=e83] [cursor=pointer]:
                  - text: Aktiviert
                  - generic [ref=e84]: 
              - generic [ref=e88]:
                - generic [ref=e89] [cursor=pointer]:
                  - generic [ref=e91]: E2E Active mpl9drgnq1gj
                  - generic [ref=e96]: Ampl9
                  - generic [ref=e99]:
                    - generic [ref=e100]: 
                    - generic [ref=e101]: "0"
                  - generic [ref=e103]:
                    - generic:
                      - switch [disabled]
                  - button "" [ref=e106]:
                    - generic [ref=e107]: 
                - generic [ref=e108] [cursor=pointer]:
                  - generic [ref=e110]: E2E Active mplakhj5007g
                  - generic [ref=e115]: Ampla
                  - generic [ref=e118]:
                    - generic [ref=e119]: 
                    - generic [ref=e120]: "0"
                  - generic [ref=e122]:
                    - generic:
                      - switch [disabled]
                  - button "" [ref=e125]:
                    - generic [ref=e126]: 
                - generic [ref=e127] [cursor=pointer]:
                  - generic [ref=e129]: E2E Create mpl9dlha7tr2
                  - generic [ref=e134]: Cmpl9
                  - generic [ref=e137]:
                    - generic [ref=e138]: 
                    - generic [ref=e139]: "5"
                  - generic [ref=e141]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e144]:
                    - generic [ref=e145]: 
                - generic [ref=e146] [cursor=pointer]:
                  - generic [ref=e148]: E2E Create mplakcgmyzqv
                  - generic [ref=e153]: Cmpla
                  - generic [ref=e156]:
                    - generic [ref=e157]: 
                    - generic [ref=e158]: "0"
                  - generic [ref=e160]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e163]:
                    - generic [ref=e164]: 
                - generic [ref=e165] [cursor=pointer]:
                  - generic [ref=e167]: E2E Edited mpl9dnw57obs
                  - generic [ref=e172]: Dmpl9
                  - generic [ref=e175]:
                    - generic [ref=e176]: 
                    - generic [ref=e177]: "0"
                  - generic [ref=e179]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e182]:
                    - generic [ref=e183]: 
                - generic [ref=e184] [cursor=pointer]:
                  - generic [ref=e186]: E2E Edited mplakdv177wf
                  - generic [ref=e191]: Dmpla
                  - generic [ref=e194]:
                    - generic [ref=e195]: 
                    - generic [ref=e196]: "0"
                  - generic [ref=e198]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e201]:
                    - generic [ref=e202]: 
                - generic [ref=e203] [cursor=pointer]:
                  - generic [ref=e205]: E2E Quota mpl9dpvq0070
                  - generic [ref=e210]: Qmpl9
                  - generic [ref=e213]:
                    - generic [ref=e214]: 
                    - generic [ref=e215]: "0"
                  - generic [ref=e217]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e220]:
                    - generic [ref=e221]: 
                - generic [ref=e222] [cursor=pointer]:
                  - generic [ref=e224]: E2E Quota mplakfh416zm
                  - generic [ref=e229]: Qmpla
                  - generic [ref=e232]:
                    - generic [ref=e233]: 
                    - generic [ref=e234]: "0"
                  - generic [ref=e236]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e239]:
                    - generic [ref=e240]: 
                - generic [ref=e241] [cursor=pointer]:
                  - generic [ref=e243]: E2E Unit mpl9dt1ks3nd
                  - generic [ref=e248]: Umpl9
                  - generic [ref=e251]:
                    - generic [ref=e252]: 
                    - generic [ref=e253]: "0"
                  - generic [ref=e255]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e258]:
                    - generic [ref=e259]: 
                - generic [ref=e260] [cursor=pointer]:
                  - generic [ref=e262]: E2E Unit mplakite3rys
                  - generic [ref=e267]: Umpla
                  - generic [ref=e270]:
                    - generic [ref=e271]: 
                    - generic [ref=e272]: "0"
                  - generic [ref=e274]:
                    - generic:
                      - switch [checked] [disabled]
                  - button "" [ref=e277]:
                    - generic [ref=e278]: 
      - generic [ref=e282]:
        - link " Impressum" [ref=e285] [cursor=pointer]:
          - /url: /pages/sitenotice
          - generic [ref=e286]: 
          - generic [ref=e287]: Impressum
        - link " E2E Test Title mpl9e5zstm3l" [ref=e290] [cursor=pointer]:
          - /url: /pages/privacy
          - generic [ref=e291]: 
          - generic [ref=e292]: E2E Test Title mpl9e5zstm3l
        - generic [ref=e296] [cursor=pointer]: 
    - generic:
      - generic:
        - alertdialog
  - dialog "Team bearbeiten" [ref=e298]:
    - generic [ref=e301]:
      - generic [ref=e302]: Team bearbeiten
      - button "Close" [ref=e305] [cursor=pointer]:
        - img [ref=e306]
    - generic [ref=e309]:
      - generic [ref=e311]:
        - generic [ref=e312]:
          - generic [ref=e313]: Teamname
          - textbox [active] [ref=e314]: E2E Active mpl9drgnq1gj
        - generic [ref=e315]:
          - generic [ref=e316]: Kürzel
          - textbox [ref=e317]: Ampl9
        - generic [ref=e318]:
          - generic [ref=e319]: Sollanteil an Bewerbungen
          - generic [ref=e320]:
            - spinbutton "optional" [ref=e322]
            - button "" [ref=e324] [cursor=pointer]:
              - generic [ref=e325]: 
          - generic [ref=e326]: Prozentualer oder gewichteter Sollanteil an der Gesamtzahl aller Bewerbungen
        - generic [ref=e327]:
          - generic [ref=e328]: Aktiviert
          - switch [ref=e330] [cursor=pointer]
      - generic [ref=e333]:
        - button " Löschen" [ref=e336] [cursor=pointer]:
          - generic [ref=e337]: 
          - generic [ref=e338]: Löschen
        - button " Abbrechen" [ref=e340] [cursor=pointer]:
          - generic [ref=e341]: 
          - generic [ref=e342]: Abbrechen
        - button " Speichern" [ref=e344] [cursor=pointer]:
          - generic [ref=e345]: 
          - generic [ref=e346]: 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 | 
```