// @ts-nocheck
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
// Stub foundry global for conditional base class
beforeEach(() => {
vi.stubGlobal('Hooks', { on: vi.fn(() => 99), off: vi.fn() });
vi.stubGlobal('game', { user: { setFlag: vi.fn(), getFlag: vi.fn(() => null) } });
});
afterEach(() => {
vi.unstubAllGlobals();
vi.clearAllMocks();
});
import { ScenePresetPanel } from '../../../../src/ui/gm/ScenePresetPanel.js';
describe('ScenePresetPanel', () => {
let adapter;
let scenePresetManager;
let panel;
beforeEach(() => {
adapter = {
scenes: { current: vi.fn(() => ({ id: 'scene1', name: 'Test Scene' })) },
i18n: { localize: vi.fn((key) => key) },
notifications: { info: vi.fn() },
};
scenePresetManager = {
list: vi.fn(() => [
{ name: 'Preset 1' },
{ name: 'Preset 2' },
]),
_getSceneFlagData: vi.fn(() => ({})),
_getAutoApplyConfig: vi.fn(() => ({ enabled: false, presetName: null, preDelay: 0 })),
configureAutoApply: vi.fn().mockResolvedValue(undefined),
};
panel = new ScenePresetPanel(adapter, scenePresetManager);
});
describe('constructor', () => {
it('is side-effect-free: does not call Hooks.on', () => {
expect(Hooks.on).not.toHaveBeenCalled();
});
it('stores adapter and scenePresetManager references', () => {
expect(panel._adapter).toBe(adapter);
expect(panel._scenePresetManager).toBe(scenePresetManager);
});
it('initializes _element to null', () => {
expect(panel._element).toBeNull();
});
it('initializes _isOpen to false', () => {
expect(panel._isOpen).toBe(false);
});
it('initializes _currentScene to null', () => {
expect(panel._currentScene).toBeNull();
});
it('initializes handlers to null', () => {
expect(panel._clickHandler).toBeNull();
expect(panel._changeHandler).toBeNull();
expect(panel._inputHandler).toBeNull();
});
it('sets MAX_PREDELAY to 5000', () => {
expect(panel._MAX_PREDELAY).toBe(5000);
});
it('sets MIN_PREDELAY to 0', () => {
expect(panel._MIN_PREDELAY).toBe(0);
});
});
describe('init()', () => {
it('creates the DOM element', () => {
panel.init();
expect(panel._element).toBeInstanceOf(HTMLElement);
expect(panel._element.className).toBe('directors-board__preset-panel');
});
it('sets role attribute to region', () => {
panel.init();
expect(panel._element.getAttribute('role')).toBe('region');
});
it('sets aria-label using i18n', () => {
panel.init();
expect(adapter.i18n.localize).toHaveBeenCalledWith('video-view-manager.scenePresetPanel.title');
expect(panel._element.getAttribute('aria-label')).toBe('video-view-manager.scenePresetPanel.title');
});
it('sets aria-expanded to false initially', () => {
panel.init();
expect(panel._element.getAttribute('aria-expanded')).toBe('false');
});
it('sets display to none initially', () => {
panel.init();
expect(panel._element.style.display).toBe('none');
});
it('sets up event listeners', () => {
panel.init();
expect(panel._clickHandler).toBeDefined();
expect(panel._inputHandler).toBeDefined();
});
it('calls _refresh() to populate initial content', () => {
const refreshSpy = vi.spyOn(panel, '_refresh');
panel.init();
expect(refreshSpy).toHaveBeenCalled();
});
});
describe('element getter', () => {
it('returns the panel element after init', () => {
panel.init();
expect(panel.element).toBe(panel._element);
});
it('returns null before init', () => {
expect(panel.element).toBeNull();
});
});
describe('toggle()', () => {
beforeEach(() => {
panel.init();
});
it('opens the panel when closed', () => {
panel._isOpen = false;
panel._element.style.display = 'none';
panel.toggle();
expect(panel._isOpen).toBe(true);
expect(panel._element.style.display).toBe('block');
});
it('closes the panel when open', () => {
panel._isOpen = true;
panel._element.style.display = 'block';
panel.toggle();
expect(panel._isOpen).toBe(false);
expect(panel._element.style.display).toBe('none');
});
it('is a no-op when element is null', () => {
panel._element = null;
panel.toggle();
expect(panel._isOpen).toBe(false);
});
});
describe('open()', () => {
beforeEach(() => {
panel.init();
});
it('sets _isOpen to true', () => {
panel.open();
expect(panel._isOpen).toBe(true);
});
it('sets display to block', () => {
panel.open();
expect(panel._element.style.display).toBe('block');
});
it('sets aria-expanded to true', () => {
panel.open();
expect(panel._element.getAttribute('aria-expanded')).toBe('true');
});
it('calls _refresh()', () => {
const refreshSpy = vi.spyOn(panel, '_refresh');
panel.open();
expect(refreshSpy).toHaveBeenCalled();
});
it('is a no-op when element is null', () => {
panel._element = null;
panel.open();
expect(panel._isOpen).toBe(false);
});
});
describe('close()', () => {
beforeEach(() => {
panel.init();
});
it('sets _isOpen to false', () => {
panel._isOpen = true;
panel.close();
expect(panel._isOpen).toBe(false);
});
it('sets display to none', () => {
panel._element.style.display = 'block';
panel.close();
expect(panel._element.style.display).toBe('none');
});
it('sets aria-expanded to false', () => {
panel._element.setAttribute('aria-expanded', 'true');
panel.close();
expect(panel._element.getAttribute('aria-expanded')).toBe('false');
});
it('is a no-op when element is null', () => {
panel._element = null;
panel.close();
expect(panel._isOpen).toBe(false);
});
});
describe('_refresh()', () => {
beforeEach(() => {
panel.init();
});
it('is a no-op when element is null', async () => {
panel._element = null;
await panel._refresh();
// Should not throw
});
it('builds empty HTML when no scene is current', async () => {
adapter.scenes.current.mockReturnValue(null);
await panel._refresh();
expect(panel._element.innerHTML).toContain('noScene');
});
it('stores current scene and builds HTML with scene', async () => {
const mockScene = { id: 'scene1', name: 'Test Scene' };
adapter.scenes.current.mockReturnValue(mockScene);
await panel._refresh();
expect(panel._currentScene).toBe(mockScene);
expect(scenePresetManager.list).toHaveBeenCalled();
});
it('updates toggle aria-pressed state based on auto-apply enabled', async () => {
scenePresetManager._getAutoApplyConfig.mockReturnValue({ enabled: true, presetName: null, preDelay: 0 });
await panel._refresh();
const toggle = panel._element.querySelector('[data-action="toggle-auto-apply"]');
expect(toggle).not.toBeNull();
expect(toggle.getAttribute('aria-pressed')).toBe('true');
});
});
describe('_buildEmptyHtml()', () => {
beforeEach(() => {
panel.init();
});
it('returns HTML with no scene message', () => {
const html = panel._buildEmptyHtml();
expect(html).toContain('noScene');
expect(html).toContain('directors-board__preset-panel-title');
});
it('uses i18n for message', () => {
panel._buildEmptyHtml();
expect(adapter.i18n.localize).toHaveBeenCalledWith('video-view-manager.scenePresetPanel.noScene');
});
it('escapes HTML in message', () => {
adapter.i18n.localize = vi.fn(() => '');
const html = panel._buildEmptyHtml();
expect(html).not.toContain('' }],
});
expect(html).not.toContain('');
expect(result).not.toContain('<');
expect(result).not.toContain('>');
expect(result).not.toContain('"');
});
});
});