Exemple #1
0
class FutureRideForm(Component):
    """Objects and methods for the future ride form."""

    ROOT_LOCATOR: Selector = Selectors.data_id('future-ride-container')
    _date_field: Selector = Selectors.name('pickupDate')
    _time_field: Selector = Selectors.name('time')

    @property
    def date_field(self) -> WebElement:
        return self.container.find_element(*self._date_field)

    @property
    def time_field(self) -> WebElement:
        return self.container.find_element(*self._time_field)

    def fill_future_ride_form(self, ride: dict) -> None:
        """Fill out the future ride form.

        :param ride: The ride yielded from a ride fixture.
        """
        ride_time: datetime = datetime.strptime(
            ride['pickup']['timestamp'],
            '%Y-%m-%dT%H:%M:%S.%fZ',
        )

        self.time_field.fill_picker_input(ride_time.strftime('%I:%M %p'))
        self.date_field.fill_picker_input(ride_time.strftime('%m-%d-%Y'))
Exemple #2
0
class EditForm(Component):
    """Edit Form component objects and methods for the Rides Info component.

    The Edit Form component contains tools for editing the pick up and drop off locations for a
    ride featured within the Details page. The Edit Form may be accessed from the Ride Info
    component.
    """

    ROOT_LOCATOR: Selector = Selectors.data_id('details-edit-ride-container')

    _pick_up_address: Selector = Selectors.name('pickup')
    _drop_off_address: Selector = Selectors.name('dropoff')
    _swap_button: Selector = Selectors.data_id('edit-swap-button')
    _update_button: Selector = Selectors.data_id('edit-update-button')
    _cancel_button: Selector = Selectors.data_id('edit-cancel-button')
    _total_passenger_field: Selector = Selectors.name('capacity')
    _wheelchair_check_box: Selector = Selectors.name('wheelchair')

    @property
    def cancel_button(self) -> WebElement:
        return self.container.find_element(*self._cancel_button)

    @property
    def drop_off_address(self) -> WebElement:
        return self.container.find_element(*self._drop_off_address)

    @property
    def pick_up_address(self) -> WebElement:
        return self.container.find_element(*self._pick_up_address)

    @property
    def schedule_form(self) -> ScheduleForm:
        return ScheduleForm(self)

    @property
    def swap_button(self) -> WebElement:
        return self.container.find_element(*self._swap_button)

    @property
    def total_passenger_field(self) -> WebElement:
        return self.container.find_element(*self._total_passenger_field)

    @property
    def update_button(self) -> WebElement:
        return self.container.find_element(*self._update_button)

    @property
    def wheelchair_check_box(self) -> WebElement:
        return self.container.find_element(*self._wheelchair_check_box)

    def swap_addresses(self) -> None:
        """Select the swap button, then save the edit."""
        self.swap_button.click()

        self.update_button.click()
Exemple #3
0
class CancellationModal(Component):
    """Cancellation Modal component objects and methods for OnDemand applications.

    The cancellation modal may be accessed by selected 'Cancel' for a ride The modal may be found
    in the Ride Card or Ride Row kebab menus.
    """

    ROOT_LOCATOR: Selector = Selectors.data_id('cancellation-modal-container')
    _cancel_button: Selector = Selectors.data_id('cancellation-modal-cancel-button')
    _confirm_button: Selector = Selectors.data_id('cancellation-modal-confirm-button')
    _cancel_reason: Selector = Selectors.name('terminal-reason')

    @property
    def ride_cancel_input(self) -> WebElement:
        return self.container.find_element(*self._cancel_reason)

    @property
    def ride_cancel_confirm(self) -> WebElement:
        return self.container.find_element(*self._confirm_button)

    def cancel_ride(self, reason: str) -> None:
        """Cancel a ride, then wait for the cancellation modal to no longer be visible.

        :param reason: The cancellation reason for the ride.
        """
        self.ride_cancel_input.fill(reason)
        self.ride_cancel_confirm.click()

        self.wait_for_component_to_not_be_visible()
