Selenium IDE is failing to capture element based off its title attribute - selenium

I'm using the selenium IDE for Chrome on Mac Big Sur. I notice the IDs for a particular page keep changing and so I want my SElenium playback to use something more constant. Specifically, I'd like to capture a click on this element ...
<th scope="col" role="columnheader" data-field="parentName" aria-haspopup="true" rowspan="1" data-title="Parent Institution" data-index="1" id="05abd234-04a8-409c-99e9-90fd772f0dd2" class="k-header k-with-icon k-filterable" data-role="columnsorter"><a class="k-grid-filter" href="#" title="Filter" aria-label="Filter" tabindex="-1"><span class="k-icon k-i-filter"></span></a><a class="k-link" href="#">Parent Institution</a></th>
So I thought I could use the TH title attribute. In my ".side" file, I set up my selector like so
}, {
"id": "b3839cf6-9347-4a43-9208-922e2975fc33",
"comment": "click parent menu",
"command": "click",
"target": "css=title^='Parent Institution'",
"targets": [
["css=#5ba47ffd-b9ec-41e6-b4e6-924bf3d688bc", "css:finder"],
["xpath=//th[#id='dd03982f-9fdb-4140-bb24-93f9582c6bad']/a/span", "xpath:idRelative"],
["xpath=//th[3]/a/span", "xpath:position"]
],
"value": ""
}, {
But when doing playback, the IDE still seems to fail to detect this element. Is there a different way I should be writing this command to accurately select CSS based on the TH "title" attribute?

The value of the id attribute of the <th> element is dynamically generated. So everytime you access the application or within a interval the value of the id attribute of the <th> element will get changed.
Moreover, the clickable element is a tag:
<a class="k-link" href="#">Parent Institution</a>
Solution
To click on the element you can use either of the following Locator Strategies:
Using link_text:
Parent Institution
Using css_selector:
th[data-field='parentName'][data-title='Parent Institution'] a.k-grid-filter[title='Filter'][aria-label='Filter'] +a.k-link
Using xpath:
//th[#data-field='parentName'][#data-title='Parent Institution']//a[text()='Parent Institution']

Related

Timed out retrying: cy.type() failed because this element is not visible. has CSS property: position: fixed and it's being covered by another element:

Unable to find the textbox element in a new pop-up window.
Actual Result:
Expected Result:
Able to type value in the text box.
Adding the cypress snippet below,
it("Add business test",function(){
cy.xpath("//a[contains(.,'1099/W-2')]").click({force:true});
cy.wait(5000);
cy.get(':nth-child(2) > .btn-hover-shrink > .v-btn__content').click({force: true});
cy.contains('Start Now').click({force:true});
//Add business pop-up open
cy.contains('Business Name').click({force: true}).type("Test LLC");
})
You can add {force: true} with type() to disable error checking -
cy.get('[id*="input-"]').type("Test LLC", {force: true});
The error message indicates that you are trying to type() into the label. That's because cy.contains('sometext') selects the element "owning" the text, which is the label, but you can also select a parent by using the pattern cy.contains(<parentSelector>, 'sometext')
Take a look at the page DOM, if you have a common parent of the <label> and the <textarea> (or <input>), like this
<div>
<label>Business Name</label>
<input />
</div>
you can target that parent in the .contains()
cy.contains('div', 'Business Name')
.find('input') // drill down to the element receiving the text
.should('be.visible') // since there's a toolbar in the mix, wait for visibility
.type('Test LLC')
An alternative might be to use .closest()
cy.contains('Business Name') // gives you the label
.closest('input') // nearby element receiving the text
.should('be.visible') // wait for visibility
.type('Test LLC')
Here's one more way, making use of the label's "for" attribute
cy.contains('Business Name') // gives you the label
.invoke('attr', 'for') // which id is it for?
.then(id => {
cy.get('#' + id) // get the actionable element
.should('be.visible') // wait for visibility
.type('Test LLC')
})
Taking a look at the Vuetify form component here which has a similar HTML to yours
<div class="v-text-field__slot">
<label for="input-6" class="v-label theme--light" style="left: 0px; right: auto; position: absolute;">Last name</label>
<input required="required" id="input-6" type="text">
</div>
the same test code you have succeeds on the sample code
cy.contains('Last name')
.click({force: true})
.type("Test LLC"); // text appears in the input
but if I simulate the covering toolbar, it fails with the same error you have.
Adding .type("Test LLC", {force: true}) also fails with a different error
cy.contains('Last name')
.click({force: true})
.type("Test LLC", {force: true});
cy.type() failed because it requires a valid typeable element.
Using the parent contains to find the "typeable element" and applying force: true option works
cy.contains('div', 'Business Name')
.find('input')
.should('be.visible')
.type("Test LLC", {force: true})
This assumes the toolbar remains static and does not animate away, in which case it would work without the force: true option.

How to click checkbox after getting a value from below its preceding webelement

I need to click a dynamic checkbox getting generated i.e "Rec136"
What i have is the name="345551" and value="345551"
driver.findElement(By.xpath(".//*[contains(text(),'345551')]")).getText()
I tried clicking the checkbox:-
executor.executeScript("arguments[0].click();",driver.findElement(By.xpath(".//*[contains(text(),'345551')]")));
HTML:-
<tr id="Rec136">
<td align="center" width="10%">
<input name="345551" value="345551-1" type="checkbox"/>
</td>
<td align="center" width="10%">bnnsnjad</td>
After inspecting the checkbox , found path is:
.//*[#id='Rec136']/td[1]/input (Need to click)
How to click the checkbox (.//*[#id='Rec136']/td[1]/input) after getting the element using "contains" . In short , how to click the above checkbox after getting the value "345551" ?
You can try with this xpath :
//tr[contains(#id,'Rec136')]/descendant::input
However the id is getting generated dynamically. So it is not a good practice to use these kind of ID's.
in code :
driver.findElement(By.xpath("//tr[contains(#id,'Rec136')]/descendant::input")).click();
If you want to click on check box with the respective name , then the xpath would be :
//td[contains(text(),'bnnsnjad')]/preceding-sibling::td/input
code :
driver.findElement(By.xpath("//td[contains(text(),'bnnsnjad')]/preceding-sibling::td/input ")).click();
If id is dynamic and you have the name/value then you can try:
driver.findElement(By.xpath("//input[name()='345551']")).click();
OR
driver.findElement(By.xpath("//input[contains(#value,'345551')]")).click();

Selenium IDE: How to assert attribute exists

I'm using Selenium IDE.
I know how to test if an element's attribute has a certain value. But how do I test if the attribute exists in the first place?
Here is the line which successfully tests if the attribute has a certain value:
<tr>
<td>assertAttribute</td>
<td>id=_ctl0_MainPlaceHolder_dgMemberList_DXSelBtn0#disabled</td>
<td>disabled</td>
</tr>
Here is the line which unsuccessfully tests if the attribute exists in the first place:
<tr>
<td>assertElementPresent</td>
<td>id=_ctl0_MainPlaceHolder_dgMemberList_DXSelBtn0#disabled</td>
<td></td>
</tr>
How do I get it to work?
Thank,
-Ilya
You can use the "getAttribute" method, and if it returns "null" it means that there is no attribute at all...
From Selenium documentation:
WebElement.getAttribute( attributeName ) → Thenable<(string|null)>
Schedules a command to query for the value of the given attribute of the element. Will return the current value, even if it has been modified after the page has been loaded. More exactly, this method will return the value of the given attribute, unless that attribute is not present, in which case the value of the property with the same name is returned. If neither value is set, null is returned (for example, the "value" property of a textarea element). The "style" attribute is converted as best can be to a text representation with a trailing semi-colon.
For example:
HTML code:
<div id="a" >1</div>
<div id="a" x="xxx" >2</div>
<div id="a" x >3</div>
Test code in Nodejs:
var webdriver = require('selenium-webdriver');
var capabilitiesObj = {
'browserName' : 'firefox'
};
var driver = new webdriver.Builder().withCapabilities(capabilitiesObj).build();
driver.get('http://localhost/customer.js/temp/index60.html');
driver.findElements(webdriver.By.css('div[id=a]')).then((elements) => {
elements[0].getAttribute('x').then((att)=> {
console.log(att);
});
}).catch(console.log.bind(console));
driver.quit();
The result for each div will be different:
for div 1: null
for div 2: 'xxx'
for div 3: ''
I don't think the simple id locator handles the attribute. So switch to xpath:
This should work:
<tr>
<td>verifyElementPresent</td>
<td>xpath=//.[#id='id3' and #attribute1]</td>
<td></td>
</tr>
Note that if you change the specific id (id1, id2, id3) it will pass for the first 2 ids but fail for the 3rd:
<div id="id1" attribute1="xyz" style="background-color: transparent;">Some text</div>
<div id="id2" attribute1="" style="background-color: transparent;">Some text</div>
<div id="id3" style="background-color: transparent;">Some text</div>

Get xpath for div inside td tag

I tired a lot to get the xpath of the div which displays as "カーク商品掲載カタログ Online" on screen, but I'm not able to. The application is made using ZK framework hence it has random ID's.
<td z.type="Lic" id="z_mk_qr1" class="activeCatalogVersionTreeItem z-list-cell" z.zcls="z-list-cell" onmouseout="dragHoverClick( $e('z_mk_qr1'), event, true, null, 0);" onmouseover="dragHoverClick( $e('z_mk_qr1'), event, false, 'PerspectiveDND', 500);">
<div id="z_mk_qr1!cave" class="z-list-cell-cnt z-overflow-hidden">カーク商品掲載カタログ Online
<span id="z_mk_rr1" class="catalog-mnemonic-label z-label" z.zcls="z-label"> (STO-O)
</span>
</div>
</td>
I thought the xpath should be something like //div[contains(text(),'カーク商品掲載カタログ Online')], but it doesn't work.
Thanks!
Try the below cssSelector to identify the required element.
td.activeCatalogVersionTreeItem div.z-list-cell-cnt
You may use partial text match in this case as follows:
//div[contains(text(), 'Online')]
Check the link below for more:
https://sqa.stackexchange.com/questions/10342/how-to-find-element-using-contains-in-xpath

How can I select checkboxes using the Selenium Java WebDriver?

How can I check the checkboxes using an id or XPath expression? Is there a method similar to select by visibletext for a dropdown?
Going through the examples given for all other related questions, I could not find a proper solution that works in a concise way that by few line or method I can check a chekbox or radio button.
A sample HTML section is below:
<tbody>
<tr>
<td>
<span class="120927">
<input id="ctl00_CM_ctl01_chkOptions_0" type="checkbox" name="ctl00$CM$ctl01$chkOptions$0"/>
<label for="ctl00_CM_ctl01_chkOptions_0">housingmoves</label>
</span>
</td>
</tr>
<tr>
<td>
<span class="120928">
<input id="ctl00_CM_ctl01_chkOptions_1" type="checkbox" name="ctl00$CM$ctl01$chkOptions$1"/>
<label for="ctl00_CM_ctl01_chkOptions_1">Seaside & Country Homes</label>
</span>
</td>
</tr>
</tbody>
Selecting a checkbox is similar to clicking a button.
driver.findElement(By.id("idOfTheElement")).click();
will do.
However, you can also see whether the checkbox is already checked. The following snippet checks whether the checkbox is selected or not. If it is not selected, then it selects.
if ( !driver.findElement(By.id("idOfTheElement")).isSelected() )
{
driver.findElement(By.id("idOfTheElement")).click();
}
It appears that the Internet Explorer driver does not interact with everything in the same way the other drivers do and checkboxes is one of those cases.
The trick with checkboxes is to send the Space key instead of using a click (only needed on Internet Explorer), like so in C#:
if (driver.Capabilities.BrowserName.Equals(“internet explorer"))
driver.findElement(By.id("idOfTheElement").SendKeys(Keys.Space);
else
driver.findElement(By.id("idOfTheElement").Click();
If you want to click on all checkboxes at once, a method like this will do:
private void ClickAllCheckboxes()
{
foreach (IWebElement e in driver.FindElements(By.xpath("//input[#type='checkbox']")))
{
if(!e.Selected)
e.Click();
}
}
Solution for C#
try
{
IWebElement TargetElement = driver.FindElement(By.XPath(xPathVal));
if (!TargetElement.Selected)
{
TargetElement.SendKeys(Keys.Space);
}
}
catch (Exception e)
{
}
You can use the following code:
List<WebElement> checkbox = driver.findElements(By.name("vehicle"));
((WebElement) checkbox.get(0)).click();
My HTML code was as follows:
<.input type="checkbox" name="vehicle" value="Bike">I have a bike<br/>
<.input type="checkbox" name="vehicle" value="Car">I have a car<br/>
To get the checkbox for 'Seaside & Country Homes', use this XPath:
//label[text()='Seaside & Country Homes']/preceding-sibling::input[#type='checkbox']
To get the checkbox for 'housingmoves', use this XPath:
//label[text()='housingmoves']/preceding-sibling::input[#type='checkbox']
The principle here is to get the label with the text you want, then get the checkbox that is before the label, since that seems to be how your HTML is laid out.
To get all checkboxes, you would start a little higher up and then work down, so that is to say get the table, and then get any checkbox within a span:
//table/descendant::span/input[#type='checkbox']
I found that sometimes JavaScript doesn't allow me to click the checkbox because was working with the element by onchange event.
And that sentence helps me to allow the problem:
driver.findElement(By.xpath(".//*[#id='theID']")).sendKeys(Keys.SPACE);
This should help -
IWebElement elementToClick = driver.findElement(By.xpath(""//input[contains(#id, 'lstCategory_0')]"));
elementToClick.Click();
You can also pass an id.
If you want something like visible text you can "find element" by name if they have names.
The below code will first get all the checkboxes present on the page, and then deselect all the checked boxes.
List<WebElement> allCheckbox = driver.findElements(By
.xpath("//input[#type='checkbox']"));
for (WebElement ele : allCheckbox) {
if (ele.isSelected()) {
ele.click();
}
}
A solution using WebDriver and C# is below. The key idea is to get the ID of the checkbox from the labels' 'for' attribute, and use that to identify the checkbox.
The code will also set the checkbox state only if it needs to be changed.
public void SetCheckboxStatus(string value, bool toCheck)
{
// Get the label containing the checkbox state
IWebElement labelElement = this.Driver.FindElement(By.XPath(string.Format("//label[.='{0}']",value)));
string checkboxId = labelElement.GetAttribute("for");
IWebElement checkbox = this.Driver.FindElement(By.Id(checkboxId));
if (toCheck != checkbox.Selected)
{
checkbox.Click();
}
}
Maybe a good starting point:
isChecked = driver.findElement((By.id("idOftheElement"))).getAttribute("name");
if(!isChecked.contains("chkOptions$1"))
{
driver.FindElement(By.Id("idOfTheElement")).Click();
}
Running this approach will in fact toggle the checkbox; .isSelected() in Java/Selenium 2 apparently always returns false (at least with the Java, Selenium, and Firefox versions I tested it with).
The selection of the proper checkbox isn't where the problem lies -- rather, it is in distinguishing correctly the initial state to needlessly avoid reclicking an already-checked box.
To select a checkbox, use the "WebElement" class.
To operate on a drop-down list, use the "Select" class.
Step 1:
The object locator supposed to be used here is XPath. So derive the XPath for those two checkboxes.
String housingmoves="//label[contains(text(),'housingmoves')]/preceding-sibling::input";
String season_country_homes="//label[contains(text(),'Seaside & Country Homes')]/preceding-sibling::input";
Step 2:
Perform a click on the checkboxes
driver.findElement(By.xpath(housingmoves)).click();
driver.findElement(By.xpath(season_country_homes)).click();
For a partial match, do the following:
getDriver().findElement(By.cssSelector("<tag name>[id*='id pattern to look for']")).click();
Here is the C# version of Scott Crowe's answer. I found that both IEDriver and ChromeDriver responded to sending a Key.Space instead of clicking on the checkbox.
if (((RemoteWebDriver)driver).Capabilities.BrowserName == "firefox")
{
// Firefox
driver.FindElement(By.Id("idOfTheElement")).Click();
}
else
{
// Chrome and Internet Explorer
driver.FindElement(By.Id("idOfTheElement")).SendKeys(Keys.Space);
}
I tried with various approaches, but nothing worked. I kept getting "Cannot click element" or ElementNotVisibleException.
I was able to find the input, but I couldn't check it. Now, I'm clicking on the div that contains the checkbox and it works with following HTML (CSS based on Bootstrap).
#foreach (var item in Model)
{
<tr>
<td>
<div id="#item.Id" class="checkbox">
<label><input type="checkbox" class="selectone" value="#item.Id"></label>
</div>
</td>
<td val="#item.Id">
#item.Detail
</td>
<td>
<div>#item.Desc
</div>
</td>
<td>
#Html.ActionLink("Edit", "Create", new { EditId = item.Id })
</td>
</tr>
}
This is the code for WebDriver:
var table = driver.FindElement(By.TagName("table"));
var tds = table.FindElements(By.TagName("td"));
var itemTds = tds.Where(t => t.Text == itemtocheck);
foreach (var td in itemTds)
{
var CheckBoxTd = tds[tds.IndexOf(td) - 1];
var val = td.GetAttribute("val");
CheckBoxTd.FindElement(By.Id(val)).Click();
}
In this approach, I give the item id as id for the div and also add an attribute for td with that id. Once I find the td of the item that needs to be checked, I can find the div before that td and click it. We can also use the XPath query that supports before (here is the example http://learn-automation.com/how-to-write-dynamic-xpath-in-selenium/).