mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-25 08:48:13 +02:00
89 lines
2.8 KiB
Python
89 lines
2.8 KiB
Python
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from api.services.workflow.dto import WebhookNodeData
|
||
|
|
from api.tasks.run_integrations import _execute_webhook_node
|
||
|
|
|
||
|
|
|
||
|
|
def _mock_httpx_client(captured: dict):
|
||
|
|
"""Build a patch target for httpx.AsyncClient that records the request kwargs."""
|
||
|
|
response = MagicMock()
|
||
|
|
response.status_code = 200
|
||
|
|
response.raise_for_status = MagicMock()
|
||
|
|
|
||
|
|
async def _request(**kwargs):
|
||
|
|
captured.update(kwargs)
|
||
|
|
return response
|
||
|
|
|
||
|
|
client = MagicMock()
|
||
|
|
client.request = AsyncMock(side_effect=_request)
|
||
|
|
|
||
|
|
ctx = MagicMock()
|
||
|
|
ctx.__aenter__ = AsyncMock(return_value=client)
|
||
|
|
ctx.__aexit__ = AsyncMock(return_value=False)
|
||
|
|
return MagicMock(return_value=ctx)
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_webhook_injects_disposition_when_absent():
|
||
|
|
"""call_disposition is added to the payload when the template omits it."""
|
||
|
|
webhook = WebhookNodeData(
|
||
|
|
name="Test Webhook",
|
||
|
|
enabled=True,
|
||
|
|
endpoint_url="https://example.com/hook",
|
||
|
|
payload_template={"event": "call_done"},
|
||
|
|
)
|
||
|
|
render_context = {"gathered_context": {"call_disposition": "no-answer"}}
|
||
|
|
|
||
|
|
captured: dict = {}
|
||
|
|
with patch(
|
||
|
|
"api.tasks.run_integrations.httpx.AsyncClient", _mock_httpx_client(captured)
|
||
|
|
):
|
||
|
|
ok = await _execute_webhook_node(webhook, render_context, organization_id=1)
|
||
|
|
|
||
|
|
assert ok is True
|
||
|
|
assert captured["json"] == {
|
||
|
|
"event": "call_done",
|
||
|
|
"call_disposition": "no-answer",
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_webhook_preserves_template_disposition():
|
||
|
|
"""A disposition key set explicitly in the template is not overwritten."""
|
||
|
|
webhook = WebhookNodeData(
|
||
|
|
name="Test Webhook",
|
||
|
|
enabled=True,
|
||
|
|
endpoint_url="https://example.com/hook",
|
||
|
|
payload_template={"call_disposition": "custom-from-template"},
|
||
|
|
)
|
||
|
|
render_context = {"gathered_context": {"call_disposition": "no-answer"}}
|
||
|
|
|
||
|
|
captured: dict = {}
|
||
|
|
with patch(
|
||
|
|
"api.tasks.run_integrations.httpx.AsyncClient", _mock_httpx_client(captured)
|
||
|
|
):
|
||
|
|
await _execute_webhook_node(webhook, render_context, organization_id=1)
|
||
|
|
|
||
|
|
assert captured["json"]["call_disposition"] == "custom-from-template"
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_webhook_injects_empty_disposition_when_context_missing():
|
||
|
|
"""Missing gathered_context values fall back to an empty string, not omission."""
|
||
|
|
webhook = WebhookNodeData(
|
||
|
|
name="Test Webhook",
|
||
|
|
enabled=True,
|
||
|
|
endpoint_url="https://example.com/hook",
|
||
|
|
payload_template={},
|
||
|
|
)
|
||
|
|
|
||
|
|
captured: dict = {}
|
||
|
|
with patch(
|
||
|
|
"api.tasks.run_integrations.httpx.AsyncClient", _mock_httpx_client(captured)
|
||
|
|
):
|
||
|
|
await _execute_webhook_node(webhook, {}, organization_id=1)
|
||
|
|
|
||
|
|
assert captured["json"] == {"call_disposition": ""}
|