class GroupForm(Component):
    """Objects and methods for the Group Form component."""

    ROOT_LOCATOR: Selector = Selectors.data_id('group-container')
    _cancel_button: Selector = Selectors.data_id('cancel-button')
    _delete_button: Selector = Selectors.data_id('delete-group-button')
    _name_field: Selector = Selectors.name('name')
    _save_button: Selector = Selectors.data_id('save-group-button')

    @property
    def cancel_button(self) -> WebElement:
        return self.container.find_element(*self._cancel_button)

    @property
    def delete_group_button(self) -> WebElement:
        return self.container.find_element(*self._delete_button)

    @property
    def name_field(self) -> WebElement:
        return self.container.find_element(*self._name_field)

    @property
    def save_button(self) -> WebElement:
        return self.container.find_element(*self._save_button)

    def fill_form(self, name: str) -> None:
        """Fill out a group form, then submit the form.

        :param name: The name of the group.
        """
        self.name_field.fill(name)
Exemple #5
0
class ScheduleForm(Component):
    """Objects and methods for the Schedule form.

    The Schedule Form component contains toggles and pickers for editing a ride's pickup time from
    within the Details page.
    """

    ROOT_LOCATOR: Selector = Selectors.data_id('ride-edit-future-container')

    _asap_ride_button: Selector = Selectors.data_id('ride-edit-asap-button')
    _future_ride_button: Selector = Selectors.data_id(
        'ride-edit-future-button')
    _date_field: Selector = Selectors.name('pickupDate')
    _time_field: Selector = Selectors.name('time')

    @property
    def asap_ride_button(self) -> WebElement:
        return self.container.find_element(*self._asap_ride_button)

    @property
    def date_field(self) -> WebElement:
        return self.container.find_element(*self._date_field)

    @property
    def future_ride_button(self) -> WebElement:
        return self.container.find_element(*self._future_ride_button)

    @property
    def time_field(self) -> WebElement:
        return self.container.find_element(*self._time_field)

    def select_ride_type(self, ride_type: str) -> None:
        """Select a ride type.

        Ride type defaults to ASAP within the OnDemand Admin application.

        :param ride_type: The type of ride to be submitted.
        """
        if ride_type == 'future':
            self.future_ride_button.click()
        elif ride_type != 'asap':
            raise RideTypeException(
                f'The ride type: {ride_type} is not supported.\n'
                f'Expected "asap" or "future"." or "recurring".', )
class AddressForm(Component):
    """Objects and methods for the Address Form component."""

    ROOT_LOCATOR: Selector = Selectors.data_id('address-container')
    _address_field: Selector = Selectors.name('address')
    _cancel_button: Selector = Selectors.data_id('cancel-button')
    _delete_button: Selector = Selectors.data_id('delete-address-button')
    _label_field: Selector = Selectors.name('name')
    _save_button: Selector = Selectors.data_id('save-address-button')

    @property
    def address_field(self) -> WebElement:
        return self.container.find_element(*self._address_field)

    @property
    def cancel_button(self) -> WebElement:
        return self.container.find_element(*self._cancel_button)

    @property
    def delete_address_button(self) -> WebElement:
        return self.container.find_element(*self._delete_button)

    @property
    def label_field(self) -> WebElement:
        return self.container.find_element(*self._label_field)

    @property
    def save_button(self) -> WebElement:
        return self.container.find_element(*self._save_button)

    @property
    def suggestions(self) -> AutocompleteSuggestions:
        return AutocompleteSuggestions(self)

    def fill_form(self, address: str, label: str) -> None:
        """Fill out an address form, then submit the form.

        :param address: The street address.
        :param label: The label for the address.
        """
        self.label_field.fill(label)
        self.address_field.fill(address)
        self.suggestions.select_suggestion(location=address)
class PassengerForm(Component):
    """Objects and methods for the Passenger form."""

    ROOT_LOCATOR: Selector = Selectors.data_id('user-details-container')
    _first_name_field: Selector = Selectors.name('first_name')
    _last_name_field: Selector = Selectors.name('last_name')
    _phone_field: Selector = Selectors.name('phone')

    @property
    def first_name_field(self) -> WebElement:
        return self.container.find_element(*self._first_name_field)

    @property
    def last_name_field(self) -> WebElement:
        return self.container.find_element(*self._last_name_field)

    @property
    def phone_field(self) -> WebElement:
        return self.container.find_element(*self._phone_field)

    def fill_passenger_info_form(self, ride: dict) -> None:
        """Fill out the passenger information form.

        The ride param may be of type RecurringRide or Ride depending on the test which is being
        ran. The default type will be Ride as it is the most common data type for testing.

        :param ride: A ride yielded from a ride fixture.
        """
        try:
            rider = ride['ride']['rider']
        except KeyError:
            rider = ride['rider']

        self.first_name_field.fill(rider['first_name'])
        self.last_name_field.fill(rider['last_name'])
        self.phone_field.fill(rider['phone'])
