refactor(sim): single-board example load rebuilds from scratch
Cleaner follow-up to the multi-board residue fix. Instead of removing the extra boards and retyping the surviving one (which left a stale id such as "stm32-bluepill" on what was now an Arduino Uno), the single-board path now tears every board down and adds exactly one fresh board of the target kind. This mirrors the multi-board and board-less paths and guarantees the surviving board's id matches its kind. Drops the now-unused setBoardType/activeBoardId destructures and tightens the boardFilter cast off `any`. Strengthens the regression test to assert the surviving board's id and kind. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
0d5a1d5838
commit
af39225688
|
|
@ -121,14 +121,20 @@ describe('loadExample — multi-board to single-board leaves no residue (bug 3)'
|
||||||
resetStores();
|
resetStores();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('a single-board example after a multi-board example ends with exactly one board', async () => {
|
it('a single-board example after a multi-board example ends with exactly one clean board', async () => {
|
||||||
// Multi-board example: STM32 Blue Pill + Arduino Uno.
|
// Multi-board example: STM32 Blue Pill + Arduino Uno.
|
||||||
await loadExample(findExample('stm32-uno-gpio-mirror'));
|
await loadExample(findExample('stm32-uno-gpio-mirror'));
|
||||||
expect(useSimulatorStore.getState().boards.length).toBe(2);
|
expect(useSimulatorStore.getState().boards.length).toBe(2);
|
||||||
|
|
||||||
// Single-board example must reduce the canvas back to one board.
|
// Single-board example must reduce the canvas back to one board, freshly
|
||||||
|
// built — its id must match its kind (no stale "stm32-bluepill" id left
|
||||||
|
// on what is now an Arduino Uno).
|
||||||
await loadExample(findExample('blink-led'));
|
await loadExample(findExample('blink-led'));
|
||||||
expect(useSimulatorStore.getState().boards.length).toBe(1);
|
const after = useSimulatorStore.getState();
|
||||||
|
expect(after.boards.length).toBe(1);
|
||||||
|
expect(after.boards[0].boardKind).toBe('arduino-uno');
|
||||||
|
expect(after.boards[0].id).toBe('arduino-uno');
|
||||||
|
expect(after.activeBoardId).toBe('arduino-uno');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('residue cleanup also applies when extra boards were added manually', async () => {
|
it('residue cleanup also applies when extra boards were added manually', async () => {
|
||||||
|
|
|
||||||
|
|
@ -88,9 +88,7 @@ export async function loadExample(
|
||||||
const {
|
const {
|
||||||
setComponents,
|
setComponents,
|
||||||
setWires,
|
setWires,
|
||||||
setBoardType,
|
|
||||||
setBoardLanguageMode,
|
setBoardLanguageMode,
|
||||||
activeBoardId,
|
|
||||||
boards,
|
boards,
|
||||||
addBoard,
|
addBoard,
|
||||||
removeBoard,
|
removeBoard,
|
||||||
|
|
@ -186,43 +184,33 @@ export async function loadExample(
|
||||||
recalculateAllWirePositions();
|
recalculateAllWirePositions();
|
||||||
} else {
|
} else {
|
||||||
// ── Single-board loading ─────────────────────────────────────────────
|
// ── Single-board loading ─────────────────────────────────────────────
|
||||||
// Analog-only and digital-only SPICE examples are board-less. Remove every
|
// Tear the canvas down to nothing first, then (unless the example is
|
||||||
// existing board so the canvas opens with just the circuit (boards are now
|
// board-less) add exactly one fresh board of the target kind.
|
||||||
// optional — you can have 0, 1, or many at any time).
|
//
|
||||||
const filter = (example as any).boardFilter;
|
// Analog-only and digital-only SPICE examples are board-less — they open
|
||||||
|
// with just the circuit (boards are optional: 0, 1, or many at any time).
|
||||||
|
//
|
||||||
|
// Rebuilding from scratch — rather than reusing and retyping a leftover
|
||||||
|
// board from a previous (possibly multi-board) example — is what keeps
|
||||||
|
// this prolijo: a single-board example always ends with exactly one
|
||||||
|
// board whose id matches its kind. The old reuse path left a stale id
|
||||||
|
// (e.g. "stm32-bluepill" on what was now an Arduino Uno) and any extra
|
||||||
|
// boards as residue. This mirrors the multi-board path above; the
|
||||||
|
// setComponents/setWires calls below replace components and wires
|
||||||
|
// wholesale.
|
||||||
|
const filter = (example as { boardFilter?: string }).boardFilter;
|
||||||
const isBoardless = filter === 'analog' || filter === 'digital';
|
const isBoardless = filter === 'analog' || filter === 'digital';
|
||||||
if (isBoardless) {
|
|
||||||
const currentIds = boards.map((b) => b.id);
|
boards.forEach((b) => removeBoard(b.id));
|
||||||
currentIds.forEach((id) => removeBoard(id));
|
|
||||||
} else {
|
if (!isBoardless) {
|
||||||
const targetBoard = example.boardType || 'arduino-uno';
|
const targetBoard = example.boardType || 'arduino-uno';
|
||||||
// A previous MULTI-board example may have left several boards on the
|
|
||||||
// canvas. A single-board example must end with exactly one board, so
|
|
||||||
// drop every board past the first before retyping it. Without this
|
|
||||||
// the extra boards (and their editor file groups) linger as residue
|
|
||||||
// from the previous example. setComponents/setWires below already
|
|
||||||
// replace the components and wires wholesale; boards were the one
|
|
||||||
// piece of state this path never reset.
|
|
||||||
const existing = useSimulatorStore.getState().boards;
|
|
||||||
if (existing.length > 1) {
|
|
||||||
existing.slice(1).forEach((b) => removeBoard(b.id));
|
|
||||||
}
|
|
||||||
// If boards[] is empty (e.g. a previous analog example removed every
|
|
||||||
// board), setBoardType can't work — it only maps over existing entries.
|
|
||||||
// Add a fresh board instead.
|
|
||||||
if (useSimulatorStore.getState().boards.length === 0) {
|
|
||||||
const newId = addBoard(
|
const newId = addBoard(
|
||||||
targetBoard as BoardKind,
|
targetBoard as BoardKind,
|
||||||
DEFAULT_BOARD_POSITION.x,
|
DEFAULT_BOARD_POSITION.x,
|
||||||
DEFAULT_BOARD_POSITION.y,
|
DEFAULT_BOARD_POSITION.y,
|
||||||
);
|
);
|
||||||
setActiveBoardId(newId);
|
setActiveBoardId(newId);
|
||||||
} else {
|
|
||||||
// Reuse the surviving board, but make sure it's the active one
|
|
||||||
// first — setBoardType retypes whatever board is active.
|
|
||||||
setActiveBoardId(useSimulatorStore.getState().boards[0].id);
|
|
||||||
setBoardType(targetBoard);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── MicroPython + multi-file payloads ────────────────────────────────
|
// ── MicroPython + multi-file payloads ────────────────────────────────
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue