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

166 lines
6.9 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';
feat(custom-chip): newly-added programmable chip auto-gets an editable program; chaser-c goes board-less Two fixes from live testing feedback: 1. Adding a programmable chip (Z80/8080) from the gallery created NO program group — only the chip(s) from the example had one. Root cause: 'programmable' was detected by a non-empty programFile, but a fresh chip's programFile is empty until the user writes one. Now detection uses the canonical signal — chip.json's programTargets — via isProgrammableChip(). When such a chip lands with no program yet, the file explorer seeds an editable program.c (DEFAULT_CHIP_PROGRAM_C, a working walking-LED skeleton) into its own group and stamps programFile/programTarget onto the component so Compile/Run can build it. Behaviour/driver and predefined chips (no programTargets) still get no group — edited in the chip designer. 2. z80-led-chaser-c now runs board-less on a regulated power supply (no Arduino, mirroring z80-larson-no-board) — the Arduino only ever supplied 5V and added confusion. chaser.c stays the chip's editable program in its own section. - romCompileService: isProgrammableChip(), DEFAULT_CHIP_PROGRAM_FILE/_C. - FileExplorer: detect by programTargets; auto-seed program.c + persist programFile/programTarget for fresh chips. - examples-retro-intel: chaser-c -> board-less (psu + 8 resistors + 8 LEDs), drop the now-unused Arduino sketch const; fix a stale sdcc --code-loc comment. - Tests: board+chip case moved to z80-larson-scanner (still board-based); isProgrammableChip unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:52:11 +07:00
import { isProgrammableChip } from '../services/romCompileService';
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));
});
});
feat(custom-chip): program lives in its own editor group, not the board sketch A programmable custom-chip (a CPU emulator that runs a ROM/program, e.g. the Z80 or 8080) now keeps its program (larson.s, chaser.c, ...) in a dedicated editor file group — group-chip-<chipId> — rendered as its own collapsible section in the file explorer, exactly like each board owns its sketch group. Behaviour/driver chips and predefined chips carry no programFile and get no group; they stay editable only in the chip designer. Fixes two reported issues on the Z80 examples: - /example/z80-larson-no-board: the board-less chip example now opens its program (larson.s) as the active group, editable on the left — previously the editor showed but no file appeared. - /example/z80-led-chaser-c: the chip program (chaser.c) no longer shows as a sibling tab inside the Arduino sketch group; it sits in its own chip section instead. The board group shows only sketch.ino. Details: - useEditorStore: chipFileGroupId()/CHIP_GROUP_PREFIX helpers. - loadExample: seedChipProgramGroups() routes each chip's programFile into its own group (seeded from the example files), sweeps stale chip groups, keeps the program OUT of the board group, and for a board-less chip example makes the chip group active so the program is the editable file shown. - EditorToolbar.prepareCustomChips: resolves the program from the chip's own group (falls back to board files for older projects) before assembling ROM. - FileExplorer: renders one collapsible section per programmable chip with an IC icon; clicking switches the editor to the chip group. Lazy-creates a group for chips dropped on the canvas. - projectPayload + vlxFile: serialise chip groups alongside board groups and include them in the dirty-check hash, so chip-program edits persist on save / autosave / .vlx export and round-trip via replaceFileGroups on load. - Regression tests for board-less + board+chip routing and stale-group sweep. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:07:56 +07:00
describe('loadExample — programmable-chip program lives in its own group', () => {
beforeEach(() => {
resetStores();
});
it('board-less chip example opens the chip program (larson.s) as the active group, editable', async () => {
await loadExample(findExample('z80-larson-no-board'));
const ed = useEditorStore.getState();
expect(useSimulatorStore.getState().boards.length).toBe(0);
// The chip owns a group-chip-<id> group with its program file.
const chipGroupId = 'group-chip-z80cpu';
expect(ed.fileGroups[chipGroupId], 'chip group exists').toBeDefined();
expect(ed.fileGroups[chipGroupId].map((f) => f.name)).toContain('larson.s');
// That group is the active one (program shows on the left, editable).
expect(ed.activeGroupId).toBe(chipGroupId);
const larson = ed.fileGroups[chipGroupId].find((f) => f.name === 'larson.s');
expect(larson?.content.length ?? 0, 'larson.s is non-empty').toBeGreaterThan(0);
expect(activeSketchContent(), 'editor shows the larson.s program').toBe(larson?.content);
});
it('board + chip example keeps the chip program OUT of the board sketch group', async () => {
feat(custom-chip): newly-added programmable chip auto-gets an editable program; chaser-c goes board-less Two fixes from live testing feedback: 1. Adding a programmable chip (Z80/8080) from the gallery created NO program group — only the chip(s) from the example had one. Root cause: 'programmable' was detected by a non-empty programFile, but a fresh chip's programFile is empty until the user writes one. Now detection uses the canonical signal — chip.json's programTargets — via isProgrammableChip(). When such a chip lands with no program yet, the file explorer seeds an editable program.c (DEFAULT_CHIP_PROGRAM_C, a working walking-LED skeleton) into its own group and stamps programFile/programTarget onto the component so Compile/Run can build it. Behaviour/driver and predefined chips (no programTargets) still get no group — edited in the chip designer. 2. z80-led-chaser-c now runs board-less on a regulated power supply (no Arduino, mirroring z80-larson-no-board) — the Arduino only ever supplied 5V and added confusion. chaser.c stays the chip's editable program in its own section. - romCompileService: isProgrammableChip(), DEFAULT_CHIP_PROGRAM_FILE/_C. - FileExplorer: detect by programTargets; auto-seed program.c + persist programFile/programTarget for fresh chips. - examples-retro-intel: chaser-c -> board-less (psu + 8 resistors + 8 LEDs), drop the now-unused Arduino sketch const; fix a stale sdcc --code-loc comment. - Tests: board+chip case moved to z80-larson-scanner (still board-based); isProgrammableChip unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:52:11 +07:00
await loadExample(findExample('z80-larson-scanner'));
feat(custom-chip): program lives in its own editor group, not the board sketch A programmable custom-chip (a CPU emulator that runs a ROM/program, e.g. the Z80 or 8080) now keeps its program (larson.s, chaser.c, ...) in a dedicated editor file group — group-chip-<chipId> — rendered as its own collapsible section in the file explorer, exactly like each board owns its sketch group. Behaviour/driver chips and predefined chips carry no programFile and get no group; they stay editable only in the chip designer. Fixes two reported issues on the Z80 examples: - /example/z80-larson-no-board: the board-less chip example now opens its program (larson.s) as the active group, editable on the left — previously the editor showed but no file appeared. - /example/z80-led-chaser-c: the chip program (chaser.c) no longer shows as a sibling tab inside the Arduino sketch group; it sits in its own chip section instead. The board group shows only sketch.ino. Details: - useEditorStore: chipFileGroupId()/CHIP_GROUP_PREFIX helpers. - loadExample: seedChipProgramGroups() routes each chip's programFile into its own group (seeded from the example files), sweeps stale chip groups, keeps the program OUT of the board group, and for a board-less chip example makes the chip group active so the program is the editable file shown. - EditorToolbar.prepareCustomChips: resolves the program from the chip's own group (falls back to board files for older projects) before assembling ROM. - FileExplorer: renders one collapsible section per programmable chip with an IC icon; clicking switches the editor to the chip group. Lazy-creates a group for chips dropped on the canvas. - projectPayload + vlxFile: serialise chip groups alongside board groups and include them in the dirty-check hash, so chip-program edits persist on save / autosave / .vlx export and round-trip via replaceFileGroups on load. - Regression tests for board-less + board+chip routing and stale-group sweep. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:07:56 +07:00
const ed = useEditorStore.getState();
const sim = useSimulatorStore.getState();
feat(custom-chip): newly-added programmable chip auto-gets an editable program; chaser-c goes board-less Two fixes from live testing feedback: 1. Adding a programmable chip (Z80/8080) from the gallery created NO program group — only the chip(s) from the example had one. Root cause: 'programmable' was detected by a non-empty programFile, but a fresh chip's programFile is empty until the user writes one. Now detection uses the canonical signal — chip.json's programTargets — via isProgrammableChip(). When such a chip lands with no program yet, the file explorer seeds an editable program.c (DEFAULT_CHIP_PROGRAM_C, a working walking-LED skeleton) into its own group and stamps programFile/programTarget onto the component so Compile/Run can build it. Behaviour/driver and predefined chips (no programTargets) still get no group — edited in the chip designer. 2. z80-led-chaser-c now runs board-less on a regulated power supply (no Arduino, mirroring z80-larson-no-board) — the Arduino only ever supplied 5V and added confusion. chaser.c stays the chip's editable program in its own section. - romCompileService: isProgrammableChip(), DEFAULT_CHIP_PROGRAM_FILE/_C. - FileExplorer: detect by programTargets; auto-seed program.c + persist programFile/programTarget for fresh chips. - examples-retro-intel: chaser-c -> board-less (psu + 8 resistors + 8 LEDs), drop the now-unused Arduino sketch const; fix a stale sdcc --code-loc comment. - Tests: board+chip case moved to z80-larson-scanner (still board-based); isProgrammableChip unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:52:11 +07:00
// Board group shows only the sketch — larson.s is NOT a sibling tab.
feat(custom-chip): program lives in its own editor group, not the board sketch A programmable custom-chip (a CPU emulator that runs a ROM/program, e.g. the Z80 or 8080) now keeps its program (larson.s, chaser.c, ...) in a dedicated editor file group — group-chip-<chipId> — rendered as its own collapsible section in the file explorer, exactly like each board owns its sketch group. Behaviour/driver chips and predefined chips carry no programFile and get no group; they stay editable only in the chip designer. Fixes two reported issues on the Z80 examples: - /example/z80-larson-no-board: the board-less chip example now opens its program (larson.s) as the active group, editable on the left — previously the editor showed but no file appeared. - /example/z80-led-chaser-c: the chip program (chaser.c) no longer shows as a sibling tab inside the Arduino sketch group; it sits in its own chip section instead. The board group shows only sketch.ino. Details: - useEditorStore: chipFileGroupId()/CHIP_GROUP_PREFIX helpers. - loadExample: seedChipProgramGroups() routes each chip's programFile into its own group (seeded from the example files), sweeps stale chip groups, keeps the program OUT of the board group, and for a board-less chip example makes the chip group active so the program is the editable file shown. - EditorToolbar.prepareCustomChips: resolves the program from the chip's own group (falls back to board files for older projects) before assembling ROM. - FileExplorer: renders one collapsible section per programmable chip with an IC icon; clicking switches the editor to the chip group. Lazy-creates a group for chips dropped on the canvas. - projectPayload + vlxFile: serialise chip groups alongside board groups and include them in the dirty-check hash, so chip-program edits persist on save / autosave / .vlx export and round-trip via replaceFileGroups on load. - Regression tests for board-less + board+chip routing and stale-group sweep. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:07:56 +07:00
const board = sim.boards.find((b) => b.id === sim.activeBoardId) ?? sim.boards[0];
const boardFiles = (ed.fileGroups[board.activeFileGroupId] ?? []).map((f) => f.name);
expect(boardFiles).toContain('sketch.ino');
feat(custom-chip): newly-added programmable chip auto-gets an editable program; chaser-c goes board-less Two fixes from live testing feedback: 1. Adding a programmable chip (Z80/8080) from the gallery created NO program group — only the chip(s) from the example had one. Root cause: 'programmable' was detected by a non-empty programFile, but a fresh chip's programFile is empty until the user writes one. Now detection uses the canonical signal — chip.json's programTargets — via isProgrammableChip(). When such a chip lands with no program yet, the file explorer seeds an editable program.c (DEFAULT_CHIP_PROGRAM_C, a working walking-LED skeleton) into its own group and stamps programFile/programTarget onto the component so Compile/Run can build it. Behaviour/driver and predefined chips (no programTargets) still get no group — edited in the chip designer. 2. z80-led-chaser-c now runs board-less on a regulated power supply (no Arduino, mirroring z80-larson-no-board) — the Arduino only ever supplied 5V and added confusion. chaser.c stays the chip's editable program in its own section. - romCompileService: isProgrammableChip(), DEFAULT_CHIP_PROGRAM_FILE/_C. - FileExplorer: detect by programTargets; auto-seed program.c + persist programFile/programTarget for fresh chips. - examples-retro-intel: chaser-c -> board-less (psu + 8 resistors + 8 LEDs), drop the now-unused Arduino sketch const; fix a stale sdcc --code-loc comment. - Tests: board+chip case moved to z80-larson-scanner (still board-based); isProgrammableChip unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:52:11 +07:00
expect(boardFiles, 'larson.s must not pollute the board group').not.toContain('larson.s');
feat(custom-chip): program lives in its own editor group, not the board sketch A programmable custom-chip (a CPU emulator that runs a ROM/program, e.g. the Z80 or 8080) now keeps its program (larson.s, chaser.c, ...) in a dedicated editor file group — group-chip-<chipId> — rendered as its own collapsible section in the file explorer, exactly like each board owns its sketch group. Behaviour/driver chips and predefined chips carry no programFile and get no group; they stay editable only in the chip designer. Fixes two reported issues on the Z80 examples: - /example/z80-larson-no-board: the board-less chip example now opens its program (larson.s) as the active group, editable on the left — previously the editor showed but no file appeared. - /example/z80-led-chaser-c: the chip program (chaser.c) no longer shows as a sibling tab inside the Arduino sketch group; it sits in its own chip section instead. The board group shows only sketch.ino. Details: - useEditorStore: chipFileGroupId()/CHIP_GROUP_PREFIX helpers. - loadExample: seedChipProgramGroups() routes each chip's programFile into its own group (seeded from the example files), sweeps stale chip groups, keeps the program OUT of the board group, and for a board-less chip example makes the chip group active so the program is the editable file shown. - EditorToolbar.prepareCustomChips: resolves the program from the chip's own group (falls back to board files for older projects) before assembling ROM. - FileExplorer: renders one collapsible section per programmable chip with an IC icon; clicking switches the editor to the chip group. Lazy-creates a group for chips dropped on the canvas. - projectPayload + vlxFile: serialise chip groups alongside board groups and include them in the dirty-check hash, so chip-program edits persist on save / autosave / .vlx export and round-trip via replaceFileGroups on load. - Regression tests for board-less + board+chip routing and stale-group sweep. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:07:56 +07:00
// The chip program lives in its own group instead.
const chipGroupId = 'group-chip-z80cpu';
feat(custom-chip): newly-added programmable chip auto-gets an editable program; chaser-c goes board-less Two fixes from live testing feedback: 1. Adding a programmable chip (Z80/8080) from the gallery created NO program group — only the chip(s) from the example had one. Root cause: 'programmable' was detected by a non-empty programFile, but a fresh chip's programFile is empty until the user writes one. Now detection uses the canonical signal — chip.json's programTargets — via isProgrammableChip(). When such a chip lands with no program yet, the file explorer seeds an editable program.c (DEFAULT_CHIP_PROGRAM_C, a working walking-LED skeleton) into its own group and stamps programFile/programTarget onto the component so Compile/Run can build it. Behaviour/driver and predefined chips (no programTargets) still get no group — edited in the chip designer. 2. z80-led-chaser-c now runs board-less on a regulated power supply (no Arduino, mirroring z80-larson-no-board) — the Arduino only ever supplied 5V and added confusion. chaser.c stays the chip's editable program in its own section. - romCompileService: isProgrammableChip(), DEFAULT_CHIP_PROGRAM_FILE/_C. - FileExplorer: detect by programTargets; auto-seed program.c + persist programFile/programTarget for fresh chips. - examples-retro-intel: chaser-c -> board-less (psu + 8 resistors + 8 LEDs), drop the now-unused Arduino sketch const; fix a stale sdcc --code-loc comment. - Tests: board+chip case moved to z80-larson-scanner (still board-based); isProgrammableChip unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:52:11 +07:00
expect(ed.fileGroups[chipGroupId]?.map((f) => f.name)).toContain('larson.s');
feat(custom-chip): program lives in its own editor group, not the board sketch A programmable custom-chip (a CPU emulator that runs a ROM/program, e.g. the Z80 or 8080) now keeps its program (larson.s, chaser.c, ...) in a dedicated editor file group — group-chip-<chipId> — rendered as its own collapsible section in the file explorer, exactly like each board owns its sketch group. Behaviour/driver chips and predefined chips carry no programFile and get no group; they stay editable only in the chip designer. Fixes two reported issues on the Z80 examples: - /example/z80-larson-no-board: the board-less chip example now opens its program (larson.s) as the active group, editable on the left — previously the editor showed but no file appeared. - /example/z80-led-chaser-c: the chip program (chaser.c) no longer shows as a sibling tab inside the Arduino sketch group; it sits in its own chip section instead. The board group shows only sketch.ino. Details: - useEditorStore: chipFileGroupId()/CHIP_GROUP_PREFIX helpers. - loadExample: seedChipProgramGroups() routes each chip's programFile into its own group (seeded from the example files), sweeps stale chip groups, keeps the program OUT of the board group, and for a board-less chip example makes the chip group active so the program is the editable file shown. - EditorToolbar.prepareCustomChips: resolves the program from the chip's own group (falls back to board files for older projects) before assembling ROM. - FileExplorer: renders one collapsible section per programmable chip with an IC icon; clicking switches the editor to the chip group. Lazy-creates a group for chips dropped on the canvas. - projectPayload + vlxFile: serialise chip groups alongside board groups and include them in the dirty-check hash, so chip-program edits persist on save / autosave / .vlx export and round-trip via replaceFileGroups on load. - Regression tests for board-less + board+chip routing and stale-group sweep. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:07:56 +07:00
// With a board present the board sketch stays the active group.
expect(ed.activeGroupId).toBe(board.activeFileGroupId);
});
it('chip groups from a previous example do not leak into the next', async () => {
feat(custom-chip): newly-added programmable chip auto-gets an editable program; chaser-c goes board-less Two fixes from live testing feedback: 1. Adding a programmable chip (Z80/8080) from the gallery created NO program group — only the chip(s) from the example had one. Root cause: 'programmable' was detected by a non-empty programFile, but a fresh chip's programFile is empty until the user writes one. Now detection uses the canonical signal — chip.json's programTargets — via isProgrammableChip(). When such a chip lands with no program yet, the file explorer seeds an editable program.c (DEFAULT_CHIP_PROGRAM_C, a working walking-LED skeleton) into its own group and stamps programFile/programTarget onto the component so Compile/Run can build it. Behaviour/driver and predefined chips (no programTargets) still get no group — edited in the chip designer. 2. z80-led-chaser-c now runs board-less on a regulated power supply (no Arduino, mirroring z80-larson-no-board) — the Arduino only ever supplied 5V and added confusion. chaser.c stays the chip's editable program in its own section. - romCompileService: isProgrammableChip(), DEFAULT_CHIP_PROGRAM_FILE/_C. - FileExplorer: detect by programTargets; auto-seed program.c + persist programFile/programTarget for fresh chips. - examples-retro-intel: chaser-c -> board-less (psu + 8 resistors + 8 LEDs), drop the now-unused Arduino sketch const; fix a stale sdcc --code-loc comment. - Tests: board+chip case moved to z80-larson-scanner (still board-based); isProgrammableChip unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:52:11 +07:00
await loadExample(findExample('z80-larson-scanner'));
feat(custom-chip): program lives in its own editor group, not the board sketch A programmable custom-chip (a CPU emulator that runs a ROM/program, e.g. the Z80 or 8080) now keeps its program (larson.s, chaser.c, ...) in a dedicated editor file group — group-chip-<chipId> — rendered as its own collapsible section in the file explorer, exactly like each board owns its sketch group. Behaviour/driver chips and predefined chips carry no programFile and get no group; they stay editable only in the chip designer. Fixes two reported issues on the Z80 examples: - /example/z80-larson-no-board: the board-less chip example now opens its program (larson.s) as the active group, editable on the left — previously the editor showed but no file appeared. - /example/z80-led-chaser-c: the chip program (chaser.c) no longer shows as a sibling tab inside the Arduino sketch group; it sits in its own chip section instead. The board group shows only sketch.ino. Details: - useEditorStore: chipFileGroupId()/CHIP_GROUP_PREFIX helpers. - loadExample: seedChipProgramGroups() routes each chip's programFile into its own group (seeded from the example files), sweeps stale chip groups, keeps the program OUT of the board group, and for a board-less chip example makes the chip group active so the program is the editable file shown. - EditorToolbar.prepareCustomChips: resolves the program from the chip's own group (falls back to board files for older projects) before assembling ROM. - FileExplorer: renders one collapsible section per programmable chip with an IC icon; clicking switches the editor to the chip group. Lazy-creates a group for chips dropped on the canvas. - projectPayload + vlxFile: serialise chip groups alongside board groups and include them in the dirty-check hash, so chip-program edits persist on save / autosave / .vlx export and round-trip via replaceFileGroups on load. - Regression tests for board-less + board+chip routing and stale-group sweep. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:07:56 +07:00
expect(useEditorStore.getState().fileGroups['group-chip-z80cpu']).toBeDefined();
// A plain board example with no custom chip must clear the stale chip group.
await loadExample(findExample('blink-led'));
expect(
useEditorStore.getState().fileGroups['group-chip-z80cpu'],
'stale chip group swept on next load',
).toBeUndefined();
});
});
feat(custom-chip): newly-added programmable chip auto-gets an editable program; chaser-c goes board-less Two fixes from live testing feedback: 1. Adding a programmable chip (Z80/8080) from the gallery created NO program group — only the chip(s) from the example had one. Root cause: 'programmable' was detected by a non-empty programFile, but a fresh chip's programFile is empty until the user writes one. Now detection uses the canonical signal — chip.json's programTargets — via isProgrammableChip(). When such a chip lands with no program yet, the file explorer seeds an editable program.c (DEFAULT_CHIP_PROGRAM_C, a working walking-LED skeleton) into its own group and stamps programFile/programTarget onto the component so Compile/Run can build it. Behaviour/driver and predefined chips (no programTargets) still get no group — edited in the chip designer. 2. z80-led-chaser-c now runs board-less on a regulated power supply (no Arduino, mirroring z80-larson-no-board) — the Arduino only ever supplied 5V and added confusion. chaser.c stays the chip's editable program in its own section. - romCompileService: isProgrammableChip(), DEFAULT_CHIP_PROGRAM_FILE/_C. - FileExplorer: detect by programTargets; auto-seed program.c + persist programFile/programTarget for fresh chips. - examples-retro-intel: chaser-c -> board-less (psu + 8 resistors + 8 LEDs), drop the now-unused Arduino sketch const; fix a stale sdcc --code-loc comment. - Tests: board+chip case moved to z80-larson-scanner (still board-based); isProgrammableChip unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 03:52:11 +07:00
describe('isProgrammableChip — detects ROM-loading CPUs by programTargets', () => {
it('true when chip.json declares programTargets, even with no programFile yet', () => {
// A chip freshly dropped from the gallery: programFile empty, but its
// chip.json marks it a CPU. It must still be treated as programmable so a
// program file gets created for it.
expect(
isProgrammableChip({ chipJson: JSON.stringify({ programTargets: ['z80'] }), programFile: '' }),
).toBe(true);
});
it('true when a programFile is already set', () => {
expect(isProgrammableChip({ chipJson: '{}', programFile: 'larson.s' })).toBe(true);
});
it('false for a behaviour chip (no programTargets, no programFile)', () => {
expect(
isProgrammableChip({ chipJson: JSON.stringify({ name: 'Servo driver' }), programFile: '' }),
).toBe(false);
expect(isProgrammableChip({})).toBe(false);
expect(isProgrammableChip(null)).toBe(false);
});
});