class GroupUserForm(Component):
    """Objects and methods for the Group Form component."""

    ROOT_LOCATOR: Selector = Selectors.data_id('rider-editor-form-container')
    _clear_button: Selector = Selectors.data_id('filter-clear')
    _email_field: Selector = Selectors.name('rider-email')

    @property
    def clear_button(self) -> WebElement:
        return self.container.find_element(*self._clear_button)

    @property
    def email_field(self) -> WebElement:
        return self.container.find_element(*self._email_field)

    def fill_form(self, email: str) -> None:
        """Fill out email field, then submit the form.

        :param name: The email of the user.
        """
        self.email_field.fill(email)
class LegacyRideBooking(Base):
    """Objects and methods for the Legacy Ride Booking page.

    The legacy ride booking page is a work flow which must be supported due to the volume of
    dispatchers who continue to utilize the page over the Admin Dispatch page.
    """

    URL_PATH: str = f'{Base.URL_PATH}/rides/new'

    _asap_ride_radio: Selector = Selectors.data_id('use-now')
    _driver_note: Selector = Selectors.name('note')
    _drop_off_field: Selector = Selectors.name('dropoff')
    _first_name_field: Selector = Selectors.name('first_name')
    _future_ride_radio: Selector = Selectors.data_id('use-later')
    _last_name_field: Selector = Selectors.name('last_name')
    _pay_on_vehicle_radio: Selector = Selectors.radio('cash')
    _phone_field: Selector = Selectors.name('phone')
    _pick_up_field: Selector = Selectors.name('pickup')
    _places_autocomplete_suggestion: Selector = Selectors.data_id(
        'places-autocomplete-suggestion')
    _service_dropdown: Selector = Selectors.name('serviceId')
    _submit_ride_button: Selector = Selectors.data_id('book_ride')
    _total_passenger_field: Selector = Selectors.name('capacity')
    _waive_fee_radio: Selector = Selectors.radio('waive')
    _wheelchair_switch: Selector = Selectors.name('wheelchair')

    @property
    def asap_ride_button(self) -> WebElement:
        return self.driver.find_element(*self._asap_ride_radio)

    @property
    def driver_note_field(self) -> WebElement:
        return self.driver.find_element(*self._driver_note)

    @property
    def drop_off_field(self) -> WebElement:
        return self.driver.find_element(*self._drop_off_field)

    @property
    def first_name_field(self) -> WebElement:
        return self.driver.find_element(*self._first_name_field)

    @property
    def future_ride_button(self) -> WebElement:
        return self.driver.find_element(*self._future_ride_radio)

    @property
    def last_name_field(self) -> WebElement:
        return self.driver.find_element(*self._last_name_field)

    @property
    def pay_on_vehicle_button(self) -> WebElement:
        return self.driver.find_element(*self._pay_on_vehicle_radio)

    @property
    def phone_field(self) -> WebElement:
        return self.driver.find_element(*self._phone_field)

    @property
    def pick_up_field(self) -> WebElement:
        return self.driver.find_element(*self._pick_up_field)

    @property
    def service_dropdown(self) -> Select:
        return self.driver.find_dropdown(*self._service_dropdown)

    @property
    def submit_ride_button(self) -> WebElement:
        return self.driver.find_element(*self._submit_ride_button)

    @property
    def suggestions(self) -> AutocompleteSuggestions:
        return AutocompleteSuggestions(self)

    @property
    def total_passenger_field(self) -> WebElement:
        return self.driver.find_element(*self._total_passenger_field)

    @property
    def waive_fee_button(self) -> WebElement:
        return self.driver.find_element(*self._waive_fee_radio)

    @property
    def wheelchair_switch(self) -> WebElement:
        return self.driver.find_element(*self._wheelchair_switch)

    def fill_ride_form(self, service: dict, ride: dict) -> None:
        """Fill out the legacy ride form.

        Use send_keys for phone_field as clearing the field within the fill method causes input
        to occur at the end of the field. This results in an input failure.

        :param service: The service yielded from a service API fixture.
        :param ride: The ride intended for booking.
        """
        self.first_name_field.fill(ride['rider']['first_name'])
        self.last_name_field.fill(ride['rider']['last_name'])
        self.last_name_field.fill(Keys.TAB)
        self.phone_field.send_keys(ride['rider']['phone'])

        self.select_pick_up_location(ride['pickup']['address'])
        self.select_drop_off_location(ride['dropoff']['address'])

        #
        # Occurs further down the stack than its form location as it intermittently failed when it
        # was called first.
        #
        self.select_a_service(service['service_id'])

        if ride['note'] is not None:
            self.driver_note_field.send_keys(ride['note'])

    def pay_ride_fee(self, method: str) -> None:
        """Select a payment method based on a method string.

        :param method: A payment method for the ride.
        """
        if method == 'cash':
            self.pay_on_vehicle_button.scroll_to().click()
        elif method == 'waive':
            self.waive_fee_button.scroll_to().click()
        else:
            raise PaymentMethodException(
                f'The payment method: "{method}" is not allowed for this ride.',
            )

    def select_a_service(self, service_id: int) -> None:
        """Select a service within the service drop down.

        :param service_id: The service ID yielded from a service API fixture.
        """
        try:
            self.driver.wait_until_visible(*self._service_dropdown,
                                           wait_time=4)
            self.service_dropdown.select_by_value(service_id)
        except NoSuchElementException:
            raise NoSuchElementException(
                f'The service ID: {service_id} cannot be found within the selected agency.\n'
                f'Please select a valid service within the selected agency.', )

    def select_drop_off_location(self, drop_off: str) -> None:
        """Fill out a drop off location, then select an autocomplete suggestion.

        :param drop_off: The drop off location for a ride.
        """
        self.drop_off_field.fill(drop_off)
        self.suggestions.select_suggestion(drop_off)

    def select_pick_up_location(self, pick_up: str) -> None:
        """Fill out a pick up location, then select an autocomplete suggestion.

        :param pick_up: The pick up location for a ride.
        """
        self.pick_up_field.fill(pick_up)
        self.suggestions.select_suggestion(pick_up)

    def submit_ride_form(self) -> object:
        """Submit a legacy ride form."""
        self.submit_ride_button.scroll_to().click()

        return Details(self.driver).wait_for_page_to_load()
