Locating a child of a child in Selenium (Python) - python

I'm trying to locate two input fields on an unordered menu list, but Selenium is unable to find them. So far I've attempted to locate them by xpath and class name with an ordinal identifier
("//input[#class=x-form-text x-form-field][4]")
but it either doesn't locate the element or it says it is improperly formatted. The only success I've had is if I use the id, but the number on the end changes every time the page loads.
Is there any way to have it locate the menu list, then the list item, and then the input field? I am totally stumped.
Notes about the menu list: It changes size based on resolution and if it becomes much smaller a down arrow icon will appear and the fields towards the bottom of the list will disappear unless that down button is selected.
Here's an example of the html:
<ul id="ext-gen406" class="x-menu-list">
<li id="ext-comp-1237" class="list-item ">
<li id="ext-comp-1238" class="list-item ">
<li id="ext-comp-1239" class="list-item ">
<li id="ext-comp-1240" class="list-item ">
<li id="ext-comp-1241" class="list-item ">
<li id="ext-comp-1242" class="list-item ">
<li id="ext-comp-1207" class="list-item sep-li">
<li id="ext-comp-1243" class="list-item ">
<li id="ext-comp-1244" class="list-item ">
<li id="ext-comp-1208" class="list-item sep-li">
<li id="ext-comp-1245" class="list-item ">
<li id="ext-comp-1246" class="list-item ">
<li id="ext-comp-1247" class="list-item ">
<div class='xtb-text'>Text Field Label</div>
<li id="ext-comp-1248" class="list-item ">
<div id="ext-gen424" class="x-form-field-wrap x-form-field-trigger-wrap">
<input id="ext-comp-1248" class="x-form-text x-form-field"name="ext-comp-1248"
</div>
<li id="ext-comp-1249" class="list-item ">
<li id="ext-comp-1250" class="list-item ">
<div class="x-form-field-wrap x-form-field-trigger-wrap" id="ext-gen426">
<input id="ext-comp-1250" name="ext-comp-1250" class="x-form-text x-form-field"
</div>
<li id="ext-comp-1251" class="list-item ">
<li id="ext-comp-1252" class="list-item ">
</ul>

You can use cssSelector to solve the issue,
driver.find_element_by_css_selector("ul.x-menu-list input.x-form-field:nth-child(1)") //first input box
driver.find_element_by_css_selector("ul.x-menu-list input.x-form-field:nth-child(2)") //second input box

I tried this method and for some reason it only locates the first input field. It doesn't locate any of the other input fields in the list. (There are 12). Can someone provide more information on how to use nth children?
In this case you should try using find_elements to find all input elements and perform certain action on particular element using index below :-
all_inputs = driver.find_elements_by_css_selector("ul.x-menu-list > li.list-item input.x-form-text")
The two input fields that I'm trying to locate are the 9th and 10th input fields in this list.
#now use index to get desire input element
if len(all_inputs) >= 10:
desire_input_9 = all_inputs[8]
desire_input_10 = all_inputs[9]

Ok, so... I finally figured it out!
Here is what worked for me:
driver.find_element_by_xpath("//li/div[contains(text(), 'Text labeling input field')]/../following-sibling::li/div/input")

Related

Select dropdown in Selenium Python

I can't select values in a list. I tried using find_element_by_class_name() to open the menu but when I need to select a <li> returns that element doesn't have a function click().
Here the code:
click_menu = driver.find_element_by_class_name("periodSelector")
click_menu[1].click()
Here is the HTML that I am trying to parse:
<div data-period-selector="" data-period="periodFilter">
<div class="periodSelectorContainer">
<div class="btn-group periodSelector">
<button class="flat-btn dropdown-toggle periodToggle ng-binding" data-toggle="dropdown"> 20/02/2021 - 22/03/2021 <span class="dropdown-arrow"></span> </button>
<ul class="dropdown-menu">
<li>
<a href="javascript:void(0);" class="new-financ" ng-click="selectToday()"><i></i>
<span class="pull-left">Hoje</span>
<span class="pull-right"></span>
</a>
</li>
<li>
<a href="javascript:void(0);" class="new-financ" ng-click="selectThisWeek()"><i>
</li>
There are multiple class names you have to use a css selector.
click_menu = driver.find_element_by_css_selector("button.flat-btn.dropdown-toggle.periodToggle.ng-binding")
click_menu.click()
Clicks 1st li tag.
driver.find_element_by_xpath("ul[#class='dropdown-menu']/li[1]").click()
periodSelector is a class on a DIV
<div class="btn-group periodSelector">
I'm assuming that you need to click on the BUTTON
<button class="flat-btn dropdown-toggle periodToggle ng-binding" data-toggle="dropdown">
Most of those classes seem generic (probably not unique) but I'm guessing that periodToggle might be unique given the date range. Try
driver.find_element_by_css_selector("button.periodToggle").click()
NOTE:
You have an error in your code. You are using .find_element_by_class_name() (singular) but have array notation on the next line, click_menu[1]. In this case, you can just use click_menu.click(). You'd only need the array notation if you were using .find_elements_by_*() (note the plural, elements).

