const assert = require('node:assert/strict'); const http = require('node:http'); const test = require('node:test'); const jwt = require('jsonwebtoken'); const app = require('../app'); const db = require('../src/config/db'); const JWT_SECRET = process.env.JWT_SECRET || 'test-jwt-secret'; process.env.JWT_SECRET = JWT_SECRET; let originalQuery; const createToken = (payload = {}) => jwt.sign( { id: 1, dni: '58045340X', id_proveedor: 675, ...payload }, JWT_SECRET, { expiresIn: '1h' } ); const withServer = async (callback) => new Promise((resolve, reject) => { const server = app.listen(0, '127.0.0.1'); server.on('error', reject); server.on('listening', async () => { try { const result = await callback(server); server.close((closeError) => { if (closeError) { reject(closeError); return; } resolve(result); }); } catch (error) { server.close(() => reject(error)); } }); }); const requestJson = async ({ port, path, authorization }) => new Promise((resolve, reject) => { const req = http.request( { hostname: '127.0.0.1', port, method: 'GET', path, headers: authorization ? { authorization } : {} }, (res) => { let rawBody = ''; res.on('data', (chunk) => { rawBody += chunk; }); res.on('end', () => { const body = rawBody ? JSON.parse(rawBody) : null; resolve({ statusCode: res.statusCode, body }); }); } ); req.on('error', reject); req.end(); }); test.before(() => { originalQuery = db.query; }); test.after(() => { db.query = originalQuery; }); test('GET /api/trips/active está registrado en /api', () => { const apiRouterLayers = app._router.stack.filter( (layer) => layer.name === 'router' && layer.regexp && layer.regexp.toString().includes('^\\/api\\/?(?=\\/|$)') ); assert.ok(apiRouterLayers.length > 0, 'Router /api is not mounted'); const activeRouteLayer = apiRouterLayers .flatMap((routerLayer) => routerLayer.handle.stack) .find( (layer) => layer.route && layer.route.path === '/trips/active' && layer.route.methods.get ); assert.ok(activeRouteLayer, 'GET /api/trips/active route is not defined'); }); test('GET /api/trips/active devuelve viaje activo', async () => { const mockedTrip = { id_viaje: 123, cod_viaje: 'AB-2024-001', n_proveedor: 1, id_estado: 4, estado: 'CARGA DE MERCANCÍA', estado_en: 'CARGO LOADING', nombrea: 'ORIGEN', nombreb: 'DESTINO', direcciona: 'Direccion A', direccionb: 'Direccion B', fecha_salida: '2026-02-06 08:30:00', fecha_llegada: '2026-02-06 14:45:00', inicio_fin: 'ES-28001/ES-08001', matricula: '1234ABC', observaciones_mercancia: 'Fragil' }; db.query = async (sql, params) => { assert.match(sql, /FROM c_viajes_proveedor p/); assert.match(sql, /INNER JOIN t_viaje_estados e/); assert.match(sql, /fecha_salida/); assert.match(sql, /fecha_llegada/); assert.match(sql, /INNER JOIN m_proveedores_trasportistas t/); assert.deepEqual(params, ['58045340X', 2, 6]); return [[mockedTrip]]; }; const response = await withServer(async (server) => requestJson({ port: server.address().port, path: '/api/trips/active', authorization: `Bearer ${createToken()}` }) ); assert.equal(response.statusCode, 200); assert.deepEqual(response.body, { success: true, active_trip: mockedTrip }); }); test('GET /api/trips/active devuelve active_trip null cuando no hay', async () => { db.query = async () => [[]]; const response = await withServer(async (server) => requestJson({ port: server.address().port, path: '/api/trips/active', authorization: `Bearer ${createToken()}` }) ); assert.equal(response.statusCode, 200); assert.deepEqual(response.body, { success: true, active_trip: null }); }); test('GET /api/trips/active devuelve fechas con hora completa', async () => { db.query = async () => [[{ id_viaje: 123, cod_viaje: 'AB-2024-001', n_proveedor: 1, id_estado: 4, estado: 'CARGA DE MERCANCÍA', estado_en: 'CARGO LOADING', nombrea: 'ORIGEN', nombreb: 'DESTINO', direcciona: 'Direccion A', direccionb: 'Direccion B', fecha_salida: '2026-02-06 08:30:00', fecha_llegada: '2026-02-06 14:45:00', inicio_fin: 'ES-28001/ES-08001', matricula: '1234ABC', observaciones_mercancia: 'Fragil' }]]; const response = await withServer(async (server) => requestJson({ port: server.address().port, path: '/api/trips/active', authorization: `Bearer ${createToken()}` }) ); assert.equal(response.statusCode, 200); assert.match(response.body.active_trip.fecha_salida, /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/); assert.match(response.body.active_trip.fecha_llegada, /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/); }); test('GET /api/trips/active devuelve 401 sin token', async () => { db.query = async () => { throw new Error('db.query should not be called without token'); }; const response = await withServer(async (server) => requestJson({ port: server.address().port, path: '/api/trips/active' }) ); assert.equal(response.statusCode, 401); }); test('GET /api/trips/active devuelve 500 en error interno', async () => { db.query = async () => { throw new Error('forced db failure'); }; const response = await withServer(async (server) => requestJson({ port: server.address().port, path: '/api/trips/active', authorization: `Bearer ${createToken()}` }) ); assert.equal(response.statusCode, 500); assert.deepEqual(response.body, { success: false, error: 'Internal server error' }); });