/** * Depth-2 route smoke-import tests * * Locks in the DC-005 path fix (commit c39c80b) so future refactors can't * reintroduce broken require() paths in depth-2 route files. * * Background: * - The DC-005 src/ refactor moved route files into depth-2 subdirectories * (routes/auth/, routes/recipes/, routes/apps/, routes/arr/, routes/config/). * - The path-rewrite script left 67 broken require() paths across 21 files: * class A: '../../../src/...' (3 levels, goes above package root) * class B: '../src/utils/...' (1 level, resolves to nonexistent routes/src/) * class C: routes/apps/restore.js used 'utilities/responses' instead of 'utils/responses' * - The bug shipped because NO TEST imported any depth-2 route file. Only * depth-1 routes were tested. * * These tests do not exercise the routes' handler logic — that would require * building full app contexts per route family. They only verify: * 1. The module can be loaded without a MODULE_NOT_FOUND error. * 2. It exports a callable factory function (module.exports = function(deps){...}). * 3. The factory runs without throwing when given the minimum required deps. * * That alone catches ~80% of the DC-005 class: any require() with a wrong path * blows up at module load time, before the factory is even called. Path bugs * that only manifest at handler invocation time (e.g. require of a dep only * used inside a handler body) won't be caught — but those are rare. */ const fs = require('fs'); const path = require('path'); const { universalDeps } = require('./test-helpers/universal-deps'); const PKG_ROOT = path.join(__dirname, '..'); const DEPTH2_DIRS = ['apps', 'arr', 'auth', 'config', 'recipes']; function discoverDepth2Routes() { const out = []; for (const sub of DEPTH2_DIRS) { const dir = path.join(PKG_ROOT, 'routes', sub); if (!fs.existsSync(dir)) continue; for (const f of fs.readdirSync(dir).filter(x => x.endsWith('.js'))) { out.push(path.join('routes', sub, f)); } } return out.sort(); } describe('Depth-2 Route Smoke Imports (locks in DC-005 path fix)', () => { const routes = discoverDepth2Routes(); // routes/auth/totp.js was already fixed in the DC-006 commit (one of the // 21 files in the DC-005 fix batch). It was the first to be detected because // DC-006 added tests that imported it. Every other route in this list has // historically had ZERO test coverage — that's the gap this test closes. describe.each(routes)('module %s', (relPath) => { test('loads without MODULE_NOT_FOUND (catches DC-005 class A/B/C paths)', () => { // If any require() in this file uses '../../../src/...' (class A) or // '../src/utils/...' (class B) or wrong directory name (class C), // this require() throws and the test fails. expect(() => require(path.join(PKG_ROOT, relPath))).not.toThrow(); }); test('exports a factory function (module.exports = function(deps){...})', () => { const factory = require(path.join(PKG_ROOT, relPath)); expect(typeof factory).toBe('function'); }); test('factory runs without throwing given minimal deps', () => { const factory = require(path.join(PKG_ROOT, relPath)); // universalDeps is a Proxy that returns no-op functions for any // property access. So both patterns work: // function({ a, b, c }) { ... } // picks a, b, c from universalDeps // function(ctx) { ctx.licenseManager.requirePremium(...) } // works // Any factory destructure is satisfied. Any method call returns undefined // (callable no-op), so handler-invocation paths also don't crash here. // We are ONLY catching module-load failures and factory-call-time // failures — not handler-invocation behaviour. expect(() => factory(universalDeps)).not.toThrow(); }); }); describe('Source-of-truth: no broken paths introduced', () => { test('no depth-2 route uses ../../../src/ (class A)', () => { const offenders = []; for (const relPath of routes) { const content = fs.readFileSync(path.join(PKG_ROOT, relPath), 'utf8'); if (content.match(/require\(['"]\.\.\/\.\.\/\.\.\/src/)) offenders.push(relPath); } expect(offenders).toEqual([]); }); test('no depth-2 route uses ../src/ (class B — would resolve to routes/src/)', () => { const offenders = []; for (const relPath of routes) { const content = fs.readFileSync(path.join(PKG_ROOT, relPath), 'utf8'); // Match '../src/' NOT preceded by another '/' (which would be class A) if (content.match(/require\(['"]\.\.\/src\//)) offenders.push(relPath); } expect(offenders).toEqual([]); }); test('no depth-2 route uses src/utilities/responses (class C — module lives at src/utils/responses)', () => { const offenders = []; for (const relPath of routes) { const content = fs.readFileSync(path.join(PKG_ROOT, relPath), 'utf8'); if (content.match(/['"]\.\.\/\.\.\/src\/utilities\/responses['"]/)) offenders.push(relPath); } expect(offenders).toEqual([]); }); }); });