xpeditis2.0/apps/backend/test-csv-api.js
2025-11-04 07:30:15 +01:00

383 lines
11 KiB
JavaScript

/**
* CSV Rate API Test Script (Node.js)
*
* Usage: node test-csv-api.js
*
* Tests all CSV rate endpoints and verifies comparator functionality
*/
const API_URL = 'http://localhost:4000';
// Color codes for terminal output
const colors = {
reset: '\x1b[0m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
};
function printTest(number, description) {
console.log(`${colors.yellow}[TEST ${number}] ${description}${colors.reset}`);
}
function printSuccess(message) {
console.log(`${colors.green}${message}${colors.reset}`);
}
function printError(message) {
console.log(`${colors.red}${message}${colors.reset}`);
}
function printInfo(message) {
console.log(`${colors.blue}${message}${colors.reset}`);
}
async function authenticateUser() {
printTest(1, 'Authenticating as regular user');
const response = await fetch(`${API_URL}/api/v1/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'test4@xpeditis.com',
password: 'SecurePassword123',
}),
});
const data = await response.json();
if (data.accessToken) {
printSuccess('Regular user authenticated');
printInfo(`Token: ${data.accessToken.substring(0, 20)}...`);
return data.accessToken;
} else {
printError('Failed to authenticate regular user');
console.log('Response:', data);
throw new Error('Authentication failed');
}
}
async function testGetCompanies(token) {
printTest(2, 'GET /rates/companies - Get available companies');
const response = await fetch(`${API_URL}/api/v1/rates/companies`, {
headers: { Authorization: `Bearer ${token}` },
});
const data = await response.json();
console.log(JSON.stringify(data, null, 2));
if (data.total === 5) {
printSuccess('Got 5 companies (including Test Maritime Express)');
printInfo(`Companies: ${data.companies.join(', ')}`);
} else {
printError(`Expected 5 companies, got ${data.total}`);
}
console.log('');
return data;
}
async function testGetFilterOptions(token) {
printTest(3, 'GET /rates/filters/options - Get filter options');
const response = await fetch(`${API_URL}/api/v1/rates/filters/options`, {
headers: { Authorization: `Bearer ${token}` },
});
const data = await response.json();
console.log(JSON.stringify(data, null, 2));
printSuccess('Filter options retrieved');
console.log('');
return data;
}
async function testBasicSearch(token) {
printTest(4, 'POST /rates/search-csv - Basic rate search (NLRTM → USNYC)');
const response = await fetch(`${API_URL}/api/v1/rates/search-csv`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
origin: 'NLRTM',
destination: 'USNYC',
volumeCBM: 25.5,
weightKG: 3500,
palletCount: 10,
containerType: 'LCL',
}),
});
const data = await response.json();
console.log(JSON.stringify(data, null, 2));
printInfo(`Total results: ${data.totalResults}`);
// Check if Test Maritime Express is in results
const hasTestMaritime = data.results.some(r => r.companyName === 'Test Maritime Express');
if (hasTestMaritime) {
printSuccess('Test Maritime Express found in results');
const testPrice = data.results.find(r => r.companyName === 'Test Maritime Express').totalPrice
.amount;
printInfo(`Test Maritime Express price: $${testPrice}`);
} else {
printError('Test Maritime Express NOT found in results');
}
// Count unique companies
const uniqueCompanies = [...new Set(data.results.map(r => r.companyName))];
printInfo(`Results from ${uniqueCompanies.length} different companies`);
if (uniqueCompanies.length >= 3) {
printSuccess('Multiple companies in comparator ✓');
} else {
printError(`Expected multiple companies, got ${uniqueCompanies.length}`);
}
console.log('');
return data;
}
async function testCompanyFilter(token) {
printTest(5, 'POST /rates/search-csv - Filter by Test Maritime Express only');
const response = await fetch(`${API_URL}/api/v1/rates/search-csv`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
origin: 'NLRTM',
destination: 'USNYC',
volumeCBM: 25.5,
weightKG: 3500,
palletCount: 10,
containerType: 'LCL',
filters: {
companies: ['Test Maritime Express'],
},
}),
});
const data = await response.json();
console.log(JSON.stringify(data.results.slice(0, 3), null, 2));
const uniqueCompanies = [...new Set(data.results.map(r => r.companyName))];
if (uniqueCompanies.length === 1 && uniqueCompanies[0] === 'Test Maritime Express') {
printSuccess('Company filter working correctly');
} else {
printError(`Company filter not working - got: ${uniqueCompanies.join(', ')}`);
}
console.log('');
return data;
}
async function testPriceFilter(token) {
printTest(6, 'POST /rates/search-csv - Filter by price range ($900-$1200)');
const response = await fetch(`${API_URL}/api/v1/rates/search-csv`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
origin: 'NLRTM',
destination: 'USNYC',
volumeCBM: 25.5,
weightKG: 3500,
palletCount: 10,
containerType: 'LCL',
filters: {
minPrice: 900,
maxPrice: 1200,
currency: 'USD',
},
}),
});
const data = await response.json();
printInfo(`Results in price range $900-$1200: ${data.totalResults}`);
const prices = data.results.map(r => r.totalPrice.amount);
const minPrice = Math.min(...prices);
const maxPrice = Math.max(...prices);
if (minPrice >= 900 && maxPrice <= 1200) {
printSuccess(`Price filter working correctly (range: $${minPrice} - $${maxPrice})`);
} else {
printError(`Price filter not working - got range: $${minPrice} - $${maxPrice}`);
}
console.log('');
return data;
}
async function testTransitFilter(token) {
printTest(7, 'POST /rates/search-csv - Filter by max transit days (≤23 days)');
const response = await fetch(`${API_URL}/api/v1/rates/search-csv`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
origin: 'NLRTM',
destination: 'USNYC',
volumeCBM: 25.5,
weightKG: 3500,
containerType: 'LCL',
filters: {
maxTransitDays: 23,
},
}),
});
const data = await response.json();
printInfo(`Results with transit ≤23 days: ${data.totalResults}`);
const maxTransit = Math.max(...data.results.map(r => r.transitDays));
if (maxTransit <= 23) {
printSuccess(`Transit filter working correctly (max: ${maxTransit} days)`);
} else {
printError(`Transit filter not working - max transit: ${maxTransit} days`);
}
console.log('');
return data;
}
async function testSurchargeFilter(token) {
printTest(8, 'POST /rates/search-csv - Filter for rates without surcharges (all-in prices)');
const response = await fetch(`${API_URL}/api/v1/rates/search-csv`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
origin: 'NLRTM',
destination: 'USNYC',
volumeCBM: 25.5,
weightKG: 3500,
containerType: 'LCL',
filters: {
withoutSurcharges: true,
},
}),
});
const data = await response.json();
printInfo(`Results without surcharges: ${data.totalResults}`);
const withSurcharges = data.results.filter(r => r.hasSurcharges).length;
if (withSurcharges === 0) {
printSuccess('Surcharge filter working correctly');
} else {
printError(`Surcharge filter not working - found ${withSurcharges} results with surcharges`);
}
console.log('');
return data;
}
async function testComparator(token) {
printTest(9, 'COMPARATOR TEST - Show all 5 companies for NLRTM → USNYC');
const response = await fetch(`${API_URL}/api/v1/rates/search-csv`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
origin: 'NLRTM',
destination: 'USNYC',
volumeCBM: 25,
weightKG: 3500,
palletCount: 10,
containerType: 'LCL',
}),
});
const data = await response.json();
console.log('\nCompany Comparison Table:');
console.log('=========================');
data.results.slice(0, 10).forEach(result => {
console.log(
`${result.companyName}: $${result.totalPrice.amount} ${result.totalPrice.currency} - ${result.transitDays} days - Match: ${result.matchScore}%`
);
});
const uniqueCompanies = [...new Set(data.results.map(r => r.companyName))];
printInfo('Companies in results:');
uniqueCompanies.forEach(company => console.log(` - ${company}`));
// Check if Test Maritime Express has lowest price
const sortedByPrice = [...data.results].sort((a, b) => a.totalPrice.amount - b.totalPrice.amount);
const lowestPriceCompany = sortedByPrice[0].companyName;
const lowestPrice = sortedByPrice[0].totalPrice.amount;
if (lowestPriceCompany === 'Test Maritime Express') {
printSuccess('Test Maritime Express has the lowest price ✓');
printInfo(`Lowest price: $${lowestPrice} (Test Maritime Express)`);
} else {
printError(
`Expected Test Maritime Express to have lowest price, but got: ${lowestPriceCompany}`
);
}
console.log('');
return data;
}
async function runTests() {
console.log(`${colors.blue}========================================${colors.reset}`);
console.log(`${colors.blue}CSV Rate API Test Script${colors.reset}`);
console.log(`${colors.blue}========================================${colors.reset}`);
console.log('');
try {
// Authenticate
const token = await authenticateUser();
console.log('');
// Run all tests
await testGetCompanies(token);
await testGetFilterOptions(token);
await testBasicSearch(token);
await testCompanyFilter(token);
await testPriceFilter(token);
await testTransitFilter(token);
await testSurchargeFilter(token);
await testComparator(token);
console.log(`${colors.blue}========================================${colors.reset}`);
console.log(`${colors.green}✓ All public endpoint tests completed!${colors.reset}`);
console.log(`${colors.blue}========================================${colors.reset}`);
console.log('');
console.log('Next steps:');
console.log('1. Run admin tests with an admin account');
console.log('2. Test CSV upload functionality');
console.log('3. Test CSV validation endpoint');
} catch (error) {
printError(`Test failed: ${error.message}`);
console.error(error);
process.exit(1);
}
}
// Run tests
runTests();