Files
Atomizer/atomizer-dashboard/frontend/src/test/setup.ts
Anto01 c4a3cff91a feat(canvas): Studio Enhancement Phase 1 & 2 - v2.0 architecture and file structure
Phase 1 - Foundation:
- Add NodeConfigPanelV2 using useSpecStore for AtomizerSpec v2.0 mode
- Deprecate AtomizerCanvas and useCanvasStore with migration docs
- Add VITE_USE_LEGACY_CANVAS env var for emergency fallback
- Enhance NodePalette with collapse support, filtering, exports
- Add drag-drop support to SpecRenderer with default node data
- Setup test infrastructure (Vitest + Playwright configs)
- Add useSpecStore unit tests (15 tests)

Phase 2 - File Structure & Model:
- Create FileStructurePanel with tree view of study files
- Add ModelNodeV2 with collapsible file dependencies
- Add tabbed left sidebar (Components/Files tabs)
- Add GET /api/files/structure/{study_id} backend endpoint
- Auto-expand 1_setup folders in file tree
- Show model file introspection with solver type and expressions

Technical:
- All TypeScript checks pass
- All 15 unit tests pass
- Production build successful
2026-01-20 11:53:26 -05:00

138 lines
3.6 KiB
TypeScript

/**
* Vitest Test Setup
*
* This file runs before each test file to set up the testing environment.
*/
/// <reference types="vitest/globals" />
import '@testing-library/jest-dom';
import { vi, beforeAll, afterAll, afterEach } from 'vitest';
// Type for global context
declare const global: typeof globalThis;
// ============================================================================
// Mock Browser APIs
// ============================================================================
// Mock ResizeObserver (used by ReactFlow)
global.ResizeObserver = vi.fn().mockImplementation(() => ({
observe: vi.fn(),
unobserve: vi.fn(),
disconnect: vi.fn(),
}));
// Mock IntersectionObserver
global.IntersectionObserver = vi.fn().mockImplementation(() => ({
observe: vi.fn(),
unobserve: vi.fn(),
disconnect: vi.fn(),
}));
// Mock matchMedia
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: vi.fn().mockImplementation((query: string) => ({
matches: false,
media: query,
onchange: null,
addListener: vi.fn(),
removeListener: vi.fn(),
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
dispatchEvent: vi.fn(),
})),
});
// Mock scrollTo
Element.prototype.scrollTo = vi.fn();
window.scrollTo = vi.fn();
// Mock fetch for API calls
global.fetch = vi.fn();
// ============================================================================
// Mock localStorage
// ============================================================================
const localStorageMock = {
getItem: vi.fn(),
setItem: vi.fn(),
removeItem: vi.fn(),
clear: vi.fn(),
length: 0,
key: vi.fn(),
};
Object.defineProperty(window, 'localStorage', { value: localStorageMock });
// ============================================================================
// Mock WebSocket
// ============================================================================
class MockWebSocket {
static readonly CONNECTING = 0;
static readonly OPEN = 1;
static readonly CLOSING = 2;
static readonly CLOSED = 3;
readonly CONNECTING = 0;
readonly OPEN = 1;
readonly CLOSING = 2;
readonly CLOSED = 3;
url: string;
readyState: number = MockWebSocket.CONNECTING;
onopen: ((event: Event) => void) | null = null;
onclose: ((event: CloseEvent) => void) | null = null;
onmessage: ((event: MessageEvent) => void) | null = null;
onerror: ((event: Event) => void) | null = null;
constructor(url: string) {
this.url = url;
// Simulate connection after a tick
setTimeout(() => {
this.readyState = MockWebSocket.OPEN;
this.onopen?.(new Event('open'));
}, 0);
}
send = vi.fn();
close = vi.fn(() => {
this.readyState = MockWebSocket.CLOSED;
this.onclose?.(new CloseEvent('close'));
});
}
global.WebSocket = MockWebSocket as any;
// ============================================================================
// Console Suppression (optional)
// ============================================================================
// Suppress console.error for expected test warnings
const originalError = console.error;
beforeAll(() => {
console.error = (...args: any[]) => {
// Suppress React act() warnings
if (typeof args[0] === 'string' && args[0].includes('Warning: An update to')) {
return;
}
originalError.call(console, ...args);
};
});
afterAll(() => {
console.error = originalError;
});
// ============================================================================
// Cleanup
// ============================================================================
afterEach(() => {
vi.clearAllMocks();
localStorageMock.getItem.mockReset();
localStorageMock.setItem.mockReset();
});