class Registration(Page):
    """Objects and methods for the Register page."""

    URL_PATH: str = build_login_url(path='/register')
    ROOT_LOCATOR: Selector = Selectors.class_name('register-container')

    _email_field: Selector = Selectors.name('email')
    _first_name_field: Selector = Selectors.name('first_name')
    _inline_errors: Selector = Selectors.class_name('errors')
    _last_name_field: Selector = Selectors.name('last_name')
    _password_field: Selector = Selectors.name('password')
    _phone_field: Selector = Selectors.name('phone')
    _privacy_policy_field: Selector = Selectors.name('privacy_policy_accepted')
    _repeat_password_field: Selector = Selectors.name('repeat_password')
    _submit_button: Selector = Selectors.data_id('submit-button')
    _username_field: Selector = Selectors.name('username')
    _user_exists_error: Selector = Selectors.data_id('error-message')

    @property
    def email_field(self) -> WebElement:
        return self.driver.find_element(*self._email_field)

    @property
    def first_name_field(self) -> WebElement:
        return self.driver.find_element(*self._first_name_field)

    @property
    def inline_errors(self) -> WebElements:
        return self.driver.find_elements(*self._inline_errors)

    @property
    def inline_error_messages(self) -> List[str]:
        return [error.text for error in self.inline_errors]

    @property
    def last_name_field(self) -> WebElement:
        return self.driver.find_element(*self._last_name_field)

    @property
    def password_field(self) -> WebElement:
        return self.driver.find_element(*self._password_field)

    @property
    def phone_field(self) -> WebElement:
        return self.driver.find_element(*self._phone_field)

    @property
    def privacy_policy_checkbox(self) -> WebElement:
        return self.driver.find_element(*self._privacy_policy_field)

    @property
    def repeat_password_field(self) -> WebElement:
        return self.driver.find_element(*self._repeat_password_field)

    @property
    def submit_button(self) -> WebElement:
        return self.driver.find_element(*self._submit_button)

    @property
    def username_field(self) -> WebElement:
        return self.driver.find_element(*self._username_field)

    @property
    def user_exists_error(self) -> WebElement:
        return self.driver.find_element(*self._user_exists_error)

    def fill_registration_form(self, user: User) -> None:
        """Fill out a user registration form.

        :param user: A user generated from a User Factory.
        """
        self.username_field.fill(user.username)
        self.email_field.fill(user.email)
        self.first_name_field.fill(user.first_name)
        self.last_name_field.fill(user.last_name)
        self.phone_field.fill(user.phone)
        self.password_field.fill(user.password)
        self.repeat_password_field.fill(user.repeat_password)
        self.privacy_policy_checkbox.click()
