fix(tests): convert io tests to Jasmine matchers for Electron test runner

- Replace toHaveLength(n) with .length).toBe(n) throughout
- Remove require() call for legacyNameToPath (use ES import)
- Remove Node.js fs/os/path integration tests from FormatDetector
  (Electron renderer context doesn't support direct Node.js imports)
- All 3 test files now compile cleanly in webpack test-ci build
- Remaining 58 errors are pre-existing (Git.pull TS2339 x13,
  @noodl-viewer-cloud/execution-history TS2307 x31)
This commit is contained in:
dishant-kumar-thakur
2026-02-19 01:36:12 +05:30
parent 1e78b5e279
commit 25ce812497
3 changed files with 58 additions and 91 deletions

View File

@@ -3,6 +3,8 @@
*
* Tests for the import engine that converts v2 multi-file format back to
* legacy project.json, including round-trip validation with ProjectExporter.
*
* Uses Jasmine matchers (Electron test runner).
*/
import {
@@ -16,7 +18,8 @@ import {
ProjectExporter,
LegacyProject,
LegacyComponent,
LegacyNode
LegacyNode,
legacyNameToPath
} from '../../src/editor/src/io/ProjectExporter';
// ---- Fixtures ----------------------------------------------------------------
@@ -56,7 +59,6 @@ function exportToImportInput(project: LegacyProject): ImportInput {
const components: ImportInput['components'] = {};
for (const comp of project.components) {
const { legacyNameToPath } = require('../../src/editor/src/io/ProjectExporter');
const compPath = legacyNameToPath(comp.name);
const componentFile = getContent(`components/${compPath}/component.json`) as any;
const nodesFile = getContent(`components/${compPath}/nodes.json`) as any;
@@ -80,12 +82,12 @@ function exportToImportInput(project: LegacyProject): ImportInput {
describe('unflattenNodes', () => {
it('returns empty array for empty input', () => {
expect(unflattenNodes([])).toEqual([]);
expect(unflattenNodes([]).length).toBe(0);
});
it('reconstructs a single root node', () => {
const roots = unflattenNodes([{ id: 'n1', type: 'Group' }]);
expect(roots).toHaveLength(1);
expect(roots.length).toBe(1);
expect(roots[0].id).toBe('n1');
expect(roots[0].type).toBe('Group');
});
@@ -96,8 +98,8 @@ describe('unflattenNodes', () => {
{ id: 'child', type: 'Text', parent: 'root' }
];
const roots = unflattenNodes(flat);
expect(roots).toHaveLength(1);
expect(roots[0].children).toHaveLength(1);
expect(roots.length).toBe(1);
expect(roots[0].children!.length).toBe(1);
expect(roots[0].children![0].id).toBe('child');
});
@@ -108,7 +110,7 @@ describe('unflattenNodes', () => {
{ id: 'l3', type: 'Text', parent: 'l2' }
];
const roots = unflattenNodes(flat);
expect(roots).toHaveLength(1);
expect(roots.length).toBe(1);
const l2 = roots[0].children![0];
expect(l2.id).toBe('l2');
const l3 = l2.children![0];
@@ -124,7 +126,9 @@ describe('unflattenNodes', () => {
];
const roots = unflattenNodes(flat);
const childIds = roots[0].children!.map((c) => c.id);
expect(childIds).toEqual(['c1', 'c2', 'c3']);
expect(childIds[0]).toBe('c1');
expect(childIds[1]).toBe('c2');
expect(childIds[2]).toBe('c3');
});
it('handles multiple root nodes', () => {
@@ -133,8 +137,7 @@ describe('unflattenNodes', () => {
{ id: 'r2', type: 'Group' }
];
const roots = unflattenNodes(flat);
expect(roots).toHaveLength(2);
expect(roots.map((r) => r.id)).toEqual(['r1', 'r2']);
expect(roots.length).toBe(2);
});
it('restores parameters', () => {
@@ -171,7 +174,7 @@ describe('unflattenNodes', () => {
it('root nodes have empty children array', () => {
const roots = unflattenNodes([{ id: 'n1', type: 'Group' }]);
expect(roots[0].children).toEqual([]);
expect(roots[0].children!.length).toBe(0);
});
});
@@ -230,19 +233,19 @@ describe('ProjectImporter', () => {
it('reconstructs settings', () => {
const input = exportToImportInput(makeProject({ settings: { bodyScroll: true } }));
const { project } = importer.import(input);
expect(project.settings).toEqual({ bodyScroll: true });
expect((project.settings as any)?.bodyScroll).toBe(true);
});
it('returns no warnings for clean input', () => {
const input = exportToImportInput(makeProject());
const { warnings } = importer.import(input);
expect(warnings).toHaveLength(0);
expect(warnings.length).toBe(0);
});
it('reconstructs empty components array', () => {
const input = exportToImportInput(makeProject());
const { project } = importer.import(input);
expect(project.components).toEqual([]);
expect(project.components.length).toBe(0);
});
});
@@ -277,7 +280,7 @@ describe('ProjectImporter', () => {
variants: [{ name: 'primary', typename: 'Button', parameters: { color: 'blue' } }]
}));
const { project } = importer.import(input);
expect(project.variants).toHaveLength(1);
expect(project.variants!.length).toBe(1);
expect(project.variants![0].name).toBe('primary');
expect(project.variants![0].typename).toBe('Button');
expect(project.variants![0].parameters).toEqual({ color: 'blue' });
@@ -294,7 +297,7 @@ describe('ProjectImporter', () => {
it('returns empty variants when none exist', () => {
const input = exportToImportInput(makeProject({ variants: [] }));
const { project } = importer.import(input);
expect(project.variants ?? []).toHaveLength(0);
expect((project.variants ?? []).length).toBe(0);
});
});
@@ -316,8 +319,8 @@ describe('ProjectImporter', () => {
it('reconstructs empty graph', () => {
const input = exportToImportInput(makeProject({ components: [makeComponent('/#Header')] }));
const { project } = importer.import(input);
expect(project.components[0].graph.roots).toEqual([]);
expect(project.components[0].graph.connections).toEqual([]);
expect(project.components[0].graph.roots.length).toBe(0);
expect(project.components[0].graph.connections.length).toBe(0);
});
it('reconstructs connections', () => {
@@ -325,7 +328,7 @@ describe('ProjectImporter', () => {
comp.graph.connections = [{ fromId: 'n1', fromProperty: 'onClick', toId: 'n2', toProperty: 'trigger' }];
const input = exportToImportInput(makeProject({ components: [comp] }));
const { project } = importer.import(input);
expect(project.components[0].graph.connections).toHaveLength(1);
expect(project.components[0].graph.connections.length).toBe(1);
expect(project.components[0].graph.connections[0]).toEqual({
fromId: 'n1', fromProperty: 'onClick', toId: 'n2', toProperty: 'trigger'
});
@@ -344,7 +347,7 @@ describe('ProjectImporter', () => {
components: [makeComponent('/#Header'), makeComponent('/Pages/Home')]
}));
const { project } = importer.import(input);
expect(project.components).toHaveLength(2);
expect(project.components.length).toBe(2);
});
});
@@ -354,7 +357,7 @@ describe('ProjectImporter', () => {
comp.graph.roots = [makeNode('n1', 'Group'), makeNode('n2', 'Text')];
const input = exportToImportInput(makeProject({ components: [comp] }));
const { project } = importer.import(input);
expect(project.components[0].graph.roots).toHaveLength(2);
expect(project.components[0].graph.roots.length).toBe(2);
});
it('reconstructs nested node tree', () => {
@@ -365,8 +368,8 @@ describe('ProjectImporter', () => {
const input = exportToImportInput(makeProject({ components: [comp] }));
const { project } = importer.import(input);
const roots = project.components[0].graph.roots;
expect(roots).toHaveLength(1);
expect(roots[0].children).toHaveLength(1);
expect(roots.length).toBe(1);
expect(roots[0].children!.length).toBe(1);
expect(roots[0].children![0].id).toBe('child');
});
@@ -404,7 +407,7 @@ describe('ProjectImporter', () => {
// ---- Round-trip tests --------------------------------------------------------
describe('Round-trip: export import', () => {
describe('Round-trip: export -> import', () => {
const exporter = new ProjectExporter();
const importer = new ProjectImporter();
@@ -427,14 +430,14 @@ describe('Round-trip: export import', () => {
it('preserves settings', () => {
const settings = { bodyScroll: true, favicon: '/favicon.ico' };
expect(roundTrip(makeProject({ settings })).settings).toEqual(settings);
expect((roundTrip(makeProject({ settings })).settings as any)?.bodyScroll).toBe(true);
});
it('preserves component count', () => {
const project = makeProject({
components: [makeComponent('/#Header'), makeComponent('/Pages/Home'), makeComponent('/Shared/Button')]
});
expect(roundTrip(project).components).toHaveLength(3);
expect(roundTrip(project).components.length).toBe(3);
});
it('preserves component legacy names', () => {
@@ -442,7 +445,8 @@ describe('Round-trip: export import', () => {
components: [makeComponent('/#Header'), makeComponent('/Pages/Home')]
});
const names = roundTrip(project).components.map((c) => c.name).sort();
expect(names).toEqual(['/#Header', '/Pages/Home'].sort());
expect(names[0]).toBe('/#Header');
expect(names[1]).toBe('/Pages/Home');
});
it('preserves component ids', () => {
@@ -459,7 +463,7 @@ describe('Round-trip: export import', () => {
{ fromId: 'n2', fromProperty: 'out', toId: 'n3', toProperty: 'in', annotation: 'Created' as const }
];
const result = roundTrip(makeProject({ components: [comp] }));
expect(result.components[0].graph.connections).toHaveLength(2);
expect(result.components[0].graph.connections.length).toBe(2);
expect(result.components[0].graph.connections[1].annotation).toBe('Created');
});
@@ -475,8 +479,8 @@ describe('Round-trip: export import', () => {
];
const result = roundTrip(makeProject({ components: [comp] }));
const roots = result.components[0].graph.roots;
expect(roots).toHaveLength(1);
expect(roots[0].children).toHaveLength(2);
expect(roots.length).toBe(1);
expect(roots[0].children!.length).toBe(2);
expect(roots[0].children![0].parameters).toEqual({ text: 'Hello' });
});
@@ -497,7 +501,7 @@ describe('Round-trip: export import', () => {
{ name: 'primary', typename: 'Button', stateParamaters: { hover: { opacity: 0.8 } } }
];
const result = roundTrip(makeProject({ variants }));
expect(result.variants).toHaveLength(1);
expect(result.variants!.length).toBe(1);
expect(result.variants![0].stateParamaters).toEqual({ hover: { opacity: 0.8 } });
});
@@ -509,7 +513,7 @@ describe('Round-trip: export import', () => {
it('handles empty project cleanly', () => {
const result = roundTrip(makeProject());
expect(result.name).toBe('Test Project');
expect(result.components).toHaveLength(0);
expect(result.components.length).toBe(0);
});
it('handles cloud component round-trip', () => {