🧪 Testing Infrastructure (45 tests, 100% passing) - Implemented Jest + Supertest framework for automated testing - Unit tests: 5 tests for auth middleware (100% coverage) - Integration tests: 40 tests covering admin, consent, migration, upload APIs - Test execution time: ~10 seconds for full suite - Coverage: 26% statements, 15% branches (realistic start) - In-memory SQLite database for isolated testing - Singleton server pattern for fast test execution - Automatic cleanup and teardown 🔒 Admin API Authentication - Bearer token authentication for all admin endpoints - requireAdminAuth middleware with ADMIN_API_KEY validation - Protected routes: /api/admin/*, /api/system/migration/migrate|rollback - Complete authentication guide in AUTHENTICATION.md - HTTP 403 for missing/invalid tokens, 500 if not configured - Ready for production with token rotation support 📋 API Route Documentation - Single Source of Truth: backend/src/routes/routeMappings.js - Comprehensive route overview in backend/src/routes/README.md - Express routing order documented (specific before generic) - Frontend integration guide with authentication examples - OpenAPI auto-generation integrated 🐛 Bug Fixes - Fixed SQLite connection not properly awaited (caused test hangs) - Fixed upload validation checking req.files.file before req.files - Fixed Express route order (consent before admin router) - Fixed test environment using /tmp for uploads (permission issues) 📚 Documentation Updates - Updated README.md with testing and authentication features - Updated README.dev.md with testing section and API development guide - Updated CHANGELOG.md with complete feature documentation - Updated FEATURE_PLAN-autogen-openapi.md (status: 100% complete) - Added frontend/MIGRATION-GUIDE.md for frontend team 🚀 Frontend Impact Frontend needs to add Bearer token to all /api/admin/* calls. See frontend/MIGRATION-GUIDE.md for detailed instructions. Test Status: ✅ 45/45 passing (100%) Backend: ✅ Production ready Frontend: ⚠️ Migration required (see MIGRATION-GUIDE.md)
126 lines
4.2 KiB
JavaScript
126 lines
4.2 KiB
JavaScript
const { getRequest } = require('../testServer');
|
|
|
|
describe('Consent Management API', () => {
|
|
const validToken = process.env.ADMIN_API_KEY || 'test-admin-key-12345';
|
|
|
|
describe('GET /api/admin/social-media/platforms', () => {
|
|
it('should return list of social media platforms', async () => {
|
|
const response = await getRequest()
|
|
.get('/api/admin/social-media/platforms')
|
|
.set('Authorization', `Bearer ${validToken}`)
|
|
.expect('Content-Type', /json/)
|
|
.expect(200);
|
|
|
|
expect(Array.isArray(response.body)).toBe(true);
|
|
});
|
|
|
|
it('should include platform metadata', async () => {
|
|
const response = await getRequest()
|
|
.get('/api/admin/social-media/platforms')
|
|
.set('Authorization', `Bearer ${validToken}`);
|
|
|
|
if (response.body.length > 0) {
|
|
const platform = response.body[0];
|
|
expect(platform).toHaveProperty('id');
|
|
expect(platform).toHaveProperty('platform_name');
|
|
expect(platform).toHaveProperty('display_name');
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('GET /api/admin/groups/:groupId/consents', () => {
|
|
it('should return 404 for non-existent group', async () => {
|
|
await getRequest()
|
|
.get('/api/admin/groups/non-existent-group/consents')
|
|
.set('Authorization', `Bearer ${validToken}`)
|
|
.expect(404);
|
|
});
|
|
|
|
it('should reject path traversal attempts', async () => {
|
|
await getRequest()
|
|
.get('/api/admin/groups/../../../etc/passwd/consents')
|
|
.set('Authorization', `Bearer ${validToken}`)
|
|
.expect(404);
|
|
});
|
|
});
|
|
|
|
describe('POST /api/admin/groups/:groupId/consents', () => {
|
|
it('should require admin authorization', async () => {
|
|
await getRequest()
|
|
.post('/api/admin/groups/test-group-id/consents')
|
|
.send({ consents: {} })
|
|
.expect(403); // No auth header
|
|
});
|
|
|
|
it('should require valid consent data with auth', async () => {
|
|
const response = await getRequest()
|
|
.post('/api/admin/groups/test-group-id/consents')
|
|
.set('Authorization', `Bearer ${validToken}`)
|
|
.send({})
|
|
.expect(400);
|
|
|
|
expect(response.body).toHaveProperty('error');
|
|
});
|
|
});
|
|
|
|
describe('GET /api/admin/groups/by-consent', () => {
|
|
it('should return filtered groups', async () => {
|
|
const response = await getRequest()
|
|
.get('/api/admin/groups/by-consent')
|
|
.set('Authorization', `Bearer ${validToken}`)
|
|
.expect('Content-Type', /json/)
|
|
.expect(200);
|
|
|
|
expect(response.body).toHaveProperty('groups');
|
|
expect(response.body).toHaveProperty('count');
|
|
expect(Array.isArray(response.body.groups)).toBe(true);
|
|
});
|
|
|
|
it('should accept platform filter', async () => {
|
|
const response = await getRequest()
|
|
.get('/api/admin/groups/by-consent?platformId=1')
|
|
.set('Authorization', `Bearer ${validToken}`)
|
|
.expect(200);
|
|
|
|
expect(response.body).toHaveProperty('groups');
|
|
expect(response.body).toHaveProperty('filters');
|
|
});
|
|
|
|
it('should accept consent filter', async () => {
|
|
const response = await getRequest()
|
|
.get('/api/admin/groups/by-consent?displayInWorkshop=true')
|
|
.set('Authorization', `Bearer ${validToken}`)
|
|
.expect(200);
|
|
|
|
expect(response.body).toHaveProperty('groups');
|
|
expect(response.body.filters).toHaveProperty('displayInWorkshop', true);
|
|
});
|
|
});
|
|
|
|
describe('GET /api/admin/consents/export', () => {
|
|
it('should require admin authorization', async () => {
|
|
await getRequest()
|
|
.get('/api/admin/consents/export')
|
|
.expect(403);
|
|
});
|
|
|
|
it('should return CSV format with auth and format parameter', async () => {
|
|
const response = await getRequest()
|
|
.get('/api/admin/consents/export?format=csv')
|
|
.set('Authorization', `Bearer ${validToken}`)
|
|
.expect(200);
|
|
|
|
expect(response.headers['content-type']).toMatch(/text\/csv/);
|
|
expect(response.headers['content-disposition']).toMatch(/attachment/);
|
|
});
|
|
|
|
it('should include CSV header', async () => {
|
|
const response = await getRequest()
|
|
.get('/api/admin/consents/export?format=csv')
|
|
.set('Authorization', `Bearer ${validToken}`);
|
|
|
|
expect(response.text).toContain('group_id');
|
|
});
|
|
});
|
|
});
|