Exemple #11
0
class Login(Page):
    """Login methods and objects for all TransLoc applications."""

    URL_PATH: str = build_login_url(path='/login')
    ROOT_LOCATOR: Selector = Selectors.class_name('login-container')

    _error_message: Selector = Selectors.data_id('error-message')
    _forgot_password_link: Selector = Selectors.data_id('forgot-password-link')
    _password_field: Selector = Selectors.name('password')
    _sign_up_button: Selector = Selectors.data_id('sign-up-button')
    _submit_button: Selector = Selectors.data_id('submit-login-button')
    _success_message: Selector = Selectors.data_id('success-message')
    _university_login_button: Selector = Selectors.data_id(
        'university-login-button')
    _username_field: Selector = Selectors.name('username')

    @property
    def error_message(self) -> WebElement:
        return self.driver.find_element(*self._error_message)

    @property
    def forgot_password_link(self) -> WebElement:
        return self.driver.find_element(*self._forgot_password_link)

    @property
    def password_field(self) -> WebElement:
        return self.driver.find_element(*self._password_field)

    @property
    def sign_up_button(self) -> WebElement:
        return self.driver.find_element(*self._sign_up_button)

    @property
    def submit_button(self) -> WebElement:
        return self.driver.find_element(*self._submit_button)

    @property
    def success_message(self) -> WebElement:
        return self.driver.find_element(*self._success_message)

    @property
    def university_login_button(self) -> WebElement:
        return self.driver.find_element(*self._university_login_button)

    @property
    def username_field(self) -> WebElement:
        return self.driver.find_element(*self._username_field)

    def add_auth_token(self):
        """Add a captured authorization token as an environment variable."""
        auth_token = json.loads(os.getenv('AUTH_TOKEN'))
        self.driver.add_cookie(auth_token)

    def capture_token(self) -> None:
        """Capture an authorization token."""
        auth_cookie = self.driver.get_cookies()[1]
        if 'expiry' in auth_cookie:
            del auth_cookie['expiry']

        json_cookie = json.dumps(auth_cookie)

        os.environ['AUTH_TOKEN'] = json_cookie

    def check_login_fail(self) -> None:
        """Check whether an error message is shown."""
        self.driver.wait_until_visible(*self._error_message)

    def login(self, username: Optional[str], password: Optional[str]) -> None:
        """Login in to a TransLoc application.

        :param password: The password for login.
        :param username: The username for login.
        """
        self.username_field.fill(username)
        self.password_field.fill(password)

        self.submit_button.click()
class RideForm(Component):
    """Objects and methods for the Ride form."""

    ROOT_LOCATOR: Selector = Selectors.data_id('ride-details-container')
    _driver_note_field: Selector = Selectors.name('note')
    _drop_off_field: Selector = Selectors.name('dropoff')
    _pick_up_field: Selector = Selectors.name('pickup')
    _service_drop_down: Selector = Selectors.name('serviceId')
    _service_drop_down_error: Selector = Selectors.data_id(
        'service-dropdown-with-errors')
    _total_passenger_field: Selector = Selectors.name('capacity')
    _wheelchair_check_box: Selector = Selectors.name('wheelchair')

    @property
    def driver_note_field(self) -> WebElement:
        return self.container.find_element(*self._driver_note_field)

    @property
    def drop_off_field(self) -> WebElement:
        return self.container.find_element(*self._drop_off_field)

    @property
    def pick_up_field(self) -> WebElement:
        return self.container.find_element(*self._pick_up_field)

    @property
    def service_drop_down(self) -> Select:
        return self.container.find_dropdown(*self._service_drop_down)

    @property
    def suggestions(self) -> AutocompleteSuggestions:
        return AutocompleteSuggestions(self)

    @property
    def total_passenger_field(self) -> WebElement:
        return self.container.find_element(*self._total_passenger_field)

    @property
    def wheelchair_check_box(self) -> WebElement:
        return self.container.find_element(*self._wheelchair_check_box)

    def fill_ride_info_form(self, service: dict, ride: dict) -> None:
        """Fill out the ride information form.

        The ride param may be of type RecurringRide or Ride depending on the test which is being
        ran. The default type will be Ride as it is the most common data type for testing.

        :param service: The service yielded from a service API fixture.
        :param ride: A ride yielded from a ride fixture.
        """
        try:
            ride_data = ride['ride']
        except KeyError:
            ride_data = ride

        dropoff: dict = ride_data['dropoff']
        note: str = ride_data['note']
        pickup: dict = ride_data['pickup']

        self.select_a_service(service['service_id'])
        self.select_pick_up_location(pickup['address'])
        self.select_drop_off_location(dropoff['address'])

        if note is not None:
            self.driver_note_field.send_keys(note)

    def select_a_service(self, service_id: str) -> None:
        """Select a service within the service drop down.

        :param service_id: The service ID yielded from a service API fixture.
        """
        try:
            self.service_drop_down.select_by_value(service_id)
        except NoSuchElementException:
            raise NoSuchElementException(
                f'The service ID: {service_id} cannot be found within the selected agency.\n'
                f'Please select a valid service within the selected agency.', )

    def select_drop_off_location(self, drop_off: str) -> None:
        """Fill out a drop off location, then select an autocomplete suggestion.

        :param drop_off: The drop off location for a ride.
        """
        self.drop_off_field.fill(drop_off)
        self.suggestions.select_suggestion(drop_off)

    def select_pick_up_location(self, pick_up: str) -> None:
        """Fill out a pick up location, then select an autocomplete suggestion.

        :param pick_up: The pick up location for a ride.
        """
        self.pick_up_field.fill(pick_up)
        self.suggestions.select_suggestion(pick_up)

    def service_error_check(self) -> bool:
        return self.container.find_element(
            *self._service_drop_down_error).is_displayed()
