348 lines
14 KiB
Markdown
348 lines
14 KiB
Markdown
# 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: equipment.spec.ts >> Equipment Management >> can unequip an item from a slot
|
||
- Location: e2e/equipment.spec.ts:113:7
|
||
|
||
# Error details
|
||
|
||
```
|
||
Error: expect(locator).toBeVisible() failed
|
||
|
||
Locator: locator('text=Hands').locator('..').locator('button').first()
|
||
Expected: visible
|
||
Timeout: 5000ms
|
||
Error: element(s) not found
|
||
|
||
Call log:
|
||
- Expect "toBeVisible" with timeout 5000ms
|
||
- waiting for locator('text=Hands').locator('..').locator('button').first()
|
||
|
||
```
|
||
|
||
# Page snapshot
|
||
|
||
```yaml
|
||
- 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:55
|
||
- 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]: "14"
|
||
- generic [ref=e21]: / 100
|
||
- generic [ref=e22]:
|
||
- text: +2.8 mana/hr
|
||
- generic [ref=e23]: (1.4x 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" [active] [selected] [ref=e87]
|
||
- tab "🔧 Craft" [ref=e88]
|
||
- tab "💎 Loot" [ref=e89]
|
||
- tab "🏆 Achieve" [ref=e90]
|
||
- tab "📊 Stats" [ref=e91]
|
||
- tab "🐛 Debug" [ref=e92]
|
||
- tab "📖 Grimoire" [ref=e93]
|
||
- tabpanel "🛡️ Gear" [ref=e94]:
|
||
- generic [ref=e95]:
|
||
- generic [ref=e96]:
|
||
- generic [ref=e97]:
|
||
- heading "Equipped Gear" [level=3] [ref=e98]
|
||
- generic [ref=e100]: 4 / 8 slots filled
|
||
- generic [ref=e101]:
|
||
- generic [ref=e102]:
|
||
- heading "Weapon & Shield" [level=4] [ref=e103]
|
||
- generic [ref=e104]:
|
||
- 'button "Main Hand slot: Basic Staff" [ref=e106]':
|
||
- generic [ref=e107]:
|
||
- generic [ref=e108]:
|
||
- img [ref=e109]
|
||
- generic [ref=e114]: Main Hand
|
||
- button "Unequip Basic Staff" [ref=e115]:
|
||
- img [ref=e116]
|
||
- generic [ref=e119]:
|
||
- generic [ref=e120]:
|
||
- text: Basic Staff
|
||
- generic [ref=e121]: 2-Handed
|
||
- generic [ref=e122]: "Enchantments: 1/50"
|
||
- generic [ref=e124]: Mana Bolt
|
||
- button "Off Hand slot (blocked by 2-handed weapon) (empty)" [ref=e125]:
|
||
- generic [ref=e127]:
|
||
- img [ref=e128]
|
||
- generic [ref=e130]: Off Hand
|
||
- generic [ref=e131]:
|
||
- img
|
||
- text: Occupied — 2H Weapon
|
||
- generic [ref=e132]:
|
||
- img [ref=e133]
|
||
- text: Blocked by 2-handed weapon
|
||
- generic [ref=e135]:
|
||
- heading "Armor" [level=4] [ref=e136]
|
||
- generic [ref=e137]:
|
||
- button "Head slot (empty)" [ref=e139]:
|
||
- generic [ref=e141]:
|
||
- img [ref=e142]
|
||
- generic [ref=e147]: Head
|
||
- generic [ref=e148]: Head
|
||
- 'button "Body slot: Civilian Shirt" [ref=e150]':
|
||
- generic [ref=e151]:
|
||
- generic [ref=e152]:
|
||
- img [ref=e153]
|
||
- generic [ref=e155]: Body
|
||
- button "Unequip Civilian Shirt" [ref=e156]:
|
||
- img [ref=e157]
|
||
- generic [ref=e160]:
|
||
- generic [ref=e161]: Civilian Shirt
|
||
- generic [ref=e162]: "Enchantments: 0/30"
|
||
- 'button "Hands slot: Civilian Gloves" [ref=e164]':
|
||
- generic [ref=e165]:
|
||
- generic [ref=e166]:
|
||
- img [ref=e167]
|
||
- generic [ref=e172]: Hands
|
||
- button "Unequip Civilian Gloves" [ref=e173]:
|
||
- img [ref=e174]
|
||
- generic [ref=e177]:
|
||
- generic [ref=e178]: Civilian Gloves
|
||
- generic [ref=e179]: "Enchantments: 0/20"
|
||
- 'button "Feet slot: Civilian Shoes" [ref=e181]':
|
||
- generic [ref=e182]:
|
||
- generic [ref=e183]:
|
||
- img [ref=e184]
|
||
- generic [ref=e187]: Feet
|
||
- button "Unequip Civilian Shoes" [ref=e188]:
|
||
- img [ref=e189]
|
||
- generic [ref=e192]:
|
||
- generic [ref=e193]: Civilian Shoes
|
||
- generic [ref=e194]: "Enchantments: 0/15"
|
||
- generic [ref=e195]:
|
||
- heading "Accessories" [level=4] [ref=e196]
|
||
- generic [ref=e197]:
|
||
- button "Accessory 1 slot (empty)" [ref=e199]:
|
||
- generic [ref=e201]:
|
||
- img [ref=e202]
|
||
- generic [ref=e205]: Accessory 1
|
||
- generic [ref=e206]: Accessory 1
|
||
- button "Accessory 2 slot (empty)" [ref=e208]:
|
||
- generic [ref=e210]:
|
||
- img [ref=e211]
|
||
- generic [ref=e214]: Accessory 2
|
||
- generic [ref=e215]: Accessory 2
|
||
- generic [ref=e216]:
|
||
- heading "Equipment Inventory (0 items)" [level=3] [ref=e218]
|
||
- status [ref=e219]: No unequipped items. Craft new gear in the Crafting tab.
|
||
- generic [ref=e220]:
|
||
- heading "Equipment Stats Summary" [level=3] [ref=e222]
|
||
- generic [ref=e223]:
|
||
- generic [ref=e224]:
|
||
- generic [ref=e225]: "4"
|
||
- generic [ref=e226]: Total Items
|
||
- generic [ref=e227]:
|
||
- generic [ref=e228]: "4"
|
||
- generic [ref=e229]: Equipped
|
||
- generic [ref=e230]:
|
||
- generic [ref=e231]: "0"
|
||
- generic [ref=e232]: In Inventory
|
||
- generic [ref=e233]:
|
||
- generic [ref=e234]: "1"
|
||
- generic [ref=e235]: Total Enchantments
|
||
- generic [ref=e236]:
|
||
- heading "✨ Enchantment Power" [level=3] [ref=e238]
|
||
- generic [ref=e239]:
|
||
- generic [ref=e240]:
|
||
- generic [ref=e241]: "Enchantment Power:"
|
||
- generic [ref=e242]: 1.00×
|
||
- paragraph [ref=e243]: Increases the power of all enchantments by 0%. Multiplier applied to all enchantment effects.
|
||
- generic [ref=e244]:
|
||
- generic [ref=e245]: "Active Effects from Equipment:"
|
||
- generic [ref=e247]: No active effects
|
||
- region "Notifications (F8)":
|
||
- list
|
||
- region "Notifications (F8)":
|
||
- list
|
||
- button "Open Next.js Dev Tools" [ref=e253] [cursor=pointer]:
|
||
- img [ref=e254]
|
||
- alert [ref=e257]
|
||
```
|
||
|
||
# Test source
|
||
|
||
```ts
|
||
28 |
|
||
29 | // Verify equipment UI elements
|
||
30 | const equippedGearHeading = page.locator('text="Equipped Gear"');
|
||
31 | await expect(equippedGearHeading).toBeVisible({ timeout: 5000 });
|
||
32 | });
|
||
33 |
|
||
34 | test('shows equipment slots with labels', async ({ page }) => {
|
||
35 | await page.goto('/');
|
||
36 | await page.evaluate(() => {
|
||
37 | Object.keys(localStorage)
|
||
38 | .filter((k) => k.startsWith('mana-loop-'))
|
||
39 | .forEach((k) => localStorage.removeItem(k));
|
||
40 | });
|
||
41 | await page.reload();
|
||
42 | await page.waitForLoadState('networkidle');
|
||
43 |
|
||
44 | await page.getByRole('tab', { name: /🛡️ Gear/ }).click();
|
||
45 |
|
||
46 | // Check for expected slot labels - use role=heading or more specific selectors
|
||
47 | // Main Hand slot
|
||
48 | const mainHandSection = page.locator('text=Main Hand');
|
||
49 | await expect(mainHandSection.first()).toBeVisible();
|
||
50 |
|
||
51 | // Off Hand
|
||
52 | const offHandSection = page.locator('text=Off Hand');
|
||
53 | await expect(offHandSection.first()).toBeVisible();
|
||
54 |
|
||
55 | // Head
|
||
56 | const headSection = page.locator('text=Head');
|
||
57 | await expect(headSection.first()).toBeVisible();
|
||
58 |
|
||
59 | // Body
|
||
60 | const bodySection = page.locator('text=Body');
|
||
61 | await expect(bodySection.first()).toBeVisible();
|
||
62 |
|
||
63 | // Hands
|
||
64 | const handsSection = page.locator('text=Hands');
|
||
65 | await expect(handsSection.first()).toBeVisible();
|
||
66 |
|
||
67 | // Feet
|
||
68 | const feetSection = page.locator('text=Feet');
|
||
69 | await expect(feetSection.first()).toBeVisible();
|
||
70 |
|
||
71 | // Accessory 1 and 2
|
||
72 | const acc1Section = page.locator('text=Accessory 1');
|
||
73 | await expect(acc1Section.first()).toBeVisible();
|
||
74 | const acc2Section = page.locator('text=Accessory 2');
|
||
75 | await expect(acc2Section.first()).toBeVisible();
|
||
76 | });
|
||
77 |
|
||
78 | test('shows starting equipment already equipped', async ({ page }) => {
|
||
79 | await page.goto('/');
|
||
80 | await page.evaluate(() => {
|
||
81 | Object.keys(localStorage)
|
||
82 | .filter((k) => k.startsWith('mana-loop-'))
|
||
83 | .forEach((k) => localStorage.removeItem(k));
|
||
84 | });
|
||
85 | await page.reload();
|
||
86 | await page.waitForLoadState('networkidle');
|
||
87 |
|
||
88 | await page.getByRole('tab', { name: /🛡️ Gear/ }).click();
|
||
89 |
|
||
90 | // The player starts with a Basic Staff in main hand (as an equipped item)
|
||
91 | const mainHandSlot = page.locator('text=Main Hand >> .. >> text=Basic Staff');
|
||
92 | await expect(mainHandSlot).toBeVisible({ timeout: 5000 });
|
||
93 | });
|
||
94 |
|
||
95 | test('2-handed weapon blocks offhand slot', async ({ page }) => {
|
||
96 | await page.goto('/');
|
||
97 | await page.evaluate(() => {
|
||
98 | Object.keys(localStorage)
|
||
99 | .filter((k) => k.startsWith('mana-loop-'))
|
||
100 | .forEach((k) => localStorage.removeItem(k));
|
||
101 | });
|
||
102 | await page.reload();
|
||
103 | await page.waitForLoadState('networkidle');
|
||
104 |
|
||
105 | await page.getByRole('tab', { name: /🛡️ Gear/ }).click();
|
||
106 |
|
||
107 | // The starting basic staff is 2-handed
|
||
108 | // The offhand slot should show as blocked with "Occupied — 2H Weapon"
|
||
109 | const offHandBlocked = page.locator('text=Occupied').first();
|
||
110 | await expect(offHandBlocked).toBeVisible({ timeout: 5000 });
|
||
111 | });
|
||
112 |
|
||
113 | test('can unequip an item from a slot', async ({ page }) => {
|
||
114 | await page.goto('/');
|
||
115 | await page.evaluate(() => {
|
||
116 | Object.keys(localStorage)
|
||
117 | .filter((k) => k.startsWith('mana-loop-'))
|
||
118 | .forEach((k) => localStorage.removeItem(k));
|
||
119 | });
|
||
120 | await page.reload();
|
||
121 | await page.waitForLoadState('networkidle');
|
||
122 |
|
||
123 | await page.getByRole('tab', { name: /🛡️ Gear/ }).click();
|
||
124 |
|
||
125 | // Find an equiped slot with an unequip button (the X button)
|
||
126 | // The hands slot has civilian gloves equipped
|
||
127 | const handsSlot = page.locator('text=Hands >> .. >> button').first();
|
||
> 128 | await expect(handsSlot).toBeVisible({ timeout: 5000 });
|
||
| ^ Error: expect(locator).toBeVisible() failed
|
||
129 | // Note: exact behavior of unequip depends on implementation state
|
||
130 | });
|
||
131 | });
|
||
``` |