diff --git a/.github/workflows/test-selenoid.yml b/.github/workflows/test-selenoid.yml index ee3441a..f093c0d 100644 --- a/.github/workflows/test-selenoid.yml +++ b/.github/workflows/test-selenoid.yml @@ -10,9 +10,9 @@ jobs: name: Run test suite runs-on: ubuntu-latest env: - LOCALTEST: 1 + SELENOIDTEST: 1 steps: - name: Checkout code uses: actions/checkout@v3 - name: Run tests - run: LOCALTEST=1 docker-compose -f docker-compose.test.yml run bot python -m pytest tests/bot/test_bot.py::test_selenoid_text -vv \ No newline at end of file + run: docker-compose -f docker-compose.test.yml run bot python -m pytest tests/bot/test_bot_selenoid.py -vv \ No newline at end of file diff --git a/README.md b/README.md index 211d3d8..73fab91 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,10 @@ killall python ``` ## Tests -docker-compose run bot python -m pytest tests/bot/test_bot.py::test_selenoid_text + +```bash +SELENOIDTEST=1 docker-compose -f docker-compose.test.yml run bot python -m pytest tests/bot/test_bot_selenoid.py::test_selenoid_text -vv +``` ## Help article diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 212dda1..1becee9 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -40,7 +40,7 @@ services: USER: root restart: unless-stopped environment: - LOCALTEST: ${LOCALTEST} + SELENOIDTEST: ${SELENOIDTEST} depends_on: - selenoid volumes: diff --git a/tests/bot/test_bot.py b/tests/bot/test_bot.py index 2a8e453..2182db3 100644 --- a/tests/bot/test_bot.py +++ b/tests/bot/test_bot.py @@ -1,6 +1,4 @@ -import os import time -from unittest import mock import pytest from aiogram import Bot, Dispatcher, types @@ -8,15 +6,15 @@ from aiogram.dispatcher.filters.builtin import Command from aiogram.types import Update from app.core.bot import TransportBot from tests.conftest import FakeTelegram -from tests.data.factories import UserFactory +from tests.data.factories import ChatFactory, UserFactory pytestmark = [ pytest.mark.asyncio, ] -async def test_parse_yandex_maps(bot: Bot) -> None: - tg_user = UserFactory().as_dict() +async def test_get_me_from_bot(bot: Bot) -> None: + tg_user = UserFactory()._asdict() user = types.User(**tg_user) async with FakeTelegram(message_data=tg_user): @@ -45,21 +43,8 @@ async def test_update(dispatcher_fixture: Dispatcher) -> None: 'update_id': 957250703, 'message': { 'message_id': 417070387, - 'from': { - 'id': 417070387, - 'is_bot': False, - 'first_name': 'Dmitry', - 'last_name': 'Afanasyev', - 'username': 'Balshtg', - 'language_code': 'en', - }, - 'chat': { - 'id': 417070387, - 'first_name': 'Dmitry', - 'last_name': 'Afanasyev', - 'username': 'Balshtg', - 'type': 'private', - }, + 'from': UserFactory()._asdict(), + 'chat': ChatFactory()._asdict(), 'date': time.time(), 'text': '/chatid', 'entities': [{'type': 'bot_command', 'offset': 0, 'length': 7}], @@ -71,66 +56,3 @@ async def test_update(dispatcher_fixture: Dispatcher) -> None: update = Update(**data) result = await TransportBot.echo(update.message) assert result == types.Message(**data) - - -@pytest.mark.skipif( - bool(os.environ.get("LOCALTEST", False)) is False, - reason="Schemathesis test will be skipped if environment var SCHEMATHESIS=1 is not set", -) -async def test_selenoid_text(dispatcher_fixture: Dispatcher) -> None: - data = { - 'id': '1791303673263594560', - 'from': { - 'id': 417070387, - 'is_bot': False, - 'first_name': 'Dmitry', - 'last_name': 'Afanasyev', - 'username': 'Balshtg', - 'language_code': 'en', - }, - 'message': { - 'message_id': 1316, - 'from': { - 'id': 5494499556, - 'is_bot': False, - 'first_name': 'balshbot_transport', - 'username': 'balshbot_transport_bot', - }, - 'chat': { - 'id': 417070387, - 'first_name': 'Dmitry', - 'last_name': 'Afanasyev', - 'username': 'Balshtg', - 'type': 'private', - }, - 'date': 1661692626, - 'text': 'Остановка Б. Академическая ул, д. 15\n\nАвтобус 300 - прибывает\nАвтобус Т19 - 7 мин', - 'reply_markup': { - 'inline_keyboard': [ - [ - { - 'text': 'Дом -> Офис', - 'callback_data': 'station:home->office', - }, - { - 'text': 'Офис -> Дом', - 'callback_data': 'station:office->home', - }, - ] - ] - }, - }, - 'chat_instance': '-6044557427944557947', - 'data': 'station:home->office', - } - TransportBot.bot = dispatcher_fixture.bot - - # @mock.patch('app.core.bot.TransportBot.bot.send_message') - with mock.patch( - 'app.core.bot.TransportBot.bot.send_message', - return_value=data['message']['chat'], # type: ignore - ): - async with FakeTelegram(message_data=data): - call_back = types.CallbackQuery(**data) - result = await TransportBot.home_office(query=call_back, callback_data={}) - assert result == data['message']['chat'] # type: ignore diff --git a/tests/bot/test_bot_selenoid.py b/tests/bot/test_bot_selenoid.py new file mode 100644 index 0000000..581ec6d --- /dev/null +++ b/tests/bot/test_bot_selenoid.py @@ -0,0 +1,76 @@ +import os +from unittest import mock + +import pytest +from aiogram import Dispatcher, types +from app.core.bot import TransportBot +from core.parse_web import WebParser +from faker import Faker +from tests.conftest import FakeTelegram +from tests.data.factories import ChatFactory, UserFactory + +pytestmark = [ + pytest.mark.asyncio, + pytest.mark.skipif( + bool(os.environ.get("SELENOIDTEST", False)) is False, + reason="Selenoid test must be run with selenoid server", + ), +] + + +async def test_selenoid_text(dispatcher_fixture: Dispatcher, faker: Faker) -> None: + data = { + 'id': '1791303673263594560', + 'from': UserFactory()._asdict(), + 'message': { + 'message_id': faker.random_int(), + 'from': { + 'id': faker.random_int(), + 'is_bot': False, + 'first_name': 'balshbot_transport', + 'username': 'balshbot_transport_bot', + }, + 'chat': ChatFactory()._asdict(), + 'date': 1661692626, + 'text': 'Остановка Б. Академическая ул, д. 15\n\nАвтобус 300 - прибывает\nАвтобус Т19 - 7 мин', + 'reply_markup': { + 'inline_keyboard': [ + [ + { + 'text': 'Дом -> Офис', + 'callback_data': 'station:home->office', + }, + { + 'text': 'Офис -> Дом', + 'callback_data': 'station:office->home', + }, + ] + ] + }, + }, + 'chat_instance': f'-{faker.random_int()}', + 'data': 'station:home->office', + } + TransportBot.bot = dispatcher_fixture.bot + + # @mock.patch('app.core.bot.TransportBot.bot.send_message') + with mock.patch( + 'app.core.bot.TransportBot.bot.send_message', + return_value=data['message']['chat'], + ): + async with FakeTelegram(message_data=data): + call_back = types.CallbackQuery(**data) + result = await TransportBot.home_office(query=call_back, callback_data={}) + assert result == data['message']['chat'] + + +async def test_selenoid_parse_yandex() -> None: + driver = WebParser.get_driver() + text = WebParser.parse_yandex_maps( + driver=driver, + url='https://yandex.ru/maps/213/moscow/stops/stop__9640740/?ll=37.527924%2C55.823470&tab=overview&z=21', + message='Остановка Б. Академическая ул, д. 15', + ) + assert 'Остановка Б. Академическая ул, д. 15' in text + assert 'Автобус 300' in text + assert 'Автобус Т19' in text diff --git a/tests/data/factories.py b/tests/data/factories.py index 920f133..ea310a1 100644 --- a/tests/data/factories.py +++ b/tests/data/factories.py @@ -1,6 +1,6 @@ import factory from faker import Faker -from tests.data.models import User +from tests.data.models import Chat, User faker = Faker('ru_RU') @@ -15,3 +15,14 @@ class UserFactory(factory.Factory): class Meta: model = User + + +class ChatFactory(factory.Factory): + id = factory.Sequence(lambda n: 1 + n) + first_name = factory.Faker('first_name') + last_name = factory.Faker('last_name') + username = faker.profile(fields=['username'])['username'] + type = 'private' + + class Meta: + model = Chat diff --git a/tests/data/models.py b/tests/data/models.py index 2cab4ca..985832b 100644 --- a/tests/data/models.py +++ b/tests/data/models.py @@ -1,7 +1,7 @@ """" Dict data set for Telegram message types """ -from typing import Any, NamedTuple +from typing import NamedTuple class User(NamedTuple): @@ -12,8 +12,13 @@ class User(NamedTuple): username: str | None language_code: str - def as_dict(self) -> dict[str, Any]: - return self._asdict() + +class Chat(NamedTuple): + id: int + first_name: str | None + last_name: str | None + username: str + type: str USER = {