During my Python & Selenium self-learning I came across a blocker while trying to access and select elements of a drop down.
Problem statement –
As a traveler, I want to select Business class for my flight on the Air NewZealand website , just to remind myself how atrociously expensive flying business class is .
Initial analysis –
Using Chrome Dev tools, I inspected the drop down and was expecting the various drop down entries to each have a unique id/index , so that I can select “business class” directly.
But lo-behold, the drop-down element is a <select> HTML that I had not worked with before. And each option was a <option> tag nested under the <select> tag.
Potential ways I thought to solve this –
- Find the drop down using it’s id (
driver.find_element_by_id) and find a way to iterate through the options based on their text . Likely to be brittle if the option text changes
- Directly find the XPath of the option that I want and click it .
On further googling however, I found that the Selenium library offered an out of the box class to handle <select> web elements ! 🙂
This class has some handy dandy methods to retrieve all the options under the select tag , select them by value or index etc.
- Select the option at the given index. This is done by examing the “index” attribute of an element, and not merely by counting.
- index – The option at this index will be selected
throws NoSuchElementException If there is no option with specisied index in SELECT
- Select all options that have a value matching the argument. That is, when given “foo” this would select an option like:
- value – The value to match against
throws NoSuchElementException If there is no option with specisied value in SELECT
My solution –
Here is a simple Python script the uses the Select class and some of it’s method to solve the problem above.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
|from selenium import webdriver|
|from selenium.webdriver.common.keys import Keys|
|from selenium.common.exceptions import NoSuchElementException|
|from selenium.common.exceptions import TimeoutException|
|from selenium.webdriver.common.by import By|
|from selenium.webdriver.support.ui import WebDriverWait|
|from selenium.webdriver.support import expected_conditions as EC|
|from selenium.webdriver.support.select import Select|
|# for easy future changes and code maintainbility i have added all the locators and parameters like username/password at the top of the test|
|driver = webdriver.Chrome()|
|CONTINUE_BUTTON = (By.XPATH,'//*[@id="cms-search-panel-container"]/div/div/div/form/div/div/button')|
|FLIGHT_CLASS_DROPDOWN = (By.ID,'serviceclass')|
|FLIGHT_CLASS_NAME = 'BUSINESS'|
|URL = 'https://www.airnewzealand.co.nz/home'|
|# wait for the continue button to appear|
|continue_button = WebDriverWait(driver,10).until(EC.presence_of_element_located(CONTINUE_BUTTON))|
|# wait for the fligh class dropdown to appear|
|flight_class_dropdown = WebDriverWait(driver,10).until(EC.presence_of_element_located(FLIGHT_CLASS_DROPDOWN))|
|#select the drop down using the Select class imported from from selenium.webdriver.support.select|
|select = Select(flight_class_dropdown)|
|# select an option from the drop down based on a value, i did not go for a index in case the index changes due to addition or removal of entries|
|except(NoSuchElementException,TimeoutException) as e:|
|# fail the Test if the element can not be found or timeout occurs|
|print('Test failed, the flight class drop down could not be found ')|
|test = AirNZ_flight_class()|