velxio/frontend/src/__tests__/load-example-transitions.te...

86 lines
3.4 KiB
TypeScript
Raw Normal View History

// @vitest-environment jsdom
/**
* Regression test for the bug where switching between a board-less example
* (analog / digital SPICE-only) and a board-based example (Arduino Uno) left
* the editor showing the OLD file's content (or nothing at all).
*
* Root cause: `loadExample.ts` single-board path called
* `useEditorStore.setCode()`, which writes to whatever file `activeFileId`
* happens to point at. But after a board-less example removed every board,
* its file group was deleted — and `activeFileId` still pointed at the now-
* orphan ID, so `setCode` was a silent no-op against the freshly-recreated
* Arduino file group.
*/
import { describe, it, expect, beforeEach } from 'vitest';
import { useEditorStore } from '../store/useEditorStore';
import { useSimulatorStore } from '../store/useSimulatorStore';
import { useElectricalStore } from '../store/useElectricalStore';
import { loadExample } from '../utils/loadExample';
import { exampleProjects } from '../data/examples';
function resetStores() {
// Clear all boards completely (also clears the file groups they own).
const sim = useSimulatorStore.getState();
const ids = sim.boards.map((b) => b.id);
for (const id of ids) sim.removeBoard(id);
useElectricalStore.getState().setPaused(false);
}
function findExample(id: string) {
const e = exampleProjects.find((x) => x.id === id);
if (!e) throw new Error(`Example not found: ${id}`);
return e;
}
function activeSketchContent(): string | undefined {
const { files, activeFileId } = useEditorStore.getState();
return files.find((f) => f.id === activeFileId)?.content;
}
describe('loadExample — board-less → board-based transition', () => {
beforeEach(() => {
resetStores();
});
it('loads Arduino Uno code into the editor after a board-less ANALOG example', async () => {
// 1. Board-less analog circuit
await loadExample(findExample('an-voltage-divider'));
expect(useSimulatorStore.getState().boards.length).toBe(0);
// 2. Now load an Arduino Uno example
const uno = findExample('blink-led');
await loadExample(uno);
expect(useSimulatorStore.getState().boards.length).toBeGreaterThanOrEqual(1);
const code = activeSketchContent();
expect(code, 'editor content after Uno load').toBeDefined();
expect(code, 'editor must contain the Uno example body').toContain(uno.code.slice(0, 40));
});
it('loads Arduino Uno code into the editor after a board-less DIGITAL example', async () => {
await loadExample(findExample('digital-and-two-switches'));
expect(useSimulatorStore.getState().boards.length).toBe(0);
const uno = findExample('blink-led');
await loadExample(uno);
const code = activeSketchContent();
expect(code, 'editor content after Uno load').toBeDefined();
expect(code, 'editor must contain the Uno example body').toContain(uno.code.slice(0, 40));
});
it('switching between two board-less examples does not break a later board load', async () => {
await loadExample(findExample('an-voltage-divider'));
await loadExample(findExample('digital-xor-difference'));
await loadExample(findExample('an-rc-low-pass'));
const uno = findExample('blink-led');
await loadExample(uno);
const code = activeSketchContent();
expect(code, 'editor content after 3 board-less → Uno load').toBeDefined();
expect(code, 'editor must contain the Uno example body').toContain(uno.code.slice(0, 40));
});
});