diablo2-web/tests/hotkeys.test.ts

148 lines
4.7 KiB
TypeScript

/**
* Tests for SkillHotkeysHud, speedbars, keybindings, and Attack slot binding (Issue #151).
*/
import { describe, expect, it, beforeEach } from 'vitest'
import {
SkillHotkeysHud,
LEFT_SKILL_BOUNDS,
RIGHT_SKILL_BOUNDS,
DEFAULT_SORCERESS_SKILLS,
resolveSkillIcon,
getAvailableSkillsForSide,
} from '../src/ui/hotkeys.ts'
describe('SkillHotkeysHud & Dual Slot Mechanics', () => {
let hud: SkillHotkeysHud
beforeEach(() => {
hud = new SkillHotkeysHud()
})
it('initializes with expected default skills and state', () => {
expect(hud.leftSkillId).toBe(47) // Fire Ball
expect(hud.rightSkillId).toBe(64) // Frozen Orb
expect(hud.selectionOpen).toBeNull()
expect(hud.availableSkills.length).toBeGreaterThanOrEqual(10)
// Skill 0 is available
const attack = hud.availableSkills.find((s) => s.skillId === 0)
expect(attack).toBeDefined()
expect(attack!.leftUsable).toBe(true)
expect(attack!.rightUsable).toBe(true)
})
it('opens and closes left selection speedbar on click', () => {
// Click center of left skill icon
const leftX = LEFT_SKILL_BOUNDS.x + 24
const leftY = LEFT_SKILL_BOUNDS.y + 24
const handled = hud.handleClick(leftX, leftY)
expect(handled).toBe(true)
expect(hud.selectionOpen).toBe('left')
// Click again to close
hud.handleClick(leftX, leftY)
expect(hud.selectionOpen).toBeNull()
})
it('opens and closes right selection speedbar on click', () => {
// Click center of right skill icon
const rightX = RIGHT_SKILL_BOUNDS.x + 24
const rightY = RIGHT_SKILL_BOUNDS.y + 24
const handled = hud.handleClick(rightX, rightY)
expect(handled).toBe(true)
expect(hud.selectionOpen).toBe('right')
// Click outside to close
hud.handleClick(100, 100)
expect(hud.selectionOpen).toBeNull()
})
it('allows selecting Normal Attack from left speedbar palette', () => {
hud.openSpeedbar('left')
expect(hud.selectionOpen).toBe('left')
// Find Attack in speedbar layout
const speedbarSkills = hud.getSpeedbarSkills('left')
const attackEntry = speedbarSkills.find((e) => e.skill.skillId === 0)
expect(attackEntry).toBeDefined()
// Click on Attack icon in speedbar
const clicked = hud.handleClick(attackEntry!.x + 10, attackEntry!.y + 10)
expect(clicked).toBe(true)
expect(hud.leftSkillId).toBe(0)
expect(hud.selectionOpen).toBeNull() // closed after selection
})
it('allows selecting Normal Attack from right speedbar palette', () => {
hud.openSpeedbar('right')
expect(hud.selectionOpen).toBe('right')
const speedbarSkills = hud.getSpeedbarSkills('right')
const attackEntry = speedbarSkills.find((e) => e.skill.skillId === 0)
expect(attackEntry).toBeDefined()
const clicked = hud.handleClick(attackEntry!.x + 10, attackEntry!.y + 10)
expect(clicked).toBe(true)
expect(hud.rightSkillId).toBe(0)
expect(hud.selectionOpen).toBeNull()
})
it('supports dual slot binding with Attack on both slots', () => {
hud.assignSkill('left', 0)
hud.assignSkill('right', 0)
expect(hud.leftSkillId).toBe(0)
expect(hud.rightSkillId).toBe(0)
// Verify resolveSkillIcon works for both slots
const leftIcon = resolveSkillIcon(hud.leftSkillId)
const rightIcon = resolveSkillIcon(hud.rightSkillId)
expect(leftIcon.skillId).toBe(0)
expect(rightIcon.skillId).toBe(0)
expect(leftIcon.name).toBe('Attack')
expect(rightIcon.name).toBe('Attack')
expect(leftIcon.iconPath).toBe('/skills/icon_0.png')
expect(rightIcon.iconPath).toBe('/skills/icon_0.png')
})
it('manages F1-F8 hotkey bindings and key presses', () => {
// Bind F1 to Attack (0)
hud.setHotkey('F1', 0)
expect(hud.getHotkey('F1')).toBe(0)
// Bind F2 to Frozen Orb (64)
hud.setHotkey('F2', 64)
expect(hud.getHotkey('F2')).toBe(64)
// Pressing F1 assigns right skill to 0
const handledF1 = hud.handleKeyDown('F1')
expect(handledF1).toBe(true)
expect(hud.rightSkillId).toBe(0)
// Pressing F2 assigns right skill to 64
const handledF2 = hud.handleKeyDown('F2')
expect(handledF2).toBe(true)
expect(hud.rightSkillId).toBe(64)
})
it('handles mouse hover over skill buttons and speedbar icons', () => {
hud.handleMouseMove(LEFT_SKILL_BOUNDS.x + 10, LEFT_SKILL_BOUNDS.y + 10)
expect(hud.hoverSkillId).toBe(hud.leftSkillId)
hud.handleMouseMove(RIGHT_SKILL_BOUNDS.x + 10, RIGHT_SKILL_BOUNDS.y + 10)
expect(hud.hoverSkillId).toBe(hud.rightSkillId)
hud.openSpeedbar('left')
const speedbarSkills = hud.getSpeedbarSkills('left')
const attackEntry = speedbarSkills.find((e) => e.skill.skillId === 0)
expect(attackEntry).toBeDefined()
hud.handleMouseMove(attackEntry!.x + 10, attackEntry!.y + 10)
expect(hud.hoverSpeedbarSkillId).toBe(0)
})
})