"""Tests for WhatsApp webhook endpoints.""" import pytest from fastapi.testclient import TestClient from src.main import create_app @pytest.fixture def client(): """Create test client.""" app = create_app() return TestClient(app) class TestWebhookVerification: """Test GET /webhooks/whatsapp verification endpoint.""" def test_verify_subscription_success(self, client, monkeypatch): """Successful webhook verification returns challenge.""" monkeypatch.setenv("META_WEBHOOK_VERIFY_TOKEN", "test-token") response = client.get( "/api/v1/webhooks/whatsapp", params={ "hub.mode": "subscribe", "hub.verify_token": "test-token", "hub.challenge": "123456789", }, ) assert response.status_code == 200 assert response.text == "123456789" def test_verify_subscription_invalid_token(self, client, monkeypatch): """Invalid token returns 403.""" monkeypatch.setenv("META_WEBHOOK_VERIFY_TOKEN", "test-token") response = client.get( "/api/v1/webhooks/whatsapp", params={ "hub.mode": "subscribe", "hub.verify_token": "wrong-token", "hub.challenge": "123456789", }, ) assert response.status_code == 403 class TestWebhookReceive: """Test POST /webhooks/whatsapp message reception.""" def test_receive_text_message(self, client): """Process incoming text message.""" payload = { "object": "whatsapp_business_account", "entry": [{ "id": "WHATSAPP_BUSINESS_ACCOUNT_ID", "changes": [{ "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "16505551111", "phone_number_id": "123456789", }, "contacts": [{ "profile": {"name": "Test User"}, "wa_id": "5216641234567", }], "messages": [{ "from": "5216641234567", "id": "wamid.TEST123", "timestamp": "1234567890", "text": {"body": "Hola, quiero agendar una cita"}, "type": "text", }], }, "field": "messages", }], }], } response = client.post("/api/v1/webhooks/whatsapp", json=payload) # In development, it processes synchronously assert response.status_code == 200 data = response.json() assert data["status"] in ("processed", "no_messages") def test_receive_status_update(self, client): """Acknowledge status update without processing.""" payload = { "object": "whatsapp_business_account", "entry": [{ "id": "WHATSAPP_BUSINESS_ACCOUNT_ID", "changes": [{ "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "16505551111", "phone_number_id": "123456789", }, "statuses": [{ "id": "wamid.TEST123", "status": "delivered", "timestamp": "1234567890", "recipient_id": "5216641234567", }], }, "field": "messages", }], }], } response = client.post("/api/v1/webhooks/whatsapp", json=payload) assert response.status_code == 200 data = response.json() assert data["status"] == "acknowledged" def test_invalid_payload(self, client): """Invalid payload should be ignored gracefully.""" payload = {"object": "not_whatsapp"} response = client.post("/api/v1/webhooks/whatsapp", json=payload) assert response.status_code == 200 assert response.json()["status"] == "ignored"