swiftops-backend / tests /integration /test_complete_lesley_profile.js
kamau1's picture
fix: sync models and tests with DB asset/account schemas
dd5b6b1
#!/usr/bin/env node
/**
* Complete Lesley's Profile - Full Test
* Tests financial accounts, assets, and location updates
*/
const https = require('https');
const BASE_URL = 'https://kamau1-swiftops-backend.hf.space';
const ADMIN_EMAIL = 'lewis.kamau421@gmail.com';
const ADMIN_PASSWORD = 'TestPass123';
const LESLEY_EMAIL = 'lesley@example.com';
let adminToken = null;
let lesleyUserId = null;
let financialAccountId = null;
let assetAssignmentId = null;
const colors = {
reset: '\x1b[0m',
green: '\x1b[32m',
red: '\x1b[31m',
yellow: '\x1b[33m',
blue: '\x1b[36m',
magenta: '\x1b[35m',
cyan: '\x1b[96m'
};
function log(message, color = 'reset') {
console.log(`${colors[color]}${message}${colors.reset}`);
}
function makeRequest(method, path, data = null, token = null) {
return new Promise((resolve, reject) => {
const url = new URL(path, BASE_URL);
const options = {
method,
headers: { 'Content-Type': 'application/json' },
timeout: 30000
};
if (token) {
options.headers['Authorization'] = `Bearer ${token}`;
}
log(` β†’ ${method} ${path}`, 'yellow');
const req = https.request(url, options, (res) => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
try {
const response = { status: res.statusCode, data: body ? JSON.parse(body) : null };
log(` ← ${res.statusCode} ${res.statusMessage}`, 'yellow');
resolve(response);
} catch (e) {
log(` ← ${res.statusCode} (non-JSON)`, 'yellow');
resolve({ status: res.statusCode, data: body });
}
});
});
req.on('error', reject);
req.on('timeout', () => {
req.destroy();
reject(new Error('Request timeout'));
});
if (data) req.write(JSON.stringify(data));
req.end();
});
}
async function step1_Login() {
log('\nπŸ” Step 1: Login as Admin', 'blue');
const response = await makeRequest('POST', '/api/v1/auth/login', {
email: ADMIN_EMAIL,
password: ADMIN_PASSWORD
});
if (response.status === 200) {
adminToken = response.data.access_token;
log('βœ… Login successful', 'green');
log(` Token: ${adminToken.substring(0, 30)}...`);
return true;
} else {
log(`❌ Login failed: ${response.status}`, 'red');
return false;
}
}
async function step2_GetLesleyUserId() {
log('\nπŸ” Step 2: Get Lesley\'s User ID', 'blue');
const response = await makeRequest('GET', `/api/v1/users/search?email=${LESLEY_EMAIL}`, null, adminToken);
if (response.status === 200 && response.data.length > 0) {
const user = response.data[0];
lesleyUserId = user.id;
log('βœ… Found Lesley\'s user account', 'green');
log(` User ID: ${lesleyUserId}`);
log(` Email: ${user.email}`);
log(` Name: ${user.name}`);
return true;
} else {
log('❌ Could not find Lesley\'s user account', 'red');
return false;
}
}
async function step3_CreateFinancialAccount() {
log('\nπŸ’° Step 3: Create Financial Account', 'blue');
const response = await makeRequest('POST', `/api/v1/financial-accounts/user/${lesleyUserId}`, {
account_name: 'M-Pesa Account',
payout_method: 'mobile_money',
mobile_money_provider: 'Safaricom',
mobile_money_phone: '+254712345678',
mobile_money_account_name: 'Lesley Wanjiru',
is_primary: true
}, adminToken);
if (response.status === 201) {
financialAccountId = response.data.id;
log('βœ… Financial account created', 'green');
log(` Account ID: ${financialAccountId}`);
log(` Method: ${response.data.payout_method}`);
log(` Name: ${response.data.account_name}`);
log(` Phone: ${response.data.mobile_money_phone}`);
log(` Provider: ${response.data.mobile_money_provider}`);
log(` Primary: ${response.data.is_primary}`);
return true;
} else {
log(`❌ Failed to create account: ${response.status}`, 'red');
log(` ${JSON.stringify(response.data, null, 2)}`);
return false;
}
}
async function step4_GetFinancialAccounts() {
log('\nπŸ’³ Step 4: Get Financial Accounts', 'blue');
const response = await makeRequest('GET', `/api/v1/financial-accounts/user/${lesleyUserId}`, null, adminToken);
if (response.status === 200) {
log('βœ… Retrieved financial accounts', 'green');
log(` Total Accounts: ${response.data.length}`);
response.data.forEach((acc, i) => {
log(` ${i + 1}. ${acc.account_name} (${acc.payout_method})`);
if (acc.mobile_money_phone) log(` Phone: ${acc.mobile_money_phone}`);
if (acc.bank_account_number) log(` Account: ${acc.bank_account_number}`);
});
return true;
} else {
log(`❌ Failed to get accounts: ${response.status}`, 'red');
return false;
}
}
async function step5_UpdateLocation() {
log('\nπŸ“ Step 5: Update Location', 'blue');
const response = await makeRequest('PUT', `/api/v1/profile/${lesleyUserId}/location`, {
current_location_name: 'Nairobi Office',
current_country: 'Kenya',
current_region: 'Nairobi County',
current_city: 'Nairobi',
current_address_line1: 'Kenyatta Avenue',
current_address_line2: 'Building 12, Floor 3',
current_latitude: -1.286389,
current_longitude: 36.817223,
current_maps_link: 'https://maps.google.com/?q=-1.286389,36.817223'
}, adminToken);
if (response.status === 200) {
log('βœ… Location updated', 'green');
log(` Location: ${response.data.current_location_name}`);
log(` City: ${response.data.current_city}`);
log(` Country: ${response.data.current_country}`);
log(` Address: ${response.data.current_address_line1}`);
log(` Coordinates: ${response.data.current_latitude}, ${response.data.current_longitude}`);
return true;
} else {
log(`❌ Failed to update location: ${response.status}`, 'red');
log(` ${JSON.stringify(response.data, null, 2)}`);
return false;
}
}
async function step6_AssignAsset() {
log('\nπŸ”§ Step 6: Assign Asset', 'blue');
const response = await makeRequest('POST', `/api/v1/asset-assignments/user/${lesleyUserId}`, {
asset_type: 'PPE',
asset_name: 'Safety Helmet',
serial_number: 'HELMET-001',
condition_on_assign: 'good',
notes: 'Standard safety helmet for field work'
}, adminToken);
if (response.status === 201) {
assetAssignmentId = response.data.id;
log('βœ… Asset assigned', 'green');
log(` Assignment ID: ${assetAssignmentId}`);
log(` Asset: ${response.data.asset_name}`);
log(` Type: ${response.data.asset_type}`);
log(` Serial: ${response.data.serial_number}`);
log(` Condition: ${response.data.condition_on_assign}`);
return true;
} else {
log(`❌ Failed to assign asset: ${response.status}`, 'red');
log(` ${JSON.stringify(response.data, null, 2)}`);
return false;
}
}
async function step7_AssignMoreAssets() {
log('\nπŸ› οΈ Step 7: Assign More Assets', 'blue');
const assets = [
{
asset_type: 'PPE',
asset_name: 'Safety Vest',
serial_number: 'VEST-042',
condition_on_assign: 'good',
notes: 'High visibility vest'
},
{
asset_type: 'Laptop',
asset_name: 'Tablet',
serial_number: 'TAB-156',
condition_on_assign: 'good',
notes: 'Samsung Galaxy Tab for field reporting'
}
];
let success = 0;
for (const asset of assets) {
const response = await makeRequest('POST', `/api/v1/asset-assignments/user/${lesleyUserId}`, asset, adminToken);
if (response.status === 201) {
success++;
log(` βœ“ Assigned: ${asset.asset_name}`, 'green');
} else {
log(` βœ— Failed: ${asset.asset_name}`, 'red');
}
}
log(`βœ… Assigned ${success}/${assets.length} additional assets`, 'green');
return success === assets.length;
}
async function step8_GetAssetAssignments() {
log('\nπŸ“¦ Step 8: Get Asset Assignments', 'blue');
const response = await makeRequest('GET', `/api/v1/asset-assignments/user/${lesleyUserId}`, null, adminToken);
if (response.status === 200) {
log('βœ… Retrieved asset assignments', 'green');
log(` Total Assets: ${response.data.length}`);
response.data.forEach((asset, i) => {
const status = asset.is_active ? '🟒 Active' : 'πŸ”΄ Returned';
log(` ${i + 1}. ${asset.asset_name} (${asset.asset_type}) - ${status}`);
if (asset.serial_number) log(` Serial: ${asset.serial_number}`);
});
return true;
} else {
log(`❌ Failed to get assets: ${response.status}`, 'red');
return false;
}
}
async function step9_ValidateProfile() {
log('\nβœ… Step 9: Validate Complete Profile', 'blue');
const response = await makeRequest('GET', `/api/v1/profile/${lesleyUserId}/validation`, null, adminToken);
if (response.status === 200) {
log('βœ… Validation complete', 'green');
log(` Is Valid: ${response.data.is_valid}`);
log(` Completion: ${response.data.completion_percentage}%`);
if (response.data.missing_fields.length > 0) {
log(` Missing: ${response.data.missing_fields.join(', ')}`, 'yellow');
} else {
log(` All required fields complete! πŸŽ‰`, 'green');
}
if (response.data.warnings.length > 0) {
log(` Warnings:`, 'yellow');
response.data.warnings.forEach(w => log(` - ${w}`, 'yellow'));
}
return true;
} else {
log(`❌ Validation failed: ${response.status}`, 'red');
return false;
}
}
async function step10_GetFinalProfile() {
log('\nπŸ“Š Step 10: Get Final Profile Status', 'blue');
const response = await makeRequest('GET', `/api/v1/profile/${lesleyUserId}`, null, adminToken);
if (response.status === 200) {
const profile = response.data;
log('βœ… Final profile retrieved', 'green');
log(`\n Profile Completion: ${profile.completion_status.completion_percentage}%`);
log(` ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
log(` Basic Info: ${profile.completion_status.basic_info ? 'βœ“' : 'βœ—'}`);
log(` Health Info: ${profile.completion_status.health_info ? 'βœ“' : 'βœ—'}`);
log(` PPE Sizes: ${profile.completion_status.ppe_sizes ? 'βœ“' : 'βœ—'}`);
log(` Location: ${profile.completion_status.location ? 'βœ“' : 'βœ—'}`);
log(` Financial: ${profile.completion_status.financial_accounts ? 'βœ“' : 'βœ—'} (${profile.financial_accounts_count} accounts)`);
log(` Assets: ${profile.asset_assignments_count} assigned`);
log(` Documents: ${profile.completion_status.documents ? 'βœ“' : 'βœ—'} (${profile.documents_count} docs)`);
return true;
} else {
log(`❌ Failed: ${response.status}`, 'red');
return false;
}
}
async function runTest() {
log('='.repeat(70), 'blue');
log('🎯 Complete Lesley\'s Profile - Full Test', 'blue');
log(' Testing: Financial Accounts, Assets, Location', 'cyan');
log('='.repeat(70), 'blue');
const results = [];
// Setup
if (!await step1_Login()) {
log('\n❌ Cannot continue without login', 'red');
process.exit(1);
}
results.push({ name: 'Login', status: true });
if (!await step2_GetLesleyUserId()) {
log('\n❌ Cannot continue without user ID', 'red');
process.exit(1);
}
results.push({ name: 'Get User ID', status: true });
// Financial Account Tests
results.push({ name: 'Create Financial Account', status: await step3_CreateFinancialAccount() });
results.push({ name: 'Get Financial Accounts', status: await step4_GetFinancialAccounts() });
// Location Test
results.push({ name: 'Update Location', status: await step5_UpdateLocation() });
// Asset Assignment Tests
results.push({ name: 'Assign Asset', status: await step6_AssignAsset() });
results.push({ name: 'Assign More Assets', status: await step7_AssignMoreAssets() });
results.push({ name: 'Get Asset Assignments', status: await step8_GetAssetAssignments() });
// Validation
results.push({ name: 'Validate Profile', status: await step9_ValidateProfile() });
results.push({ name: 'Get Final Status', status: await step10_GetFinalProfile() });
// Summary
log('\n' + '='.repeat(70), 'blue');
log('πŸ“Š Test Summary', 'blue');
log('='.repeat(70), 'blue');
let passed = 0, failed = 0;
results.forEach(r => {
const icon = r.status ? 'βœ…' : '❌';
const color = r.status ? 'green' : 'red';
log(`${icon} ${r.name}`, color);
if (r.status) passed++; else failed++;
});
log('\n' + '-'.repeat(70));
log(`Total: ${results.length} | Passed: ${passed} | Failed: ${failed}`);
if (failed === 0) {
log('\nπŸŽ‰ All tests passed! Profile is complete!', 'green');
log(`\n✨ Lesley's complete profile summary:`, 'magenta');
log(` User ID: ${lesleyUserId}`, 'magenta');
log(` Financial Account: ${financialAccountId}`, 'magenta');
log(` Asset Assignment: ${assetAssignmentId}`, 'magenta');
log(` All changes logged in audit_logs table`, 'magenta');
} else {
log(`\n⚠️ ${failed} step(s) failed`, 'red');
}
}
runTest().catch(error => {
log(`\nπŸ’₯ Fatal error: ${error.message}`, 'red');
console.error(error);
process.exit(1);
});