Files
Mana-Loop/playwright-report/data/e3d1abb209771785e7247c38fd372d8fd61b7ea4.md
T
2026-05-13 12:16:11 +02:00

13 KiB

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: enchanting.spec.ts >> Enchanting Flow >> can select equipment type and effect in Design stage
  • Location: e2e/enchanting.spec.ts:67:7

Error details

Error: locator.click: Error: strict mode violation: getByRole('button') resolved to 6 elements:
    1) <button data-slot="button" class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive text-primary-foreground shad…>…</button> aka getByRole('button', { name: 'Gather +1 Mana' })
    2) <button class="flex items-center justify-between w-full text-xs text-gray-400 hover:text-gray-300 mb-2">…</button> aka getByRole('button', { name: 'Elemental Mana (1)' })
    3) <button data-slot="button" class="inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive text-primary-foreground shadow-xs hover…>…</button> aka getByRole('button', { name: 'Climb the Spire' })
    4) <button data-slot="action-button" class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[var(--radius)] text-sm font-medium transition-all duration-100 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-[var(--border-focus)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-base)] bg-[var(--interactive-primary)] text-white …>…</button> aka getByRole('button', { name: 'Fabricate' })
    5) <button data-slot="action-button" class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[var(--radius)] text-sm font-medium transition-all duration-100 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-[var(--border-focus)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-base)] bg-[var(--interactive-secondary)] text-[var…>…</button> aka getByRole('button', { name: 'Enchant' })
    6) <button id="next-logo" aria-haspopup="menu" data-next-mark="true" aria-expanded="false" aria-label="Open Next.js Dev Tools" data-nextjs-dev-tools-button="true" aria-controls="nextjs-dev-tools-menu">…</button> aka getByRole('button', { name: 'Open Next.js Dev Tools' })

Call log:
  - waiting for getByRole('button')

Page snapshot

