UNPKG

@ordojs/core

Version:

Core compiler and runtime for OrdoJS framework

316 lines (279 loc) 10.3 kB
/** * @fileoverview Tests for FileSystemRouter */ import { mkdir, rm } from 'fs/promises'; import path from 'path'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { FileSystemRouter } from './fs-router.js'; // Mock the OrdoJSLexer and OrdoJSParser vi.mock('./lexer.js', () => ({ OrdoJSLexer: class MockLexer { tokenize() { return []; } } })); vi.mock('./parser.js', () => ({ OrdoJSParser: class MockParser { constructor() {} parse() { return { component: { name: 'TestComponent', serverBlock: { functions: [] } } }; } } })); describe('FileSystemRouter', () => { const testRoutesDir = 'test-routes'; let router: FileSystemRouter; beforeEach(async () => { // Create test routes directory await mkdir(testRoutesDir, { recursive: true }); router = new FileSystemRouter({ routesDir: testRoutesDir, extensions: ['.ordo'], generateCatchAll: true, baseUrl: '/' }); }); afterEach(async () => { // Clean up test directory try { await rm(testRoutesDir, { recursive: true, force: true }); } catch (error) { // Ignore cleanup errors } }); describe('filePathToRoutePath', () => { it('should convert index files to root paths', () => { const testCases = [ { input: 'index.ordo', expected: '/' }, { input: 'about/index.ordo', expected: '/about' }, { input: 'blog/posts/index.ordo', expected: '/blog/posts' } ]; for (const { input, expected } of testCases) { const filePath = path.join(testRoutesDir, input); const routePath = (router as any).filePathToRoutePath(filePath); expect(routePath).toBe(expected); } }); it('should convert dynamic routes correctly', () => { const testCases = [ { input: 'users/[id].ordo', expected: '/users/:id' }, { input: 'blog/[slug].ordo', expected: '/blog/:slug' }, { input: 'posts/[category]/[id].ordo', expected: '/posts/:category/:id' } ]; for (const { input, expected } of testCases) { const filePath = path.join(testRoutesDir, input); const routePath = (router as any).filePathToRoutePath(filePath); expect(routePath).toBe(expected); } }); it('should convert catch-all routes correctly', () => { const testCases = [ { input: 'docs/[...slug].ordo', expected: '/docs/*slug' }, { input: '[...path].ordo', expected: '/*path' } ]; for (const { input, expected } of testCases) { const filePath = path.join(testRoutesDir, input); const routePath = (router as any).filePathToRoutePath(filePath); expect(routePath).toBe(expected); } }); }); describe('extractRouteParams', () => { it('should extract dynamic parameters', () => { const testCases = [ { path: '/users/:id', expected: ['id'] }, { path: '/posts/:category/:id', expected: ['category', 'id'] }, { path: '/docs/*slug', expected: ['slug'] }, { path: '/static', expected: [] } ]; for (const { path, expected } of testCases) { const params = (router as any).extractRouteParams(path); expect(params).toEqual(expected); } }); }); describe('calculateRoutePriority', () => { it('should assign correct priorities', () => { const testCases = [ { path: '/about', isDynamic: false, isCatchAll: false, expectedPriority: 2 }, // 1 + 1 slash { path: '/users/:id', isDynamic: true, isCatchAll: false, expectedPriority: 5 }, // 2 + 1 param + 2 slashes { path: '/docs/*slug', isDynamic: false, isCatchAll: true, expectedPriority: 102 }, // 100 + 2 slashes { path: '/', isDynamic: false, isCatchAll: false, expectedPriority: 2 } // 1 + 1 slash ]; for (const { path, isDynamic, isCatchAll, expectedPriority } of testCases) { const priority = (router as any).calculateRoutePriority(path, isDynamic, isCatchAll); expect(priority).toBe(expectedPriority); } }); }); describe('matchRoute', () => { it('should match static routes correctly', () => { const route = { path: '/about', isDynamic: false, isCatchAll: false, params: [] }; expect((router as any).matchRoute(route, '/about')).toBe(true); expect((router as any).matchRoute(route, '/about/')).toBe(false); expect((router as any).matchRoute(route, '/contact')).toBe(false); }); it('should match dynamic routes correctly', () => { const route = { path: '/users/:id', isDynamic: true, isCatchAll: false, params: ['id'] }; expect((router as any).matchRoute(route, '/users/123')).toBe(true); expect((router as any).matchRoute(route, '/users/abc')).toBe(true); expect((router as any).matchRoute(route, '/users')).toBe(false); expect((router as any).matchRoute(route, '/users/123/edit')).toBe(false); }); it('should match catch-all routes correctly', () => { const route = { path: '/docs/*slug', isDynamic: false, isCatchAll: true, params: ['slug'] }; expect((router as any).matchRoute(route, '/docs/getting-started')).toBe(true); expect((router as any).matchRoute(route, '/docs/api/reference')).toBe(true); expect((router as any).matchRoute(route, '/docs')).toBe(false); expect((router as any).matchRoute(route, '/blog/post')).toBe(false); }); }); describe('extractParams', () => { it('should extract parameters from matched paths', () => { const testCases = [ { route: { path: '/users/:id', params: ['id'], isDynamic: true, isCatchAll: false }, pathname: '/users/123', expected: { id: '123' } }, { route: { path: '/posts/:category/:id', params: ['category', 'id'], isDynamic: true, isCatchAll: false }, pathname: '/posts/tech/456', expected: { category: 'tech', id: '456' } }, { route: { path: '/docs/*slug', params: ['slug'], isDynamic: false, isCatchAll: true }, pathname: '/docs/getting-started/installation', expected: { slug: 'getting-started/installation' } }, { route: { path: '/about', params: [], isDynamic: false, isCatchAll: false }, pathname: '/about', expected: {} } ]; for (const { route, pathname, expected } of testCases) { const params = router.extractParams(route as any, pathname); expect(params).toEqual(expected); } }); }); describe('generateNavigationUtils', () => { it('should generate navigation utilities with route map', async () => { // Mock routes (router as any).routes = [ { path: '/', componentName: 'HomePage' }, { path: '/users', componentName: 'UsersPage' }, { path: '/users/:id', componentName: 'UserDetailPage', params: ['id'] } ]; // Generate navigation utilities const navigationUtils = router.generateNavigationUtils(); expect(navigationUtils).toContain('export const ROUTES'); expect(navigationUtils).toContain('HomePage'); expect(navigationUtils).toContain('UsersPage'); expect(navigationUtils).toContain('UserDetailPage'); expect(navigationUtils).toContain('export function generateUrl'); expect(navigationUtils).toContain('export function navigate'); expect(navigationUtils).toContain('export function replace'); expect(navigationUtils).toContain('export function getCurrentRoute'); }); }); describe('generateCodeSplittingConfig', () => { it('should generate code splitting configuration', async () => { // Mock routes (router as any).routes = [ { path: '/', componentName: 'HomePage', filePath: path.join(testRoutesDir, 'index.ordo') }, { path: '/blog', componentName: 'BlogPage', filePath: path.join(testRoutesDir, 'blog', 'index.ordo') }, { path: '/admin', componentName: 'AdminPage', filePath: path.join(testRoutesDir, 'admin', 'index.ordo') } ]; // Generate code splitting config const config = router.generateCodeSplittingConfig(); expect(config).toHaveProperty('index'); expect(config).toHaveProperty('blog'); expect(config).toHaveProperty('admin'); expect(config.index).toContain(path.join(testRoutesDir, 'index.ordo')); expect(config.blog).toContain(path.join(testRoutesDir, 'blog', 'index.ordo')); expect(config.admin).toContain(path.join(testRoutesDir, 'admin', 'index.ordo')); }); }); describe('route filtering methods', () => { it('should filter routes correctly', async () => { // Mock routes (router as any).routes = [ { path: '/about', componentName: 'AboutPage', isDynamic: false, isCatchAll: false, prerender: false }, { path: '/users/:id', componentName: 'UserPage', isDynamic: true, isCatchAll: false, prerender: false }, { path: '/docs/*slug', componentName: 'DocsPage', isDynamic: false, isCatchAll: true, prerender: false }, { path: '/blog', componentName: 'BlogPage', isDynamic: false, isCatchAll: false, prerender: true } ]; // Test filtering methods const staticRoutes = router.getStaticRoutes(); const dynamicRoutes = router.getDynamicRoutes(); const prerenderRoutes = router.getPrerenderRoutes(); expect(staticRoutes).toHaveLength(2); // about and blog expect(dynamicRoutes).toHaveLength(1); // users/:id expect(prerenderRoutes).toHaveLength(1); // blog expect(staticRoutes.some(r => r.path === '/about')).toBe(true); expect(dynamicRoutes.some(r => r.path === '/users/:id')).toBe(true); expect(prerenderRoutes.some(r => r.path === '/blog')).toBe(true); }); }); });