import { test } from 'node:test'; import assert from 'node:assert/strict'; import { fileURLToPath } from 'node:url'; // Stage-5 cutover: index.js/stats.js/publish.js no longer hard-code the dialog; // they go through the shared plugin manager singleton (src/plugins.js), loaded // from config.plugins. This proves the singleton + the rewired route modules // resolve (guards the moved-file import paths) — handlers aren't called, so // dummy supabase/JWT env is enough, as in dialog-plugin.test.js. process.env.CMS_CONFIG ||= fileURLToPath(new URL('../../examples/openbureau.config.js', import.meta.url)); process.env.SUPABASE_URL ||= 'http://localhost'; process.env.SUPABASE_SERVICE_KEY ||= 'x'; process.env.JWT_SECRET ||= 'x'; process.env.SITE_DIR ||= '/tmp/nosite'; const { manager } = await import('../src/plugins.js'); test('plugins.js: manager loaded from config.plugins (openbureau → dialog)', () => { assert.deepEqual(manager.names(), ['dialog']); assert.equal(manager.has('dialog'), true); }); test('cutover: stats.js still resolves with the manager dependency', async () => { const stats = (await import('../src/routes/stats.js')).default; assert.equal(typeof stats.fetch, 'function'); // a Hono app }); test('cutover: publish.js still resolves with the manager dependency', async () => { const publish = (await import('../src/routes/publish.js')).default; assert.equal(typeof publish.fetch, 'function'); }); test('cutover: collectStats exposes dialog under its plugin name', async () => { // Counts hit a dummy supabase → each count() swallows the error and returns 0, // but the SHAPE (the stats.js contract) must hold: { dialog: { forums, … } }. const merged = await manager.collectStats({}); assert.deepEqual(merged.dialog, { forums: 0, threads: 0, comments: 0 }); const dialog = merged.dialog || { forums: 0, threads: 0, comments: 0 }; assert.deepEqual(Object.keys(dialog).sort(), ['comments', 'forums', 'threads']); });