Files
scrying-pool/tests/unit/ui/gm/DirectorsBoard.test.js
T
uberwald 5b421d6d49 Fix DirectorsBoard position loading error
- Fixed TypeError: Cannot assign to read only property 'position' of object
- Changed _loadPosition() to use Object.assign() instead of direct assignment
- Added null check for this.options?.position to handle both Foundry and test environments
- Updated fallback _AppBase class to store options in constructor for test compatibility
- Added comprehensive tests for _loadPosition() method

The error occurred because in FoundryVTT v14, ApplicationV2 freezes the options object,
making direct assignment to this.options.position impossible. Using Object.assign()
merges the properties instead, which works with both frozen and unfrozen objects.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-05-24 13:50:46 +02:00

730 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: 400,
height: 300,
});
});
});
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(
'video-view-manager',
'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: 400,
height: 300,
});
});
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();
});
});
});