- Updated package.json to include new test scripts for API testing. - Modified postcss.config.mjs to correctly configure Tailwind CSS and autoprefixer. - Enhanced MenuGeneratorPage component to accept starter, main, and dessert requests. - Updated API route to handle new menu generation parameters and log requests. - Created LOGIN_CREDENTIALS.md for admin login information and user management instructions. - Implemented test-api.mjs script to automate API endpoint testing and validate responses.
237 lines
5.6 KiB
JavaScript
Executable File
237 lines
5.6 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
/**
|
|
* API Test Script
|
|
* Tester alle API endpoints for at sikre de svarer korrekt
|
|
*/
|
|
|
|
import { spawn } from 'child_process';
|
|
|
|
const BASE_URL = process.env.TEST_URL || 'http://localhost:3002';
|
|
let serverProcess = null;
|
|
let testsPassed = 0;
|
|
let testsFailed = 0;
|
|
|
|
// ANSI farve koder
|
|
const colors = {
|
|
reset: '\x1b[0m',
|
|
red: '\x1b[31m',
|
|
green: '\x1b[32m',
|
|
yellow: '\x1b[33m',
|
|
blue: '\x1b[34m',
|
|
cyan: '\x1b[36m',
|
|
};
|
|
|
|
function log(message, color = colors.reset) {
|
|
console.log(`${color}${message}${colors.reset}`);
|
|
}
|
|
|
|
// Start development server hvis ikke eksternt URL
|
|
async function startServer() {
|
|
if (process.env.TEST_URL) {
|
|
log(`Using external server: ${BASE_URL}`, colors.cyan);
|
|
return;
|
|
}
|
|
|
|
log('Starting development server...', colors.yellow);
|
|
serverProcess = spawn('npm', ['run', 'dev'], {
|
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
shell: true
|
|
});
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const timeout = setTimeout(() => {
|
|
reject(new Error('Server startup timeout'));
|
|
}, 30000);
|
|
|
|
serverProcess.stdout.on('data', (data) => {
|
|
const output = data.toString();
|
|
if (output.includes('Ready')) {
|
|
clearTimeout(timeout);
|
|
log('✓ Server started', colors.green);
|
|
// Vent lidt ekstra for at sikre server er klar
|
|
setTimeout(resolve, 2000);
|
|
}
|
|
});
|
|
|
|
serverProcess.stderr.on('data', (data) => {
|
|
console.error(data.toString());
|
|
});
|
|
});
|
|
}
|
|
|
|
// Stop server
|
|
function stopServer() {
|
|
if (serverProcess) {
|
|
log('Stopping server...', colors.yellow);
|
|
serverProcess.kill();
|
|
}
|
|
}
|
|
|
|
// Test en API endpoint
|
|
async function testEndpoint(name, method, path, options = {}) {
|
|
const url = `${BASE_URL}${path}`;
|
|
const { body, headers = {}, expectedStatus = 200, skipBodyCheck = false } = options;
|
|
|
|
try {
|
|
const fetchOptions = {
|
|
method,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...headers
|
|
}
|
|
};
|
|
|
|
if (body) {
|
|
fetchOptions.body = JSON.stringify(body);
|
|
}
|
|
|
|
log(`\nTesting: ${method} ${path}`, colors.cyan);
|
|
const response = await fetch(url, fetchOptions);
|
|
|
|
// Tjek status code
|
|
if (response.status !== expectedStatus) {
|
|
throw new Error(`Expected status ${expectedStatus}, got ${response.status}`);
|
|
}
|
|
|
|
// Tjek response body hvis ikke skippet
|
|
if (!skipBodyCheck) {
|
|
const contentType = response.headers.get('content-type');
|
|
if (contentType && contentType.includes('application/json')) {
|
|
const data = await response.json();
|
|
if (!data) {
|
|
throw new Error('Empty JSON response');
|
|
}
|
|
}
|
|
}
|
|
|
|
log(`✓ ${name}`, colors.green);
|
|
testsPassed++;
|
|
return true;
|
|
} catch (error) {
|
|
log(`✗ ${name}: ${error.message}`, colors.red);
|
|
testsFailed++;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Kør alle tests
|
|
async function runTests() {
|
|
log('\n=== API Test Suite ===\n', colors.blue);
|
|
|
|
// GET endpoints
|
|
await testEndpoint('GET /api/packages', 'GET', '/api/packages');
|
|
await testEndpoint('GET /api/menus', 'GET', '/api/menus');
|
|
await testEndpoint('GET /api/availability/weekly', 'GET', '/api/availability/weekly');
|
|
|
|
// POST endpoints (forventer fejl uden auth/data)
|
|
await testEndpoint(
|
|
'POST /api/menu-generator (uden data)',
|
|
'POST',
|
|
'/api/menu-generator',
|
|
{
|
|
body: { prompt: 'test', courses: 3 },
|
|
expectedStatus: 200
|
|
}
|
|
);
|
|
|
|
await testEndpoint(
|
|
'POST /api/menu-generator (image generation)',
|
|
'POST',
|
|
'/api/menu-generator',
|
|
{
|
|
body: {
|
|
generateImage: true,
|
|
menuDescription: 'Test menu with elegant dishes'
|
|
},
|
|
expectedStatus: 200,
|
|
skipBodyCheck: true // Kan fejle hvis ingen OPENAI_API_KEY
|
|
}
|
|
);
|
|
|
|
await testEndpoint(
|
|
'POST /api/contact',
|
|
'POST',
|
|
'/api/contact',
|
|
{
|
|
body: { name: 'Test', email: 'test@test.com', message: 'Test' },
|
|
expectedStatus: 500, // Kan fejle uden email config
|
|
skipBodyCheck: true
|
|
}
|
|
);
|
|
|
|
// Auth endpoints (forventer 400 ved invalid data)
|
|
await testEndpoint(
|
|
'POST /api/auth/login (invalid)',
|
|
'POST',
|
|
'/api/auth/login',
|
|
{
|
|
body: { email: 'invalid@test.com', password: 'wrong' },
|
|
expectedStatus: 400 // Invalid credentials
|
|
}
|
|
);
|
|
|
|
// Protected endpoints (kan være åbne i dev mode)
|
|
await testEndpoint(
|
|
'GET /api/bookings (uden auth)',
|
|
'GET',
|
|
'/api/bookings',
|
|
{ expectedStatus: 200, skipBodyCheck: true } // Kan være åben i dev
|
|
);
|
|
|
|
await testEndpoint(
|
|
'POST /api/bookings (uden auth)',
|
|
'POST',
|
|
'/api/bookings',
|
|
{
|
|
body: { date: '2025-12-01', guests: 10 },
|
|
expectedStatus: 400 // Invalid data format
|
|
}
|
|
);
|
|
|
|
await testEndpoint(
|
|
'GET /api/availability/blocked (uden auth)',
|
|
'GET',
|
|
'/api/availability/blocked',
|
|
{ expectedStatus: 200, skipBodyCheck: true } // Kan være åben i dev
|
|
);
|
|
|
|
// Vis resultater
|
|
log('\n=== Test Results ===', colors.blue);
|
|
log(`Passed: ${testsPassed}`, colors.green);
|
|
if (testsFailed > 0) {
|
|
log(`Failed: ${testsFailed}`, colors.red);
|
|
}
|
|
log(`Total: ${testsPassed + testsFailed}`, colors.cyan);
|
|
|
|
return testsFailed === 0;
|
|
}
|
|
|
|
// Main
|
|
async function main() {
|
|
try {
|
|
await startServer();
|
|
const success = await runTests();
|
|
stopServer();
|
|
process.exit(success ? 0 : 1);
|
|
} catch (error) {
|
|
log(`\nError: ${error.message}`, colors.red);
|
|
stopServer();
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Handle cleanup på exit
|
|
process.on('SIGINT', () => {
|
|
log('\nTest interrupted', colors.yellow);
|
|
stopServer();
|
|
process.exit(130);
|
|
});
|
|
|
|
process.on('SIGTERM', () => {
|
|
stopServer();
|
|
process.exit(143);
|
|
});
|
|
|
|
main();
|