diablo2-web/tests/p0-530-missile-art-failfast...

126 lines
4.2 KiB
TypeScript

import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { MISSILE_METAS } from '../src/client/render/missiles-meta.ts'
import type { SpriteRenderer } from '../src/client/render/renderer.ts'
import { loadItemsAtlas } from '../src/client/scene/ground-item-renderer.ts'
import {
drawExplosion,
drawMissileProjectile,
loadMissileArtMap,
loadOverlayArtMap,
} from '../src/client/scene/missile-overlay-renderer.ts'
describe('P0 #530: Missile Art Fail-Fast & Removal of Procedural drawSolid / fireexplode Fallbacks', () => {
afterEach(() => {
vi.unstubAllGlobals()
})
it('includes canonical MISSILE_METAS alias keys for frozenorbbolt, frozenorbnova, icestormimpactvar02, and hydra_turret', () => {
expect(MISSILE_METAS.frozenorbbolt).toBeDefined()
expect(MISSILE_METAS.frozenorbbolt?.name).toBe('icebolt')
expect(MISSILE_METAS.frozenorbnova).toBeDefined()
expect(MISSILE_METAS.frozenorbnova?.name).toBe('icebolt')
expect(MISSILE_METAS.icestormimpactvar02).toBeDefined()
expect(MISSILE_METAS.icestormimpactvar02?.name).toBe('blizzardexplode3')
expect(MISSILE_METAS.hydra_turret).toBeDefined()
expect(MISSILE_METAS.hydra_turret?.name).toBe('hydra')
})
it('fails fast with a descriptive Error in loadMissileArtMap when fetch returns HTTP 404', async () => {
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
vi.stubGlobal(
'fetch',
vi.fn(async () => ({
ok: false,
status: 404,
})),
)
vi.stubGlobal('createImageBitmap', vi.fn())
const dummyRenderer = { addAtlas: vi.fn() } as unknown as SpriteRenderer
await expect(loadMissileArtMap(dummyRenderer, '/packs')).rejects.toThrow(
/\[loadMissileArtMap\] Failed to load .*HTTP 404/,
)
expect(errorSpy).toHaveBeenCalled()
errorSpy.mockRestore()
})
it('fails fast with a descriptive Error in loadOverlayArtMap when fetch returns HTTP 500', async () => {
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
vi.stubGlobal(
'fetch',
vi.fn(async () => ({
ok: false,
status: 500,
})),
)
vi.stubGlobal('createImageBitmap', vi.fn())
const dummyRenderer = { addAtlas: vi.fn() } as unknown as SpriteRenderer
await expect(loadOverlayArtMap(dummyRenderer, '/packs')).rejects.toThrow(
/\[loadOverlayArtMap\] Failed to load .*HTTP 500/,
)
expect(errorSpy).toHaveBeenCalled()
errorSpy.mockRestore()
})
it('fails fast with a descriptive Error in loadItemsAtlas when all candidate URLs return HTTP 404', async () => {
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
vi.stubGlobal(
'fetch',
vi.fn(async () => ({
ok: false,
status: 404,
})),
)
vi.stubGlobal('createImageBitmap', vi.fn())
const dummyRenderer = { addAtlas: vi.fn() } as unknown as SpriteRenderer
await expect(loadItemsAtlas(dummyRenderer, '/packs')).rejects.toThrow(
/\[loadItemsAtlas\] Failed to load items-atlas\.png from all candidates/,
)
expect(errorSpy).toHaveBeenCalled()
errorSpy.mockRestore()
})
it('never calls renderer.drawSolid in drawMissileProjectile or drawExplosion when art is undefined', () => {
const drawSolid = vi.fn()
const draw = vi.fn()
const mockRenderer = { draw, drawSolid } as unknown as SpriteRenderer
drawMissileProjectile(mockRenderer, {
skillId: '36',
missileType: 'firebolt',
x: 100,
y: 100,
vx: 5,
vy: 5,
damage: 10,
ttl: 20,
fromPlayer: true,
})
drawExplosion(mockRenderer, {
x: 120,
y: 120,
radius: 40,
frame: 2,
maxFrames: 16,
missileType: 'iceexplode',
})
expect(draw).not.toHaveBeenCalled()
expect(drawSolid).not.toHaveBeenCalled()
})
it('contains no borrowed fireexplode fallback or 8x8 yellow drawSolid in world-renderer.ts', () => {
const worldRendererSrc = readFileSync(
resolve(process.cwd(), 'src/client/scene/world-renderer.ts'),
'utf8',
)
expect(worldRendererSrc).not.toContain("missileArtMap.get('fireexplode')")
expect(worldRendererSrc).not.toContain('[0.9, 0.9, 0.2, 1]')
})
})