Checkbox id keeps changing in webpage causing selenium script to fail - selenium

I am trying to automate a click on a certain checkbox. However after every run the checkbox id changes and script fails to find the element. Is there an alternate way of writing an xpath
<span id="field_key$0993573c-83b4-30d4-9139-44e44b496d0f$1food_contamination-checkbox" class="v-checkbox v-widget" ca-help-field-id="undefined">
<input id="gwt-uid-193" type="checkbox" value="on" tabindex="0" checked=""/>
<label for="gwt-uid-193"/>
</span>
xpath I used was this:
//*[#id='gwt-uid-193']

If the parent <span> id is fixed you can use it and go one level down to the checkbox
driver.findElement(By.cssSelector("#field_key$0993573c-83b4-30d4-9139-44e44b496d0f$1food_contamination-checkbox > input"));
Or use the parent class
driver.findElement(By.cssSelector(".checkbox > input"));
And if you have only one checkbox you can use the type attribute
driver.findElement(By.cssSelector("[type='checkbox']"));

I found a solution myself. We can use xpath based on the position of the checkbox, i.e.:
// input[#type='checkbox'])[position()=3]
This can be used for radio buttons as well. Replace checkbox with radio.

Related

Xpath Changes regularly

I have an issue. When I select an xpath and run the test sometimes the first few times it works. After some time it fails, and when i go check the xpath again i discover that somethings in it has changed. This isn't a web application that is being updated constantly . What do you think the problem could be?
for example the name in the code changes regularly . Here it is turnOverAvailableInd1 later it may become turnOverAvailableInd2.
<td>Is turnover figure available?</td>
<td valign="baseline">
<input type="radio" name="turnOverAvailableInd1" value="Y" onclick="javascript:turnOverAvailableToggle(this);" id="turnOverAvailableInd1Yes">YES
<input type="radio" name="turnOverAvailableInd1" value="N" onclick="javascript:turnOverAvailableToggle(this);" id="turnOverAvailableInd1No">NO
</td>
This is how i select the radio button
Select Radio Button turnOverAvailableInd1 N
You can use the other locator like, ID, CSS Selector or different XPATH like below
//input[#id='turnOverAvailableInd1Yes'] // For YES radio button
//input[#id ='turnOverAvailableInd1No'] //For NO radio button
OR
You can use the Value like below
//input[#value='Y'] //For YES radio button
//input [#value= 'N'] //For NO radio button
OR
//*[contains(text()='YES')] //For YES radio button
//*[contains(text()='NO')] //For NO radio button
You can find more here
If I understand your question correctly, you want an xpath that can work whether then name is "turnOverAvailableInd" appended by some number. If so, the following xpaths could work:
//input[#value='Y' and contains(#name,'turnOverAvailableInd')]
//input[#value='N' and contains(#name,'turnOverAvailableInd')]

If multiple edit buttons is having same HTML coding how will I click the button in Selenium

I'm new to Selenium. Below is code:
<i _ngcontent-c13="" aria-hidden="true" class="fa fa-edit" style="color: green;cursor: pointer;"></i>
I have all edit buttons with the same type. How do I click on each of the buttons? Can anyone help me with the XPath?
EASY
Right click on element in browser > inspect > right click on the highlighted code > copy > copy xpath. Now we have the xpath so:
driver.findElement(By.xpath("paste_xpath")).some_action();
Let me know if this works, there are more other options to discuss + add the code block that contains all the buttons.
HARD
First we need to get the xpath, you can build it based on the formula:
Xpath=//tagname[#attribute='value']
Where:
// : Select current node.
Tagname: Tagname of the particular node.
#:Select attribute. Attribute: Attribute name of the node.
Value: Value of the attribute.
More details you can find HERE
Thanks,

Splinter Is it possible to use browser.fill without name as a query

I would like to use an absolute xpath to fill in a search bar. The ids and classes are dynamically generated and there is no name variable or instance. So it feels like I'm stuck without a tool to fill in boxes without the named variable.
Is there a way around this? Can I somehow change the absolute xpath to look like its a name assignment and then query and fill based on the new 'type' I assigned the absolute xpath?
Is there a method for this in Selenium if not available in Splinter?
I've select by CSS and I'm finding this error 'selenium.common.exceptions.InvalidElementStateException: Message: Element is not currently interactable and may not be manipulated'
Edit:
<div class="type-ahead-input-container" role="search">
<div class="type-ahead-input-wrapper">
<div class="type-ahead-input">
<label class="visually-hidden" for="a11y-ember10393">
Search
</label>
<!---->
<input id="a11y-ember10393" class="ember-text-field ember-view" aria-
autocomplete="list" autocomplete="off" spellcheck="false"
placeholder="Search" autocorrect="off" autocapitalize="off" role="combobox"
aria-expanded="true" aria-owns="ember11064" data-artdeco-is-focused="true"/>
<div class="type-ahead-input-icons">
<!---->
</div>
</div>
<!---->
</div>
</div>
As you have asked Is there a method for this in Selenium, the Answer is Yes.
Selenium supports Sikuli. Sikuli automates anything you see on the screen. It uses image recognition to identify and control GUI components. It is useful when there is no easy access to a GUI's internal or source code.
You can find more about Sikuli here.
Let me know if this answers your question.
When you get an error-message like that, it could be that your search result is not what you expected. It could be that you are getting more than one result, ie a list. On a list you can not input.
You can find the input boxes with an xpath, select the prefered one from the list (by trying) and put a text in it with the WebDriverElement _set_value method. That is not appropriate because of the _, but it is usefull.
input_list = browser.find_by_xpath('//div[#class="type-ahead-input"]/input[#class="ember-textfield ember-view"]')
input_list[1]._set_value('just a text to see whether it is working')

