Files
scrap/tests/api/test_webhooks_funcs.py
Gilles Soulier 152c2724fc feat: improve SPA scraping and increase test coverage
- Add SPA support for Playwright with wait_for_network_idle and extra_wait_ms
- Add BaseStore.get_spa_config() and requires_playwright() methods
- Implement AliExpress SPA config with JSON price extraction patterns
- Fix Amazon price parsing to prioritize whole+fraction combination
- Fix AliExpress regex patterns (remove double backslashes)
- Add CLI tests: detect, doctor, fetch, parse, run commands
- Add API tests: auth, logs, products, scraping_logs, webhooks

Tests: 417 passed, 85% coverage

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 14:46:55 +01:00

160 lines
5.5 KiB
Python

"""Tests API endpoints webhooks."""
from datetime import datetime
from unittest.mock import MagicMock, patch
import pytest
from fastapi import HTTPException
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
from pricewatch.app.api.main import (
list_webhooks,
create_webhook,
update_webhook,
delete_webhook,
)
from pricewatch.app.api.schemas import WebhookCreate, WebhookUpdate
class MockWebhook:
"""Mock Webhook model."""
def __init__(self, **kwargs):
self.id = kwargs.get("id", 1)
self.url = kwargs.get("url", "https://example.com/webhook")
self.events = kwargs.get("events", ["price_change", "stock_change"])
self.active = kwargs.get("active", True)
self.created_at = kwargs.get("created_at", datetime.now())
self.last_triggered_at = kwargs.get("last_triggered_at")
class TestListWebhooks:
"""Tests list_webhooks endpoint."""
def test_list_webhooks_empty(self):
"""Liste vide de webhooks."""
session = MagicMock()
mock_query = MagicMock()
mock_query.all.return_value = []
session.query.return_value = mock_query
with patch("pricewatch.app.api.main._webhook_to_out") as mock_to_out:
result = list_webhooks(session=session)
assert result == []
class TestCreateWebhook:
"""Tests create_webhook endpoint."""
def test_create_webhook_integrity_error(self):
"""Erreur d'integrite lors de creation webhook leve 500."""
# Note: le code actuel ne distingue pas IntegrityError de SQLAlchemyError
session = MagicMock()
session.add = MagicMock()
session.commit = MagicMock(side_effect=IntegrityError("duplicate", {}, None))
session.rollback = MagicMock()
payload = WebhookCreate(
event="price_change",
url="https://example.com/webhook",
)
with patch("pricewatch.app.api.main.Webhook"):
with pytest.raises(HTTPException) as exc_info:
create_webhook(payload, session)
assert exc_info.value.status_code == 500
def test_create_webhook_db_error(self):
"""Erreur DB lors de creation webhook leve 500."""
session = MagicMock()
session.add = MagicMock()
session.commit = MagicMock(side_effect=SQLAlchemyError("error"))
session.rollback = MagicMock()
payload = WebhookCreate(
event="price_change",
url="https://example.com/webhook",
)
with patch("pricewatch.app.api.main.Webhook"):
with pytest.raises(HTTPException) as exc_info:
create_webhook(payload, session)
assert exc_info.value.status_code == 500
class TestUpdateWebhook:
"""Tests update_webhook endpoint."""
def test_update_webhook_not_found(self):
"""Update webhook non trouve leve 404."""
session = MagicMock()
mock_query = MagicMock()
mock_query.filter.return_value.one_or_none.return_value = None
session.query.return_value = mock_query
payload = WebhookUpdate(active=False)
with pytest.raises(HTTPException) as exc_info:
update_webhook(99999, payload, session)
assert exc_info.value.status_code == 404
def test_update_webhook_db_error(self):
"""Erreur DB lors d'update webhook leve 500."""
session = MagicMock()
mock_webhook = MockWebhook()
mock_query = MagicMock()
mock_query.filter.return_value.one_or_none.return_value = mock_webhook
session.query.return_value = mock_query
session.commit = MagicMock(side_effect=SQLAlchemyError("error"))
session.rollback = MagicMock()
payload = WebhookUpdate(active=False)
with patch("pricewatch.app.api.main._webhook_to_out"):
with pytest.raises(HTTPException) as exc_info:
update_webhook(1, payload, session)
assert exc_info.value.status_code == 500
class TestDeleteWebhook:
"""Tests delete_webhook endpoint."""
def test_delete_webhook_not_found(self):
"""Delete webhook non trouve leve 404."""
session = MagicMock()
mock_query = MagicMock()
mock_query.filter.return_value.one_or_none.return_value = None
session.query.return_value = mock_query
with pytest.raises(HTTPException) as exc_info:
delete_webhook(99999, session)
assert exc_info.value.status_code == 404
def test_delete_webhook_success(self):
"""Delete webhook avec succes."""
session = MagicMock()
mock_webhook = MockWebhook()
mock_query = MagicMock()
mock_query.filter.return_value.one_or_none.return_value = mock_webhook
session.query.return_value = mock_query
session.delete = MagicMock()
session.commit = MagicMock()
result = delete_webhook(1, session)
assert result == {"status": "deleted"}
session.delete.assert_called_once()
def test_delete_webhook_db_error(self):
"""Erreur DB lors de delete webhook leve 500."""
session = MagicMock()
mock_webhook = MockWebhook()
mock_query = MagicMock()
mock_query.filter.return_value.one_or_none.return_value = mock_webhook
session.query.return_value = mock_query
session.delete = MagicMock()
session.commit = MagicMock(side_effect=SQLAlchemyError("error"))
session.rollback = MagicMock()
with pytest.raises(HTTPException) as exc_info:
delete_webhook(1, session)
assert exc_info.value.status_code == 500