Files
scrying-pool/tests/unit/ui/gm/DirectorsBoard.test.js
uberwald 3faab3e3e4
CI / ci (push) Successful in 44s
CLeanup unused stuff
2026-05-25 21:35:02 +02:00

732 lines
26 KiB
JavaScript

// @ts-nocheck
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
// Stub foundry global for conditional base class — must NOT be present at module load time
// so the fallback class is used. The module is imported after this comment block.
// We only stub `foundry` in specific tests that need runtime foundry calls (none here).
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 { DirectorsBoard } from '../../../../src/ui/gm/DirectorsBoard.js';
describe('DirectorsBoard', () => {
let stateStore;
let controller;
let adapter;
let scenePresetManager;
let board;
beforeEach(() => {
stateStore = { getState: vi.fn(() => 'active') };
controller = { action: vi.fn(), hasPendingOp: vi.fn(() => false), getRevision: vi.fn(() => 0) };
adapter = {
users: {
get: vi.fn(() => ({ name: 'Alice', avatar: null })),
all: vi.fn(() => [{ id: 'u1' }]),
},
scenes: {
current: vi.fn(() => null),
},
};
scenePresetManager = {
list: vi.fn(() => []),
save: vi.fn(),
load: vi.fn(),
_getSceneFlagData: vi.fn(() => null),
_getAutoApplyConfig: vi.fn(() => ({ enabled: false, presetName: null, preDelay: 0 })),
};
board = new DirectorsBoard(stateStore, controller, adapter, scenePresetManager);
});
describe('constructor', () => {
it('is side-effect-free: does not call Hooks.on', () => {
expect(Hooks.on).not.toHaveBeenCalled();
});
it('sets _hookId to null initially', () => {
expect(board._hookId).toBeNull();
});
it('stores stateStore, controller, adapter, scenePresetManager references', () => {
expect(board._stateStore).toBe(stateStore);
expect(board._controller).toBe(controller);
expect(board._adapter).toBe(adapter);
expect(board._scenePresetManager).toBe(scenePresetManager);
});
it('initializes _saveDialog and _loadDialog to null', () => {
expect(board._saveDialog).toBeNull();
expect(board._loadDialog).toBeNull();
});
it('has DEFAULT_OPTIONS with position', () => {
expect(DirectorsBoard.DEFAULT_OPTIONS.position).toEqual({
width: 420,
height: 480,
left: 20,
top: 100,
});
});
});
describe('_loadPosition()', () => {
// Helper to create a board with options for testing _loadPosition
function createBoardWithOptions(options = {}) {
return new DirectorsBoard(
stateStore,
controller,
adapter,
scenePresetManager,
undefined,
options
);
}
it('loads position from user flag when saved state has open=true', () => {
const savedState = {
open: true,
left: 100,
top: 200,
width: 500,
height: 600,
};
game.user.getFlag.mockReturnValue(savedState);
const boardWithOptions = createBoardWithOptions({ position: {} });
boardWithOptions._loadPosition();
expect(game.user.getFlag).toHaveBeenCalledWith(
'scrying-pool',
'directorsBoardState'
);
// Position should be merged into options.position (not replaced)
expect(boardWithOptions.options.position).toEqual({
left: 100,
top: 200,
width: 500,
height: 600,
});
});
it('uses defaults when saved state has no width/height', () => {
const savedState = {
open: true,
left: 100,
top: 200,
};
game.user.getFlag.mockReturnValue(savedState);
const boardWithOptions = createBoardWithOptions({ position: {} });
boardWithOptions._loadPosition();
expect(boardWithOptions.options.position).toEqual({
left: 100,
top: 200,
width: 420,
height: 480,
});
});
it('does not modify position when saved state is null', () => {
game.user.getFlag.mockReturnValue(null);
const boardWithOptions = createBoardWithOptions({ position: { width: 400, height: 300 } });
const originalPosition = boardWithOptions.options.position;
boardWithOptions._loadPosition();
expect(boardWithOptions.options.position).toBe(originalPosition);
});
it('does not modify position when open is false', () => {
game.user.getFlag.mockReturnValue({ open: false, left: 100, top: 200 });
const boardWithOptions = createBoardWithOptions({ position: { width: 400, height: 300 } });
const originalPosition = boardWithOptions.options.position;
boardWithOptions._loadPosition();
expect(boardWithOptions.options.position).toBe(originalPosition);
});
it('does not modify position when left is null', () => {
game.user.getFlag.mockReturnValue({ open: true, left: null, top: 200 });
const boardWithOptions = createBoardWithOptions({ position: { width: 400, height: 300 } });
const originalPosition = boardWithOptions.options.position;
boardWithOptions._loadPosition();
expect(boardWithOptions.options.position).toBe(originalPosition);
});
it('does not throw when options is undefined', () => {
game.user.getFlag.mockReturnValue({ open: true, left: 100, top: 200 });
// Board created without options (fallback class doesn't set options)
expect(() => board._loadPosition()).not.toThrow();
});
it('handles errors gracefully and logs to console', () => {
game.user.getFlag.mockImplementation(() => {
throw new Error('Flag read error');
});
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
const boardWithOptions = createBoardWithOptions({ position: { width: 400, height: 300 } });
const originalPosition = boardWithOptions.options.position;
boardWithOptions._loadPosition();
expect(consoleSpy).toHaveBeenCalledWith(
'[ScryingPool] Failed to load directors board position:',
expect.any(Error)
);
expect(boardWithOptions.options.position).toBe(originalPosition);
});
});
describe('init()', () => {
it('registers scrying-pool:stateChanged hook', () => {
board.init();
expect(Hooks.on).toHaveBeenCalledWith('scrying-pool:stateChanged', expect.any(Function));
});
it('stores the returned hook id in _hookId', () => {
board.init();
expect(board._hookId).toBe(99);
});
});
describe('teardown()', () => {
it('calls Hooks.off with the stored hook id', () => {
board.init();
board.teardown();
expect(Hooks.off).toHaveBeenCalledWith('scrying-pool:stateChanged', 99);
});
it('sets _hookId to null after teardown', () => {
board.init();
board.teardown();
expect(board._hookId).toBeNull();
});
it('is a no-op when init was not called', () => {
expect(() => board.teardown()).not.toThrow();
expect(Hooks.off).not.toHaveBeenCalled();
});
});
describe('_dispatchToggle()', () => {
it('calls controller.action with positional args (active→hidden)', () => {
stateStore.getState.mockReturnValue('active');
board._dispatchToggle('u1');
expect(controller.action).toHaveBeenCalledWith('board', 'u1', 'hidden', expect.any(String), expect.any(Number));
});
it('calls controller.action with targetState active (hidden→active)', () => {
stateStore.getState.mockReturnValue('hidden');
board._dispatchToggle('u2');
expect(controller.action).toHaveBeenCalledWith('board', 'u2', 'active', expect.any(String), expect.any(Number));
});
it('does not dispatch if userId is falsy', () => {
board._dispatchToggle(null);
board._dispatchToggle(undefined);
board._dispatchToggle('');
expect(controller.action).not.toHaveBeenCalled();
});
it('does not dispatch if controller reports pending op', () => {
controller.hasPendingOp.mockReturnValue(true);
board._dispatchToggle('u1');
expect(controller.action).not.toHaveBeenCalled();
});
it('defaults to active state when stateStore returns null', () => {
stateStore.getState.mockReturnValue(null);
board._dispatchToggle('u1');
expect(controller.action).toHaveBeenCalledWith('board', 'u1', 'hidden', expect.any(String), expect.any(Number));
});
});
describe('toggle()', () => {
it('calls render({ force: true }) when not rendered', async () => {
board._rendered = false;
const renderSpy = vi.spyOn(board, 'render').mockResolvedValue(undefined);
await board.toggle();
expect(renderSpy).toHaveBeenCalledWith({ force: true });
});
it('calls close() when rendered', async () => {
board._rendered = true;
const closeSpy = vi.spyOn(board, 'close').mockResolvedValue(undefined);
await board.toggle();
expect(closeSpy).toHaveBeenCalled();
});
});
describe('_onStateChanged()', () => {
it('calls render({ force: true }) when board is rendered', () => {
board._rendered = true;
const renderSpy = vi.spyOn(board, 'render').mockResolvedValue(undefined);
board._onStateChanged({ userId: 'u1', newState: 'hidden' });
expect(renderSpy).toHaveBeenCalledWith({ force: true });
});
it('does not call render when board is not rendered', () => {
board._rendered = false;
const renderSpy = vi.spyOn(board, 'render').mockResolvedValue(undefined);
board._onStateChanged({ userId: 'u1', newState: 'hidden' });
expect(renderSpy).not.toHaveBeenCalled();
});
});
describe('_prepareContext()', () => {
it('returns board context with participants from adapter', async () => {
const ctx = await board._prepareContext({});
expect(ctx.participants).toHaveLength(1);
expect(ctx.participants[0].userId).toBe('u1');
expect(ctx.isEmpty).toBe(false);
});
it('returns isEmpty=true when adapter has no users', async () => {
adapter.users.all.mockReturnValue([]);
const ctx = await board._prepareContext({});
expect(ctx.isEmpty).toBe(true);
});
it('returns hasUndo=false when _undoSnapshot is null', async () => {
board._undoSnapshot = null;
const ctx = await board._prepareContext({});
expect(ctx.hasUndo).toBe(false);
});
it('returns hasUndo=true when _undoSnapshot is set', async () => {
board._undoSnapshot = new Map([['u1', 'hidden']]);
const ctx = await board._prepareContext({});
expect(ctx.hasUndo).toBe(true);
});
it('returns hasRestore=false when _spotlightSnapshot is null', async () => {
board._spotlightSnapshot = null;
const ctx = await board._prepareContext({});
expect(ctx.hasRestore).toBe(false);
});
it('returns hasRestore=true when _spotlightSnapshot is set', async () => {
board._spotlightSnapshot = new Map([['u1', 'active']]);
const ctx = await board._prepareContext({});
expect(ctx.hasRestore).toBe(true);
});
});
describe('DEFAULT_OPTIONS', () => {
it('has correct id', () => {
expect(DirectorsBoard.DEFAULT_OPTIONS.id).toBe('scrying-pool-directors-board');
});
it('has classes including scrying-pool and directors-board', () => {
expect(DirectorsBoard.DEFAULT_OPTIONS.classes).toContain('scrying-pool');
expect(DirectorsBoard.DEFAULT_OPTIONS.classes).toContain('directors-board');
});
});
describe('PARTS', () => {
it('has a board part with the correct template path', () => {
expect(DirectorsBoard.PARTS.board.template).toContain('directors-board.hbs');
});
});
describe('showAll()', () => {
it('calls controller.action with active for each non-ghost user', () => {
adapter.users.all.mockReturnValue([{ id: 'u1' }, { id: 'u2' }, { id: 'u3' }]);
stateStore.getState.mockImplementation(id => id === 'u3' ? 'ghost' : 'hidden');
board.showAll();
expect(controller.action).toHaveBeenCalledTimes(2);
expect(controller.action).toHaveBeenCalledWith('board', 'u1', 'active', expect.any(String), expect.any(Number));
expect(controller.action).toHaveBeenCalledWith('board', 'u2', 'active', expect.any(String), expect.any(Number));
expect(controller.action).not.toHaveBeenCalledWith('board', 'u3', expect.anything(), expect.anything(), expect.anything());
});
it('stores pre-action snapshot in _undoSnapshot (non-ghost users only)', () => {
adapter.users.all.mockReturnValue([{ id: 'u1' }, { id: 'u2' }, { id: 'u3' }]);
stateStore.getState.mockImplementation(id => {
if (id === 'u1') return 'hidden';
if (id === 'u2') return 'active';
return 'ghost';
});
board.showAll();
expect(board._undoSnapshot).toBeInstanceOf(Map);
expect(board._undoSnapshot.get('u1')).toBe('hidden');
expect(board._undoSnapshot.get('u2')).toBe('active');
expect(board._undoSnapshot.has('u3')).toBe(false);
});
it('clears _spotlightSnapshot when called', () => {
board._spotlightSnapshot = new Map([['u1', 'active']]);
adapter.users.all.mockReturnValue([{ id: 'u1' }]);
stateStore.getState.mockReturnValue('hidden');
board.showAll();
expect(board._spotlightSnapshot).toBeNull();
});
it('skips participants with pending ops', () => {
adapter.users.all.mockReturnValue([{ id: 'u1' }, { id: 'u2' }]);
stateStore.getState.mockReturnValue('hidden');
controller.hasPendingOp.mockImplementation(id => id === 'u1');
board.showAll();
expect(controller.action).toHaveBeenCalledTimes(1);
expect(controller.action).toHaveBeenCalledWith('board', 'u2', 'active', expect.any(String), expect.any(Number));
});
it('is a no-op when all users are ghost', () => {
adapter.users.all.mockReturnValue([{ id: 'u1' }]);
stateStore.getState.mockReturnValue('ghost');
board.showAll();
expect(controller.action).not.toHaveBeenCalled();
});
});
describe('hideAll()', () => {
it('calls controller.action with hidden for each non-ghost user', () => {
adapter.users.all.mockReturnValue([{ id: 'u1' }, { id: 'u2' }]);
stateStore.getState.mockReturnValue('active');
board.hideAll();
expect(controller.action).toHaveBeenCalledTimes(2);
expect(controller.action).toHaveBeenCalledWith('board', 'u1', 'hidden', expect.any(String), expect.any(Number));
expect(controller.action).toHaveBeenCalledWith('board', 'u2', 'hidden', expect.any(String), expect.any(Number));
});
it('stores pre-action snapshot in _undoSnapshot', () => {
adapter.users.all.mockReturnValue([{ id: 'u1' }]);
stateStore.getState.mockReturnValue('active');
board.hideAll();
expect(board._undoSnapshot).toBeInstanceOf(Map);
expect(board._undoSnapshot.get('u1')).toBe('active');
});
it('clears _spotlightSnapshot when called', () => {
board._spotlightSnapshot = new Map([['u1', 'active']]);
adapter.users.all.mockReturnValue([{ id: 'u1' }]);
stateStore.getState.mockReturnValue('active');
board.hideAll();
expect(board._spotlightSnapshot).toBeNull();
});
it('excludes ghost-state participants', () => {
adapter.users.all.mockReturnValue([{ id: 'u1' }, { id: 'u2' }]);
stateStore.getState.mockImplementation(id => id === 'u2' ? 'ghost' : 'active');
board.hideAll();
expect(controller.action).toHaveBeenCalledTimes(1);
expect(controller.action).toHaveBeenCalledWith('board', 'u1', 'hidden', expect.any(String), expect.any(Number));
});
});
describe('undo()', () => {
it('restores participants to snapshot states', () => {
board._undoSnapshot = new Map([['u1', 'hidden'], ['u2', 'active']]);
stateStore.getState.mockReturnValue('active');
board.undo();
expect(controller.action).toHaveBeenCalledWith('board', 'u1', 'hidden', expect.any(String), expect.any(Number));
expect(controller.action).toHaveBeenCalledWith('board', 'u2', 'active', expect.any(String), expect.any(Number));
});
it('clears _undoSnapshot after use (single-step only)', async () => {
board._undoSnapshot = new Map([['u1', 'hidden']]);
stateStore.getState.mockReturnValue('active');
await board.undo();
expect(board._undoSnapshot).toBeNull();
});
it('is a no-op when _undoSnapshot is null', () => {
board._undoSnapshot = null;
board.undo();
expect(controller.action).not.toHaveBeenCalled();
});
it('second undo is unavailable after first (no-op)', async () => {
board._undoSnapshot = new Map([['u1', 'hidden']]);
stateStore.getState.mockReturnValue('active');
await board.undo();
board.undo();
expect(controller.action).toHaveBeenCalledTimes(1);
});
it('skips ghost-state participants during undo', () => {
board._undoSnapshot = new Map([['u1', 'active'], ['u2', 'hidden']]);
stateStore.getState.mockImplementation(id => id === 'u2' ? 'ghost' : 'active');
board.undo();
expect(controller.action).toHaveBeenCalledTimes(1);
expect(controller.action).toHaveBeenCalledWith('board', 'u1', 'active', expect.any(String), expect.any(Number));
});
it('skips participants with pending ops during undo', () => {
board._undoSnapshot = new Map([['u1', 'hidden'], ['u2', 'hidden']]);
stateStore.getState.mockReturnValue('active');
controller.hasPendingOp.mockImplementation(id => id === 'u1');
board.undo();
expect(controller.action).toHaveBeenCalledTimes(1);
expect(controller.action).toHaveBeenCalledWith('board', 'u2', 'hidden', expect.any(String), expect.any(Number));
});
});
});
describe('DirectorsBoard spotlight', () => {
let stateStore, controller, adapter, board;
beforeEach(() => {
vi.stubGlobal('Hooks', { on: vi.fn(() => 1), off: vi.fn(), once: vi.fn() });
vi.stubGlobal('game', { keybindings: { register: vi.fn() } });
stateStore = {
getState: vi.fn(),
getAll: vi.fn(() => new Map()),
};
controller = {
action: vi.fn(),
hasPendingOp: vi.fn(() => false),
getRevision: vi.fn(() => 0),
};
adapter = {
users: { all: vi.fn(() => [{ id: 'u1' }, { id: 'u2' }, { id: 'u3' }]) },
scenes: { current: vi.fn(() => null) },
i18n: { localize: vi.fn((key) => key) },
};
board = new DirectorsBoard(stateStore, controller, adapter, null);
board.rendered = false;
board.render = vi.fn();
});
afterEach(() => vi.unstubAllGlobals());
describe('spotlight(userId)', () => {
it('sets focusedId active, all others hidden, captures snapshot, clears undo', () => {
stateStore.getState.mockImplementation(id => ({ u1: 'hidden', u2: 'active', u3: 'active' }[id]));
board._undoSnapshot = new Map([['u1', 'hidden']]);
board.spotlight('u1');
expect(controller.action).toHaveBeenCalledWith('board', 'u1', 'active', expect.any(String), expect.any(Number));
expect(controller.action).toHaveBeenCalledWith('board', 'u2', 'hidden', expect.any(String), expect.any(Number));
expect(controller.action).toHaveBeenCalledWith('board', 'u3', 'hidden', expect.any(String), expect.any(Number));
});
it('stores pre-spotlight snapshot in _spotlightSnapshot', () => {
stateStore.getState.mockImplementation(id => id === 'u1' ? 'active' : 'hidden');
board.spotlight('u1');
expect(board._spotlightSnapshot).toBeInstanceOf(Map);
expect(board._spotlightSnapshot.size).toBe(3);
});
it('clears _undoSnapshot when spotlight is called', () => {
stateStore.getState.mockReturnValue('active');
board._undoSnapshot = new Map([['u1', 'hidden']]);
board.spotlight('u2');
expect(board._undoSnapshot).toBeNull();
});
it('excludes ghost participants from spotlight', () => {
stateStore.getState.mockImplementation(id => id === 'u3' ? 'ghost' : 'active');
board.spotlight('u1');
const calls = controller.action.mock.calls.map(c => c[1]);
expect(calls).not.toContain('u3');
});
});
describe('restoreSpotlight()', () => {
it('restores participants to pre-spotlight snapshot states', () => {
board._spotlightSnapshot = new Map([['u1', 'hidden'], ['u2', 'active'], ['u3', 'hidden']]);
stateStore.getState.mockReturnValue('active');
board.restoreSpotlight();
expect(controller.action).toHaveBeenCalledWith('board', 'u1', 'hidden', expect.any(String), expect.any(Number));
expect(controller.action).toHaveBeenCalledWith('board', 'u2', 'active', expect.any(String), expect.any(Number));
});
it('clears _spotlightSnapshot after restore', async () => {
board._spotlightSnapshot = new Map([['u1', 'active']]);
stateStore.getState.mockReturnValue('active');
await board.restoreSpotlight();
expect(board._spotlightSnapshot).toBeNull();
});
it('is a no-op when _spotlightSnapshot is null', () => {
board._spotlightSnapshot = null;
board.restoreSpotlight();
expect(controller.action).not.toHaveBeenCalled();
});
it('skips ghost participants during restore', () => {
board._spotlightSnapshot = new Map([['u1', 'active'], ['u2', 'hidden']]);
stateStore.getState.mockImplementation(id => id === 'u2' ? 'ghost' : 'active');
board.restoreSpotlight();
expect(controller.action).toHaveBeenCalledTimes(1);
expect(controller.action).toHaveBeenCalledWith('board', 'u1', 'active', expect.any(String), expect.any(Number));
});
});
describe('spotlightFocused()', () => {
it('is a no-op if no participant is focused', () => {
board._focusedUserId = null;
board.spotlightFocused();
expect(controller.action).not.toHaveBeenCalled();
});
it('calls spotlight() with the currently focused userId', () => {
stateStore.getState.mockReturnValue('active');
board._focusedUserId = 'u2';
const spy = vi.spyOn(board, 'spotlight');
board.spotlightFocused();
expect(spy).toHaveBeenCalledWith('u2');
});
});
// --------------------------------------------------------------------------
// Preset Save/Load Tests
// --------------------------------------------------------------------------
describe('_prepareContext() with presets', () => {
it('should include presetCount in context', async () => {
// Create a board with a scenePresetManager that has presets
const presetManagerWithPresets = {
list: vi.fn().mockReturnValue([
{ name: 'Preset 1' },
{ name: 'Preset 2' },
]),
save: vi.fn(),
load: vi.fn(),
};
const boardWithPresets = new DirectorsBoard(stateStore, controller, adapter, presetManagerWithPresets);
const context = await boardWithPresets._prepareContext();
expect(context.presetCount).toBe(2);
expect(context.hasPresets).toBe(true);
});
it('should include hasPresets false when no presets', async () => {
// Create a board with a scenePresetManager that has no presets
const presetManagerNoPresets = {
list: vi.fn().mockReturnValue([]),
save: vi.fn(),
load: vi.fn(),
};
const boardNoPresets = new DirectorsBoard(stateStore, controller, adapter, presetManagerNoPresets);
const context = await boardNoPresets._prepareContext();
expect(context.presetCount).toBe(0);
expect(context.hasPresets).toBe(false);
});
it('should handle missing scenePresetManager gracefully', async () => {
const boardWithoutManager = new DirectorsBoard(stateStore, controller, adapter, null);
const context = await boardWithoutManager._prepareContext();
expect(context.presetCount).toBe(0);
expect(context.hasPresets).toBe(false);
});
});
describe('_onSavePreset()', () => {
it('should have _onSavePreset method defined', () => {
expect(board._onSavePreset).toBeDefined();
expect(typeof board._onSavePreset).toBe('function');
});
it('should have _onLoadPreset method defined', () => {
expect(board._onLoadPreset).toBeDefined();
expect(typeof board._onLoadPreset).toBe('function');
});
it('should have _closePresetDialogs method defined', () => {
expect(board._closePresetDialogs).toBeDefined();
expect(typeof board._closePresetDialogs).toBe('function');
});
});
describe('click handler with preset actions', () => {
it('should have click handler that processes save-preset action', () => {
// The click handler is created in _onRender, so we need to set up the element first
const mockElement = {
querySelectorAll: vi.fn().mockReturnValue([]),
querySelector: vi.fn(() => null),
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
prepend: vi.fn(),
after: vi.fn(),
};
board.element = mockElement;
board.rendered = true;
board._onRender(mockElement);
const clickHandler = board._clickHandler;
expect(clickHandler).toBeDefined();
// Verify the handler processes the action by checking it doesn't throw
expect(typeof clickHandler).toBe('function');
});
it('should have _onSavePreset method', () => {
expect(board._onSavePreset).toBeDefined();
expect(typeof board._onSavePreset).toBe('function');
});
it('should have _onLoadPreset method', () => {
expect(board._onLoadPreset).toBeDefined();
expect(typeof board._onLoadPreset).toBe('function');
});
});
describe('cleanup on close', () => {
it('should call _closePresetDialogs on _onClose', async () => {
// Spy on the method
const closeSpy = vi.spyOn(board, '_closePresetDialogs');
// Call _onClose
await board._onClose({});
// _closePresetDialogs should be called
expect(closeSpy).toHaveBeenCalled();
closeSpy.mockRestore();
});
it('should close save dialog on _closePresetDialogs', () => {
// Use the board created in beforeEach
const saveDialog = { close: vi.fn().mockResolvedValue({}) };
board._saveDialog = saveDialog;
board._loadDialog = null;
board._closePresetDialogs();
expect(saveDialog.close).toHaveBeenCalled();
expect(board._saveDialog).toBeNull();
});
it('should close load dialog on _closePresetDialogs', () => {
// Use the board created in beforeEach
const loadDialog = { close: vi.fn().mockResolvedValue({}) };
board._saveDialog = null;
board._loadDialog = loadDialog;
board._closePresetDialogs();
expect(loadDialog.close).toHaveBeenCalled();
expect(board._loadDialog).toBeNull();
});
});
});