0

I am trying to select an option from the drop down menu using selenium python depending on the value evaluated by the below line of code

elem = driver.find_element('xpath','xpath_value')
select = Select(driver.find_element('xpath','//*[@id="qty"]'))
select.select_by_visible_text(elem.text)  # value of elem.text = 1

The HTML code for the drop down menu is as per below

<select ng-disabled="c.data.product.limitPartsQuantity" ng-if="part.dist_channel_status_msg == 'Orderable' &amp;&amp; !c.data.isLightUser &amp;&amp; part.orderable &amp;&amp; !part.part_error" id="qty" name="qty" ng-model="part.quantity" ng-change="c.partSelected(part)" class="ng-valid ng-scope ng-not-empty ng-dirty ng-valid-parse ng-touched" style=""> <option value="0">0</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> <option value="6">6</option> <option value="7">7</option> <option value="8">8</option> <option value="9">9</option> <option value="10">10</option> <!-- ngIf: c.data.type=='trade' && c.pcf==false --><option ng-if="c.data.type=='trade' &amp;&amp; c.pcf==false" value="15" class="ng-scope" style="">15</option><!-- end ngIf: c.data.type=='trade' && c.pcf==false --> <!-- ngIf: c.data.type=='trade' && c.pcf==false --><option ng-if="c.data.type=='trade' &amp;&amp; c.pcf==false" value="20" class="ng-scope">20</option><!-- end ngIf: c.data.type=='trade' && c.pcf==false --> <!-- ngIf: c.data.type=='trade' && c.pcf==false --><option ng-if="c.data.type=='trade' &amp;&amp; c.pcf==false" value="25" class="ng-scope">25</option><!-- end ngIf: c.data.type=='trade' && c.pcf==false --> <!-- ngIf: c.data.type=='trade' && c.pcf==false --><option ng-if="c.data.type=='trade' &amp;&amp; c.pcf==false" value="30" class="ng-scope">30</option><!-- end ngIf: c.data.type=='trade' && c.pcf==false --> <!-- ngIf: c.data.type=='trade' && c.pcf==false --><option ng-if="c.data.type=='trade' &amp;&amp; c.pcf==false" value="50" class="ng-scope">50</option><!-- end ngIf: c.data.type=='trade' && c.pcf==false --> <!-- ngIf: c.data.type=='trade' && c.pcf==false --><option ng-if="c.data.type=='trade' &amp;&amp; c.pcf==false" value="75" class="ng-scope">75</option><!-- end ngIf: c.data.type=='trade' && c.pcf==false --> <!-- ngIf: c.data.type=='trade' && c.pcf==false --><option ng-if="c.data.type=='trade' &amp;&amp; c.pcf==false" value="100" class="ng-scope">100</option><!-- end ngIf: c.data.type=='trade' && c.pcf==false --> </select>

But when the code is run , the following error is generated

selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document

I can resolve the error by modifying the code as per below

elem = driver.find_element('xpath','xpath_value')
value = elem.text            # value = 1
select = Select(driver.find_element('xpath','//*[@id="qty"]'))
select.select_by_visible_text(value)

I would like to know why the first lines of code failed but the second works , even though they are basically the same expression .

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
Abhishek
  • 43
  • 1
  • 6

1 Answers1

-1

From the HTML you have provided:

<select ng-disabled="c.data.product.limitPartsQuantity" ng-if="part.dist_channel_status_msg == 'Orderable' &amp;&amp; !c.data.isLightUser &amp;&amp; part.orderable &amp;&amp; !part.part_error" id="qty" name="qty" ng-model="part.quantity" ng-change="c.partSelected(part)" class="ng-valid ng-scope ng-not-empty ng-dirty ng-valid-parse ng-touched" style=""> 
    <option value="0">0</option> 
    <option value="1">1</option> 
    <option value="2">2</option> 
    ...  
    ... 
    ...  
    <option value="10">10</option> 
    <!-- ngIf: c.data.type=='trade' && c.pcf==false -->
    <option ng-if="c.data.type=='trade' &amp;&amp; c.pcf==false" value="15" class="ng-scope" style="">15</option>
    <!-- end ngIf: c.data.type=='trade' && c.pcf==false --> 
    ...
    ...
    ...
    <option ng-if="c.data.type=='trade' &amp;&amp; c.pcf==false" value="100" class="ng-scope">100</option>
    <!-- end ngIf: c.data.type=='trade' && c.pcf==false --> 
</select>

it is quite evident that the element and it's decendant <option> elements are Angular elements.


Solution

To select the <option> with text as 1 you need to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following locator strategies:

  • Using CSS_SELECTOR and select_by_value():

    Select(WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "select#qty[name='qty'][ng-model$='quantity'][ng-change*='partSelected']")))).select_by_value('1')
    
  • Using XPATH and select_by_visible_text():

    Select(WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//select[@id='qty' and @name='qty'][contains(@ng-model, 'quantity') and contains(@ng-change, 'partSelected')]")))).select_by_visible_text('1')
    
  • Note : You have to add the following imports :

    from selenium.webdriver.support.ui import Select
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352