diablo2-web/tests/glacial-spike-quickbar.test.ts

160 lines
6.2 KiB
TypeScript

import { describe, it, expect, beforeEach } from 'vitest'
import { SkillHotkeysHud, DEFAULT_SORCERESS_SKILLS, LEFT_SKILL_BOUNDS, RIGHT_SKILL_BOUNDS } from '../src/ui/hotkeys.ts'
import { HudManager } from '../src/ui/hud-manager.ts'
import { CLASS_DEFAULT_SKILLS, createStarterProfileForClass } from '../src/game/class-starter-profiles.ts'
import { SKILLS_BY_ID } from '../src/data/skills-catalog.ts'
describe('Issue Fix: Glacial Spike (#55) and All Active Skills on Quickbar Speedbars', () => {
let hud: SkillHotkeysHud
beforeEach(() => {
hud = new SkillHotkeysHud()
})
describe('1. Sorceress Right-Click & Left-Click Quickbar includes Glacial Spike', () => {
it('has Glacial Spike (55) in DEFAULT_SORCERESS_SKILLS with level 10 and authentic mana', () => {
const entry = DEFAULT_SORCERESS_SKILLS.find(s => s.skillId === 55)
expect(entry).toBeDefined()
expect(entry!.name).toBe('Glacial Spike')
expect(entry!.nameZh).toBe('冰尖柱')
expect(entry!.level).toBe(10)
expect(entry!.manaCost).toBeCloseTo(14.5, 1)
expect(entry!.leftUsable).toBe(true)
expect(entry!.rightUsable).toBe(true)
})
it('shows Glacial Spike in right-click speedbar popup cells', () => {
const rightCells = hud.getSpeedbarSkills('right')
const spikeCell = rightCells.find(c => c.skill.skillId === 55)
expect(spikeCell).toBeDefined()
expect(spikeCell!.skill.name).toBe('Glacial Spike')
expect(spikeCell!.skill.nameZh).toBe('冰尖柱')
})
it('shows Glacial Spike in left-click speedbar popup cells', () => {
const leftCells = hud.getSpeedbarSkills('left')
const spikeCell = leftCells.find(c => c.skill.skillId === 55)
expect(spikeCell).toBeDefined()
expect(spikeCell!.skill.name).toBe('Glacial Spike')
})
it('assigns Glacial Spike to right-click slot when clicked in right speedbar', () => {
hud.openSpeedbar('right')
expect(hud.selectionOpen).toBe('right')
const rightCells = hud.getSpeedbarSkills('right')
const spikeCell = rightCells.find(c => c.skill.skillId === 55)!
expect(spikeCell).toBeDefined()
const handled = hud.handleClick(spikeCell.x + 10, spikeCell.y + 10)
expect(handled).toBe(true)
expect(hud.rightSkillId).toBe(55)
expect(hud.selectionOpen).toBeNull()
})
it('assigns Glacial Spike to left-click slot when clicked in left speedbar', () => {
hud.openSpeedbar('left')
expect(hud.selectionOpen).toBe('left')
const leftCells = hud.getSpeedbarSkills('left')
const spikeCell = leftCells.find(c => c.skill.skillId === 55)!
expect(spikeCell).toBeDefined()
const handled = hud.handleClick(spikeCell.x + 10, spikeCell.y + 10)
expect(handled).toBe(true)
expect(hud.leftSkillId).toBe(55)
expect(hud.selectionOpen).toBeNull()
})
})
describe('2. All 7 Classes Starter Profiles include all Active Skills', () => {
it('provides all 26 active skills on Sorceress right-click speedbar', () => {
const sorProfile = createStarterProfileForClass('sor')
const rightSkills = sorProfile.availableSkills.filter(s => s.rightUsable)
// 3 universal (Attack 0, Throw 2, Unsummon 3) + 26 Sorceress active = 29
expect(rightSkills.length).toBe(29)
// Glacial Spike is explicitly present
expect(rightSkills.some(s => s.skillId === 55)).toBe(true)
})
it('provides all active skills for all 7 classes without passives', () => {
const classes = ['ama', 'sor', 'nec', 'pal', 'bar', 'dru', 'ass'] as const
const expectedActiveCounts: Record<string, number> = {
ama: 27, // 3 universal + 24 active
sor: 29, // 3 universal + 26 active
nec: 30, // 3 universal + 27 active
pal: 33, // 3 universal + 30 active
bar: 23, // 3 universal + 20 active
dru: 32, // 3 universal + 29 active
ass: 31, // 3 universal + 28 active
}
for (const cls of classes) {
const skills = CLASS_DEFAULT_SKILLS[cls]
expect(skills.length).toBe(expectedActiveCounts[cls])
// None should be passive
for (const s of skills) {
expect(s.isPassive).toBeFalsy()
}
}
})
})
describe('3. HudManager Skill Tree Allocation dynamically updates Available Skills', () => {
const mockCanvas = {
width: 800,
height: 600,
style: { cursor: '' },
addEventListener: () => {},
removeEventListener: () => {},
getContext: () => null,
} as unknown as HTMLCanvasElement
function createMockHud() {
const hud = new HudManager(mockCanvas, {
onToggleAutomap: () => {},
onWaypointTeleport: () => {},
})
hud.switchClass('sor')
return hud
}
it('initializes HudManager with Glacial Spike available in Sorceress profile', () => {
const hudManager = createMockHud()
expect(hudManager.hotkeys.availableSkills.some(s => s.skillId === 55)).toBe(true)
})
it('allocates new skill in skill tree and adds it to hotkeys.availableSkills', () => {
const hudManager = createMockHud()
// Open Skill tree panel
hudManager.rightPanel = 'skill'
hudManager.skillTree.visible = true
hudManager.skillTree.unspentSkillPoints = 5
// Select lightning tab (tab 1)
hudManager.skillTree.activeTab = 1
// Find Nova (48) which requires level 12 and has reqskills: Static Field (42) which is already allocated in starter
const nova = hudManager.hotkeys.availableSkills.find(s => s.skillId === 48)
expect(nova).toBeDefined()
// Allocate point into Nova by clicking on it
const node = hudManager.skillTree.getSkillTree().find(n => n.skillId === 48)!
expect(node).toBeDefined()
const prevPoints = hudManager.skillTree.hardPoints.get(48) ?? 0
const allocated = hudManager.skillTree.allocateSkill(48)
expect(allocated).toBe(true)
// Test handleSkillAllocated
const privateMethod = (hudManager as any).handleSkillAllocated.bind(hudManager)
privateMethod(48)
const updatedNova = hudManager.hotkeys.availableSkills.find(s => s.skillId === 48)
expect(updatedNova).toBeDefined()
expect(updatedNova!.level).toBe(prevPoints + 1)
})
})
})