- generic [ref=e1]:
  - generic [ref=e2]:
    - banner [ref=e3]:
      - generic [ref=e4]:
        - heading "MANA LOOP" [level=1] [ref=e5]
        - generic [ref=e7]:
          - generic [ref=e8]:
            - generic [ref=e9]: Day 1
            - generic [ref=e10]: 01:02
          - generic [ref=e11]:
            - generic [ref=e12]: "0"
            - generic [ref=e13]: Insight
    - main [ref=e14]:
      - generic [ref=e15]:
        - generic [ref=e17]:
          - generic [ref=e18]:
            - generic [ref=e19]:
              - generic [ref=e20]: "12"
              - generic [ref=e21]: / 100
            - generic [ref=e22]:
              - text: +2.3 mana/hr
              - generic [ref=e23]: (1.1x med)
          - progressbar [ref=e24]
          - button "Gather +1 Mana" [ref=e26]:
            - img
            - text: Gather +1 Mana
          - generic [ref=e27]:
            - button "Elemental Mana (1)" [ref=e28]:
              - generic [ref=e29]: Elemental Mana (1)
              - img [ref=e30]
            - generic [ref=e33]:
              - generic [ref=e34]:
                - generic [ref=e35]: 🔗
                - generic [ref=e36]: Transference
              - generic [ref=e39]: 0/10
        - button "Climb the Spire" [ref=e40]:
          - img
          - text: Climb the Spire
        - generic [ref=e42]:
          - generic [ref=e43]:
            - img [ref=e44]
            - generic [ref=e46]: Current Activity
          - generic [ref=e47]: Meditating
        - generic [ref=e48]:
          - generic [ref=e49]: "1"
          - generic [ref=e50]: "2"
          - generic [ref=e51]: "3"
          - generic [ref=e52]: "4"
          - generic [ref=e53]: "5"
          - generic [ref=e54]: "6"
          - generic [ref=e55]: "7"
          - generic [ref=e56]: "8"
          - generic [ref=e57]: "9"
          - generic [ref=e58]: "10"
          - generic [ref=e59]: "11"
          - generic [ref=e60]: "12"
          - generic [ref=e61]: "13"
          - generic [ref=e62]: "14"
          - generic [ref=e63]: "15"
          - generic [ref=e64]: "16"
          - generic [ref=e65]: "17"
          - generic [ref=e66]: "18"
          - generic [ref=e67]: "19"
          - generic [ref=e68]: "20"
          - generic [ref=e69]: "21"
          - generic [ref=e70]: "22"
          - generic [ref=e71]: "23"
          - generic [ref=e72]: "24"
          - generic [ref=e73]: "25"
          - generic [ref=e74]: "26"
          - generic [ref=e75]: "27"
          - generic [ref=e76]: "28"
          - generic [ref=e77]: "29"
          - generic [ref=e78]: "30"
      - generic [ref=e80]:
        - tablist [ref=e81]:
          - tab "⚔️ Spire" [ref=e82]
          - tab "✨ Attune" [ref=e83]
          - tab "🗿 Golems" [ref=e84]
          - tab "📚 Skills" [ref=e85]
          - tab "🔮 Spells" [ref=e86]
          - tab "🛡️ Gear" [ref=e87]
          - tab "🔧 Craft" [active] [selected] [ref=e88]
          - tab "💎 Loot" [ref=e89]
          - tab "🏆 Achieve" [ref=e90]
          - tab "📊 Stats" [ref=e91]
          - tab "🐛 Debug" [ref=e92]
          - tab "📖 Grimoire" [ref=e93]
        - tabpanel "🔧 Craft" [ref=e94]:
          - generic [ref=e95]:
            - generic [ref=e97]:
              - button "Fabricate" [ref=e98]:
                - img
                - text: Fabricate
              - button "Enchant" [ref=e99]:
                - img
                - text: Enchant
            - generic [ref=e100]:
              - generic [ref=e101]:
                - generic [ref=e103]:
                  - img [ref=e104]
                  - text: Available Blueprints
                - generic [ref=e113]:
                  - img [ref=e114]
                  - paragraph [ref=e118]: No blueprints discovered yet.
                  - paragraph [ref=e119]: Defeat guardians to find blueprints!
              - generic [ref=e120]:
                - generic [ref=e122]:
                  - img [ref=e123]
                  - text: Materials (0)
                - generic [ref=e131]:
                  - img [ref=e132]
                  - paragraph [ref=e134]: No materials collected yet.
                  - paragraph [ref=e135]: Defeat floors to gather materials!
  - region "Notifications (F8)":
    - list
  - region "Notifications (F8)":
    - list
  - button "Open Next.js Dev Tools" [ref=e141] [cursor=pointer]:
    - img [ref=e142]
  - alert [ref=e145]

