backend: Updated configuration for backend unit testing
Sets up Jest with ts-jest for unit and integration tests. Includes configurations for: - ESM support - Module resolution - Path aliasing - Adds unit tests to validate path utilities
This commit is contained in:
parent
4e65ca2d04
commit
498e837c70
@ -3,28 +3,29 @@ import { createDefaultEsmPreset } from 'ts-jest';
|
|||||||
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
||||||
const jestConfig = {
|
const jestConfig = {
|
||||||
displayName: 'backend',
|
displayName: 'backend',
|
||||||
...createDefaultEsmPreset({
|
...createDefaultEsmPreset(),
|
||||||
tsconfig: 'tsconfig.json'
|
|
||||||
}),
|
|
||||||
testTimeout: 60000,
|
testTimeout: 60000,
|
||||||
resolver: 'ts-jest-resolver',
|
resolver: 'ts-jest-resolver',
|
||||||
testMatch: ['**/?(*.)+(spec|test).[tj]s?(x)'],
|
testMatch: ['**/?(*.)+(spec|test).[tj]s?(x)'],
|
||||||
moduleFileExtensions: ['js', 'ts', 'json', 'node'],
|
moduleFileExtensions: ['js', 'ts', 'json', 'node'],
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
globals: {
|
extensionsToTreatAsEsm: ['.ts'],
|
||||||
'ts-jest': {
|
|
||||||
tsconfig: 'tsconfig.json'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
'^@openvidu-meet/typings$': '<rootDir>/../typings/src/index.ts'
|
'^@openvidu-meet/typings$': '<rootDir>/../typings/src/index.ts',
|
||||||
|
'^(\\.{1,2}/.*)\\.js$': '$1' // Permite importar .js que resuelven a .ts
|
||||||
},
|
},
|
||||||
// transform: {
|
transform: {
|
||||||
// '^.+\\.tsx?$': ['ts-jest', {
|
'^.+\\.tsx?$': ['ts-jest', {
|
||||||
// // Opcionalmente, especifica el archivo tsconfig si es necesario
|
tsconfig: {
|
||||||
// tsconfig: 'tsconfig.json',
|
module: 'esnext',
|
||||||
// }],
|
moduleResolution: 'node16',
|
||||||
// },
|
esModuleInterop: true,
|
||||||
|
allowSyntheticDefaultImports: true,
|
||||||
|
isolatedModules: true
|
||||||
|
},
|
||||||
|
useESM: true
|
||||||
|
}]
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default jestConfig;
|
export default jestConfig;
|
||||||
|
|||||||
@ -43,7 +43,7 @@
|
|||||||
"test:integration-participants": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/participants\" --ci --reporters=default --reporters=jest-junit",
|
"test:integration-participants": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/participants\" --ci --reporters=default --reporters=jest-junit",
|
||||||
"test:integration-meetings": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/meetings\" --ci --reporters=default --reporters=jest-junit",
|
"test:integration-meetings": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/meetings\" --ci --reporters=default --reporters=jest-junit",
|
||||||
"test:integration-users": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/users\" --ci --reporters=default --reporters=jest-junit",
|
"test:integration-users": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/integration/api/users\" --ci --reporters=default --reporters=jest-junit",
|
||||||
"test:unit": "pnpm exec jest --runInBand --forceExit --testPathPattern \"tests/unit\" --ci --reporters=default --reporters=jest-junit",
|
"test:unit": "node --experimental-vm-modules ../../node_modules/.bin/jest --runInBand --forceExit --testPathPattern \"tests/unit\" --ci --reporters=default --reporters=jest-junit",
|
||||||
"lint:fix": "eslint src --fix",
|
"lint:fix": "eslint src --fix",
|
||||||
"format:code": "prettier --ignore-path .gitignore --write '**/*.{ts,js,json,md}'"
|
"format:code": "prettier --ignore-path .gitignore --write '**/*.{ts,js,json,md}'"
|
||||||
},
|
},
|
||||||
|
|||||||
190
meet-ce/backend/tests/unit/path.utils.spec.ts
Normal file
190
meet-ce/backend/tests/unit/path.utils.spec.ts
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user