import { describe, expect, it } from 'vitest';
import { Lighting } from '../Lighting';
import { GLOW_BASE_PX, type LightFrame } from '../lightSim';
function makeLighting(maxLights = 16): Lighting {
// Без renderer: glow-текстура = Texture.WHITE, пул и логика тестируются в node.
return new Lighting({ width: 480, height: 270, maxLights });
}
describe('Lighting: ambient', () => {
it('ambient-спрайт: multiply, белый, на всю сцену', () => {
const l = makeLighting();
const ambient = l.children[0];
expect(ambient.blendMode).toBe('multiply');
expect(ambient.tint).toBe(0xffffff);
expect(ambient.width).toBe(480);
expect(ambient.height).toBe(270);
l.destroy();
});
it('setAmbient без fade применяется мгновенно', () => {
const l = makeLighting();
l.setAmbient(0x54586a);
expect(l.ambientColor).toBe(0x54586a);
expect(l.children[0].tint).toBe(0x54586a);
l.destroy();
});
it('setAmbient с fade — лерп к целевому цвету', () => {
const l = makeLighting();
l.setAmbient(0x000000);
l.setAmbient(0xffffff, 1);
l.update(0.5);
const mid = l.children[0].tint;
expect(mid).not.toBe(0x000000);
expect(mid).not.toBe(0xffffff);
l.update(0.5);
expect(l.children[0].tint).toBe(0xffffff);
expect(l.ambientColor).toBe(0xffffff);
l.destroy();
});
});
describe('Lighting: источники', () => {
it('upsertLight добавляет источник, кадр читается после update', () => {
const l = makeLighting();
l.upsertLight({ id: 'hearth', x: 100, y: 50, color: 0xf2b45a });
l.update(1 / 60);
const frames = l.frames();
expect(frames.length).toBe(1);
expect(frames[0].tint).toBe(0xf2b45a);
expect(frames[0].alpha).toBeGreaterThan(0);
l.destroy();
});
it('лишние источники сверх пула игнорируются', () => {
const l = makeLighting(2);
l.upsertLight({ id: 'a', x: 0, y: 0, color: 0xffffff });
l.upsertLight({ id: 'b', x: 0, y: 0, color: 0xffffff });
l.upsertLight({ id: 'c', x: 0, y: 0, color: 0xffffff });
expect(l.frames().length).toBe(2);
expect(l.hasLight('c')).toBe(false);
l.destroy();
});
it('removeLight возвращает спрайт в пул: число детей стабильно', () => {
const l = makeLighting();
const before = l.children.length;
l.upsertLight({ id: 'a', x: 0, y: 0, color: 0xffffff });
l.upsertLight({ id: 'b', x: 0, y: 0, color: 0xffffff });
l.removeLight('a');
l.upsertLight({ id: 'c', x: 0, y: 0, color: 0xffffff });
expect(l.children.length).toBe(before);
expect(l.hasLight('a')).toBe(false);
expect(l.hasLight('c')).toBe(true);
l.destroy();
});
it('setLightPos/setLightEnabled отражаются в кадрах', () => {
const l = makeLighting();
l.upsertLight({ id: 'a', x: 0, y: 0, color: 0xffffff, radius: 2 * GLOW_BASE_PX });
l.setLightPos('a', 123, 45);
l.setLightEnabled('a', false);
l.update(1 / 60);
const f: LightFrame = l.frames()[0];
expect(f.x).toBe(123);
expect(f.y).toBe(45);
expect(f.alpha).toBe(0);
l.destroy();
});
it('upsertLight обновляет параметры существующего', () => {
const l = makeLighting();
l.upsertLight({ id: 'a', x: 0, y: 0, color: 0xffffff, intensity: 0.5 });
l.upsertLight({ id: 'a', x: 7, y: 8, color: 0x112233, intensity: 1, flicker: 0 });
l.update(1 / 60);
const f = l.frames()[0];
expect(f.x).toBe(7);
expect(f.tint).toBe(0x112233);
expect(l.children.length).toBe(l.children.length); // пул не рос
l.destroy();
});
it('мерцание меняет alpha между апдейтами', () => {
const l = makeLighting();
l.upsertLight({ id: 'a', x: 0, y: 0, color: 0xffffff, flicker: 0.5 });
l.update(0);
const a1 = l.frames()[0].alpha;
l.update(0.37);
const a2 = l.frames()[0].alpha;
expect(a1).not.toBe(a2);
l.destroy();
});
});
describe('Lighting: destroy', () => {
it('не бросает и повторный вызов безопасен', () => {
const l = makeLighting();
l.upsertLight({ id: 'a', x: 0, y: 0, color: 0xffffff });
l.setAmbient(0x334455, 0.5);
l.destroy();
expect(() => l.destroy()).not.toThrow();
});
});