Click on a specific part of HTML element

I have a checkbox element on my web-page which has a partial link which reads as Read the conduct risk manual where in conduct risk manual is a link which when clicked on navigates to page that has conduct risk manual listed down.
The HTML structure for this element is as below:
<div class="checkbox">
<label>
<input ng-disabled="readonly" type="checkbox" name="policyRead" required="" ng-model="confirmOa.confirmation.policyRead" class="ng-pristine ng-untouched ng-invalid ng-invalid-required xh-highlight">
<span>Read the <a target="_blank" href="http://somesite.xyz/Conduct%Risk%Manual.pdf">Conduct Risk Manual</a></span>
</label>
</div>
Now I want to click on a check-box which used to work if I click on span element but now even if I try with below combinations of web-driver is still clicking on link Conduct Risk Manual
1) .//div/label/input[#name='policyRead']
2) .//input[#name='policyRead' and #type='checkbox']
3) .//span[contains(text(),'Read the')]
4) .//span[contains(text(),'Read')]
5) .//input[#name='startDateConfirmed']//preceding::span[1]
In the 5th xpath I have tried clicking on span element using the following HTML element which is correctly identified and clicked.
I have tried many combinations apart from those mentioned above and all the xpath's correctly highlight the expected element which means it is correctly identified. But still web-driver clicks on Conduct Risk Manual link and navigates to a new page instead of clicking corresponding checkbox.
Can we make web-driver click on a specific part of an element?
Please check xpath's wherein I have already tried using only 'Read' or 'Read the' portion of span element.
Try this below code.
Explanation: Use text method with span tag, then move ahead with preceding-sibling keyword to find input tag for clicking the checkbox element.
Note: span tag use here for reference to get the check-box element text.
WebElement checkbox = driver.findElement(By.xpath("//span[contains(text(),'Read the')]//preceding-sibling::input[#name='policyRead']"));
if(!checkbox.isSelected()) // if checkbox is not selected, then only if is condition will execute.
{
checkbox.click();
}
OR
Using Java-script executor to click the checkbox web-element.
WebElement checkbox = driver.findElement(By.xpath("//span[contains(text(),'Read the')]//preceding-sibling::input[#name='policyRead']"));
((JavascriptExecutor) driver).executeScript("arguments[0].click();", checkbox);
You can try with this code also as a tag is coming over to the checkbox.
WebElement checkBox= driver.findElement(By.xpath("//span[contains(text(),'Read the')]//preceding-sibling::input[#type='checkbox']"));
Actions action = new Actions(driver);
action.moveToElement(checkBox).click().build().perform();`
Also add import org.openqa.selenium.interactions.Actions; .

Xpath for checkboxes without IDs

What xpath can I use for something like this without using ID? Or if there are more checkboxes but IDs are still different after refreshing page?
<td class="player" style="vertical-align: top;">
<span class="gb-CheckBox">
<input id="gb-uid-120" type="checkbox" value="on" tabindex="0" style="background-color: rgb(255, 255, 255);">
<label for="gb-uid-120"></label>
</span>
</td>
Try following:
//span[#class="gb-CheckBox"]/input[#type="checkbox"]
Why not:
//input[#type='checkbox']
this should be enough and will select all inputs that are checkbox type.
If you need only from a certain area then you need to add a constraint by adding another selector in front of this like:
//div[#class='my_prefered_area']//input[#type='checkbox']
Another way of getting the selector would be to use the pare of the id that does not change like:
//input[contains(#id, 'gb-uid')]
Of course you can also add the restriction for checkbox type:
//input[contains(#id, 'gb-uid')][#type='checkbox']
Seems like you got the answer as most of the ways mentioned above are correct.
Correcting the first one path wit CSS :
td.player>span.gb-CheckBox>input[type='checkbox']
(try it removing the spaces before and after > )
Or
td.player>span.gb-CheckBox>input
Will also work.
As you mentioned, if your Id is changing frequently, that means its an dynamic webelement and
if it is changing at the end(after gb-uid- i.e. gb-uid-120, then gb-uid-121 something like this) then use contains function on Xpath as below:
//span[#class="gb-CheckBox"]/input[contains(#id, 'gb-uid-')]
You can also locate this checkbox easily using cssSelector instead of xpath which would be much faster as below :-
td.player > span.gb-CheckBox > input[type='checkbox']