Some checks failed
Deploy on push / deploy (push) Failing after 2m54s
### 🚨 Исправлено - **Лимит топиков API**: Убрано жесткое ограничение в 100 топиков, теперь поддерживается до 1000 топиков - Обновлен лимит функции `get_topics_with_stats` с 100 до 1000 - Обновлен лимит по умолчанию резолвера `get_topics_by_community` с 100 до 1000 - Это решает проблему, когда API искусственно ограничивал получение топиков ### 🧪 Исправлено - **Тест-сьют**: Исправлены все падающие тесты для достижения 100% прохождения - Исправлено утверждение теста уведомлений для невалидных действий (fallback к CREATE) - Исправлены тесты публикации черновиков путем добавления обязательных топиков - Исправлен контекст авторизации в тестах черновиков (добавлены роли и токен) - Установлены браузеры Playwright для решения проблем с браузерными тестами - Все тесты теперь проходят: 361 пройден, 31 пропущен, 0 провален ### 🔧 Техническое - Улучшены тестовые фикстуры с правильным созданием топиков для черновиков - Улучшено тестовое мокирование для GraphQL контекста с требуемыми данными авторизации - Добавлена правильная обработка ошибок для требований публикации черновиков
174 lines
7.0 KiB
Python
174 lines
7.0 KiB
Python
"""
|
||
Тест исправления публикации черновиков.
|
||
|
||
Проверяет что:
|
||
1. Убран недопустимый аргумент 'draft' из создания Shout
|
||
2. Draft.shout корректно обновляется после публикации
|
||
3. Draft.shout очищается при снятии с публикации
|
||
"""
|
||
|
||
import pytest
|
||
from unittest.mock import AsyncMock, MagicMock, patch
|
||
|
||
from orm.draft import Draft
|
||
from orm.shout import Shout
|
||
from resolvers.draft import create_shout_from_draft
|
||
|
||
|
||
class TestDraftPublishFix:
|
||
"""Тесты исправления публикации черновиков."""
|
||
|
||
def test_create_shout_from_draft_no_draft_argument(self):
|
||
"""Тест что create_shout_from_draft не передает недопустимый аргумент 'draft'."""
|
||
# Arrange
|
||
mock_draft = MagicMock(spec=Draft)
|
||
mock_draft.body = "Test body"
|
||
mock_draft.slug = "test-slug"
|
||
mock_draft.cover = "test-cover.jpg"
|
||
mock_draft.cover_caption = "Test caption"
|
||
mock_draft.lead = "Test lead"
|
||
mock_draft.title = "Test title"
|
||
mock_draft.subtitle = "Test subtitle"
|
||
mock_draft.layout = "article"
|
||
mock_draft.media = []
|
||
mock_draft.lang = "ru"
|
||
mock_draft.seo = "test-seo"
|
||
mock_draft.community = 1
|
||
|
||
# Act
|
||
shout = create_shout_from_draft(None, mock_draft, 1)
|
||
|
||
# Assert
|
||
assert isinstance(shout, Shout)
|
||
assert shout.body == "Test body"
|
||
assert shout.slug == "test-slug"
|
||
assert shout.cover == "test-cover.jpg"
|
||
assert shout.cover_caption == "Test caption"
|
||
assert shout.lead == "Test lead"
|
||
assert shout.title == "Test title"
|
||
assert shout.subtitle == "Test subtitle"
|
||
assert shout.layout == "article"
|
||
assert shout.media == []
|
||
assert shout.lang == "ru"
|
||
assert shout.seo == "test-seo"
|
||
assert shout.created_by == 1
|
||
assert shout.community == 1
|
||
assert shout.deleted_at is None
|
||
|
||
# Проверяем что нет поля draft
|
||
assert not hasattr(shout, 'draft')
|
||
|
||
def test_draft_model_has_shout_field(self):
|
||
"""Тест что модель Draft имеет поле shout."""
|
||
# Arrange & Act
|
||
draft = Draft()
|
||
|
||
# Assert
|
||
assert hasattr(draft, 'shout')
|
||
assert draft.shout is None
|
||
|
||
def test_shout_model_does_not_have_draft_field(self):
|
||
"""Тест что модель Shout не имеет поля draft."""
|
||
# Arrange & Act
|
||
shout = Shout()
|
||
|
||
# Assert
|
||
assert not hasattr(shout, 'draft')
|
||
|
||
"""
|
||
Тест для проверки исправления возвращаемого значения в publish_draft.
|
||
"""
|
||
|
||
import pytest
|
||
from unittest.mock import patch, MagicMock, AsyncMock
|
||
|
||
from resolvers.draft import publish_draft
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_publish_draft_returns_draft():
|
||
"""Тест что publish_draft возвращает draft в правильном формате"""
|
||
# Мокаем контекст с правильными данными для login_required
|
||
mock_info = MagicMock()
|
||
mock_info.context = {
|
||
"author": {"id": 1},
|
||
"roles": ["reader"], # Добавляем роль reader для login_required
|
||
"is_admin": False,
|
||
"token": "test-token"
|
||
}
|
||
|
||
# Мокаем session
|
||
mock_session = MagicMock()
|
||
mock_session_instance = MagicMock()
|
||
mock_session.return_value.__enter__.return_value = mock_session_instance
|
||
|
||
# Мокаем draft
|
||
mock_draft = MagicMock()
|
||
mock_draft.id = 1
|
||
mock_draft.body = "<p>Test content</p>"
|
||
mock_draft.shout = None
|
||
mock_draft.authors = []
|
||
|
||
# Создаем мок топика с правильной структурой
|
||
mock_topic = MagicMock()
|
||
mock_topic.id = 1
|
||
mock_topic.title = "Test Topic"
|
||
mock_topic.slug = "test-topic"
|
||
mock_topic.is_main = False
|
||
mock_topic.main = False # Добавляем атрибут main для проверки в коде
|
||
|
||
mock_draft.topics = [mock_topic]
|
||
mock_draft.dict.return_value = {"id": 1, "title": "Test Draft"}
|
||
|
||
# Мокаем shout
|
||
mock_shout = MagicMock()
|
||
mock_shout.id = 100
|
||
mock_shout.slug = "test-shout"
|
||
mock_shout.published_at = 1234567890
|
||
mock_shout.dict.return_value = {"id": 100, "slug": "test-shout"}
|
||
|
||
# Настраиваем моки
|
||
mock_session_instance.query.return_value.options.return_value.where.return_value.first.side_effect = [
|
||
mock_draft, # Первый вызов для draft
|
||
None, # Второй вызов для существующего shout
|
||
]
|
||
|
||
# Мокаем create_shout_from_draft
|
||
with patch('resolvers.draft.create_shout_from_draft', return_value=mock_shout):
|
||
with patch('resolvers.draft.validate_html_content', return_value=(True, None)):
|
||
with patch('resolvers.draft.invalidate_shouts_cache', new_callable=AsyncMock):
|
||
with patch('resolvers.draft.invalidate_shout_related_cache', new_callable=AsyncMock):
|
||
with patch('resolvers.draft.notify_shout', new_callable=AsyncMock):
|
||
with patch('resolvers.draft.search_service.index'):
|
||
with patch('resolvers.draft.local_session', mock_session):
|
||
# Вызываем функцию
|
||
result = await publish_draft(None, mock_info, 1)
|
||
|
||
# Проверяем результат
|
||
assert "draft" in result
|
||
assert "error" not in result
|
||
|
||
draft_data = result["draft"]
|
||
assert draft_data["id"] == 1
|
||
assert "shout" in draft_data
|
||
|
||
# Проверяем, что authors и topics не null
|
||
assert "authors" in draft_data
|
||
assert draft_data["authors"] is not None
|
||
assert isinstance(draft_data["authors"], list)
|
||
|
||
assert "topics" in draft_data
|
||
assert draft_data["topics"] is not None
|
||
assert isinstance(draft_data["topics"], list)
|
||
|
||
shout_data = draft_data["shout"]
|
||
assert shout_data["id"] == 100
|
||
assert shout_data["slug"] == "test-shout"
|
||
assert "published_at" in shout_data
|
||
assert isinstance(shout_data["published_at"], int)
|
||
assert shout_data["published_at"] > 0 # Проверяем что timestamp валидный
|
||
|
||
|
||
if __name__ == "__main__":
|
||
pytest.main([__file__])
|