diff --git a/resa_padel/booking.py b/resa_padel/booking.py index c3271f4..b5a58f1 100644 --- a/resa_padel/booking.py +++ b/resa_padel/booking.py @@ -3,7 +3,7 @@ import logging import config from gestion_sports_services import GestionSportsServices -from models import Action, BookingFilter, Club, Court, User +from models import Action, BookingFilter, Club, Court, Tournament, User LOGGER = logging.getLogger(__name__) @@ -51,7 +51,18 @@ async def cancel_booking_id(club: Club, user: User, booking_id: int) -> None: await service.cancel_booking_id(user, club, booking_id) -def main() -> tuple[Court, User] | None: +async def get_tournaments(club: Club, user: User) -> list[Tournament]: + """ + Cancel a booking that matches the booking id + + :param club: the club in which the booking was made + :param user: the user who made the booking + """ + service = GestionSportsServices() + return await service.get_all_tournaments(user, club) + + +def main() -> tuple[Court, User] | list[Tournament] | None: """ Main function used to book a court @@ -80,3 +91,8 @@ def main() -> tuple[Court, User] | None: club = config.get_club() booking_filter = config.get_booking_filter() asyncio.run(cancel_booking(club, user, booking_filter)) + + elif action == Action.TOURNAMENTS: + user = config.get_user() + club = config.get_club() + return asyncio.run(get_tournaments(club, user)) diff --git a/resa_padel/booking_service.py b/resa_padel/booking_service.py deleted file mode 100644 index 1c9c437..0000000 --- a/resa_padel/booking_service.py +++ /dev/null @@ -1,42 +0,0 @@ -import logging - -from aiohttp import ClientSession -from connectors import Connector -from models import BookingFilter, Club, User - -LOGGER = logging.getLogger(__name__) - - -class BookingService: - def __init__(self, club: Club, connector: Connector): - LOGGER.info("Initializing booking service at for club", club.name) - self.club = club - self.connector = connector - self.session: ClientSession | None = None - - async def __aenter__(self): - self.session = ClientSession() - return self - - async def __aexit__(self, exc_type, exc_val, exc_tb): - await self.session.close() - - async def book(self, user: User, booking_filter: BookingFilter) -> int | None: - """ - Book a court matching the booking filters for a user. - The steps to perform a booking are to go to the landing page, to log in, wait - and for the time when booking is open and then actually book the court - - :param user: the user that wants to book a court - :param booking_filter: the booking criteria - :return: the court number if the booking is successful, None otherwise - """ - if self.connector is None: - LOGGER.error("No connection to Gestion Sports is available") - return None - - if user is None or booking_filter is None: - LOGGER.error("Not enough information available to book a court") - return None - - self.connector.book(user, booking_filter) diff --git a/resa_padel/config.py b/resa_padel/config.py index a0069ae..70132b5 100644 --- a/resa_padel/config.py +++ b/resa_padel/config.py @@ -143,4 +143,4 @@ def get_action() -> Action: Get the action to perform from an environment variable :return: the action to perform """ - return Action(os.environ.get("ACTION")) + return Action(os.environ.get("ACTION").lower()) diff --git a/resa_padel/connectors.py b/resa_padel/gestion_sport_connector.py similarity index 90% rename from resa_padel/connectors.py rename to resa_padel/gestion_sport_connector.py index 5b9469e..55abcea 100644 --- a/resa_padel/connectors.py +++ b/resa_padel/gestion_sport_connector.py @@ -49,6 +49,11 @@ class GestionSportsConnector: self.club.booking_platform.urls.get(name).path, ) + def _get_url_parameter(self, name: str) -> str: + self._check_url_path_exists(name) + + return self.club.booking_platform.urls.get(name).parameter + def _get_payload_template(self, name: str) -> Path: """ Get the path to the template file for the service with the given name @@ -178,6 +183,18 @@ class GestionSportsConnector: """ return self._get_payload_template("cancellation") + @property + def tournaments_sessions_url(self) -> str: + return self._get_url_path("tournament-sessions") + + @property + def tournaments_sessions_template(self) -> Path: + return self._get_payload_template("tournament-sessions") + + @property + def tournaments_list_url(self) -> str: + return self._get_url_path("tournaments-list") + @property def available_sports(self) -> dict[str, Sport]: """ @@ -209,7 +226,7 @@ class GestionSportsConnector: payload = PayloadBuilder.build(self.login_template, user=user, club=self.club) async with session.post( - self.login_url, data=payload, headers=POST_HEADERS + self.login_url, data=payload, headers=POST_HEADERS, allow_redirects=False ) as response: resp_text = await response.text() LOGGER.debug("Connexion request response:\n%s", resp_text) @@ -421,3 +438,23 @@ class GestionSportsConnector: for booking in bookings: if booking.matches(booking_filter): return await self.cancel_booking_id(session, booking.id) + + async def send_tournaments_sessions_request( + self, session: ClientSession + ) -> ClientResponse: + payload = self.tournaments_sessions_template.read_text() + + async with session.post( + self.tournaments_sessions_url, data=payload, headers=POST_HEADERS + ) as response: + LOGGER.debug("tournament sessions: \n%s", await response.text()) + return response + + async def send_tournaments_request( + self, session: ClientSession, tournement_session_id: str + ) -> ClientResponse: + final_url = self.tournaments_list_url + tournement_session_id + LOGGER.debug("Getting tournaments list at %s", final_url) + async with session.get(final_url) as response: + LOGGER.debug("tournaments: %s\n", await response.text()) + return response diff --git a/resa_padel/gestion_sports_services.py b/resa_padel/gestion_sports_services.py index d196eba..d616484 100644 --- a/resa_padel/gestion_sports_services.py +++ b/resa_padel/gestion_sports_services.py @@ -1,10 +1,12 @@ +import json import logging import time import pendulum from aiohttp import ClientSession -from connectors import GestionSportsConnector -from models import BookingFilter, BookingOpening, Club, Court, User +from bs4 import BeautifulSoup +from gestion_sport_connector import GestionSportsConnector +from models import BookingFilter, BookingOpening, Club, Court, Tournament, User from pendulum import DateTime LOGGER = logging.getLogger(__name__) @@ -125,3 +127,62 @@ class GestionSportsServices: booking_minute = opening_time.minute return booking_date.at(booking_hour, booking_minute) + + @staticmethod + async def get_all_tournaments(user: User, club: Club) -> list[Tournament]: + connector = GestionSportsConnector(club) + async with ClientSession() as session: + await connector.land(session) + await connector.login(session, user) + + session_html = await connector.send_tournaments_sessions_request(session) + tournaments_id = GestionSportsServices.retrieve_tournament_session( + await session_html.text() + ) + + tournaments = await connector.send_tournaments_request( + session, tournaments_id + ) + return GestionSportsServices.retrieve_tournaments(await tournaments.text()) + + @staticmethod + def retrieve_tournament_session(sessions: str) -> str: + session_object = json.loads(sessions).get("Inscription tournois:school-outline") + return list(session_object.keys())[0] + + @staticmethod + def retrieve_tournaments(html: str) -> list[Tournament]: + soup = BeautifulSoup(html, "html.parser") + tournaments = [] + + cards = soup.find_all("div", {"class": "card-body"}) + for card in cards: + title = card.find("h5") + price = title.find("span").get_text().strip() + name = title.get_text().strip().removesuffix(price).strip() + elements = card.find("div", {"class": "row"}).find_all("li") + date = elements[0].get_text().strip() + start_time, end_time = ( + elements[2].get_text().strip().replace("h", ":").split(" - ") + ) + start_datetime = pendulum.from_format( + f"{date} {start_time}", "DD/MM/YYYY HH:mm" + ) + end_datetime = pendulum.from_format( + f"{date} {end_time}", "DD/MM/YYYY HH:mm" + ) + gender = elements[1].get_text().strip() + places_left = ( + card.find("span", {"class": "nb_place_libre"}).get_text().strip() + ) + tournament = Tournament( + name=name, + price=price, + start_date=start_datetime, + end_date=end_datetime, + gender=gender, + places_left=places_left, + ) + tournaments.append(tournament) + + return tournaments diff --git a/resa_padel/models.py b/resa_padel/models.py index d13b375..1fbb39c 100644 --- a/resa_padel/models.py +++ b/resa_padel/models.py @@ -70,6 +70,7 @@ class Sport(BaseModel): class Url(BaseModel): name: str path: str + parameter: Optional[str] = Field(default=None) payload_template: Optional[str] = Field(default=None, alias="payloadTemplate") @@ -210,3 +211,13 @@ class Booking(BaseModel): class Action(Enum): BOOK = "book" CANCEL = "cancel" + TOURNAMENTS = "tournaments" + + +class Tournament(BaseModel): + name: str + price: str + start_date: DateTime + end_date: DateTime + gender: str + places_left: str | int diff --git a/resa_padel/resources/gestion-sports/post-headers.json b/resa_padel/resources/gestion-sports/post-headers.json index 8adccc1..0071be4 100644 --- a/resa_padel/resources/gestion-sports/post-headers.json +++ b/resa_padel/resources/gestion-sports/post-headers.json @@ -1,12 +1,16 @@ { - "Connection": "keep-alive", + "Accept": "application/json, text/javascript, */*; q=0.01", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate, br", - "DNT": "1", + "Cache-Control": "no-cache", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", - "Accept": "application/json, text/javascript, */*; q=0.01", - "X-Requested-With": "XMLHttpRequest", + "Connection": "keep-alive", + "DNT": "1", + "Origin": "https://toulousepadelclub.gestion-sports.com", + "Pragma": "no-cache", "Sec-Fetch-Dest": "empty", "Sec-Fetch-Mode": "cors", - "Sec-Fetch-Site": "same-origin" + "Sec-Fetch-Site": "same-origin", + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "X-Requested-With": "XMLHttpRequest" } diff --git a/resa_padel/resources/gestion-sports/tournament-sessions-payload.txt b/resa_padel/resources/gestion-sports/tournament-sessions-payload.txt new file mode 100644 index 0000000..179ea03 --- /dev/null +++ b/resa_padel/resources/gestion-sports/tournament-sessions-payload.txt @@ -0,0 +1 @@ +ajax=loadSessionForSpecDay&date=all diff --git a/resa_padel/resources/platforms.yaml b/resa_padel/resources/platforms.yaml index 7f1525f..3a5a37e 100644 --- a/resa_padel/resources/platforms.yaml +++ b/resa_padel/resources/platforms.yaml @@ -17,3 +17,8 @@ platforms: - name: cancellation path: /membre/mesresas.html payloadTemplate: gestion-sports/booking-cancellation-payload.txt + - name: tournament-sessions + path: /membre/index.php + payloadTemplate: gestion-sports/tournament-sessions-payload.txt + - name: tournaments-list + path: /membre/events/event.html?event= diff --git a/tests/data/configuration/platforms.yaml b/tests/data/configuration/platforms.yaml index f3cdc8e..4d82911 100644 --- a/tests/data/configuration/platforms.yaml +++ b/tests/data/configuration/platforms.yaml @@ -16,4 +16,9 @@ platforms: payloadTemplate: gestion-sports/user-bookings-payload.txt - name: cancellation path: /cancel.html - payloadTemplate: gestion-sports/booking-cancellation-payload.txt + payloadTemplate: sports/booking-cancellation-payload.txt + - name: tournament-sessions + path: /membre/index.php + payloadTemplate: sports/tournament-sessions-payload.txt + - name: tournament-list + path: /membre/events/event.html?event= diff --git a/tests/data/responses/booking_failure.json b/tests/data/responses/booking-failure.json similarity index 100% rename from tests/data/responses/booking_failure.json rename to tests/data/responses/booking-failure.json diff --git a/tests/data/responses/booking_success.json b/tests/data/responses/booking-success.json similarity index 100% rename from tests/data/responses/booking_success.json rename to tests/data/responses/booking-success.json diff --git a/tests/data/responses/cancellation_response.json b/tests/data/responses/cancellation-response.json similarity index 100% rename from tests/data/responses/cancellation_response.json rename to tests/data/responses/cancellation-response.json diff --git a/tests/data/responses/landing_response.html b/tests/data/responses/landing-response.html similarity index 100% rename from tests/data/responses/landing_response.html rename to tests/data/responses/landing-response.html diff --git a/tests/data/responses/login_failure.json b/tests/data/responses/login-failure.json similarity index 100% rename from tests/data/responses/login_failure.json rename to tests/data/responses/login-failure.json diff --git a/tests/data/responses/login_success.json b/tests/data/responses/login-success.json similarity index 100% rename from tests/data/responses/login_success.json rename to tests/data/responses/login-success.json diff --git a/tests/data/responses/tournament-sessions.html b/tests/data/responses/tournament-sessions.html new file mode 100644 index 0000000..ff61262 --- /dev/null +++ b/tests/data/responses/tournament-sessions.html @@ -0,0 +1,1380 @@ + + + + + + Home + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ image + Le Mas + à l'instant +
+ + + +
+
+
+

Titre de la notif

+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+
+ + + + +
+ +
+ Accueil
+
+ + + 37 + +
+
+ + + + +
+
+
imageimageimageimageimageimage
imageimageimageimage
+
+ +
+
+
imageimageimageimage
imageimageimageimage
imageimage
+
+ + + + +
+ +
+

Bonjour Audiard,

+
+ +
+ + + +
+ Padel / Squash / Electrostimulation +
+
+ +
+ +
+ + + + + + + + + + +
+
+
+
+
+ +
+ Évènements +
+ +
+ +
+
+
+
+ +
+ +
+
    +
+
+ +
+
+
+
+
+ + +
+
+
+ +
Toulouse Padel Club
+

+ 11 rue Marie Louise Dissard
+ 31300
+ Toulouse
+

+ +
+
+
+ +
+ + +
+
+
+
+
+
+
+
+ + + + +
+ + +
+ + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + Accueil +
+
+ + +
+ + Actualités +
+
+ + +
+
+ + Réserver +
+
+ +
+ + +
+ + Compte +
+
+ + +
+ + Menu +
+
+ +
+ + + + + + + + + + + + + + + + + + +
+
+ +
+ Votre inscription à la partie de Tennis a bien été enregistrée !
+ Rendez-vous le 14 Janvier de 16h30 à 17h30. +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/responses/tournament-sessions.json b/tests/data/responses/tournament-sessions.json new file mode 100644 index 0000000..c1137c4 --- /dev/null +++ b/tests/data/responses/tournament-sessions.json @@ -0,0 +1,21 @@ +{ + "Inscription tournois:school-outline": { + "1174": { + "id": 1174, + "sport": "padel", + "clubName": "toulouse padel club", + "nom": "Tournoi", + "dateNextSession": "25\/03\/2024", + "dateDebut": "01\/08\/2022", + "dateFin": "01\/10\/2024", + "logo": "TCP_Ligue_Arcanthe2-01-min.png", + "nbSession": 14, + "icon": "school-outline", + "playerCanSeeThisEvent": null, + "type": "tournoi", + "isJp": false, + "isCiup": false, + "sqlDate": "2024-03-25 13:30:00" + } + } +} diff --git a/tests/data/responses/tournaments.html b/tests/data/responses/tournaments.html new file mode 100644 index 0000000..5f4a137 --- /dev/null +++ b/tests/data/responses/tournaments.html @@ -0,0 +1,2459 @@ + + + + + Evenements + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+
+ + + Retour + + + + + +
+ +
+ Evenements
+
+ + + 37 + +
+
+ + + + +
+
+ + + + + + + + +
+
+ +

Padel

+ +
+
+ + + +
+ +
+ +
+
+ + +
+ Tournoi P250 aprem + + +
+
+ 50,00 € +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    25/03/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Homme / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    13h30 - 19h00
    +
    +
    +
  • +
+
+
+ + +
+ Complet +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P25 matin + + +
+
+ 50,00 € +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    28/03/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Homme / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    08h00 - 12h00
    +
    +
    +
  • +
+
+
+ + + +
+ 1 place(s) restante(s) +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P25 matin + + +
+
+ 50,00 € +
+
+ +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    30/03/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Open / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    08h30 - 12h00
    +
    +
    +
  • +
+
+
+ + +
+ Complet +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P100 Femmes + + +
+
+ 50,00 € +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    30/03/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Femme / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    08h30 - 12h00
    +
    +
    +
  • +
+
+
+ + +
+ Exclusivement pour les femmes. +
+
+ Complet +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P250 après-midi + + +
+
+ 50,00 € +
+
+ +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    30/03/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Open / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    13h30 - 18h00
    +
    +
    +
  • +
+
+
+ + +
+ Complet +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P100 matin + + +
+
+ 50,00 € +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    04/04/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Homme / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    08h00 - 12h00
    +
    +
    +
  • +
+
+
+ + +
+ Complet +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P100 aprem + + +
+
+ 50,00 € +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    08/04/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Homme / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    13h30 - 19h00
    +
    +
    +
  • +
+
+
+ + +
+ Complet +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P25 matin + + +
+
+ 50,00 € +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    11/04/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Homme / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    08h00 - 12h00
    +
    +
    +
  • +
+
+
+ + +
+ Complet +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P100 mixte + + +
+
+ 50,00 € +
+
+ +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    20/04/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Mixte / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    08h30 - 13h00
    +
    +
    +
  • +
+
+
+ + +
+ Complet +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P100 + + +
+
+ 50,00 € +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    20/04/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Homme / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    08h30 - 13h30
    +
    +
    +
  • +
+
+
+ + +
+ Complet +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P250 hommes + + +
+
+ 50,00 € +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    20/04/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Homme / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    13h30 - 19h00
    +
    +
    +
  • +
+
+
+ + +
+ Complet +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P25 femmes + + +
+
+ 50,00 € +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    20/04/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Femme / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    14h00 - 18h30
    +
    +
    +
  • +
+
+
+ + +
+ Exclusivement pour les femmes. +
+
+ 8 place(s) restante(s) +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P250 aprem + + +
+
+ 50,00 € +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    22/04/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Homme / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    13h30 - 19h00
    +
    +
    +
  • +
+
+
+ + +
+ Complet +
+
+ +
+
+
+ +
+ +
+
+ + +
+ Tournoi P25 matin + + +
+
+ 50,00 € +
+
+
+
+
    +
  • +
    +
    + +
    +
    +
    25/04/2024
    +
    +
    +
  • + +
  • +
    +
    + +
    +
    +
    Homme / Double
    +
    +
    +
  • +
+
    +
  • +
    +
    + +
    +
    +
    08h00 - 12h00
    +
    +
    +
  • +
+
+
+ + +
+ Complet +
+
+ +
+
+
+
+ + + + + + + + + + + + + +
+ + +
+ + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ image + Le Mas + à l'instant +
+ + + +
+
+
+

Titre de la notif

+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. +
+
+
+
+
+ + + + + + + + + + +
+ + + + + + + + + + + + +
+ +
+ + Accueil +
+
+ + +
+ + Actualités +
+
+ + +
+
+ + Réserver +
+
+ +
+ + +
+ + Compte +
+
+ + +
+ + Menu +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/responses/user_bookings_get.html b/tests/data/responses/user-bookings-get.html similarity index 100% rename from tests/data/responses/user_bookings_get.html rename to tests/data/responses/user-bookings-get.html diff --git a/tests/data/responses/user_bookings_post.json b/tests/data/responses/user-bookings-post.json similarity index 100% rename from tests/data/responses/user_bookings_post.json rename to tests/data/responses/user-bookings-post.json diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py index 0e10773..666fd90 100644 --- a/tests/integration_tests/conftest.py +++ b/tests/integration_tests/conftest.py @@ -4,7 +4,7 @@ from pathlib import Path import config import pendulum import pytest -from connectors import GestionSportsConnector +from gestion_sport_connector import GestionSportsConnector from models import BookingFilter, Club, User TEST_FOLDER = Path(__file__).parent.parent @@ -36,11 +36,17 @@ def booking_filter() -> BookingFilter: @pytest.fixture def booking_success_response() -> dict: - booking_success_file = RESPONSES_FOLDER / "booking_success.json" + booking_success_file = RESPONSES_FOLDER / "booking-success.json" return json.loads(booking_success_file.read_text(encoding="utf-8")) @pytest.fixture def booking_failure_response() -> dict: - booking_failure_file = RESPONSES_FOLDER / "booking_failure.json" - return json.loads(booking_failure_file.read_text(encoding="utf-8")) + file = RESPONSES_FOLDER / "booking-failure.json" + return json.loads(file.read_text(encoding="utf-8")) + + +@pytest.fixture +def tournament_sessions_json() -> str: + file = RESPONSES_FOLDER / "tournament-sessions.json" + return file.read_text(encoding="utf-8") diff --git a/tests/integration_tests/test_booking.py b/tests/integration_tests/test_booking.py index 22e9613..db6c6e1 100644 --- a/tests/integration_tests/test_booking.py +++ b/tests/integration_tests/test_booking.py @@ -57,3 +57,18 @@ def test_main_booking(): ) def test_main_cancellation(): booking.main() + + +@patch.dict( + os.environ, + { + "CLUB_ID": "tpc", + "ACTION": "tournaments", + "LOGIN": "padel.testing@jouf.fr", + "PASSWORD": "ridicule", + }, + clear=True, +) +def test_main_tournaments(): + tournaments = booking.main() + assert len(tournaments) != 0 diff --git a/tests/integration_tests/test_connectors.py b/tests/integration_tests/test_gestion_sport_connector.py similarity index 72% rename from tests/integration_tests/test_connectors.py rename to tests/integration_tests/test_gestion_sport_connector.py index a5f3f88..4e5bb44 100644 --- a/tests/integration_tests/test_connectors.py +++ b/tests/integration_tests/test_gestion_sport_connector.py @@ -1,36 +1,15 @@ +import json import os from pathlib import Path from unittest.mock import patch -import aiohttp import pendulum import pytest -from connectors import GestionSportsConnector -from models import BookingFilter, Club -from pendulum import DateTime +from aiohttp import ClientSession +from gestion_sport_connector import GestionSportsConnector from yarl import URL -def retrieve_booking_datetime( - a_booking_filter: BookingFilter, a_club: Club -) -> DateTime: - """ - Utility to retrieve the booking datetime from the booking filter and the club - - :param a_booking_filter: the booking filter that contains the date to book - :param a_club: the club which has the number of days before the date and the booking time - """ - booking_opening = a_club.booking_platform.booking_opening - opening_time = pendulum.parse(booking_opening.opening_time) - booking_hour = opening_time.hour - booking_minute = opening_time.minute - - date_to_book = a_booking_filter.date - return date_to_book.subtract(days=booking_opening.days_before).at( - booking_hour, booking_minute - ) - - @patch.dict( os.environ, {"CLUB_ID": "tpc"}, @@ -57,6 +36,10 @@ def test_urls(connector): connector.booking_cancellation_url == "https://toulousepadelclub.gestion-sports.com/membre/mesresas.html" ) + assert ( + connector.tournaments_sessions_url + == "https://toulousepadelclub.gestion-sports.com/membre/index.php" + ) @patch.dict( @@ -76,11 +59,15 @@ def test_urls_payload_templates(connector): connector.booking_cancel_template == resources_folder / "booking-cancellation-payload.txt" ) + assert ( + connector.tournaments_sessions_template + == resources_folder / "tournament-sessions-payload.txt" + ) @pytest.mark.asyncio async def test_landing_page(connector): - async with aiohttp.ClientSession() as session: + async with ClientSession() as session: response = await connector.land(session) assert response.status == 200 @@ -93,7 +80,7 @@ async def test_landing_page(connector): @pytest.mark.asyncio async def test_login(connector, user): - async with aiohttp.ClientSession() as session: + async with ClientSession() as session: await connector.land(session) response = await connector.login(session, user) @@ -128,7 +115,7 @@ def test_get_booked_court( @pytest.mark.asyncio async def test_book_one_court(connector, user, booking_filter): - async with aiohttp.ClientSession() as session: + async with ClientSession() as session: await connector.land(session) await connector.login(session, user) @@ -156,28 +143,9 @@ def test_build_booking_datetime(connector, booking_filter): assert opening_datetime.minute == 0 -@patch("pendulum.now") -def test_wait_until_booking_time(mock_now, connector, booking_filter, club): - booking_datetime = retrieve_booking_datetime(booking_filter, club) - - seconds = [ - booking_datetime.subtract(seconds=3), - booking_datetime.subtract(seconds=2), - booking_datetime.subtract(seconds=1), - booking_datetime, - booking_datetime.add(microseconds=1), - booking_datetime.add(microseconds=2), - ] - mock_now.side_effect = seconds - - connector.wait_until_booking_time(booking_filter) - - assert pendulum.now() == booking_datetime.add(microseconds=1) - - @pytest.mark.asyncio async def test_get_hash(connector, user): - async with aiohttp.ClientSession() as session: + async with ClientSession() as session: await connector.land(session) await connector.login(session, user) @@ -197,7 +165,7 @@ def test_get_hash_input(): @pytest.mark.asyncio async def test_get_bookings(connector, user): - async with aiohttp.ClientSession() as session: + async with ClientSession() as session: await connector.land(session) await connector.login(session, user) @@ -210,7 +178,7 @@ async def test_get_bookings(connector, user): @pytest.mark.asyncio async def test_get_ongoing_bookings(connector, user): - async with aiohttp.ClientSession() as session: + async with ClientSession() as session: await connector.land(session) await connector.login(session, user) @@ -218,20 +186,13 @@ async def test_get_ongoing_bookings(connector, user): print(bookings) -@pytest.mark.asyncio -async def test_has_user_ongoing_bookings(connector, user): - assert await connector.has_user_ongoing_booking(user) - - @pytest.mark.asyncio async def test_cancel_booking_id(connector, user): - async with aiohttp.ClientSession() as session: + async with ClientSession() as session: await connector.land(session) await connector.login(session, user) - ongoing_bookings = await connector.get_ongoing_bookings(session) - booking_id = ongoing_bookings[0].id - response = await connector.cancel_booking_id(user, booking_id) + await connector.cancel_booking_id(session, 666) assert len(await connector.get_ongoing_bookings(session)) == 0 @@ -245,7 +206,33 @@ def test_find_court(connector): @pytest.mark.asyncio async def test_cancel_booking(connector, user, booking_filter): - async with aiohttp.ClientSession() as session: + async with ClientSession() as session: await connector.land(session) await connector.login(session, user) await connector.cancel_booking(session, booking_filter) + + +@pytest.mark.asyncio +async def test_tournament_sessions(connector, user): + async with ClientSession() as session: + await connector.land(session) + await connector.login(session, user) + response = await connector.send_tournaments_sessions_request(session) + + assert response.status == 200 + + all_sessions = json.loads(await response.text()) + sessions = all_sessions.get("Inscription tournois:school-outline") + assert len(sessions) == 1 + + +@pytest.mark.asyncio +async def test_send_tournaments_request(connector, user): + async with ClientSession() as session: + await connector.land(session) + await connector.login(session, user) + tournament_session_id = "1174" + response = await connector.send_tournaments_request( + session, tournament_session_id + ) + assert "Complet" in await response.text() diff --git a/tests/integration_tests/test_gestion_sports_services.py b/tests/integration_tests/test_gestion_sports_services.py index c1ccc69..323e5e0 100644 --- a/tests/integration_tests/test_gestion_sports_services.py +++ b/tests/integration_tests/test_gestion_sports_services.py @@ -18,3 +18,9 @@ async def test_user_has_available_slots(club, user): @pytest.mark.asyncio async def test_cancel_booking(club, user, booking_filter): await GestionSportsServices.cancel_booking(user, club, booking_filter) + + +@pytest.mark.asyncio +async def test_get_all_tournaments(user, club): + tournaments = await GestionSportsServices.get_all_tournaments(user, club) + assert len(tournaments) == 14 diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index 8ab4b06..bde7bae 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -3,7 +3,7 @@ from pathlib import Path import pendulum import pytest -from connectors import GestionSportsConnector +from gestion_sport_connector import GestionSportsConnector from gestion_sports_services import GestionSportsServices from models import ( BookingFilter, @@ -43,7 +43,7 @@ def court14() -> Court: @pytest.fixture -def sport1(court11, court12, court13, court14) -> Sport: +def sport1(court11: Court, court12: Court, court13: Court, court14: Court) -> Sport: return Sport( name="Sport1", id=8, @@ -75,7 +75,7 @@ def court24() -> Court: @pytest.fixture -def sport2(court21, court22, court23, court24) -> Sport: +def sport2(court21: Court, court22: Court, court23: Court, court24: Court) -> Sport: return Sport( name="Sport 2", id=10, @@ -130,9 +130,26 @@ def cancellation_url() -> Url: ) +@pytest.fixture +def tournament_sessions_url() -> Url: + return Url( + name="tournament-sessions", + path="/tournaments_sessions.php", + payloadTemplate="gestion-sports/tournament-sessions-payload.txt", + ) + + +@pytest.fixture +def tournaments_list_url() -> Url: + return Url( + name="tournaments-list", + path="/tournaments_list.html?event=", + ) + + @pytest.fixture def booking_opening() -> BookingOpening: - return BookingOpening(daysBefore=10, time="03:27") + return BookingOpening(daysBefore=7, time="00:00") @pytest.fixture @@ -142,15 +159,17 @@ def total_bookings() -> TotalBookings: @pytest.fixture def booking_platform( - booking_opening, - total_bookings, - sport1, - sport2, - landing_url, - login_url, - booking_url, - user_bookings_url, - cancellation_url, + booking_opening: BookingOpening, + total_bookings: TotalBookings, + sport1: Sport, + sport2: Sport, + landing_url: str, + login_url: str, + booking_url: str, + user_bookings_url: str, + cancellation_url: str, + tournament_sessions_url: str, + tournaments_list_url: str, ) -> BookingPlatform: return BookingPlatform( id="gestion-sports", @@ -166,12 +185,14 @@ def booking_platform( "booking": booking_url, "user-bookings": user_bookings_url, "cancellation": cancellation_url, + "tournament-sessions": tournament_sessions_url, + "tournaments-list": tournaments_list_url, }, ) @pytest.fixture -def club(booking_platform) -> Club: +def club(booking_platform: BookingPlatform) -> Club: return Club( id="super_club", name="Super Club", @@ -204,42 +225,42 @@ def booking_filter() -> BookingFilter: @pytest.fixture def landing_response() -> str: - landing_response_file = RESPONSES_FOLDER / "landing_response.html" - return landing_response_file.read_text(encoding="utf-8") + file = RESPONSES_FOLDER / "landing-response.html" + return file.read_text(encoding="utf-8") @pytest.fixture def login_success_response() -> dict: - login_success_file = RESPONSES_FOLDER / "login_success.json" + login_success_file = RESPONSES_FOLDER / "login-success.json" return json.loads(login_success_file.read_text(encoding="utf-8")) @pytest.fixture def login_failure_response() -> dict: - login_failure_file = RESPONSES_FOLDER / "login_failure.json" - return json.loads(login_failure_file.read_text(encoding="utf-8")) + file = RESPONSES_FOLDER / "login-failure.json" + return json.loads(file.read_text(encoding="utf-8")) @pytest.fixture def booking_success_response() -> dict: - booking_success_file = RESPONSES_FOLDER / "booking_success.json" - return json.loads(booking_success_file.read_text(encoding="utf-8")) + file = RESPONSES_FOLDER / "booking-success.json" + return json.loads(file.read_text(encoding="utf-8")) @pytest.fixture def booking_failure_response() -> dict: - booking_failure_file = RESPONSES_FOLDER / "booking_failure.json" - return json.loads(booking_failure_file.read_text(encoding="utf-8")) + file = RESPONSES_FOLDER / "booking-failure.json" + return json.loads(file.read_text(encoding="utf-8")) @pytest.fixture def booked_courts_response( - court11, - court12, - court13, - court14, - booking_success_response, - booking_failure_response, + court11: int, + court12: int, + court13: int, + court14: int, + booking_success_response: dict, + booking_failure_response: dict, ) -> list[tuple[int, dict]]: court1_resp = court11.id, booking_failure_response court2_resp = court12.id, booking_failure_response @@ -250,10 +271,10 @@ def booked_courts_response( @pytest.fixture def booking_success_from_start( - landing_response, - login_success_response, - booking_success_response, - booking_failure_response, + landing_response: str, + login_success_response: str, + booking_success_response: str, + booking_failure_response: str, ): return [ landing_response, @@ -267,10 +288,10 @@ def booking_success_from_start( @pytest.fixture def booking_failure_from_start( - landing_response, - login_success_response, - booking_success_response, - booking_failure_response, + landing_response: str, + login_success_response: str, + booking_success_response: str, + booking_failure_response: str, ): return [ landing_response, @@ -284,22 +305,22 @@ def booking_failure_from_start( @pytest.fixture def user_bookings_get_response() -> str: - user_bookings_file = RESPONSES_FOLDER / "user_bookings_get.html" - return user_bookings_file.read_text(encoding="utf-8") + file = RESPONSES_FOLDER / "user-bookings-get.html" + return file.read_text(encoding="utf-8") @pytest.fixture -def user_bookings_list() -> list: - user_bookings_file = RESPONSES_FOLDER / "user_bookings_post.json" - return json.loads(user_bookings_file.read_text(encoding="utf-8")) +def user_bookings_list() -> str: + file = RESPONSES_FOLDER / "user-bookings-post.json" + return json.loads(file.read_text(encoding="utf-8")) @pytest.fixture def user_has_ongoing_bookings_from_start( - landing_response, - login_success_response, - user_bookings_get_response, - user_bookings_list, + landing_response: str, + login_success_response: str, + user_bookings_get_response: str, + user_bookings_list: str, ) -> list: return [ landing_response, @@ -316,10 +337,10 @@ def user_bookings_empty_list() -> list: @pytest.fixture def user_has_no_ongoing_bookings_from_start( - landing_response, - login_success_response, - user_bookings_get_response, - user_bookings_empty_list, + landing_response: str, + login_success_response: str, + user_bookings_get_response: str, + user_bookings_empty_list: str, ) -> list: return [ landing_response, @@ -331,16 +352,16 @@ def user_has_no_ongoing_bookings_from_start( @pytest.fixture def cancellation_response() -> list: - cancellation_response_file = RESPONSES_FOLDER / "cancellation_response.json" - return json.loads(cancellation_response_file.read_text(encoding="utf-8")) + file = RESPONSES_FOLDER / "cancellation-response.json" + return json.loads(file.read_text(encoding="utf-8")) @pytest.fixture def cancellation_by_id_from_start( - landing_response, - login_success_response, - user_bookings_get_response, - cancellation_response, + landing_response: str, + login_success_response: str, + user_bookings_get_response: str, + cancellation_response: str, ): return [ landing_response, @@ -352,11 +373,11 @@ def cancellation_by_id_from_start( @pytest.fixture def cancellation_success_from_start( - landing_response, - login_success_response, - user_bookings_get_response, - user_bookings_list, - cancellation_response, + landing_response: str, + login_success_response: str, + user_bookings_get_response: str, + user_bookings_list: str, + cancellation_response: str, ): return [ landing_response, @@ -377,3 +398,30 @@ def cancellation_success_booking_filter() -> BookingFilter: @pytest.fixture def service() -> GestionSportsServices: return GestionSportsServices() + + +@pytest.fixture +def tournament_sessions_json() -> str: + file = RESPONSES_FOLDER / "tournament-sessions.json" + return file.read_text(encoding="utf-8") + + +@pytest.fixture +def tournaments_html() -> str: + file = RESPONSES_FOLDER / "tournaments.html" + return file.read_text(encoding="utf-8") + + +@pytest.fixture +def full_tournaments_responses( + landing_response: str, + login_success_response: str, + tournament_sessions_json: str, + tournaments_html: str, +) -> list[str]: + return [ + landing_response, + login_success_response, + tournament_sessions_json, + tournaments_html, + ] diff --git a/tests/unit_tests/responses.py b/tests/unit_tests/responses.py index 35982f9..8ee5c7e 100644 --- a/tests/unit_tests/responses.py +++ b/tests/unit_tests/responses.py @@ -1,3 +1,6 @@ +from gestion_sport_connector import GestionSportsConnector + + def make_landing_request_success(aioresponses, connector, landing_response): aioresponses.get( connector.landing_url, @@ -54,6 +57,26 @@ def set_bookings_response(aioresponses, connector, user_bookings_post_response): ) +def set_tournaments_sessions_response( + aioresponses, connector: GestionSportsConnector, tournaments_sessions_response +): + aioresponses.post( + connector.tournaments_sessions_url, + status=200, + body=tournaments_sessions_response, + ) + + +def set_tournaments_list_response( + aioresponses, + connector: GestionSportsConnector, + tournament_id, + tournaments_list_response, +): + url = f"{connector.tournaments_list_url}{tournament_id}" + aioresponses.get(url, status=200, body=tournaments_list_response) + + def set_full_user_bookings_responses(aioresponses, connector, responses): make_landing_request_success(aioresponses, connector, responses[0]) make_login_request_success(aioresponses, connector, responses[1]) @@ -81,3 +104,11 @@ def set_full_cancellation_responses(aioresponses, connector, responses): set_bookings_response(aioresponses, connector, responses[3]) set_cancellation_response(aioresponses, connector, responses[4]) + + +def set_full_tournaments_requests(aioresponses, connector, responses, tournament_id): + make_landing_request_success(aioresponses, connector, responses[0]) + make_login_request_success(aioresponses, connector, responses[1]) + + set_tournaments_sessions_response(aioresponses, connector, responses[2]) + set_tournaments_list_response(aioresponses, connector, tournament_id, responses[3]) diff --git a/tests/unit_tests/test_gestion_sports_connector.py b/tests/unit_tests/test_gestion_sports_connector.py index 003bab5..82be8ee 100644 --- a/tests/unit_tests/test_gestion_sports_connector.py +++ b/tests/unit_tests/test_gestion_sports_connector.py @@ -1,31 +1,24 @@ +import json from pathlib import Path from unittest.mock import patch import pytest from aiohttp import ClientSession -from connectors import GestionSportsConnector +from gestion_sport_connector import GestionSportsConnector from tests.unit_tests import responses def test_urls(connector, club): - base_url = club.booking_platform.url - relative_urls = club.booking_platform.urls + base_url = "https://ptf1.com" - relative_landing_url = relative_urls.get("landing-page").path - assert connector.landing_url == f"{base_url}/{relative_landing_url}" - - relative_login_url = relative_urls.get("login").path - assert connector.login_url == f"{base_url}/{relative_login_url}" - - relative_booking_url = relative_urls.get("booking").path - assert connector.booking_url == f"{base_url}/{relative_booking_url}" - - relative_user_bookings_url = relative_urls.get("user-bookings").path - assert connector.user_bookings_url == f"{base_url}/{relative_user_bookings_url}" - - relative_cancel_url = relative_urls.get("cancellation").path - assert connector.booking_cancellation_url == f"{base_url}/{relative_cancel_url}" + assert connector.landing_url == f"{base_url}/landing.html" + assert connector.login_url == f"{base_url}/login.html" + assert connector.booking_url == f"{base_url}/booking.html" + assert connector.user_bookings_url == f"{base_url}/user_bookings.html" + assert connector.booking_cancellation_url == f"{base_url}/cancel.html" + assert connector.tournaments_sessions_url == f"{base_url}/tournaments_sessions.php" + assert connector.tournaments_list_url == f"{base_url}/tournaments_list.html?event=" @patch("config.get_resources_folder") @@ -34,19 +27,27 @@ def test_urls_payload_templates(mock_resources, club): mock_resources.return_value = path_to_resources connector = GestionSportsConnector(club) - relative_urls = club.booking_platform.urls - login_payload = relative_urls.get("login").payload_template - assert connector.login_template == path_to_resources / login_payload - - booking_payload = relative_urls.get("booking").payload_template - assert connector.booking_template == path_to_resources / booking_payload - - user_bookings_payload = relative_urls.get("user-bookings").payload_template - assert connector.user_bookings_template == path_to_resources / user_bookings_payload - - cancel_payload = relative_urls.get("cancellation").payload_template - assert connector.booking_cancel_template == path_to_resources / cancel_payload + assert ( + connector.login_template + == path_to_resources / "gestion-sports/login-payload.txt" + ) + assert ( + connector.booking_template + == path_to_resources / "gestion-sports/booking-payload.txt" + ) + assert ( + connector.user_bookings_template + == path_to_resources / "gestion-sports/user-bookings-payload.txt" + ) + assert ( + connector.booking_cancel_template + == path_to_resources / "gestion-sports/booking-cancellation-payload.txt" + ) + assert ( + connector.tournaments_sessions_template + == path_to_resources / "gestion-sports/tournament-sessions-payload.txt" + ) @pytest.mark.asyncio @@ -143,3 +144,35 @@ async def test_cancel_booking_success( ) assert await response.json() == cancellation_success_from_start[4] + + +@pytest.mark.asyncio +async def test_tournament_sessions( + aioresponses, connector, user, tournament_sessions_json +): + responses.set_tournaments_sessions_response( + aioresponses, connector, tournament_sessions_json + ) + async with ClientSession() as session: + response = await connector.send_tournaments_sessions_request(session) + + assert response.status == 200 + + all_sessions = json.loads(await response.text()) + sessions = all_sessions.get("Inscription tournois:school-outline") + assert len(sessions) == 1 + + +@pytest.mark.asyncio +async def test_send_tournaments_request( + aioresponses, connector, user, tournaments_html +): + tournament_session_id = "255" + responses.set_tournaments_list_response( + aioresponses, connector, tournament_session_id, tournaments_html + ) + async with ClientSession() as session: + response = await connector.send_tournaments_request( + session, tournament_session_id + ) + assert "Complet" in await response.text() diff --git a/tests/unit_tests/test_gestion_sports_services.py b/tests/unit_tests/test_gestion_sports_services.py index fea8185..6cc8351 100644 --- a/tests/unit_tests/test_gestion_sports_services.py +++ b/tests/unit_tests/test_gestion_sports_services.py @@ -1,5 +1,9 @@ +from unittest.mock import patch + +import pendulum import pytest from gestion_sports_services import GestionSportsServices +from models import BookingFilter, BookingOpening from tests.unit_tests import responses @@ -108,3 +112,65 @@ async def test_cancel_booking_id( ) await gs_services.cancel_booking_id(user, club, 65464) + + +@patch("pendulum.now") +def test_wait_until_booking_time(mock_now, club, user): + booking_filter = BookingFilter( + sport_name="Sport1", date=pendulum.parse("2024-03-21T13:30:00+01:00") + ) + + booking_datetime = pendulum.parse("2024-03-14T00:00:00+01:00") + + seconds = [ + booking_datetime.subtract(seconds=3), + booking_datetime.subtract(seconds=2), + booking_datetime.subtract(seconds=1), + booking_datetime, + booking_datetime.add(microseconds=1), + booking_datetime.add(microseconds=2), + ] + mock_now.side_effect = seconds + + booking_opening = club.booking_platform.booking_opening + + GestionSportsServices.wait_until_booking_time(booking_filter, booking_opening) + + assert pendulum.now() == booking_datetime.add(microseconds=1) + + +def test_build_booking_time(): + booking_filter = BookingFilter( + sport_name="Sport1", date=pendulum.parse("2024-03-21T13:30:00+01:00") + ) + booking_opening = BookingOpening(daysBefore=7, time="00:00") + + booking_time = GestionSportsServices.build_booking_datetime( + booking_filter, booking_opening + ) + + assert booking_time == pendulum.parse("2024-03-13T23:00:00Z") + + +def test_retrieve_tournament_id(tournament_sessions_json): + session_id = GestionSportsServices.retrieve_tournament_session( + tournament_sessions_json + ) + + assert session_id == "1174" + + +def test_retrieve_tournaments(tournaments_html): + tournaments = GestionSportsServices.retrieve_tournaments(tournaments_html) + assert len(tournaments) == 14 + + +@pytest.mark.asyncio +async def test_get_all_tournaments( + aioresponses, user, connector, club, full_tournaments_responses +): + responses.set_full_tournaments_requests( + aioresponses, connector, full_tournaments_responses, 1174 + ) + tournaments = await GestionSportsServices.get_all_tournaments(user, club) + assert len(tournaments) == 14