Files
house-design/tests/themes.test.js
m 8ac5b3f1f9 Add test suite with 132 unit tests across all modules
Covers DesignState (40 tests), HouseRenderer (19), InteractionManager (24),
ThemeManager (8), ExportManager (11), and CatalogPanel (30). Uses vitest
with THREE.js mocks for browser-free testing.
2026-02-07 16:34:36 +01:00

118 lines
3.5 KiB
JavaScript

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { COLORS } from '../src/renderer.js';
import { ThemeManager } from '../src/themes.js';
import { Scene, Color } from '../tests/__mocks__/three.js';
// Snapshot of original COLORS to restore between tests (shared mutable state)
const ORIGINAL_COLORS = {
wall: { ...COLORS.wall },
floor: { ...COLORS.floor },
ceiling: COLORS.ceiling,
door: COLORS.door,
window: COLORS.window,
windowFrame: COLORS.windowFrame,
grid: COLORS.grid,
selected: COLORS.selected
};
function restoreColors() {
Object.assign(COLORS.wall, ORIGINAL_COLORS.wall);
Object.assign(COLORS.floor, ORIGINAL_COLORS.floor);
COLORS.ceiling = ORIGINAL_COLORS.ceiling;
COLORS.door = ORIGINAL_COLORS.door;
COLORS.window = ORIGINAL_COLORS.window;
COLORS.windowFrame = ORIGINAL_COLORS.windowFrame;
COLORS.grid = ORIGINAL_COLORS.grid;
COLORS.selected = ORIGINAL_COLORS.selected;
}
function makeMockRenderer() {
const scene = new Scene();
// Add mock lights to the scene
scene.add({ isAmbientLight: true, intensity: 0.6, traverse: (fn) => fn({ isAmbientLight: true, intensity: 0.6 }) });
scene.add({ isDirectionalLight: true, intensity: 0.8, traverse: (fn) => fn({ isDirectionalLight: true, intensity: 0.8 }) });
return {
scene,
currentFloor: 0,
_clearFloor: vi.fn(),
showFloor: vi.fn()
};
}
describe('ThemeManager', () => {
let tm, mockRenderer;
beforeEach(() => {
restoreColors();
mockRenderer = makeMockRenderer();
tm = new ThemeManager(mockRenderer);
});
afterEach(() => {
restoreColors();
});
describe('getThemes', () => {
it('returns array of theme descriptors', () => {
const themes = tm.getThemes();
expect(themes.length).toBeGreaterThanOrEqual(4);
for (const theme of themes) {
expect(theme).toHaveProperty('id');
expect(theme).toHaveProperty('name');
expect(theme).toHaveProperty('swatch');
expect(typeof theme.id).toBe('string');
expect(typeof theme.name).toBe('string');
expect(theme.swatch).toMatch(/^#[0-9a-f]{6}$/i);
}
});
it('includes expected theme ids', () => {
const ids = tm.getThemes().map(t => t.id);
expect(ids).toContain('default');
expect(ids).toContain('modern');
expect(ids).toContain('warm');
expect(ids).toContain('dark');
expect(ids).toContain('scandinavian');
});
});
describe('constructor', () => {
it('starts with default theme', () => {
expect(tm.currentTheme).toBe('default');
});
});
describe('applyTheme', () => {
it('updates currentTheme property', () => {
tm.applyTheme('dark');
expect(tm.currentTheme).toBe('dark');
});
it('does nothing for invalid theme id', () => {
tm.applyTheme('nonexistent');
expect(tm.currentTheme).toBe('default');
});
it('mutates the shared COLORS object', () => {
const origExterior = COLORS.wall.exterior;
tm.applyTheme('dark');
expect(COLORS.wall.exterior).toBe(0x3a3a3a);
// Restore for other tests
tm.applyTheme('default');
expect(COLORS.wall.exterior).toBe(origExterior);
});
it('calls _clearFloor and showFloor on renderer', () => {
tm.applyTheme('modern');
expect(mockRenderer._clearFloor).toHaveBeenCalled();
expect(mockRenderer.showFloor).toHaveBeenCalledWith(0);
});
it('updates scene background', () => {
tm.applyTheme('dark');
expect(mockRenderer.scene.background._hex).toBe(0x222222);
});
});
});