302 lines
9.1 KiB
Bash
Executable File
302 lines
9.1 KiB
Bash
Executable File
#!/bin/bash
|
||
# Shell Whats API Test Script
|
||
# Tests all critical endpoints to verify the backend is working properly
|
||
|
||
set -e
|
||
|
||
# Colors for output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Configuration (can be overridden via env vars)
|
||
BASE_URL="${BASE_URL:-http://localhost:3000}"
|
||
VERIFY_TOKEN="${VERIFY_TOKEN:-test-token}"
|
||
|
||
# Test counters
|
||
PASSED=0
|
||
FAILED=0
|
||
|
||
# Helper functions
|
||
print_header() {
|
||
echo ""
|
||
echo "========================================"
|
||
echo "$1"
|
||
echo "========================================"
|
||
}
|
||
|
||
print_success() {
|
||
echo -e "${GREEN}✓ PASS${NC}: $1"
|
||
((PASSED++)) || true
|
||
}
|
||
|
||
print_failure() {
|
||
echo -e "${RED}✗ FAIL${NC}: $1"
|
||
if [ -n "$2" ]; then
|
||
echo " Error: $2"
|
||
fi
|
||
((FAILED++)) || true
|
||
}
|
||
|
||
print_info() {
|
||
echo -e "${YELLOW}ℹ INFO${NC}: $1"
|
||
}
|
||
|
||
# Test 1: Health Check Endpoint
|
||
print_header "Test 1: Health Check (/health)"
|
||
HEALTH_RESPONSE=$(curl -s -w "\n%{http_code}" "${BASE_URL}/health" 2>/dev/null) || {
|
||
print_failure "Health check request failed" "Could not connect to ${BASE_URL}"
|
||
exit 1
|
||
}
|
||
|
||
HTTP_CODE=$(echo "$HEALTH_RESPONSE" | tail -n1)
|
||
BODY=$(echo "$HEALTH_RESPONSE" | sed '$d')
|
||
|
||
if [ "$HTTP_CODE" = "200" ]; then
|
||
if echo "$BODY" | grep -q '"status":"ok"'; then
|
||
print_success "Health endpoint returns 200 with status:ok"
|
||
else
|
||
print_failure "Health endpoint returned 200 but unexpected body: $BODY"
|
||
fi
|
||
else
|
||
print_failure "Health endpoint returned HTTP $HTTP_CODE" "$BODY"
|
||
fi
|
||
|
||
# Test 2: Privacy Policy Page
|
||
print_header "Test 2: Privacy Policy Page (/privacy)"
|
||
PRIVACY_RESPONSE=$(curl -s -w "\n%{http_code}" "${BASE_URL}/privacy" 2>/dev/null)
|
||
HTTP_CODE=$(echo "$PRIVACY_RESPONSE" | tail -n1)
|
||
BODY=$(echo "$PRIVACY_RESPONSE" | sed '$d')
|
||
|
||
if [ "$HTTP_CODE" = "200" ]; then
|
||
if echo "$BODY" | grep -q "Privacy Policy"; then
|
||
print_success "Privacy page returns 200 with expected content"
|
||
else
|
||
print_failure "Privacy page missing expected content"
|
||
fi
|
||
else
|
||
print_failure "Privacy page returned HTTP $HTTP_CODE"
|
||
fi
|
||
|
||
# Test 3: Terms of Service Page
|
||
print_header "Test 3: Terms of Service Page (/terms)"
|
||
TERMS_RESPONSE=$(curl -s -w "\n%{http_code}" "${BASE_URL}/terms" 2>/dev/null)
|
||
HTTP_CODE=$(echo "$TERMS_RESPONSE" | tail -n1)
|
||
BODY=$(echo "$TERMS_RESPONSE" | sed '$d')
|
||
|
||
if [ "$HTTP_CODE" = "200" ]; then
|
||
if echo "$BODY" | grep -q "Terms of Service"; then
|
||
print_success "Terms page returns 200 with expected content"
|
||
else
|
||
print_failure "Terms page missing expected content"
|
||
fi
|
||
else
|
||
print_failure "Terms page returned HTTP $HTTP_CODE"
|
||
fi
|
||
|
||
# Test 4: Meta Webhook Verification (GET /webhook)
|
||
print_header "Test 4: Meta Webhook Verification (GET /webhook)"
|
||
VERIFY_RESPONSE=$(curl -s -w "\n%{http_code}" \
|
||
"${BASE_URL}/webhook?hub.mode=subscribe&hub.verify_token=${VERIFY_TOKEN}&hub.challenge=test-challenge-123" \
|
||
2>/dev/null)
|
||
HTTP_CODE=$(echo "$VERIFY_RESPONSE" | tail -n1)
|
||
BODY=$(echo "$VERIFY_RESPONSE" | sed '$d')
|
||
|
||
if [ "$HTTP_CODE" = "200" ]; then
|
||
if [ "$BODY" = "test-challenge-123" ]; then
|
||
print_success "Webhook verification returns challenge with valid token"
|
||
else
|
||
print_failure "Webhook verification returned 200 but wrong challenge" "Got: $BODY"
|
||
fi
|
||
else
|
||
print_failure "Webhook verification returned HTTP $HTTP_CODE" "$BODY"
|
||
fi
|
||
|
||
# Test 5: Meta Webhook Verification (Invalid Token)
|
||
print_header "Test 5: Meta Webhook Verification - Invalid Token"
|
||
VERIFY_FAIL_RESPONSE=$(curl -s -w "\n%{http_code}" \
|
||
"${BASE_URL}/webhook?hub.mode=subscribe&hub.verify_token=invalid-token&hub.challenge=test" \
|
||
2>/dev/null)
|
||
HTTP_CODE=$(echo "$VERIFY_FAIL_RESPONSE" | tail -n1)
|
||
|
||
if [ "$HTTP_CODE" = "403" ]; then
|
||
print_success "Webhook verification returns 403 for invalid token"
|
||
else
|
||
print_failure "Webhook verification should return 403 for invalid token, got $HTTP_CODE"
|
||
fi
|
||
|
||
# Test 6: Meta Webhook Message Reception (POST /webhook)
|
||
print_header "Test 6: Meta Webhook Message Reception (POST /webhook)"
|
||
WEBHOOK_PAYLOAD='{
|
||
"object": "whatsapp_business_account",
|
||
"entry": [{
|
||
"id": "test-entry-id",
|
||
"changes": [{
|
||
"value": {
|
||
"messaging_product": "whatsapp",
|
||
"metadata": {
|
||
"display_phone_number": "15551234567",
|
||
"phone_number_id": "test-phone-id"
|
||
},
|
||
"contacts": [{
|
||
"profile": {"name": "Test User"},
|
||
"wa_id": "5511999999999"
|
||
}],
|
||
"messages": [{
|
||
"from": "5511999999999",
|
||
"id": "test-message-id",
|
||
"timestamp": "'$(date +%s)'",
|
||
"type": "text",
|
||
"text": {"body": "Hello, this is a test message"}
|
||
}]
|
||
},
|
||
"field": "messages"
|
||
}]
|
||
}]
|
||
}'
|
||
|
||
WEBHOOK_RESPONSE=$(curl -s -w "\n%{http_code}" \
|
||
-X POST \
|
||
-H "Content-Type: application/json" \
|
||
-d "$WEBHOOK_PAYLOAD" \
|
||
"${BASE_URL}/webhook" \
|
||
2>/dev/null)
|
||
HTTP_CODE=$(echo "$WEBHOOK_RESPONSE" | tail -n1)
|
||
|
||
if [ "$HTTP_CODE" = "200" ]; then
|
||
print_success "Webhook accepts message payload and returns 200"
|
||
else
|
||
print_failure "Webhook message reception returned HTTP $HTTP_CODE"
|
||
fi
|
||
|
||
# Test 7: Chatwoot Webhook Message (POST /chatwoot-webhook)
|
||
print_header "Test 7: Chatwoot Webhook - Outgoing Message (POST /chatwoot-webhook)"
|
||
CHATWOOT_PAYLOAD='{
|
||
"event": "message_created",
|
||
"message_type": "outgoing",
|
||
"private": false,
|
||
"content": "Test reply from agent",
|
||
"conversation": {
|
||
"id": 12345,
|
||
"meta": {
|
||
"sender": {
|
||
"phone_number": "+5511999999999"
|
||
}
|
||
}
|
||
}
|
||
}'
|
||
|
||
CHATWOOT_RESPONSE=$(curl -s -w "\n%{http_code}" \
|
||
-X POST \
|
||
-H "Content-Type: application/json" \
|
||
-d "$CHATWOOT_PAYLOAD" \
|
||
"${BASE_URL}/chatwoot-webhook" \
|
||
2>/dev/null)
|
||
HTTP_CODE=$(echo "$CHATWOOT_RESPONSE" | tail -n1)
|
||
|
||
if [ "$HTTP_CODE" = "200" ]; then
|
||
print_success "Chatwoot webhook accepts outgoing message and returns 200"
|
||
else
|
||
print_failure "Chatwoot webhook returned HTTP $HTTP_CODE"
|
||
fi
|
||
|
||
# Test 8: Chatwoot Webhook - Private Message (should be ignored)
|
||
print_header "Test 8: Chatwoot Webhook - Private Message (should be ignored)"
|
||
CHATWOOT_PRIVATE_PAYLOAD='{
|
||
"event": "message_created",
|
||
"message_type": "outgoing",
|
||
"private": true,
|
||
"content": "Private note",
|
||
"conversation": {
|
||
"id": 12345,
|
||
"meta": {
|
||
"sender": {
|
||
"phone_number": "+5511999999999"
|
||
}
|
||
}
|
||
}
|
||
}'
|
||
|
||
CHATWOOT_PRIVATE_RESPONSE=$(curl -s -w "\n%{http_code}" \
|
||
-X POST \
|
||
-H "Content-Type: application/json" \
|
||
-d "$CHATWOOT_PRIVATE_PAYLOAD" \
|
||
"${BASE_URL}/chatwoot-webhook" \
|
||
2>/dev/null)
|
||
HTTP_CODE=$(echo "$CHATWOOT_PRIVATE_RESPONSE" | tail -n1)
|
||
|
||
if [ "$HTTP_CODE" = "200" ]; then
|
||
print_success "Chatwoot webhook handles private messages (returns 200)"
|
||
else
|
||
print_failure "Chatwoot webhook for private message returned HTTP $HTTP_CODE"
|
||
fi
|
||
|
||
# Test 9: Chatwoot Webhook - Conversation Status Changed
|
||
print_header "Test 9: Chatwoot Webhook - Conversation Resolved"
|
||
CHATWOOT_STATUS_PAYLOAD='{
|
||
"event": "conversation_status_changed",
|
||
"status": "resolved",
|
||
"id": 12345
|
||
}'
|
||
|
||
CHATWOOT_STATUS_RESPONSE=$(curl -s -w "\n%{http_code}" \
|
||
-X POST \
|
||
-H "Content-Type: application/json" \
|
||
-d "$CHATWOOT_STATUS_PAYLOAD" \
|
||
"${BASE_URL}/chatwoot-webhook" \
|
||
2>/dev/null)
|
||
HTTP_CODE=$(echo "$CHATWOOT_STATUS_RESPONSE" | tail -n1)
|
||
|
||
if [ "$HTTP_CODE" = "200" ]; then
|
||
print_success "Chatwoot webhook handles status change events"
|
||
else
|
||
print_failure "Chatwoot webhook status change returned HTTP $HTTP_CODE"
|
||
fi
|
||
|
||
# Test 10: Webhook with Missing Fields (Edge Case)
|
||
print_header "Test 10: Webhook - Malformed Payload (Edge Case)"
|
||
MALFORMED_PAYLOAD='{"entry": [{"changes": [{}]}]}'
|
||
|
||
MALFORMED_RESPONSE=$(curl -s -w "\n%{http_code}" \
|
||
-X POST \
|
||
-H "Content-Type: application/json" \
|
||
-d "$MALFORMED_PAYLOAD" \
|
||
"${BASE_URL}/webhook" \
|
||
2>/dev/null)
|
||
HTTP_CODE=$(echo "$MALFORMED_RESPONSE" | tail -n1)
|
||
|
||
if [ "$HTTP_CODE" = "200" ]; then
|
||
print_success "Webhook handles malformed payload gracefully (returns 200)"
|
||
else
|
||
print_failure "Webhook malformed payload returned HTTP $HTTP_CODE"
|
||
fi
|
||
|
||
# Test 11: Root endpoint (404 expected - no root handler defined)
|
||
print_header "Test 11: Root Endpoint (/) - Expected 404"
|
||
ROOT_RESPONSE=$(curl -s -w "\n%{http_code}" "${BASE_URL}/" 2>/dev/null)
|
||
HTTP_CODE=$(echo "$ROOT_RESPONSE" | tail -n1)
|
||
|
||
# Currently no root handler is defined, so 404 is expected
|
||
if [ "$HTTP_CODE" = "404" ]; then
|
||
print_success "Root endpoint returns 404 as expected (no handler defined)"
|
||
else
|
||
print_info "Root endpoint returned HTTP $HTTP_CODE (expected 404 - no root route defined)"
|
||
# Don't count this as a failure since the behavior is correct
|
||
fi
|
||
|
||
# Summary
|
||
print_header "Test Summary"
|
||
echo "================================"
|
||
echo -e "${GREEN}Passed: $PASSED${NC}"
|
||
echo -e "${RED}Failed: $FAILED${NC}"
|
||
echo "================================"
|
||
|
||
if [ $FAILED -eq 0 ]; then
|
||
echo -e "${GREEN}All tests passed!${NC}"
|
||
exit 0
|
||
else
|
||
echo -e "${RED}Some tests failed!${NC}"
|
||
exit 1
|
||
fi
|