import { describe, it, expect, beforeAll } from '@jest/globals'; import path from 'path'; import fs from 'fs'; import * as pathUtils from '../../src/utils/path.utils.js'; /** * Tests for path.utils - Ensure robust path resolution * across different execution scenarios. * * These tests verify the module resolves project paths correctly * regardless of the directory from which the process is executed. * * NOTE: Because the module initializes on import, these tests assert * the module behavior after it has been loaded and cannot mock initialization. */ describe('path.utils - Robust project path resolution', () => { beforeAll(() => { // Silence logs during tests process.env.NODE_ENV = 'test'; }); describe('Scenario 1: Exported paths verification', () => { it('should export all required paths', () => { // Verify all exported paths exist as properties expect(pathUtils.publicDirectoryPath).toBeDefined(); expect(pathUtils.frontendDirectoryPath).toBeDefined(); expect(pathUtils.webcomponentBundlePath).toBeDefined(); expect(pathUtils.frontendHtmlPath).toBeDefined(); expect(pathUtils.publicApiHtmlFilePath).toBeDefined(); expect(pathUtils.internalApiHtmlFilePath).toBeDefined(); // Verify the paths are non-empty strings expect(typeof pathUtils.publicDirectoryPath).toBe('string'); expect(pathUtils.publicDirectoryPath.length).toBeGreaterThan(0); expect(typeof pathUtils.frontendDirectoryPath).toBe('string'); expect(pathUtils.frontendDirectoryPath.length).toBeGreaterThan(0); expect(typeof pathUtils.webcomponentBundlePath).toBe('string'); expect(pathUtils.webcomponentBundlePath.length).toBeGreaterThan(0); }); it('should build coherent paths (frontend inside public)', () => { // frontendDirectoryPath should be a subdirectory of publicDirectoryPath expect(pathUtils.frontendDirectoryPath.startsWith(pathUtils.publicDirectoryPath)).toBe(true); // Ensure it contains 'frontend' expect(pathUtils.frontendDirectoryPath).toContain('frontend'); }); it('should build webcomponentBundlePath inside public', () => { // webcomponentBundlePath must be inside publicDirectoryPath expect(pathUtils.webcomponentBundlePath.startsWith(pathUtils.publicDirectoryPath)).toBe(true); // Should end with the correct bundle name expect(pathUtils.webcomponentBundlePath).toContain('openvidu-meet.bundle.min.js'); }); it('should build coherent HTML paths', () => { // frontendHtmlPath should be inside frontendDirectoryPath expect(pathUtils.frontendHtmlPath.startsWith(pathUtils.frontendDirectoryPath)).toBe(true); expect(pathUtils.frontendHtmlPath).toContain('index.html'); // OpenAPI paths should reference 'openapi' expect(pathUtils.publicApiHtmlFilePath).toContain('openapi'); expect(pathUtils.publicApiHtmlFilePath).toContain('public.html'); expect(pathUtils.internalApiHtmlFilePath).toContain('openapi'); expect(pathUtils.internalApiHtmlFilePath).toContain('internal.html'); }); }); describe('Scenario 2: Directory structure validation', () => { it('should contain "backend" and "public" in publicDirectoryPath', () => { // Path should contain both segments expect(pathUtils.publicDirectoryPath).toContain('backend'); expect(pathUtils.publicDirectoryPath).toContain('public'); // Verify backend appears before public const segments = pathUtils.publicDirectoryPath.split(path.sep); const backendIndex = segments.findIndex((s: string) => s === 'backend'); const publicIndex = segments.findIndex((s: string) => s === 'public'); expect(backendIndex).toBeGreaterThanOrEqual(0); expect(publicIndex).toBeGreaterThan(backendIndex); }); it('should work for both meet-ce and meet-pro', () => { // Path may be identifiable as CE or PRO const isCE = pathUtils.publicDirectoryPath.includes('meet-ce'); const isPRO = pathUtils.publicDirectoryPath.includes('meet-pro'); // The structure backend/public must exist expect(pathUtils.publicDirectoryPath).toMatch(/backend[\/\\]public$/); }); }); describe('Scenario 3: Path integrity validation', () => { it('should use correct path separators for the OS', () => { // Should not contain mixed separators const hasForwardSlash = pathUtils.publicDirectoryPath.includes('/'); const hasBackslash = pathUtils.publicDirectoryPath.includes('\\'); // Must have at least one type of separator expect(hasForwardSlash || hasBackslash).toBe(true); // Verify normalized consistency const normalized = path.normalize(pathUtils.publicDirectoryPath); expect(pathUtils.publicDirectoryPath).toBe(normalized); }); it('should produce absolute paths', () => { // All exported paths must be absolute expect(path.isAbsolute(pathUtils.publicDirectoryPath)).toBe(true); expect(path.isAbsolute(pathUtils.frontendDirectoryPath)).toBe(true); expect(path.isAbsolute(pathUtils.webcomponentBundlePath)).toBe(true); expect(path.isAbsolute(pathUtils.frontendHtmlPath)).toBe(true); expect(path.isAbsolute(pathUtils.publicApiHtmlFilePath)).toBe(true); expect(path.isAbsolute(pathUtils.internalApiHtmlFilePath)).toBe(true); }); it('should resolve normalized paths (no .. or . segments)', () => { // Paths must not contain relative segments expect(pathUtils.publicDirectoryPath).not.toContain('..'); expect(pathUtils.publicDirectoryPath).not.toMatch(/\/\.\//); expect(pathUtils.frontendDirectoryPath).not.toContain('..'); expect(pathUtils.webcomponentBundlePath).not.toContain('..'); }); }); describe('Scenario 4: Existence of critical directories', () => { it('should point to a public/ directory whose parent exists', () => { // public directory might not exist at test time, // but the path should be valid const publicDir = pathUtils.publicDirectoryPath; // Parent directory must exist const parentDir = path.dirname(publicDir); expect(fs.existsSync(parentDir)).toBe(true); }); it('should have an accessible backend/ directory up the tree', () => { // Walk up from publicDirectoryPath to find backend/ let currentPath = pathUtils.publicDirectoryPath; let foundBackend = false; // Up to 10 levels for (let i = 0; i < 10; i++) { if (path.basename(currentPath) === 'backend') { foundBackend = true; // Ensure this backend dir contains src/ const srcPath = path.join(currentPath, 'src'); expect(fs.existsSync(srcPath)).toBe(true); break; } const parent = path.dirname(currentPath); if (parent === currentPath) break; // Reached root currentPath = parent; } expect(foundBackend).toBe(true); }); }); describe('Scenario 5: Robustness and consistency', () => { it('should keep the same resolution across multiple accesses', () => { // Paths must be consistent const path1 = pathUtils.publicDirectoryPath; const path2 = pathUtils.publicDirectoryPath; expect(path1).toBe(path2); expect(path1).toStrictEqual(path2); }); it('should use path.join correctly (structure verification)', () => { // frontendDirectoryPath should equal public + frontend const expectedFrontend = path.join(pathUtils.publicDirectoryPath, 'frontend'); expect(pathUtils.frontendDirectoryPath).toBe(expectedFrontend); // Verify webcomponent const expectedWebcomponent = path.join( pathUtils.publicDirectoryPath, 'webcomponent', 'openvidu-meet.bundle.min.js' ); expect(pathUtils.webcomponentBundlePath).toBe(expectedWebcomponent); }); }); });