#!/bin/bash # CSV Rate API Test Script # This script tests all CSV rate endpoints set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color API_URL="http://localhost:4000" TOKEN="" ADMIN_TOKEN="" echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}CSV Rate API Test Script${NC}" echo -e "${BLUE}========================================${NC}" echo "" # Function to print test header print_test() { echo -e "${YELLOW}[TEST $1] $2${NC}" } # Function to print success print_success() { echo -e "${GREEN}✓ $1${NC}" } # Function to print error print_error() { echo -e "${RED}✗ $1${NC}" } # Function to print info print_info() { echo -e "${BLUE}→ $1${NC}" } # Step 1: Get authentication token print_test "1" "Authenticating as regular user" LOGIN_RESPONSE=$(curl -s -X POST "$API_URL/api/v1/auth/login" \ -H "Content-Type: application/json" \ -d '{ "email": "test4@xpeditis.com", "password": "SecurePassword123" }') TOKEN=$(echo $LOGIN_RESPONSE | jq -r '.accessToken') if [ "$TOKEN" != "null" ] && [ -n "$TOKEN" ]; then print_success "Regular user authenticated" print_info "Token: ${TOKEN:0:20}..." else print_error "Failed to authenticate regular user" echo "Response: $LOGIN_RESPONSE" exit 1 fi echo "" # Step 2: Test GET /rates/companies print_test "2" "GET /rates/companies - Get available companies" COMPANIES_RESPONSE=$(curl -s -X GET "$API_URL/api/v1/rates/companies" \ -H "Authorization: Bearer $TOKEN") echo "$COMPANIES_RESPONSE" | jq '.' COMPANIES_COUNT=$(echo $COMPANIES_RESPONSE | jq '.total') if [ "$COMPANIES_COUNT" -eq 5 ]; then print_success "Got 5 companies (including Test Maritime Express)" else print_error "Expected 5 companies, got $COMPANIES_COUNT" fi echo "" # Step 3: Test GET /rates/filters/options print_test "3" "GET /rates/filters/options - Get filter options" FILTERS_RESPONSE=$(curl -s -X GET "$API_URL/api/v1/rates/filters/options" \ -H "Authorization: Bearer $TOKEN") echo "$FILTERS_RESPONSE" | jq '.' print_success "Filter options retrieved" echo "" # Step 4: Test POST /rates/search-csv - Basic search print_test "4" "POST /rates/search-csv - Basic rate search (NLRTM → USNYC)" SEARCH_RESPONSE=$(curl -s -X POST "$API_URL/api/v1/rates/search-csv" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{ "origin": "NLRTM", "destination": "USNYC", "volumeCBM": 25.5, "weightKG": 3500, "palletCount": 10, "containerType": "LCL" }') echo "$SEARCH_RESPONSE" | jq '.' TOTAL_RESULTS=$(echo $SEARCH_RESPONSE | jq '.totalResults') print_info "Total results: $TOTAL_RESULTS" # Check if Test Maritime Express is in results HAS_TEST_MARITIME=$(echo $SEARCH_RESPONSE | jq '.results[] | select(.companyName == "Test Maritime Express") | .companyName' | wc -l) if [ "$HAS_TEST_MARITIME" -gt 0 ]; then print_success "Test Maritime Express found in results" # Get Test Maritime Express price TEST_PRICE=$(echo $SEARCH_RESPONSE | jq '.results[] | select(.companyName == "Test Maritime Express") | .totalPrice.amount' | head -1) print_info "Test Maritime Express price: \$$TEST_PRICE" else print_error "Test Maritime Express NOT found in results" fi # Count unique companies in results UNIQUE_COMPANIES=$(echo $SEARCH_RESPONSE | jq -r '.results[].companyName' | sort -u | wc -l) print_info "Results from $UNIQUE_COMPANIES different companies" if [ "$UNIQUE_COMPANIES" -ge 3 ]; then print_success "Multiple companies in comparator ✓" else print_error "Expected multiple companies, got $UNIQUE_COMPANIES" fi echo "" # Step 5: Test POST /rates/search-csv - Filter by company print_test "5" "POST /rates/search-csv - Filter by Test Maritime Express only" FILTER_RESPONSE=$(curl -s -X POST "$API_URL/api/v1/rates/search-csv" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{ "origin": "NLRTM", "destination": "USNYC", "volumeCBM": 25.5, "weightKG": 3500, "palletCount": 10, "containerType": "LCL", "filters": { "companies": ["Test Maritime Express"] } }') echo "$FILTER_RESPONSE" | jq '.results[0:3]' FILTER_COMPANIES=$(echo $FILTER_RESPONSE | jq -r '.results[].companyName' | sort -u) if [ "$FILTER_COMPANIES" == "Test Maritime Express" ]; then print_success "Company filter working correctly" else print_error "Company filter not working - got: $FILTER_COMPANIES" fi echo "" # Step 6: Test POST /rates/search-csv - Filter by price range print_test "6" "POST /rates/search-csv - Filter by price range (\$900-\$1200)" PRICE_FILTER_RESPONSE=$(curl -s -X POST "$API_URL/api/v1/rates/search-csv" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{ "origin": "NLRTM", "destination": "USNYC", "volumeCBM": 25.5, "weightKG": 3500, "palletCount": 10, "containerType": "LCL", "filters": { "minPrice": 900, "maxPrice": 1200, "currency": "USD" } }') PRICE_RESULTS=$(echo $PRICE_FILTER_RESPONSE | jq '.totalResults') print_info "Results in price range \$900-\$1200: $PRICE_RESULTS" # Verify all results are in range MIN_PRICE=$(echo $PRICE_FILTER_RESPONSE | jq '[.results[].totalPrice.amount] | min') MAX_PRICE=$(echo $PRICE_FILTER_RESPONSE | jq '[.results[].totalPrice.amount] | max') if (( $(echo "$MIN_PRICE >= 900" | bc -l) )) && (( $(echo "$MAX_PRICE <= 1200" | bc -l) )); then print_success "Price filter working correctly (range: \$$MIN_PRICE - \$$MAX_PRICE)" else print_error "Price filter not working - got range: \$$MIN_PRICE - \$$MAX_PRICE" fi echo "" # Step 7: Test POST /rates/search-csv - Filter by transit days print_test "7" "POST /rates/search-csv - Filter by max transit days (≤23 days)" TRANSIT_FILTER_RESPONSE=$(curl -s -X POST "$API_URL/api/v1/rates/search-csv" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{ "origin": "NLRTM", "destination": "USNYC", "volumeCBM": 25.5, "weightKG": 3500, "containerType": "LCL", "filters": { "maxTransitDays": 23 } }') TRANSIT_RESULTS=$(echo $TRANSIT_FILTER_RESPONSE | jq '.totalResults') print_info "Results with transit ≤23 days: $TRANSIT_RESULTS" MAX_TRANSIT=$(echo $TRANSIT_FILTER_RESPONSE | jq '[.results[].transitDays] | max') if [ "$MAX_TRANSIT" -le 23 ]; then print_success "Transit filter working correctly (max: $MAX_TRANSIT days)" else print_error "Transit filter not working - max transit: $MAX_TRANSIT days" fi echo "" # Step 8: Test POST /rates/search-csv - Filter by surcharges print_test "8" "POST /rates/search-csv - Filter for rates without surcharges (all-in prices)" SURCHARGE_FILTER_RESPONSE=$(curl -s -X POST "$API_URL/api/v1/rates/search-csv" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{ "origin": "NLRTM", "destination": "USNYC", "volumeCBM": 25.5, "weightKG": 3500, "containerType": "LCL", "filters": { "withoutSurcharges": true } }') SURCHARGE_RESULTS=$(echo $SURCHARGE_FILTER_RESPONSE | jq '.totalResults') print_info "Results without surcharges: $SURCHARGE_RESULTS" # Verify all results have hasSurcharges=false HAS_SURCHARGES=$(echo $SURCHARGE_FILTER_RESPONSE | jq '.results[] | select(.hasSurcharges == true)' | wc -l) if [ "$HAS_SURCHARGES" -eq 0 ]; then print_success "Surcharge filter working correctly" else print_error "Surcharge filter not working - found $HAS_SURCHARGES results with surcharges" fi echo "" # Step 9: Comparison test - Show all companies for same route print_test "9" "COMPARATOR TEST - Show all 5 companies for NLRTM → USNYC" COMPARISON_RESPONSE=$(curl -s -X POST "$API_URL/api/v1/rates/search-csv" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{ "origin": "NLRTM", "destination": "USNYC", "volumeCBM": 25, "weightKG": 3500, "palletCount": 10, "containerType": "LCL" }') echo "Company Comparison Table:" echo "=========================" echo "$COMPARISON_RESPONSE" | jq -r '.results[] | "\(.companyName): $\(.totalPrice.amount) \(.totalPrice.currency) - \(.transitDays) days - Match: \(.matchScore)%"' | head -10 COMPANY_LIST=$(echo $COMPARISON_RESPONSE | jq -r '.results[].companyName' | sort -u) print_info "Companies in results:" echo "$COMPANY_LIST" # Check if Test Maritime Express has lowest price LOWEST_PRICE_COMPANY=$(echo $COMPARISON_RESPONSE | jq -r '[.results[] | {company: .companyName, price: .totalPrice.amount}] | sort_by(.price) | .[0].company') if [ "$LOWEST_PRICE_COMPANY" == "Test Maritime Express" ]; then print_success "Test Maritime Express has the lowest price ✓" LOWEST_PRICE=$(echo $COMPARISON_RESPONSE | jq -r '[.results[]] | sort_by(.totalPrice.amount) | .[0].totalPrice.amount') print_info "Lowest price: \$$LOWEST_PRICE (Test Maritime Express)" else print_error "Expected Test Maritime Express to have lowest price, but got: $LOWEST_PRICE_COMPANY" fi echo "" echo -e "${BLUE}========================================${NC}" echo -e "${GREEN}✓ All public endpoint tests completed!${NC}" echo -e "${BLUE}========================================${NC}" echo "" echo "Next steps:" echo "1. Run admin tests with an admin account" echo "2. Test CSV upload functionality" echo "3. Test CSV validation endpoint" echo "" echo "For admin tests, you need to:" echo "1. Create an admin user or promote existing user to ADMIN role" echo "2. Authenticate to get admin JWT token" echo "3. Run admin endpoints (upload, validate, delete)"