/** * REGISTER_RE 3-arg tolerance — scaffold-routes emits mobile metadata as a 3rd * options argument (`PageRegistry.register('key', Page, { mobile: { … } })`). * Before the widening, such a registration was INVISIBLE to the aggregator: * the parsed key list came out empty, so componentRegistry.generated.ts lost * the module import and every route spun forever. These tests pin both forms * and the collision detection across them. */ import { describe, it, expect, beforeEach, afterEach } from 'vitest' import fs from 'node:fs' import os from 'node:os' import path from 'node:path' import { generate } from '../generate.js' let web: string beforeEach(() => { web = fs.mkdtempSync(path.join(os.tmpdir(), 'agg-parse-')) }) afterEach(() => { fs.rmSync(web, { recursive: true, force: true }) }) function write(rel: string, content: string): void { const abs = path.join(web, rel) fs.mkdirSync(path.dirname(abs), { recursive: true }) fs.writeFileSync(abs, content) } const HEADER = `import { PageRegistry, lazyWithRetry } from '@atlashub/smartstack';\n` describe('aggregate-component-registry — PageRegistry.register parsing', () => { it('parses 2-arg and 3-arg registrations in the same file', () => { write('src/pages/hrm/EmployeesListPage.tsx', 'export default () => null\n') write('src/pages/hrm/EmployeesDetailPage.tsx', 'export default () => null\n') write( 'src/extensions/hrmRegistry.ts', HEADER + `const EmployeesListPage = lazyWithRetry(() => import('@/pages/hrm/EmployeesListPage'));\n` + `const EmployeesDetailPage = lazyWithRetry(() => import('@/pages/hrm/EmployeesDetailPage'));\n` + `PageRegistry.register('client.hrm.employees', EmployeesListPage, {\n` + ` mobile: { support: 'adapted', offlineCapable: true },\n` + `});\n` + `PageRegistry.register('client.hrm.employees.detail', EmployeesDetailPage);\n`, ) const res = generate({ projectPath: web, exclude: [] }) expect(res.errors).toEqual([]) expect(res.collisions).toEqual([]) const parsed = res.parsed.find((p) => p.module === 'hrm') expect(parsed?.keys).toEqual(['client.hrm.employees', 'client.hrm.employees.detail']) const content = res.files.find((f) => f.path.endsWith('componentRegistry.generated.ts'))?.content expect(content).toContain(`import './hrmRegistry';`) }) it('parses a single-line 3-arg registration without offlineCapable', () => { write('src/pages/crm/ClientsListPage.tsx', 'export default () => null\n') write( 'src/extensions/crmRegistry.ts', HEADER + `const ClientsListPage = lazyWithRetry(() => import('@/pages/crm/ClientsListPage'));\n` + `PageRegistry.register('client.crm.clients', ClientsListPage, { mobile: { support: 'desktop-only' } });\n`, ) const res = generate({ projectPath: web, exclude: [] }) expect(res.parsed.find((p) => p.module === 'crm')?.keys).toEqual(['client.crm.clients']) }) it('still detects cross-module key collisions when one side is 3-arg', () => { write('src/pages/a/APage.tsx', 'export default () => null\n') write( 'src/extensions/aRegistry.ts', HEADER + `const APage = lazyWithRetry(() => import('@/pages/a/APage'));\n` + `PageRegistry.register('client.shared.thing', APage);\n`, ) write( 'src/extensions/bRegistry.ts', HEADER + `const APage = lazyWithRetry(() => import('@/pages/a/APage'));\n` + `PageRegistry.register('client.shared.thing', APage, { mobile: { support: 'adapted' } });\n`, ) const res = generate({ projectPath: web, exclude: [] }) expect(res.collisions).toEqual([{ key: 'client.shared.thing', modules: ['a', 'b'] }]) expect(res.files).toEqual([]) }) })