import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { exec } from 'node:child_process'; import { promisify } from 'node:util'; import http from 'node:http'; import https from 'node:https'; import fs from 'node:fs'; import path from 'node:path'; const execAsync = promisify(exec); const ROOT_DIR = path.resolve(__dirname, '..'); const BACKEND_PORT = 3443; const FRONTEND_PORT = 5174; describe('DTP Web Application Build Tests', () => { describe('Backend Build', () => { it('should have dist/web-app.js output', () => { const distPath = path.join(ROOT_DIR, 'dist', 'web-app.js'); expect(fs.existsSync(distPath)).toBe(true); }); }); describe('Frontend Build', () => { it('should build frontend without errors', async () => { const { stdout, stderr } = await execAsync('cd frontend && pnpm build', { cwd: ROOT_DIR, timeout: 120000, }); expect(stderr).toBe(''); expect(stdout).toContain('built in'); }, 120000); it('should have dist/client/index.html output', () => { const indexPath = path.join(ROOT_DIR, 'dist', 'client', 'index.html'); expect(fs.existsSync(indexPath)).toBe(true); }); it('should have dist/client/assets output', () => { const assetsDir = path.join(ROOT_DIR, 'dist', 'client', 'assets'); expect(fs.existsSync(assetsDir)).toBe(true); const jsFiles = fs.readdirSync(assetsDir).filter(f => f.endsWith('.js')); const cssFiles = fs.readdirSync(assetsDir).filter(f => f.endsWith('.css')); expect(jsFiles.length).toBeGreaterThan(0); expect(cssFiles.length).toBeGreaterThan(0); }); }); describe('Configuration Tests', () => { it('should have SSL certificates', () => { const keyPath = path.join(ROOT_DIR, 'ssl', 'code-dev.g4dge7.com.key'); const crtPath = path.join(ROOT_DIR, 'ssl', 'code-dev.g4dge7.com.crt'); expect(fs.existsSync(keyPath)).toBe(true); expect(fs.existsSync(crtPath)).toBe(true); }); it('should have valid SSL key file', () => { const keyPath = path.join(ROOT_DIR, 'ssl', 'code-dev.g4dge7.com.key'); const content = fs.readFileSync(keyPath, 'utf-8'); expect(content).toContain('-----BEGIN PRIVATE KEY-----'); }); it('should have valid SSL certificate', () => { const crtPath = path.join(ROOT_DIR, 'ssl', 'code-dev.g4dge7.com.crt'); const content = fs.readFileSync(crtPath, 'utf-8'); expect(content).toContain('-----BEGIN CERTIFICATE-----'); }); }); }); describe('DTP Web Application Runtime Tests', () => { let backendRunning = false; let frontendRunning = false; afterAll(async () => { // Clean up if we started processes (in real tests, you'd manage lifecycle differently) }); describe('Backend Server', () => { it('should respond on configured port', async () => { // This test checks if the backend is reachable // Note: In a real test, you'd start the backend process first const options = { hostname: 'localhost', port: BACKEND_PORT, method: 'GET', path: '/', }; return new Promise((resolve, reject) => { const req = http.request(options, (res) => { // Expect some response (will be 404 for / but proves server is running) expect(res.statusCode).toBeDefined(); resolve(); }); req.on('error', (err) => { // If connection refused, backend isn't running (this is expected for manual testing) if (err.code === 'ECONNREFUSED') { resolve(); } else { reject(err); } }); req.end(); }); }); }); describe('Frontend Proxy Configuration', () => { it('should have vite config with correct proxy settings', () => { const viteConfigPath = path.join(ROOT_DIR, 'frontend', 'vite.config.ts'); const content = fs.readFileSync(viteConfigPath, 'utf-8'); // Verify proxy targets backend port expect(content).toContain(`target: 'http://localhost:${BACKEND_PORT}'`); // Verify Socket.io proxy with websockets expect(content).toContain("'/socket.io'"); expect(content).toContain('ws: true'); // Verify auth proxy expect(content).toContain("'/auth'"); // Verify api proxy expect(content).toContain("'/api'"); }); it('should have vite config with HTTPS', () => { const viteConfigPath = path.join(ROOT_DIR, 'frontend', 'vite.config.ts'); const content = fs.readFileSync(viteConfigPath, 'utf-8'); expect(content).toContain('https:'); expect(content).toContain('.key'); expect(content).toContain('.crt'); }); it('should have correct frontend port in config', () => { const viteConfigPath = path.join(ROOT_DIR, 'frontend', 'vite.config.ts'); const content = fs.readFileSync(viteConfigPath, 'utf-8'); expect(content).toContain(`port: ${FRONTEND_PORT}`); }); }); }); describe('Environment Configuration', () => { it('should have environment variables for HTTPS', () => { const envPath = path.join(ROOT_DIR, 'src', 'config', 'env.ts'); const content = fs.readFileSync(envPath, 'utf-8'); expect(content).toContain('https'); expect(content).toContain('port: parseInt'); expect(content).toContain('keyFile'); expect(content).toContain('crtFile'); }); it('should have frontend port configured', () => { const envPath = path.join(ROOT_DIR, 'src', 'config', 'env.ts'); const content = fs.readFileSync(envPath, 'utf-8'); expect(content).toContain('frontend'); expect(content).toContain('port:'); }); }); describe('Dependencies', () => { it('should have all required dependencies in root package.json', () => { const pkgPath = path.join(ROOT_DIR, 'package.json'); const pkgContent = fs.readFileSync(pkgPath, 'utf-8'); const pkg = JSON.parse(pkgContent); // Backend dependencies expect(pkg.dependencies).toHaveProperty('socket.io'); expect(pkg.dependencies).toHaveProperty('express'); expect(pkg.dependencies).toHaveProperty('express-session'); // Frontend dependencies expect(pkg.dependencies).toHaveProperty('react'); expect(pkg.dependencies).toHaveProperty('react-dom'); // Dev dependencies expect(pkg.devDependencies).toHaveProperty('vite'); expect(pkg.devDependencies).toHaveProperty('typescript'); expect(pkg.devDependencies).toHaveProperty('vitest'); }); });