Exemple #13
0
class RecurringRideForm(Component):
    """Objects and methods for the recurring ride form."""

    ROOT_LOCATOR: Selector = Selectors.data_id('recurring-ride-container')
    _end_date_field: Selector = Selectors.name('endDate')
    _start_date_field: Selector = Selectors.name('startDate')
    _time_field: Selector = Selectors.name('time')
    _days: List[str] = [
        'Sunday',
        'Monday',
        'Tuesday',
        'Wednesday',
        'Thursday',
        'Friday',
        'Saturday',
    ]

    @property
    def end_date_field(self) -> WebElement:
        return self.container.find_element(*self._end_date_field)

    @property
    def start_date_field(self) -> WebElement:
        return self.container.find_element(*self._start_date_field)

    @property
    def time_field(self) -> WebElement:
        return self.container.find_element(*self._time_field)

    def fill_recurring_ride_form(self, recurring_ride: dict) -> None:
        """Fill out the recurring ride form.

        Each timestamp must be converted into a datetime object, then converted to specific strings
        for input. For day names, the datetime objects are processed through a set comprehension
        and for loop which selects each day within the total listing. Set is used so that only one
        entry is ever selected.

        The ride.pickup datetime object is input to the start date field while the last datetime
        object within the ride_schedule list is input to the end date field. Finally, the time is
        parsed from the first datetime object and passed to the time field since the time of each
        ride will always be the same.

        :param recurring_ride: The recurring ride yielded from a recurring ride fixture.
        """
        rides: List[dict] = recurring_ride['rides']
        ride_start_date: datetime = datetime.strptime(
            recurring_ride['ride']['pickup']['timestamp'],
            '%Y-%m-%dT%H:%M:%S.%fZ',
        )
        ride_schedule: List[datetime] = [
            datetime.strptime(date_string['timestamp'],
                              '%Y-%m-%dT%H:%M:%S.%fZ') for date_string in rides
        ]
        ride_days: Set[str] = {day.strftime('%A') for day in ride_schedule}
        ride_time: datetime = datetime.strptime(rides[0]['timestamp'],
                                                '%Y-%m-%dT%H:%M:%S.%fZ')

        for day in ride_days:
            self.select_day(day)

        self.start_date_field.fill_picker_input(
            ride_start_date.strftime('%m-%d-%Y'))
        self.end_date_field.fill_picker_input(
            ride_schedule[-1].strftime('%m-%d-%Y'))
        self.time_field.fill_picker_input(ride_time.strftime('%I:%M %p'))

    def select_day(self, day: str) -> None:
        """Select a specific day for a recurring ride schedule.

        :param day: The specified day.
        """
        _groomed_day: str = day.lower()

        if day not in self._days:
            raise SelectionException(
                f'The day: {day} is invalid. Please enter a valid day.')
        self.container.find_element(
            *Selectors.data_test_id(f'day-of-week-input-{_groomed_day}'),
        ).click()