Test source

  1   | import { test, expect } from '@playwright/test';
  2   | 
  3   | /**
  4   |  * E2E tests for the 3-step enchantment flow:
  5   |  * Design → Prepare → Apply
  6   |  *
  7   |  * These tests validate the core crafting loop works end-to-end.
  8   |  */
  9   | 
  10  | test.describe('Enchanting Flow', () => {
  11  |   /**
  12  |    * Before each test, ensure we start with a clean state.
  13  |    * The game persists state in localStorage, so we clear it.
  14  |    */
  15  |   test.beforeEach(async ({ page }) => {
  16  |     await page.goto('/');
  17  |     // Clear game state to ensure a fresh start
  18  |     await page.evaluate(() => {
  19  |       Object.keys(localStorage)
  20  |         .filter((k) => k.startsWith('mana-loop-'))
  21  |         .forEach((k) => localStorage.removeItem(k));
  22  |     });
  23  |     await page.reload();
  24  |     // Wait for the game to initialize
  25  |     await page.waitForLoadState('networkidle');
  26  |   });
  27  | 
  28  |   test('can navigate to Crafting tab', async ({ page }) => {
  29  |     // The tab bar contains a "Craft" tab
  30  |     const craftTab = page.getByRole('tab', { name: /🔧 Craft/ });
  31  |     await expect(craftTab).toBeVisible();
  32  |     await craftTab.click();
  33  | 
  34  |     // Verify we're on the crafting tab by checking for sub-tabs
  35  |     const fabricateBtn = page.getByRole('button', { hasText: 'Fabricate' });
  36  |     const enchantBtn = page.getByRole('button', { hasText: 'Enchant' });
  37  |     await expect(fabricateBtn).toBeVisible();
  38  |     await expect(enchantBtn).toBeVisible();
  39  |   });
  40  | 
  41  |   test('can switch to Enchant sub-tab and see design UI', async ({ page }) => {
  42  |     await page.goto('/');
  43  |     await page.evaluate(() => {
  44  |       Object.keys(localStorage)
  45  |         .filter((k) => k.startsWith('mana-loop-'))
  46  |         .forEach((k) => localStorage.removeItem(k));
  47  |     });
  48  |     await page.reload();
  49  |     await page.waitForLoadState('networkidle');
  50  | 
  51  |     // Navigate to Crafting tab
  52  |     await page.getByRole('tab', { name: /🔧 Craft/ }).click();
  53  | 
  54  |     // Click Enchant sub-tab
  55  |     const enchantBtn = page.getByRole('button', { hasText: 'Enchant' });
  56  |     await enchantBtn.click();
  57  | 
  58  |     // Should see the design stage UI
  59  |     const designBtn = page.getByRole('button', { hasText: 'Design' });
  60  |     const prepareBtn = page.getByRole('button', { hasText: 'Prepare' });
  61  |     const applyBtn = page.getByRole('button', { hasText: 'Apply' });
  62  |     await expect(designBtn).toBeVisible();
  63  |     await expect(prepareBtn).toBeVisible();
  64  |     await expect(applyBtn).toBeVisible();
  65  |   });
  66  | 
  67  |   test('can select equipment type and effect in Design stage', async ({ page }) => {
  68  |     await page.goto('/');
  69  |     await page.evaluate(() => {
  70  |       Object.keys(localStorage)
  71  |         .filter((k) => k.startsWith('mana-loop-'))
  72  |         .forEach((k) => localStorage.removeItem(k));
  73  |     });
  74  |     await page.reload();
  75  |     await page.waitForLoadState('networkidle');
  76  | 
  77  |     // Navigate to Crafting > Enchant > Design
  78  |     await page.getByRole('tab', { name: /🔧 Craft/ }).click();
> 79  |     await page.getByRole('button', { hasText: 'Enchant' }).click();
      |                                                            ^ Error: locator.click: Error: strict mode violation: getByRole('button') resolved to 6 elements:
  80  | 
  81  |     // The design section should show effect selectors once an equipment type is chosen
  82  |     // Look for any element matching equipment type buttons and effect-related content
  83  |     const equipmentButtons = page.locator('button:has-text("Basic Staff"), button:has-text("Apprentice Wand"), button:has-text("Oak Staff"), button:has-text("Crystal Wand")');
  84  |     const count = await equipmentButtons.count();
  85  |     expect(count).toBeGreaterThan(0);
  86  |   });
  87  | 
  88  |   test('can navigate through all 3 enchant stages', async ({ page }) => {
  89  |     await page.goto('/');
  90  |     await page.evaluate(() => {
  91  |       Object.keys(localStorage)
  92  |         .filter((k) => k.startsWith('mana-loop-'))
  93  |         .forEach((k) => localStorage.removeItem(k));
  94  |     });
  95  |     await page.reload();
  96  |     await page.waitForLoadState('networkidle');
  97  | 
  98  |     // Navigate to Crafting > Enchant
  99  |     await page.getByRole('tab', { name: /🔧 Craft/ }).click();
  100 |     await page.getByRole('button', { hasText: 'Enchant' }).click();
  101 | 
  102 |     // Verify Design stage is active
  103 |     const designBtn = page.getByRole('button', { hasText: 'Design' });
  104 |     await expect(designBtn).toBeVisible();
  105 | 
  106 |     // Switch to Prepare stage
  107 |     const prepareBtn = page.getByRole('button', { hasText: 'Prepare' });
  108 |     await prepareBtn.click();
  109 | 
  110 |     // Should see preparation UI
  111 |     const prepareHeading = page.locator('text=Select Equipment to Prepare');
  112 |     await expect(prepareHeading).toBeVisible({ timeout: 5000 });
  113 | 
  114 |     // Switch to Apply stage
  115 |     const applyBtn = page.getByRole('button', { hasText: 'Apply' });
  116 |     await applyBtn.click();
  117 | 
  118 |     // Should see application UI
  119 |     const applyHeading = page.locator('text=Select Equipment & Design');
  120 |     await expect(applyHeading).toBeVisible({ timeout: 5000 });
  121 |   });
  122 | });