python selenium get value of specific element

<li id="button1" class="on">
<div class="supply1">
<div class="buildingimg">
<a class="fastBuild tooltip js_hideTipOnMobile" title="Metallmine auf Stufe 4 ausbauen" href="javascript:void(0);" onclick="sendBuildRequest('https://s159-de.ogame.gameforge.com/game/index.php?page=resources&modus=1&type=1&menge=1&token=0c86d8a8bf9a5c559538b0e13cb462b4', null, 1);">
<img src="https://gf2.geo.gfsrv.net/cdndf/3e567d6f16d040326c7a0ea29a4f41.gif" width="22" height="14">
</a>
<a class="detail_button tooltip js_hideTipOnMobile slideIn" title="" ref="1" id="details" href="javascript:void(0);">
<span class="ecke">
<span class="level">
<span class="textlabel">
**Metallmine**
</span>
**3** </span>
</span>
</a>
</div>
</div>
</li>
<li id="button2" class="on">
<div class="supply2">
<div class="buildingimg">
<a class="fastBuild tooltip js_hideTipOnMobile" title="" href="javascript:void(0);" onclick="sendBuildRequest('https://s159-de.ogame.gameforge.com/game/index.php?page=resources&modus=1&type=2&menge=1&token=0c86d8a8bf9a5c559538b0e13cb462b4', null, 1);">
<img src="https://gf2.geo.gfsrv.net/cdndf/3e567d6f16d040326c7a0ea29a4f41.gif" width="22" height="14">
</a>
<a class="detail_button tooltip js_hideTipOnMobile slideIn" title="" ref="2" id="details" href="javascript:void(0);">
<span class="ecke">
<span class="level">
<span class="textlabel">
**Kristallmine**
</span>
**1** </span>
</span>
</a>
</div>
</div>
</li>
Dear Community,
So I want to create a bot for a browser game (just for learning purposes of course). In the game you can build and level up metal and crystall mines to get more resources. To have the best resource proportions it is best to have a metal mine which is always 2 levels higher, than your crystal mine. Writing the code to compare the levels is no problem, but I'm having problems accessing the actual values of the "level" of the mine since there is no unique attribute to them.
Above in the code you can see the "Metallmine" and "Kristallmine" and the corresponding levels. I would like to write a code similar to:
if LevelOfKristallmine - LevelOfMetallmine <-2
driver.find_element_by_whatever('upgradebutton').click()
how can I get the values of LevelOfKristallmine and LevelOfMetallmine?
Thanks alot for your answers!
You are trying to use the ID, I assume as the values? Instead copy and paste the XPath, using something like:
driver.find_element_by_xpath('*//*[#id="example-xpath"]/div/nav/ol*').click()
To copy Xpath, f12, find the element to click, right click, copy > Xpath. Then paste in the parentheses. Follow this other link and you should figure it out mate.

Selenium will not select drop down option due to visibility issues

UPDATED
In my Django settings, when I set DEBUG to false, Selenium is able to interact with the elements. It still does not work when DEBUG is set to true
So I am trying to select one option in a dropdown menu, but when I try to directly access the <select> tag I get the error ElementNotVisibleException: Message: element not interactable.
In the console whenever I click on the dropdown in only refers to an input tag that dynamically changes based on what I click on. Ultimately, I want the test to click on the dropdown and then select 'Tango' as shown in the link below.
My Selenium code is:
from selenium.webdriver import Chrome
from selenium.webdriver.support.ui import Select
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("localhost:8000/")
select = Select(driver.find_element_by_xpath('//*[#id="select-dance"]').click())
select.select_by_value('1')
And HTML:
<form onsubmit="return false;">
<div class="row border-light bg-white rounded-left rounded-right no-gutters">
<div class="col-12 col-lg px-3">
<div class="select-wrapper mdb-select">
<span class="caret"></span>
<input type="text" class="select-dropdown" readonly="true" data-activates="select-options-20f378f1-9560-4598-b8e8-
3ffe496cd688" value="Choose your dance event">
<ul id="select-options-20f378f1-9560-4598-b8e8-3ffe496cd688" class="dropdown-content select-dropdown" style="width: 658px; position:absolute;top: 0px; left: 0px;opacity: 1; display: none;">
<li class="">
<span class="filtrable">Choose your dance event</span></li>
<li class="">
<span class="filtrable">Tango</span></li>
<li class="active selected">
<span class="filtrable">Swing</span>
</li>
<li class="">
<span class="filtrable">Latin/Salsa</span>
</li>
<li class="">
<span class="filtrable">Ballroom</span>
</li>
<li class="">
<span class="filtrable">Bachata</span>
</li>
</ul>
<select class="mdb-select initialized" id="select-dance">
<option value="0">Choose your dance event</option>
<option value="1">Tango</option>
<option value="2">Swing</option>
<option value="3">Latin/Salsa</option>
<option value="4">Ballroom</option>
<option value="5">Bachata</option>
</select>
</div>
</div>
</div>
</div>
</form>
I do not know how to deal with the input tag interfering with the select (it only shows up in the elements console in Chrome).
Thank you!
You can handle by,
driver = webdriver.Chrome()
driver.get("localhost:8000/")
time.sleep(10)
select = Select(driver.find_element_by_id('select-dance'))
select.select_by_value('1')
You can try this,
driver = webdriver.Chrome()
driver.get("localhost:8000/")
time.sleep(10)
driver.find_element_by_id('select-dance').click()
when you click then new list of s will get populated under , then call select tag
select = Select(driver.find_element_by_id('select-dance'))
select.select_by_value('1')
or
select = Select(driver.find_element_by_xpath('//*[#id="select-dance"]'))
select.select_by_value('1')
Your page uses custom Select Component which is not the default html select box. In your case, they have used MDBootstrap Select Component which cannot be interacted using selenium Select class.
Please read this answer for your another question which related to the same issue.

