- Auto-fixed 4,496 lint issues (import sorting, modern syntax, etc.) - Added ignore rules for patterns intentional in this codebase: E402 (late imports), E712 (SQLAlchemy filters), B904 (raise from), SIM108/SIM105/SIM117 (readability preferences) - Added per-file ignores for tests and scripts - Excluded broken scripts/rename_terminology.py (has curly quotes) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
249 lines
7.8 KiB
Python
249 lines
7.8 KiB
Python
# tests/integration/api/v1/store/test_messages.py
|
|
"""
|
|
Integration tests for store messaging endpoints.
|
|
|
|
Tests the /api/v1/store/messages/* endpoints.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.api
|
|
@pytest.mark.store
|
|
class TestStoreMessagesListAPI:
|
|
"""Tests for store message list endpoints."""
|
|
|
|
def test_list_conversations_empty(self, client, store_user_headers):
|
|
"""Test listing conversations when none exist."""
|
|
response = client.get("/api/v1/store/messages", headers=store_user_headers)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "conversations" in data
|
|
assert "total" in data
|
|
assert "total_unread" in data
|
|
assert data["total"] == 0
|
|
|
|
def test_list_conversations_requires_auth(self, client):
|
|
"""Test that listing requires authentication."""
|
|
response = client.get("/api/v1/store/messages")
|
|
assert response.status_code == 401
|
|
|
|
def test_list_conversations_with_data(
|
|
self, client, store_user_headers, store_api_conversation
|
|
):
|
|
"""Test listing conversations with existing data."""
|
|
response = client.get("/api/v1/store/messages", headers=store_user_headers)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["total"] >= 1
|
|
|
|
def test_list_conversations_filter_by_type(
|
|
self, client, store_user_headers, store_api_conversation
|
|
):
|
|
"""Test filtering conversations by type."""
|
|
response = client.get(
|
|
"/api/v1/store/messages",
|
|
params={"conversation_type": "admin_store"},
|
|
headers=store_user_headers,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
for conv in data["conversations"]:
|
|
assert conv["conversation_type"] == "admin_store"
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.api
|
|
@pytest.mark.store
|
|
class TestStoreMessagesUnreadCountAPI:
|
|
"""Tests for unread count endpoint."""
|
|
|
|
def test_get_unread_count(self, client, store_user_headers):
|
|
"""Test getting unread count."""
|
|
response = client.get(
|
|
"/api/v1/store/messages/unread-count", headers=store_user_headers
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "total_unread" in data
|
|
assert isinstance(data["total_unread"], int)
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.api
|
|
@pytest.mark.store
|
|
class TestStoreMessagesRecipientsAPI:
|
|
"""Tests for recipients endpoint."""
|
|
|
|
def test_get_customer_recipients(
|
|
self, client, store_user_headers, test_customer
|
|
):
|
|
"""Test getting customer recipients."""
|
|
response = client.get(
|
|
"/api/v1/store/messages/recipients",
|
|
params={"recipient_type": "customer"},
|
|
headers=store_user_headers,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "recipients" in data
|
|
assert "total" in data
|
|
|
|
def test_get_recipients_requires_type(self, client, store_user_headers):
|
|
"""Test that recipient_type is required."""
|
|
response = client.get(
|
|
"/api/v1/store/messages/recipients", headers=store_user_headers
|
|
)
|
|
assert response.status_code == 422
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.api
|
|
@pytest.mark.store
|
|
class TestStoreMessagesCreateAPI:
|
|
"""Tests for conversation creation."""
|
|
|
|
def test_create_conversation_store_customer(
|
|
self, client, store_user_headers, test_customer, test_store
|
|
):
|
|
"""Test creating store-customer conversation."""
|
|
response = client.post(
|
|
"/api/v1/store/messages",
|
|
json={
|
|
"conversation_type": "store_customer",
|
|
"subject": "Customer Support",
|
|
"recipient_type": "customer",
|
|
"recipient_id": test_customer.id,
|
|
"store_id": test_store.id,
|
|
"initial_message": "Hello customer!",
|
|
},
|
|
headers=store_user_headers,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["subject"] == "Customer Support"
|
|
assert data["conversation_type"] == "store_customer"
|
|
|
|
def test_create_conversation_admin_store_not_allowed(
|
|
self, client, store_user_headers, test_admin, test_store
|
|
):
|
|
"""Test store cannot initiate admin_store conversation."""
|
|
response = client.post(
|
|
"/api/v1/store/messages",
|
|
json={
|
|
"conversation_type": "admin_store",
|
|
"subject": "Question for Admin",
|
|
"recipient_type": "admin",
|
|
"recipient_id": test_admin.id,
|
|
"store_id": test_store.id,
|
|
},
|
|
headers=store_user_headers,
|
|
)
|
|
|
|
assert response.status_code == 400
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.api
|
|
@pytest.mark.store
|
|
class TestStoreMessagesDetailAPI:
|
|
"""Tests for conversation detail."""
|
|
|
|
def test_get_conversation_detail(
|
|
self, client, store_user_headers, store_api_conversation
|
|
):
|
|
"""Test getting conversation detail."""
|
|
response = client.get(
|
|
f"/api/v1/store/messages/{store_api_conversation.id}",
|
|
headers=store_user_headers,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["id"] == store_api_conversation.id
|
|
assert "participants" in data
|
|
assert "messages" in data
|
|
|
|
def test_get_conversation_not_found(self, client, store_user_headers):
|
|
"""Test getting nonexistent conversation."""
|
|
response = client.get(
|
|
"/api/v1/store/messages/99999", headers=store_user_headers
|
|
)
|
|
assert response.status_code == 404
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.api
|
|
@pytest.mark.store
|
|
class TestStoreMessagesSendAPI:
|
|
"""Tests for sending messages."""
|
|
|
|
def test_send_message(
|
|
self, client, store_user_headers, store_api_conversation
|
|
):
|
|
"""Test sending a message."""
|
|
response = client.post(
|
|
f"/api/v1/store/messages/{store_api_conversation.id}/messages",
|
|
data={"content": "Reply from store"},
|
|
headers=store_user_headers,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["content"] == "Reply from store"
|
|
assert data["sender_type"] == "store"
|
|
|
|
def test_send_message_to_closed(
|
|
self, client, store_user_headers, store_api_closed_conversation
|
|
):
|
|
"""Test cannot send to closed conversation."""
|
|
response = client.post(
|
|
f"/api/v1/store/messages/{store_api_closed_conversation.id}/messages",
|
|
data={"content": "Test message"},
|
|
headers=store_user_headers,
|
|
)
|
|
|
|
assert response.status_code == 400
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.api
|
|
@pytest.mark.store
|
|
class TestStoreMessagesActionsAPI:
|
|
"""Tests for conversation actions."""
|
|
|
|
def test_mark_read(
|
|
self, client, store_user_headers, store_api_conversation
|
|
):
|
|
"""Test marking conversation as read."""
|
|
response = client.put(
|
|
f"/api/v1/store/messages/{store_api_conversation.id}/read",
|
|
headers=store_user_headers,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["success"] is True
|
|
assert data["unread_count"] == 0
|
|
|
|
def test_update_preferences(
|
|
self, client, store_user_headers, store_api_conversation
|
|
):
|
|
"""Test updating notification preferences."""
|
|
response = client.put(
|
|
f"/api/v1/store/messages/{store_api_conversation.id}/preferences",
|
|
json={"email_notifications": True, "muted": False},
|
|
headers=store_user_headers,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["success"] is True
|