/** * REGRESSION — the aggregator must register NOTHING of its own. * * Up to CLI 5.12 a PLATFORM_ADMIN_FALLBACK_BLOCK was prepended to every emitted * componentRegistry, registering a placeholder component on `administration` and the nine * platform-admin module keys. Its stated rationale — "otherwise DynamicRouter throws * MISSING_PAGE on every /administration/ URL" — was wrong twice over: * * 1. MissingComponentPage is only reachable from a SECTION or RESOURCE key (or an * application with zero modules), never from an application/module key. There was * nothing to guard against. * 2. A REGISTERED component always wins over the SDK's generic ApplicationHomePage / * ModuleHomePage. So the "safety net" REPLACED the platform's own landing page — and * since the scaffolded placeholder rendered `null`, every /administration/* root in * every generated client app went blank, silently. */ 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-admin-')) }) 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) } function registryOf(): string { const content = generate({ projectPath: web, exclude: [] }) .files.find((f) => f.path.endsWith('componentRegistry.generated.ts'))?.content expect(content).toBeDefined() return content as string } /** * The emitted file's own header comment legitimately MENTIONS PageRegistry.register(), * so every assertion below is made against the CODE lines only. */ function codeLinesOf(): string[] { return registryOf() .split('\n') .map((l) => l.trim()) .filter((l) => l !== '' && !l.startsWith('//')) } const HEADER = `import { PageRegistry, lazyWithRetry } from '@atlashub/smartstack';\n` describe('aggregate-component-registry — emits no registration of its own', () => { beforeEach(() => { 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('app.crm.clients', ClientsListPage);\n`, ) }) it('never emits a PageRegistry.register call', () => { expect(codeLinesOf().join('\n')).not.toContain('PageRegistry.register') }) it('never emits an administration componentKey', () => { expect(codeLinesOf().join('\n')).not.toMatch(/['"`]administration(\.[a-z0-9-]+)?['"`]/) }) it('never imports the platform-admin placeholder, nor the SDK itself', () => { const code = codeLinesOf().join('\n') expect(code).not.toContain('AdminModuleFallback') expect(code).not.toContain('@atlashub/smartstack') expect(code).not.toContain('lazyWithRetry') }) it('emits only side-effect registry imports', () => { expect(codeLinesOf()).toEqual([`import './crmRegistry';`]) }) it('aggregates a client registry that legitimately owns an administration key, with no phantom collision', () => { // Overriding a platform page stays supported — the guard is about what the AGGREGATOR // emits, never about what a client module chooses to register. Up to 5.12 such a key // appeared TWICE in the emitted file (built-in block + client registry), and keyOwners // could not see it: it only parses *Registry.ts files. write('src/pages/admin/UsersPage.tsx', 'export default () => null\n') write( 'src/extensions/admin-overrideRegistry.ts', HEADER + `const UsersPage = lazyWithRetry(() => import('@/pages/admin/UsersPage'));\n` + `PageRegistry.register('administration.users', UsersPage);\n`, ) const res = generate({ projectPath: web, exclude: [] }) expect(res.errors).toEqual([]) expect(res.collisions).toEqual([]) const content = res.files.find((f) => f.path.endsWith('componentRegistry.generated.ts'))?.content expect(content).toContain(`import './admin-overrideRegistry';`) }) })