import pytest from scraper.eurostar import _parse_graphql, search_url def _gql_response(journeys: list) -> dict: return {'data': {'journeySearch': {'outbound': {'journeys': journeys}}}} def _journey(departs: str, arrives: str, price=None, seats=None, service_name='', carrier='ES') -> dict: return { 'timing': {'departureTime': departs, 'arrivalTime': arrives}, 'fares': [{ 'classOfService': {'code': 'STANDARD'}, 'prices': {'displayPrice': price}, 'seats': seats, 'legs': [{'serviceName': service_name, 'serviceType': {'code': carrier}}] if service_name else [], }], } # --------------------------------------------------------------------------- # _parse_graphql # --------------------------------------------------------------------------- def test_parse_graphql_single_journey(): data = _gql_response([_journey('09:31', '12:55', price=156, seats=37, service_name='9014')]) services = _parse_graphql(data, 'Paris Gare du Nord') assert len(services) == 1 s = services[0] assert s['depart_st_pancras'] == '09:31' assert s['arrive_destination'] == '12:55' assert s['destination'] == 'Paris Gare du Nord' assert s['train_number'] == 'ES 9014' assert s['price'] == 156.0 assert s['seats'] == 37 def test_parse_graphql_half_pound_price(): data = _gql_response([_journey('09:01', '14:20', price=192.5, seats=25, service_name='9116')]) services = _parse_graphql(data, 'Amsterdam Centraal') assert services[0]['price'] == 192.5 def test_parse_graphql_null_price(): data = _gql_response([_journey('06:16', '11:09', price=None, seats=0)]) services = _parse_graphql(data, 'Amsterdam Centraal') assert services[0]['price'] is None assert services[0]['seats'] == 0 def test_parse_graphql_sorted_by_departure(): data = _gql_response([ _journey('10:31', '13:55'), _journey('07:31', '10:59'), ]) services = _parse_graphql(data, 'Paris Gare du Nord') assert services[0]['depart_st_pancras'] == '07:31' assert services[1]['depart_st_pancras'] == '10:31' def test_parse_graphql_deduplicates_same_departure_time(): data = _gql_response([ _journey('06:16', '11:09', price=None, seats=0), _journey('06:16', '11:09', price=None, seats=0), _journey('06:16', '11:09', price=None, seats=0), ]) services = _parse_graphql(data, 'Amsterdam Centraal') assert len(services) == 1 def test_parse_graphql_no_legs_gives_empty_train_number(): data = _gql_response([_journey('09:31', '12:55', price=156, seats=37, service_name='')]) services = _parse_graphql(data, 'Paris Gare du Nord') assert services[0]['train_number'] == '' def test_parse_graphql_empty_journeys(): data = _gql_response([]) assert _parse_graphql(data, 'Paris Gare du Nord') == [] # --------------------------------------------------------------------------- # search_url # --------------------------------------------------------------------------- def test_search_url(): url = search_url('Paris Gare du Nord', '2026-04-10') assert url == ( 'https://www.eurostar.com/search/uk-en' '?adult=1&origin=7015400&destination=8727100&outbound=2026-04-10' )