Selecting item from dropdown

I need to use selenium to select an item from a dropdown. The site looks like this
<div class="chosen-drop">
<div class="chosen-search"><input type="text" autocomplete="off"></div>
<ul class="chosen-results">
<li class="active-result style="" data-option-array-index="0">Please choose your main activity</li>
<li class="active-result" style="" data-option-array-index="1">Animals and Pets</li>
<li class="active-result" style="" data-option-array-indexx="2">Art and Culture</li>
<li class="active-result" style="" data-option-array-index="3">Babies</li>
<li class="active-result" style="" data-option-array-index="4">Beauty and Personal Care</li>
<li class="active-result" style="" data-option-array-index="5">Cars</li>
<li class="active-result" style="" data-option-array-index="6">Computer Hardware and Software</li>
</ul>
How can I select/click on "Cars"/data-option-array-index="5"?
I believe you could use a simple css selector to get element you want using :nth-child. For example to get 2 entry you could write such selector:
.choosen-drop ul>li:nth-child(2)
You can do this like, as I know java so I write code in java. First List all the locators in LIST, then using For- Each and If else you can select particular item and perform operations
//Locate all elements in list
List<WebElement> dropEle= driver.findElements(By.xpath("//ul[#class='chosen-results']//li"));
for (WebElement tempEle : dropEle) {
//condition to check text
if(tempEle.getText().contains("Cars"))
{
// Do operations
System.out.println("Pass");
}
}

How to verify dynamic element present in Selenium WebDriver

I'm writing scripts in Python using Selenium WebDriver to test a web application.
The web application allows users to ask questions, which are added to a div as they are asked. Each question div has their own "upvote" and "downvote" link/image. The image changes when the "upvote" icon is clicked, from active to inactive, or vice versa. I know that the xpath to this upvote icon is:
"//div[#id='recent-questions-container']/div/div/div/div/div[2]/div/ul/li/a/i"
This "i" at the end of the path is a class, and will either be
<i class="fa fa-2x fa-thumbs-o-up"></i>
or
<i class="fa fa-2x fa-thumbs-up clicked"></i>
depending on whether or not it is clicked. I want to verify that the correct image is in place upon being clicked. How can I do that? Ideally, I'd like to perform this verification using assertions, a la:
self.assertTrue(self.is_element_present( ... ))
Here is the html for what I'm talking about
<div id="recent-questions-container">
<div question_id="randomly generated blah" class="q row recent-question animated pulse" data-score="0">
<div class="col-xs-12">
<div class="question-content">
<p>3</p>
<div class="row question-controls">
<div class="owner-view hidden">
...
<div class="student-view">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 question-controls-left">
<ul class="list-inline">
<li>
<a href="#" class="student-view thumbs-up-to-active">
<i class="fa fa-thumbs-o-up fa-2x"></i></a>
</li>
<li>
<span class="num-votes">0</span>
</li>
<li class="thumbs-down-li">
<a href="#" class="student-view thumbs-down-to-active">
<i class="fa fa-thumbs-o-down fa-2x"></i></a>
</li>
</ul>
</div>
</div>
</div>
<hr>
</div>
</div>
</div>
... other questions ...
</div>
<hr>
</div>
</div>
</div>
</div>
You can use get_attribute to get the class attribute and then do a search if the class contains clicked to make sure it was in fact clicked
#make sure the selector is correct
xpath = "//div[#id='recent-questions-container']/div/div/div/div/div[2]/div/ul/li/a/i"
element = driver.find_element(By.XPATH, xpath)
attr = element.get_attribute('class')
if 'clicked' in attr:
print("clicked")
else:
print("was not clicked")
Edit
I would click the element and now should be expecting to change the class to active. Then find the count which should be more than 0
driver = self.driver
#perform click here
#the idea is to avoid the NoSuchElement exception
# and see if the element count is greater than 0
assert (len(driver.find_elements_by_css_selector(".student-view.thumbs-up-to-active")) > 0)

Categories