Enhance trips API with pagination and filtering support, including validation for parameters
This commit is contained in:
@@ -19,6 +19,9 @@ const LEGACY_STATUS_PHOTO_FIELD_MAX_LENGTH = 100;
|
|||||||
const LEGACY_INTERMEDIATE_POINT_VALUE_SEPARATOR = ':|:';
|
const LEGACY_INTERMEDIATE_POINT_VALUE_SEPARATOR = ':|:';
|
||||||
const LEGACY_INTERMEDIATE_POINT_REFERENCE_REGEX = /^[0-9]+$/;
|
const LEGACY_INTERMEDIATE_POINT_REFERENCE_REGEX = /^[0-9]+$/;
|
||||||
const MOBILE_TRIPS_ALLOWED_STATES = [7, 8, 9, 1];
|
const MOBILE_TRIPS_ALLOWED_STATES = [7, 8, 9, 1];
|
||||||
|
const MOBILE_TRIPS_DEFAULT_PAGE = 1;
|
||||||
|
const MOBILE_TRIPS_DEFAULT_LIMIT = 25;
|
||||||
|
const MOBILE_TRIPS_MAX_LIMIT = 100;
|
||||||
const CLEAR_STATUS_FALLBACK_STATE = 1;
|
const CLEAR_STATUS_FALLBACK_STATE = 1;
|
||||||
const INTERMEDIATE_POINT_ALLOWED_STATES = [3, 4, 5];
|
const INTERMEDIATE_POINT_ALLOWED_STATES = [3, 4, 5];
|
||||||
const INTERMEDIATE_POINT_ALLOWED_STATES_SET = new Set(INTERMEDIATE_POINT_ALLOWED_STATES);
|
const INTERMEDIATE_POINT_ALLOWED_STATES_SET = new Set(INTERMEDIATE_POINT_ALLOWED_STATES);
|
||||||
@@ -27,6 +30,7 @@ const FAILED_TRIP_STATE = 9;
|
|||||||
const AGHEERA_CLIENT_ID = 532;
|
const AGHEERA_CLIENT_ID = 532;
|
||||||
const INTERMEDIATE_POINT_STATUS_IDS = new Set([3, 4, 5]);
|
const INTERMEDIATE_POINT_STATUS_IDS = new Set([3, 4, 5]);
|
||||||
const INCIDENCE_TEXT_CONTROL_CHARACTERS_REGEX = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g;
|
const INCIDENCE_TEXT_CONTROL_CHARACTERS_REGEX = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g;
|
||||||
|
const SQL_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
||||||
const GLOBAL_STATUS_KEYS_BY_STATE_ID = new Map([
|
const GLOBAL_STATUS_KEYS_BY_STATE_ID = new Map([
|
||||||
[1, 'assigned'],
|
[1, 'assigned'],
|
||||||
[2, 'en_camino'],
|
[2, 'en_camino'],
|
||||||
@@ -48,6 +52,59 @@ const appendTripStatusDebugLog = (payload) => {
|
|||||||
|
|
||||||
console.info('[TripStatusDebug]', payload);
|
console.info('[TripStatusDebug]', payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const parseTripsPositiveInteger = (value, defaultValue) => {
|
||||||
|
if (value === undefined) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!/^\d+$/.test(String(value))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedValue = Number.parseInt(value, 10);
|
||||||
|
return parsedValue >= 1 ? parsedValue : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseTripsStatusIds = (value) => {
|
||||||
|
if (value === undefined || value === '') {
|
||||||
|
return MOBILE_TRIPS_ALLOWED_STATES;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rawStatusIds = String(value).split(',');
|
||||||
|
|
||||||
|
if (rawStatusIds.some((statusId) => !/^\d+$/.test(statusId))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rawStatusIds.map((statusId) => Number.parseInt(statusId, 10));
|
||||||
|
};
|
||||||
|
|
||||||
|
const isValidSqlDate = (value) => {
|
||||||
|
if (value === undefined) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SQL_DATE_REGEX.test(String(value))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [year, month, day] = String(value).split('-').map(Number);
|
||||||
|
const date = new Date(Date.UTC(year, month - 1, day));
|
||||||
|
|
||||||
|
return (
|
||||||
|
date.getUTCFullYear() === year &&
|
||||||
|
date.getUTCMonth() === month - 1 &&
|
||||||
|
date.getUTCDate() === day
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addOneDayToSqlDate = (value) => {
|
||||||
|
const [year, month, day] = String(value).split('-').map(Number);
|
||||||
|
const date = new Date(Date.UTC(year, month - 1, day + 1));
|
||||||
|
|
||||||
|
return date.toISOString().slice(0, 10);
|
||||||
|
};
|
||||||
const getTripStatusUpdatesLogPath = () =>
|
const getTripStatusUpdatesLogPath = () =>
|
||||||
process.env.TRIP_STATUS_UPDATES_LOG_PATH ||
|
process.env.TRIP_STATUS_UPDATES_LOG_PATH ||
|
||||||
'/var/log/status.log';
|
'/var/log/status.log';
|
||||||
@@ -3587,6 +3644,8 @@ const getActiveTrip = async (req, res) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getTrips = async (req, res) => {
|
const getTrips = async (req, res) => {
|
||||||
|
const startedAt = Date.now();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const dni = req.user?.dni;
|
const dni = req.user?.dni;
|
||||||
|
|
||||||
@@ -3594,6 +3653,79 @@ const getTrips = async (req, res) => {
|
|||||||
return res.status(401).json({ error: 'Unauthorized' });
|
return res.status(401).json({ error: 'Unauthorized' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const page = parseTripsPositiveInteger(req.query.page, MOBILE_TRIPS_DEFAULT_PAGE);
|
||||||
|
const requestedLimit = parseTripsPositiveInteger(req.query.limit, MOBILE_TRIPS_DEFAULT_LIMIT);
|
||||||
|
const statusIds = parseTripsStatusIds(req.query.status_ids);
|
||||||
|
|
||||||
|
if (page === null || requestedLimit === null || requestedLimit > MOBILE_TRIPS_MAX_LIMIT) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Invalid pagination parameters'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!statusIds || statusIds.length === 0) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Invalid status_ids parameter'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isValidSqlDate(req.query.date_from) || !isValidSqlDate(req.query.date_to)) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Invalid date parameter'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
req.query.date_from !== undefined &&
|
||||||
|
req.query.date_to !== undefined &&
|
||||||
|
req.query.date_from > req.query.date_to
|
||||||
|
) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Invalid date range'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const limit = requestedLimit;
|
||||||
|
const offset = (page - 1) * limit;
|
||||||
|
const whereClauses = [
|
||||||
|
'p.dni = ?',
|
||||||
|
'v.id_estado IN (' + statusIds.map(() => '?').join(', ') + ')'
|
||||||
|
];
|
||||||
|
const queryParams = [dni, ...statusIds];
|
||||||
|
|
||||||
|
if (req.query.date_from !== undefined) {
|
||||||
|
whereClauses.push('COALESCE(p.fecha_salida, v.fecha_salida) >= ?');
|
||||||
|
queryParams.push(req.query.date_from);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.query.date_to !== undefined) {
|
||||||
|
whereClauses.push('COALESCE(p.fecha_salida, v.fecha_salida) < ?');
|
||||||
|
queryParams.push(addOneDayToSqlDate(req.query.date_to));
|
||||||
|
}
|
||||||
|
|
||||||
|
const fromAndWhereSql = `
|
||||||
|
FROM c_viajes_proveedor p
|
||||||
|
INNER JOIN c_viajes v
|
||||||
|
ON v.id_viaje = p.id_viaje
|
||||||
|
INNER JOIN m_proveedores_trasportistas t
|
||||||
|
ON t.dni = p.dni
|
||||||
|
AND t.desactivado = 0
|
||||||
|
LEFT JOIN m_puntos_envio_recogida p1
|
||||||
|
ON p1.id_punto = p.id_punto_recogida
|
||||||
|
LEFT JOIN m_puntos_envio_recogida p2
|
||||||
|
ON p2.id_punto = p.id_punto_entrega
|
||||||
|
WHERE ${whereClauses.join('\n AND ')}`;
|
||||||
|
|
||||||
|
const [[countRow]] = await db.query(
|
||||||
|
`SELECT COUNT(*) AS total ${fromAndWhereSql}`,
|
||||||
|
queryParams
|
||||||
|
);
|
||||||
|
const total = Number.parseInt(countRow?.total, 10) || 0;
|
||||||
|
|
||||||
const [rows] = await db.query(
|
const [rows] = await db.query(
|
||||||
`SELECT
|
`SELECT
|
||||||
p.id_viaje AS id_viaje,
|
p.id_viaje AS id_viaje,
|
||||||
@@ -3688,30 +3820,32 @@ const getTrips = async (req, res) => {
|
|||||||
END AS fecha_llegada,
|
END AS fecha_llegada,
|
||||||
NULLIF(TRIM(v.observaciones_mercancia), '') AS observaciones_mercancia,
|
NULLIF(TRIM(v.observaciones_mercancia), '') AS observaciones_mercancia,
|
||||||
NULLIF(TRIM(v.observaciones_cliente), '') AS observaciones_cliente
|
NULLIF(TRIM(v.observaciones_cliente), '') AS observaciones_cliente
|
||||||
FROM c_viajes_proveedor p
|
${fromAndWhereSql}
|
||||||
INNER JOIN c_viajes v
|
ORDER BY COALESCE(p.fecha_salida, v.fecha_salida) DESC, p.id_viaje DESC
|
||||||
ON v.id_viaje = p.id_viaje
|
LIMIT ? OFFSET ?`,
|
||||||
INNER JOIN m_proveedores_trasportistas t
|
[...queryParams, limit, offset]
|
||||||
ON t.dni = p.dni
|
|
||||||
AND t.desactivado = 0
|
|
||||||
LEFT JOIN m_puntos_envio_recogida p1
|
|
||||||
ON p1.id_punto = p.id_punto_recogida
|
|
||||||
LEFT JOIN m_puntos_envio_recogida p2
|
|
||||||
ON p2.id_punto = p.id_punto_entrega
|
|
||||||
WHERE p.dni = ?
|
|
||||||
AND v.id_estado IN (?, ?, ?, ?)
|
|
||||||
ORDER BY COALESCE(p.fecha_salida, v.fecha_salida) DESC, p.id_viaje DESC`,
|
|
||||||
[
|
|
||||||
dni,
|
|
||||||
MOBILE_TRIPS_ALLOWED_STATES[0],
|
|
||||||
MOBILE_TRIPS_ALLOWED_STATES[1],
|
|
||||||
MOBILE_TRIPS_ALLOWED_STATES[2],
|
|
||||||
MOBILE_TRIPS_ALLOWED_STATES[3]
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.info('[TripsList]', {
|
||||||
|
dni,
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
filters: {
|
||||||
|
status_ids: statusIds,
|
||||||
|
date_from: req.query.date_from || null,
|
||||||
|
date_to: req.query.date_to || null
|
||||||
|
},
|
||||||
|
rows: rows.length,
|
||||||
|
total,
|
||||||
|
elapsed_ms: Date.now() - startedAt
|
||||||
|
});
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
trips: rows
|
trips: rows,
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
total,
|
||||||
|
has_more: offset + rows.length < total
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error getting trips list:', {
|
console.error('Error getting trips list:', {
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ test('GET /api/trips está registrado en /api', () => {
|
|||||||
assert.ok(tripsRouteLayer, 'GET /api/trips route is not defined');
|
assert.ok(tripsRouteLayer, 'GET /api/trips route is not defined');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/trips devuelve viajes del transportista autenticado con aliases legacy', async () => {
|
test('GET /api/trips devuelve viajes del transportista autenticado con aliases legacy e incluye asignados', async () => {
|
||||||
const mockedTrips = [
|
const mockedTrips = [
|
||||||
{
|
{
|
||||||
id_viaje: 84919,
|
id_viaje: 84919,
|
||||||
@@ -116,26 +116,36 @@ test('GET /api/trips devuelve viajes del transportista autenticado con aliases l
|
|||||||
{
|
{
|
||||||
id_viaje: 84918,
|
id_viaje: 84918,
|
||||||
cod_viaje: 'VIA-2026-0000',
|
cod_viaje: 'VIA-2026-0000',
|
||||||
id_estado: 4,
|
id_estado: 1,
|
||||||
nombrea: 'Madrid, ES',
|
nombrea: 'Madrid, ES',
|
||||||
nombreb: 'Bilbao, ES',
|
nombreb: 'Bilbao, ES',
|
||||||
fecha_salida: '2026-01-21',
|
fecha_salida: '2026-01-21',
|
||||||
fecha_llegada: '2026-01-21'
|
fecha_llegada: '2026-01-21'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
let callCount = 0;
|
||||||
|
|
||||||
db.query = async (sql, params) => {
|
db.query = async (sql, params) => {
|
||||||
|
callCount += 1;
|
||||||
assert.match(sql, /FROM c_viajes_proveedor p/);
|
assert.match(sql, /FROM c_viajes_proveedor p/);
|
||||||
assert.match(sql, /INNER JOIN c_viajes v/);
|
assert.match(sql, /INNER JOIN c_viajes v/);
|
||||||
assert.match(sql, /INNER JOIN m_proveedores_trasportistas t/);
|
assert.match(sql, /INNER JOIN m_proveedores_trasportistas t/);
|
||||||
assert.match(sql, /id_estado IN \(\?, \?, \?\)/);
|
assert.match(sql, /id_estado IN \(\?, \?, \?, \?\)/);
|
||||||
|
|
||||||
|
if (callCount === 1) {
|
||||||
|
assert.match(sql, /COUNT\(\*\) AS total/);
|
||||||
|
assert.deepEqual(params, ['58045340X', 7, 8, 9, 1]);
|
||||||
|
return [[{ total: 2 }]];
|
||||||
|
}
|
||||||
|
|
||||||
assert.match(sql, /AS id_viaje/);
|
assert.match(sql, /AS id_viaje/);
|
||||||
assert.match(sql, /AS id_estado/);
|
assert.match(sql, /AS id_estado/);
|
||||||
assert.match(sql, /AS nombrea/);
|
assert.match(sql, /AS nombrea/);
|
||||||
assert.match(sql, /AS nombreb/);
|
assert.match(sql, /AS nombreb/);
|
||||||
assert.match(sql, /AS fecha_salida/);
|
assert.match(sql, /AS fecha_salida/);
|
||||||
assert.match(sql, /AS fecha_llegada/);
|
assert.match(sql, /AS fecha_llegada/);
|
||||||
assert.deepEqual(params, ['58045340X', 7, 8, 9]);
|
assert.match(sql, /LIMIT \? OFFSET \?/);
|
||||||
|
assert.deepEqual(params, ['58045340X', 7, 8, 9, 1, 25, 0]);
|
||||||
return [mockedTrips];
|
return [mockedTrips];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -149,13 +159,23 @@ test('GET /api/trips devuelve viajes del transportista autenticado con aliases l
|
|||||||
|
|
||||||
assert.equal(response.statusCode, 200);
|
assert.equal(response.statusCode, 200);
|
||||||
assert.deepEqual(response.body, {
|
assert.deepEqual(response.body, {
|
||||||
trips: mockedTrips
|
trips: mockedTrips,
|
||||||
|
page: 1,
|
||||||
|
limit: 25,
|
||||||
|
total: 2,
|
||||||
|
has_more: false
|
||||||
});
|
});
|
||||||
assert.equal(response.body.trips[0].id_estado, 7);
|
assert.equal(response.body.trips[0].id_estado, 7);
|
||||||
|
assert.equal(response.body.trips[1].id_estado, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/trips devuelve lista vacia cuando no hay viajes', async () => {
|
test('GET /api/trips devuelve lista vacia cuando no hay viajes', async () => {
|
||||||
db.query = async () => [[]];
|
let callCount = 0;
|
||||||
|
|
||||||
|
db.query = async () => {
|
||||||
|
callCount += 1;
|
||||||
|
return callCount === 1 ? [[{ total: 0 }]] : [[]];
|
||||||
|
};
|
||||||
|
|
||||||
const response = await withServer(async (server) =>
|
const response = await withServer(async (server) =>
|
||||||
requestJson({
|
requestJson({
|
||||||
@@ -167,12 +187,16 @@ test('GET /api/trips devuelve lista vacia cuando no hay viajes', async () => {
|
|||||||
|
|
||||||
assert.equal(response.statusCode, 200);
|
assert.equal(response.statusCode, 200);
|
||||||
assert.deepEqual(response.body, {
|
assert.deepEqual(response.body, {
|
||||||
trips: []
|
trips: [],
|
||||||
|
page: 1,
|
||||||
|
limit: 25,
|
||||||
|
total: 0,
|
||||||
|
has_more: false
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/trips responde en menos de 1s para 500 viajes mockeados', async () => {
|
test('GET /api/trips responde en menos de 1s para 25 viajes mockeados', async () => {
|
||||||
const mockedTrips = Array.from({ length: 500 }, (_, index) => ({
|
const mockedTrips = Array.from({ length: 25 }, (_, index) => ({
|
||||||
id_viaje: 100000 + index,
|
id_viaje: 100000 + index,
|
||||||
cod_viaje: `VIA-2026-${String(index + 1).padStart(4, '0')}`,
|
cod_viaje: `VIA-2026-${String(index + 1).padStart(4, '0')}`,
|
||||||
id_estado: index % 2 === 0 ? 7 : 4,
|
id_estado: index % 2 === 0 ? 7 : 4,
|
||||||
@@ -182,7 +206,12 @@ test('GET /api/trips responde en menos de 1s para 500 viajes mockeados', async (
|
|||||||
fecha_llegada: '2026-01-22 18:11:00'
|
fecha_llegada: '2026-01-22 18:11:00'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
db.query = async () => [mockedTrips];
|
let callCount = 0;
|
||||||
|
|
||||||
|
db.query = async () => {
|
||||||
|
callCount += 1;
|
||||||
|
return callCount === 1 ? [[{ total: 500 }]] : [mockedTrips];
|
||||||
|
};
|
||||||
|
|
||||||
const startedAt = Date.now();
|
const startedAt = Date.now();
|
||||||
const response = await withServer(async (server) =>
|
const response = await withServer(async (server) =>
|
||||||
@@ -195,10 +224,88 @@ test('GET /api/trips responde en menos de 1s para 500 viajes mockeados', async (
|
|||||||
const elapsedMs = Date.now() - startedAt;
|
const elapsedMs = Date.now() - startedAt;
|
||||||
|
|
||||||
assert.equal(response.statusCode, 200);
|
assert.equal(response.statusCode, 200);
|
||||||
assert.equal(response.body.trips.length, 500);
|
assert.equal(response.body.trips.length, 25);
|
||||||
|
assert.equal(response.body.total, 500);
|
||||||
|
assert.equal(response.body.has_more, true);
|
||||||
assert.ok(elapsedMs < 1000, `Expected < 1000ms, got ${elapsedMs}ms`);
|
assert.ok(elapsedMs < 1000, `Expected < 1000ms, got ${elapsedMs}ms`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('GET /api/trips aplica paginacion y filtros en SQL', async () => {
|
||||||
|
const mockedTrips = [
|
||||||
|
{
|
||||||
|
id_viaje: 84919,
|
||||||
|
cod_viaje: 'VIA-2026-0001',
|
||||||
|
id_estado: 7,
|
||||||
|
nombrea: 'Barcelona, ES',
|
||||||
|
nombreb: 'Lyon, FR',
|
||||||
|
fecha_salida: '2026-06-30 06:00:00',
|
||||||
|
fecha_llegada: '2026-06-30 18:11:00'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
let callCount = 0;
|
||||||
|
|
||||||
|
db.query = async (sql, params) => {
|
||||||
|
callCount += 1;
|
||||||
|
assert.match(sql, /v\.id_estado IN \(\?, \?, \?\)/);
|
||||||
|
assert.match(sql, /COALESCE\(p\.fecha_salida, v\.fecha_salida\) >= \?/);
|
||||||
|
assert.match(sql, /COALESCE\(p\.fecha_salida, v\.fecha_salida\) < \?/);
|
||||||
|
|
||||||
|
if (callCount === 1) {
|
||||||
|
assert.match(sql, /COUNT\(\*\) AS total/);
|
||||||
|
assert.deepEqual(params, ['58045340X', 7, 8, 9, '2026-06-01', '2026-07-01']);
|
||||||
|
return [[{ total: 26 }]];
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.match(sql, /ORDER BY COALESCE\(p\.fecha_salida, v\.fecha_salida\) DESC, p\.id_viaje DESC/);
|
||||||
|
assert.match(sql, /LIMIT \? OFFSET \?/);
|
||||||
|
assert.deepEqual(params, ['58045340X', 7, 8, 9, '2026-06-01', '2026-07-01', 25, 25]);
|
||||||
|
return [mockedTrips];
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await withServer(async (server) =>
|
||||||
|
requestJson({
|
||||||
|
port: server.address().port,
|
||||||
|
path: '/api/trips?page=2&limit=25&status_ids=7,8,9&date_from=2026-06-01&date_to=2026-06-30',
|
||||||
|
authorization: `Bearer ${createToken()}`
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(response.statusCode, 200);
|
||||||
|
assert.equal(response.body.page, 2);
|
||||||
|
assert.equal(response.body.limit, 25);
|
||||||
|
assert.equal(response.body.total, 26);
|
||||||
|
assert.equal(response.body.has_more, false);
|
||||||
|
assert.deepEqual(response.body.trips, mockedTrips);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('GET /api/trips valida parametros invalidos', async () => {
|
||||||
|
db.query = async () => {
|
||||||
|
throw new Error('db.query should not be called with invalid params');
|
||||||
|
};
|
||||||
|
|
||||||
|
const invalidPaths = [
|
||||||
|
'/api/trips?page=0',
|
||||||
|
'/api/trips?limit=101',
|
||||||
|
'/api/trips?status_ids=7,x',
|
||||||
|
'/api/trips?date_from=2026-02-30',
|
||||||
|
'/api/trips?date_from=2026-07-01&date_to=2026-06-30'
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const path of invalidPaths) {
|
||||||
|
const response = await withServer(async (server) =>
|
||||||
|
requestJson({
|
||||||
|
port: server.address().port,
|
||||||
|
path,
|
||||||
|
authorization: `Bearer ${createToken()}`
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(response.statusCode, 400, path);
|
||||||
|
assert.equal(response.body.success, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('GET /api/trips devuelve 401 sin token', async () => {
|
test('GET /api/trips devuelve 401 sin token', async () => {
|
||||||
db.query = async () => {
|
db.query = async () => {
|
||||||
throw new Error('db.query should not be called without token');
|
throw new Error('db.query should not be called without token');
|
||||||
|
|||||||
Reference in New Issue
Block a user