383 lines
11 KiB
JavaScript
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();
|