Files
Tasks/backend/tests/test-logout-verify.js
2025-12-25 00:24:11 +02:00

315 lines
10 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Manual Test Script for Logout and Token Verification
* Task 14: User Logout & Token Verification
*
* Run this script with: node test-logout-verify.js
* Make sure the server is running on http://localhost:3000
*/
const axios = require('axios');
const API_BASE = 'http://localhost:3000/api';
let testToken = null;
let testUserId = null;
// Helper function for test output
function logTest(testNumber, description) {
console.log(`\n${'='.repeat(60)}`);
console.log(`${testNumber} Testing ${description}`);
console.log('='.repeat(60));
}
function logSuccess(message) {
console.log(`✅ SUCCESS: ${message}`);
}
function logError(message, error = null) {
console.log(`❌ ERROR: ${message}`);
if (error) {
if (error.response && error.response.data) {
console.log(`Response status: ${error.response.status}`);
console.log(`Response data:`, JSON.stringify(error.response.data, null, 2));
} else if (error.message) {
console.log(`Error details: ${error.message}`);
} else {
console.log(`Error:`, error);
}
}
}
// Test 1: Register a test user to get a token
async function test1_RegisterUser() {
logTest('1⃣', 'POST /api/auth/register - Get test token');
try {
const userData = {
username: `testuser${Date.now()}`,
email: `test${Date.now()}@example.com`,
password: 'Test@123'
};
console.log('Request:', JSON.stringify(userData, null, 2));
const response = await axios.post(`${API_BASE}/auth/register`, userData);
console.log('Response:', JSON.stringify(response.data, null, 2));
if (response.data.success && response.data.data.token) {
testToken = response.data.data.token;
testUserId = response.data.data.user.id;
logSuccess('User registered successfully, token obtained');
console.log('Token:', testToken.substring(0, 50) + '...');
} else {
logError('Failed to get token from registration');
}
} catch (error) {
logError('Registration failed', error);
}
}
// Test 2: Verify the token
async function test2_VerifyValidToken() {
logTest('2⃣', 'GET /api/auth/verify - Verify valid token');
if (!testToken) {
logError('No token available. Skipping test.');
return;
}
try {
const response = await axios.get(`${API_BASE}/auth/verify`, {
headers: {
'Authorization': `Bearer ${testToken}`
}
});
console.log('Response:', JSON.stringify(response.data, null, 2));
if (response.data.success && response.data.data.user) {
logSuccess('Token verified successfully');
console.log('User ID:', response.data.data.user.id);
console.log('Username:', response.data.data.user.username);
console.log('Email:', response.data.data.user.email);
console.log('Password exposed?', response.data.data.user.password ? 'YES ❌' : 'NO ✅');
} else {
logError('Token verification returned unexpected response');
}
} catch (error) {
logError('Token verification failed', error.response?.data || error.message);
}
}
// Test 3: Verify without token
async function test3_VerifyWithoutToken() {
logTest('3⃣', 'GET /api/auth/verify - Without token (should fail)');
try {
const response = await axios.get(`${API_BASE}/auth/verify`);
console.log('Response:', JSON.stringify(response.data, null, 2));
logError('Should have rejected request without token');
} catch (error) {
if (error.response && error.response.status === 401) {
console.log('Response:', JSON.stringify(error.response.data, null, 2));
logSuccess('Correctly rejected request without token (401)');
} else {
logError('Unexpected error', error.message);
}
}
}
// Test 4: Verify with invalid token
async function test4_VerifyInvalidToken() {
logTest('4⃣', 'GET /api/auth/verify - Invalid token (should fail)');
try {
const response = await axios.get(`${API_BASE}/auth/verify`, {
headers: {
'Authorization': 'Bearer invalid_token_here'
}
});
console.log('Response:', JSON.stringify(response.data, null, 2));
logError('Should have rejected invalid token');
} catch (error) {
if (error.response && error.response.status === 401) {
console.log('Response:', JSON.stringify(error.response.data, null, 2));
logSuccess('Correctly rejected invalid token (401)');
} else {
logError('Unexpected error', error.message);
}
}
}
// Test 5: Verify with malformed Authorization header
async function test5_VerifyMalformedHeader() {
logTest('5⃣', 'GET /api/auth/verify - Malformed header (should fail)');
if (!testToken) {
logError('No token available. Skipping test.');
return;
}
try {
const response = await axios.get(`${API_BASE}/auth/verify`, {
headers: {
'Authorization': testToken // Missing "Bearer " prefix
}
});
console.log('Response:', JSON.stringify(response.data, null, 2));
logError('Should have rejected malformed header');
} catch (error) {
if (error.response && error.response.status === 401) {
console.log('Response:', JSON.stringify(error.response.data, null, 2));
logSuccess('Correctly rejected malformed header (401)');
} else {
logError('Unexpected error', error.message);
}
}
}
// Test 6: Logout
async function test6_Logout() {
logTest('6⃣', 'POST /api/auth/logout - Logout');
try {
const response = await axios.post(`${API_BASE}/auth/logout`);
console.log('Response:', JSON.stringify(response.data, null, 2));
if (response.data.success) {
logSuccess('Logout successful (stateless JWT approach)');
} else {
logError('Logout returned unexpected response');
}
} catch (error) {
logError('Logout failed', error.response?.data || error.message);
}
}
// Test 7: Verify token still works after logout (JWT is stateless)
async function test7_VerifyAfterLogout() {
logTest('7⃣', 'GET /api/auth/verify - After logout (should still work)');
if (!testToken) {
logError('No token available. Skipping test.');
return;
}
try {
const response = await axios.get(`${API_BASE}/auth/verify`, {
headers: {
'Authorization': `Bearer ${testToken}`
}
});
console.log('Response:', JSON.stringify(response.data, null, 2));
if (response.data.success) {
logSuccess('Token still valid after logout (expected for stateless JWT)');
console.log('Note: In production, client should delete the token on logout');
} else {
logError('Token verification failed unexpectedly');
}
} catch (error) {
logError('Token verification failed', error.response?.data || error.message);
}
}
// Test 8: Login and verify new token
async function test8_LoginAndVerify() {
logTest('8⃣', 'POST /api/auth/login + GET /api/auth/verify - Full flow');
try {
// First, we need to use the registered user's credentials
// Get the email from the first test
const loginData = {
email: `test_${testUserId ? testUserId.split('-')[0] : ''}@example.com`,
password: 'Test@123'
};
// This might fail if we don't have the exact email, so let's just create a new user
const registerData = {
username: `logintest${Date.now()}`,
email: `logintest${Date.now()}@example.com`,
password: 'Test@123'
};
console.log('Registering new user for login test...');
const registerResponse = await axios.post(`${API_BASE}/auth/register`, registerData);
const userEmail = registerResponse.data.data.user.email;
console.log('Logging in...');
const loginResponse = await axios.post(`${API_BASE}/auth/login`, {
email: userEmail,
password: 'Test@123'
});
console.log('Login Response:', JSON.stringify(loginResponse.data, null, 2));
const loginToken = loginResponse.data.data.token;
console.log('\nVerifying login token...');
const verifyResponse = await axios.get(`${API_BASE}/auth/verify`, {
headers: {
'Authorization': `Bearer ${loginToken}`
}
});
console.log('Verify Response:', JSON.stringify(verifyResponse.data, null, 2));
if (verifyResponse.data.success) {
logSuccess('Login and token verification flow completed successfully');
} else {
logError('Token verification failed after login');
}
} catch (error) {
logError('Login and verify flow failed', error);
}
}
// Run all tests
async function runAllTests() {
console.log('\n');
console.log('╔════════════════════════════════════════════════════════════╗');
console.log('║ Logout & Token Verification Endpoint Tests (Task 14) ║');
console.log('╚════════════════════════════════════════════════════════════╝');
console.log('\nMake sure the server is running on http://localhost:3000\n');
await test1_RegisterUser();
await new Promise(resolve => setTimeout(resolve, 500)); // Small delay
await test2_VerifyValidToken();
await new Promise(resolve => setTimeout(resolve, 500));
await test3_VerifyWithoutToken();
await new Promise(resolve => setTimeout(resolve, 500));
await test4_VerifyInvalidToken();
await new Promise(resolve => setTimeout(resolve, 500));
await test5_VerifyMalformedHeader();
await new Promise(resolve => setTimeout(resolve, 500));
await test6_Logout();
await new Promise(resolve => setTimeout(resolve, 500));
await test7_VerifyAfterLogout();
await new Promise(resolve => setTimeout(resolve, 500));
await test8_LoginAndVerify();
console.log('\n');
console.log('╔════════════════════════════════════════════════════════════╗');
console.log('║ All Tests Completed ║');
console.log('╚════════════════════════════════════════════════════════════╝');
console.log('\n');
}
// Run tests
runAllTests().catch(error => {
console.error('\n❌ Fatal error running tests:', error);
process.exit(1);
});