Files
drone-detector/server/tests/routes/detections.test.js
2025-09-16 22:06:36 +02:00

406 lines
15 KiB
JavaScript

const { describe, it, beforeEach, afterEach, before, after } = require('mocha');
const { expect } = require('chai');
const sinon = require('sinon');
const request = require('supertest');
const express = require('express');
const { setupTestEnvironment, teardownTestEnvironment, cleanDatabase, createTestUser, createTestTenant, createTestDevice, createTestDetection, generateTestToken } = require('../setup');
const { authenticateToken, setModels } = require('../../middleware/auth');
describe('Detections Routes', () => {
let app, models, sequelize, detectionsRoutes;
before(async () => {
({ models, sequelize } = await setupTestEnvironment());
// Inject models globally for routes and into auth middleware for testing
global.__TEST_MODELS__ = models;
setModels(models);
// Require detections routes AFTER setting up global models
detectionsRoutes = require('../../routes/detections');
// Setup express app for testing
app = express();
app.use(express.json());
app.use(authenticateToken);
app.use('/detections', detectionsRoutes);
});
after(async () => {
// Clean up global test models
delete global.__TEST_MODELS__;
await teardownTestEnvironment();
});
beforeEach(async () => {
await cleanDatabase();
});
describe('GET /detections', () => {
it('should return detections for user tenant', async () => {
const tenant = await createTestTenant({ slug: 'test-tenant' });
const user = await createTestUser({ tenant_id: tenant.id });
const device = await createTestDevice({ tenant_id: tenant.id });
const detection = await createTestDetection({ device_id: device.id });
const token = generateTestToken(user, tenant);
const response = await request(app)
.get('/detections')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.success).to.be.true;
expect(response.body.data.detections).to.be.an('array');
expect(response.body.data.detections).to.have.length(1);
expect(response.body.data.detections[0].id).to.equal(detection.id);
});
it('should not return detections from other tenants', async () => {
const tenant1 = await createTestTenant({ slug: 'tenant1' });
const tenant2 = await createTestTenant({ slug: 'tenant2' });
const user1 = await createTestUser({ tenant_id: tenant1.id });
const device1 = await createTestDevice({ tenant_id: tenant1.id });
const device2 = await createTestDevice({ tenant_id: tenant2.id });
await createTestDetection({ device_id: device1.id });
await createTestDetection({ device_id: device2.id });
const token = generateTestToken(user1, tenant1);
const response = await request(app)
.get('/detections')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.data.detections).to.have.length(1);
});
it('should support pagination', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const device = await createTestDevice({ tenant_id: tenant.id });
// Create multiple detections
for (let i = 0; i < 15; i++) {
await createTestDetection({ device_id: device.id });
}
const token = generateTestToken(user, tenant);
const response = await request(app)
.get('/detections?page=1&limit=10')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.data.detections).to.have.length(10);
expect(response.body.data.pagination.totalPages).to.equal(2);
expect(response.body.data.pagination.hasNextPage).to.be.true;
});
it('should support sorting', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const device = await createTestDevice({ tenant_id: tenant.id });
const detection1 = await createTestDetection({
device_id: device.id,
server_timestamp: new Date('2023-01-01')
});
const detection2 = await createTestDetection({
device_id: device.id,
server_timestamp: new Date('2023-01-02')
});
const token = generateTestToken(user, tenant);
const response = await request(app)
.get('/detections?sort=server_timestamp&order=desc')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.data.detections[0].id).to.equal(detection2.id);
});
it('should support filtering by device', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const device1 = await createTestDevice({ tenant_id: tenant.id });
const device2 = await createTestDevice({ tenant_id: tenant.id });
await createTestDetection({ device_id: device1.id });
await createTestDetection({ device_id: device2.id });
const token = generateTestToken(user, tenant);
const response = await request(app)
.get(`/detections?device_id=${device1.id}`)
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.data.detections).to.have.length(1);
expect(response.body.data.detections[0].device_id).to.equal(device1.id);
});
it('should support filtering by drone type', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const device = await createTestDevice({ tenant_id: tenant.id });
await createTestDetection({ device_id: device.id, drone_type: 2 });
await createTestDetection({ device_id: device.id, drone_type: 3 });
const token = generateTestToken(user, tenant);
const response = await request(app)
.get('/detections?drone_type=2')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.data.detections).to.have.length(1);
expect(response.body.data.detections[0].drone_type).to.equal(2);
});
it('should support filtering by date range', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const device = await createTestDevice({ tenant_id: tenant.id });
await createTestDetection({
device_id: device.id,
server_timestamp: new Date('2023-01-01')
});
await createTestDetection({
device_id: device.id,
server_timestamp: new Date('2023-02-01')
});
const token = generateTestToken(user, tenant);
const response = await request(app)
.get('/detections?start_date=2023-01-15&end_date=2023-02-15')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.data.detections).to.have.length(1);
});
it('should exclude drone type 0 by default', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const device = await createTestDevice({ tenant_id: tenant.id });
await createTestDetection({ device_id: device.id, drone_type: 0 });
await createTestDetection({ device_id: device.id, drone_type: 2 });
const token = generateTestToken(user, tenant);
const response = await request(app)
.get('/detections')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.data.detections).to.have.length(1);
expect(response.body.data.detections[0].drone_type).to.equal(2);
});
it('should enhance detections with drone type info', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const device = await createTestDevice({ tenant_id: tenant.id });
const detection = await createTestDetection({
device_id: device.id,
drone_type: 2
});
const token = generateTestToken(user, tenant);
const response = await request(app)
.get('/detections')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
const returnedDetection = response.body.data.detections[0];
expect(returnedDetection.drone_type_info).to.exist;
expect(returnedDetection.drone_type_info.name).to.exist;
expect(returnedDetection.drone_type_info.threat_level).to.exist;
});
it('should include device information', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const device = await createTestDevice({
tenant_id: tenant.id,
name: 'Test Device'
});
await createTestDetection({ device_id: device.id });
const token = generateTestToken(user, tenant);
const response = await request(app)
.get('/detections')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
const detection = response.body.data.detections[0];
expect(detection.device).to.exist;
expect(detection.device.name).to.equal('Test Device');
});
it('should reject request without tenant', async () => {
const user = await createTestUser({ tenant_id: null }); // Explicitly no tenant
const token = generateTestToken(user); // No tenant
const response = await request(app)
.get('/detections')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(400);
expect(response.body.success).to.be.false;
expect(response.body.message).to.equal('No tenant context available');
});
it('should reject request for inactive tenant', async () => {
const tenant = await createTestTenant({
slug: 'inactive-tenant',
is_active: false
});
const user = await createTestUser({ tenant_id: tenant.id });
const token = generateTestToken(user, tenant);
const response = await request(app)
.get('/detections')
.set('Authorization', `Bearer ${token}`);
console.log('🔍 Inactive tenant test - Response status:', response.status);
console.log('🔍 Inactive tenant test - Response body:', response.body);
expect(response.status).to.equal(403);
expect(response.body.success).to.be.false;
expect(response.body.message).to.equal('Tenant is inactive');
});
it('should handle invalid pagination parameters', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const token = generateTestToken(user, tenant);
const response = await request(app)
.get('/detections?page=-1&limit=1000')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
// Should use default values
expect(response.body.data.pagination.page).to.equal(1);
expect(response.body.data.pagination.limit).to.equal(20);
});
});
describe('GET /detections/:id', () => {
it('should return specific detection', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const device = await createTestDevice({ tenant_id: tenant.id });
const detection = await createTestDetection({ device_id: device.id });
const token = generateTestToken(user, tenant);
const response = await request(app)
.get(`/detections/${detection.id}`)
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.success).to.be.true;
expect(response.body.data.id).to.equal(detection.id);
});
it('should not return detection from other tenant', async () => {
const tenant1 = await createTestTenant({ slug: 'tenant1' });
const tenant2 = await createTestTenant({ slug: 'tenant2' });
const user1 = await createTestUser({ tenant_id: tenant1.id });
const device2 = await createTestDevice({ tenant_id: tenant2.id });
const detection2 = await createTestDetection({ device_id: device2.id });
const token = generateTestToken(user1, tenant1);
const response = await request(app)
.get(`/detections/${detection2.id}`)
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(404);
expect(response.body.success).to.be.false;
});
it('should return 404 for non-existent detection', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const token = generateTestToken(user, tenant);
const response = await request(app)
.get('/detections/99999')
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(404);
expect(response.body.success).to.be.false;
});
it('should include enhanced detection data', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({ tenant_id: tenant.id });
const device = await createTestDevice({ tenant_id: tenant.id });
const detection = await createTestDetection({
device_id: device.id,
drone_type: 2
});
const token = generateTestToken(user, tenant);
const response = await request(app)
.get(`/detections/${detection.id}`)
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.data.drone_type_info).to.exist;
expect(response.body.data.device).to.exist;
});
});
describe('DELETE /detections/:id', () => {
it('should delete detection with admin role', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({
tenant_id: tenant.id,
role: 'admin'
});
const device = await createTestDevice({ tenant_id: tenant.id });
const detection = await createTestDetection({ device_id: device.id });
const token = generateTestToken(user, tenant);
const response = await request(app)
.delete(`/detections/${detection.id}`)
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(200);
expect(response.body.success).to.be.true;
expect(response.body.message).to.equal('Detection deleted successfully');
});
it('should reject deletion without proper permissions', async () => {
const tenant = await createTestTenant();
const user = await createTestUser({
tenant_id: tenant.id,
role: 'viewer'
});
const device = await createTestDevice({ tenant_id: tenant.id });
const detection = await createTestDetection({ device_id: device.id });
const token = generateTestToken(user, tenant);
const response = await request(app)
.delete(`/detections/${detection.id}`)
.set('Authorization', `Bearer ${token}`);
expect(response.status).to.equal(403);
expect(response.body.success).to.be.false;
});
});
});