Still new to selenium and css/xpath locators. I stumbled across a problem where CSS works but the equivalent XPath doesn't, and I'd really like to know why. I'm using Scala in the examples but it's still the normal Java Selenium2 library. I also use the FirefoxDriver
Here's the interesting part of the HTML:
...
<li class="k-item k-filter-item k-state-default k-last" role="menuitem" style="z-index: auto;">
...
<form class="k-filter-menu k-secondary">
<div>
<div class="k-filter-help-text">Show items with value that:</div>
<span class="k-widget k-dropdown k-header" style="" unselectable="on" role="listbox" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-owns="" aria-disabled="false" aria-readonly="false" aria-busy="false">
<span class="k-widget k-datetimepicker k-header" style="">
<div>
<button class="k-button" type="submit">Filter</button>
<button class="k-button" type="reset">Clear</button>
</div>
</div>
</form>
</li>
...
I'm getting the li with
val filter = driver.findElement(By.cssSelector("li.k-filter-item"))
which works for me.
Then, I want to find the button. It's a dynamic menu thingy sliding out and what not, so I need to wait for it to appear:
new WebDriverWait(driver, selectorTimeout).until(
new ExpectedCondition[Boolean] {
override def apply(d: WebDriver) = {
filter.findElement(By.cssSelector("button[type=submit]")).isDisplayed
}
})
And that works nicely, too. My question is, why doesn't the xpath equivalent work:
new WebDriverWait(driver, selectorTimeout).until(
new ExpectedCondition[Boolean] {
override def apply(d: WebDriver) = {
filter.findElement(By.xpath("//button[#type='submit']")).isDisplayed
}
})
Anybody?
[EDIT]
Selenium version: 2.35.0
FireFox driver: 2.35.0
I will try it with Opera now.
You'll need the . in front of the XPath selector anyway, so that it'll search the current element's descendants/children:
.//button[#type='submit']
Sometimes, a more elaborate XPath can also help:
.//descendant::button[#type='submit']
Related
I'm new to aurelia. I'm looking to find the best method for adding classes on click events.
I simply want to click approve or request information, and then add a class to the corresponding "contact card". This class would change the background color.
I know it's probably simple, but I thought I'd look here for the best method.
Here's an image to what I've got:
Apologies for the wait, work has been a bit busy.
This is my first time posting on S.O., so I apologize for any expectations I'm not meeting.
<div class="col-sm-4">
<button class="btn btn-success col-sm-12" click.delegate="goodBoi()">
approve contact
</button>
</div>
<div class="col-sm-4">
<button class="btn btn col-sm-12" click.delegate="requestContact()">
request information
</button>
</div>
</div>
the element to be changed is named "list-group-item", containing the
contact's details(code shown above).
<template>
<div class="contact-list">
<ul class="list-group">
<li repeat.for="contact of contacts" class="list-group-item ${contact.id === $parent.selectedId ? 'active' : ''}">
<a route-href="route: contacts; params.bind: {id:contact.id}" click.delegate="$parent.select(contact)">
<h4>${contact.firstName} ${contact.lastName}</h4>
<p>${contact.company}</p>
<p>${contact.email}</p>
<h6>${contact.approval}</h6>
</a>
<a route-href="route: contacts; params.bind: {id:contact.id}">
<p>${contact.phoneNumber}</p>
</a>
</li>
</ul>
</div>
goodBoi() {
let result = confirm("Are you sure you want to confirm this contact?");
if (result === true) {
var standingShell = document.getElementsByClassName("list-group-item");
//im hoping here I would add a class to the new variable//
this.contact.approval = 'approved';
this.save();
}
}
//confirms contact, changing color of approved contact//
//same thing here, just plan to give it a different color//
requestContact() {
let contactRequestText = "request sent to contact";
this.routeConfig.navModel.setTitle(this.contact.approval = contactRequestText);
this.ea.publish(new ContactUpdated(this.contact));
}
There are many ways to set a CSS-class using Aurelia. Following I prepared an example gist:
Template:
<template>
<h1>${message}</h1>
<div class="form-group ${clicked ? 'red' : 'blue'}" style="width: 100px; height: 100px;">
</div>
<div class="form-group">
<button click.delegate="save()">
Click me
</button>
</div>
</template>
And the code class:
#autoinject
export class App {
#bindable clicked = false;
save(){
this.clicked = true;
}
}
https://gist.run/?id=425993b04a977466fa685758389aa2b4
But there are other, cleaner ways:
using ref in a custom element.
custom attributes.
Include jQuery for using e.g. $('#myelement').addClass()
Meteor 1.6.1.1 is the latest version of my project. I am using package ian:accounts-ui-bootstrap-3 instead of accounts-ui. I have added a custom field as <select> in the code.
What I get on Screen is as below.
When I saw the HTML code, it is not adding class="form-control" to select tag.
below is the code when I inspect element on UI using Chrome.
<li id="login-dropdown-list" class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Sign in / Join <b class="caret"></b></a>
<div class="dropdown-menu">
<div class="select-dropdown">
<label>State</label><br>
<select id="login-state">
</select>
</div>
<button class="btn btn-primary col-xs-12 col-sm-12" id="login-buttons-password" type="button">
Create
</button>
<button id="back-to-login-link" class="btn btn-default col-xs-12 col-sm-12">Cancel</button>
</div>
</li>
All I want is to add class="form-control" to the select tag dynamically when component loads on screen and it must look like below;
I have tried below code, but it is not working;
Template.HomePage.onRendered(function () {
document.getElementById('login-state').classList.add('form-control');
});
Well, I tried one way to achieve this is by using Template event as below,
Template.HomePage.events({
'click #login-dropdown-list': function(event){
//document.getElementById('login-state').classList.add('form-control');
$('#login-state').addClass('form-control');
}
});
As you can see, the component gets loaded inside the li tag with id="login-dropdown-list". I simply loaded the class on click event. Even the commented code works fine.
Is this a good solution? please let me know if there much better answer to this? If it works I will definitely accept and upvote the answer.
I am trying to click a button using Selenium.
Below is the code
<div class="ui-dialog-buttonset">
<button class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" type="button" role="button" aria-disabled="false">
<span class="ui-button-text"> … </span>
</button>
I tried to do this by the css selector:
clickbutton=driver.find_element_by_css_selector("button.ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only")
**My error: Unable to locate element: { method: "css selector","selector":"button.ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only"} **
Am I approaching this wrong? Im not understanding the error. Shoud I use another Locator?
Your css selector is ok the problem is related to html code which setting aria-disabled="false" for compability. For Web3 documentation it means that related element and descandent are active but in your case it is not working.
Simple you can set the aria-disabled="true" then you can interact with the button but even you set it back to false it still works. To change the button attribute, you can use execute_script. Alternative to your css you use this css too: .ui-dialog-buttonset > button
>>> dr.find_element_by_css_selector(".ui-dialog-buttonset > button").get_attribute("aria-disabled")
u'false'
>>> dr.execute_script('document.querySelector(".ui-dialog-buttonset > button").setAttribute("aria-disabled", true)')
>>> dr.find_element_by_css_selector(".ui-dialog-buttonset > button").get_attribute("aria-disabled")
u'true'
>>> dr.find_element_by_css_selector(".ui-dialog-buttonset > button").click()
I have a checkbox that is not a "real" checkbox. The CSS looks like:
<li id="privileges:1" class="ui-tree-parent default" data-rowkey="1">
<div class="ui-tree-node ui-state-default" aria-checked="true" aria-selected="true" aria-expanded="true" role="treeitem">
<span class="ui-helper-clearfix ui-tree-node-content ui-corner-all ui-tree-selectable-node">
<span class="ui-tree-icon ui-icon ui-icon-triangle-1-s"></span>
<span></span>
<div class="ui-tree-checkbox ui-widget">
<div class="ui-tree-checkbox-box ui-widget ui-corner-all ui-state-default">
<span class="ui-tree-checkbox-icon ui-icon ui-icon-check"></span>
The last span appears when the checkbox is checked.
My coworker had the following code which after review appears to be black magic and shouldn't validate anything:
WebElement checkedBox = findElementByXpath("//li[#id='privileges:1']/div[#aria-checked='true']/span/div/div");
#SuppressWarnings("unused")
Boolean isChecked;
isChecked = checkedBox.findElement(By.xpath("//li[#id='privileges:1']/div[#aria-checked='true']/span/div/div")).isSelected();
What is the best way to validate the checkbox is checked using Selenium2/Webdriver?
This does not work:
WebElement checkedBox = findElementByClass("//li[#id='privileges:1']/div/span/div/div/span[#class='ui-tree-checkbox-icon.ui-icon.ui-icon-check']");
assertTrue(checkedBox.isEnabled());
Nor does:
WebElement checkedBox = findElementByClass("//li[#id='privileges:1']/div/span/div/div/span[#class='ui-tree-checkbox-icon.ui-icon.ui-icon-check']");
assertTrue(checkedBox.isDisplayed());
You have period/fullstops where the spaces should be in the XPath.
The period/fullstop will only work in CSS selector. Also you seem to be using the By ClassName function and passing in an XPath query. I'll assume this was just a typo.
This is what you have:
//li[#id='privileges:1']/div/span/div/div/span[#class='ui-tree-checkbox-icon.ui-icon.ui-icon-check']
It should be:
//li[#id='privileges:1']/div/span/div/div/span[#class='ui-tree-checkbox-icon ui-icon ui-icon-check']
Tip in case you didn't know: If you open Chrome Developer tools, go directly to the Console, type in:
$x("//li[#id='privileges:1']/div/span/div/div/span[#class='ui-tree-checkbox-icon.ui-icon.ui-icon-check']")
You'll see it returns nothing.
Do the same with this:
$x("//li[#id='privileges:1']/div/span/div/div/span[#class='ui-tree-checkbox-icon ui-icon ui-icon-check']")
It'll return something. Both Firebug and Chrome Developer tools can be used to execute CSS and XPath selectors. So you can see if the issue is with Selenium or the selector you are using.
Both these buttons have almost similar ID (the number on the ID may change and so is not reliable)
Both have same classes
They both reside under the same parent
Except for the span nothing is different
All the UI elements of the application I am trying to locate and build events on Using Selenium are similar to the below piece...
Can anyone please suggest how I can locate these buttons preferable with xpath?
<div id="button-1749" class="x-btn x-box-item x-toolbar-item x-btn-default-toolbar- small x-noicon x-btn-noicon x-btn-default-toolbar-small-noicon x-item-disabled x-disabled x-btn-disabled x-btn-default-toolbar-small-disabled" style="margin: 0pt; left: 1563px; top: 0px;">
<em id="button-1749-btnWrap" class="">
<button id="button-1749-btnEl" class="x-btn-center" autocomplete="off" role="button" hidefocus="true" type="button" aria-disabled="true" disabled="">
<span id="button-1749-btnInnerEl" class="x-btn-inner" style="">Delete Selected</span>
<span id="button-1749-btnIconEl" class="x-btn-icon x-hide-display"> </span>
</button>
</em>
</div>
<div id="button-1750" class="x-btn x-box-item x-toolbar-item x-btn-default-toolbar-small x-noicon x-btn-noicon x-btn-default-toolbar-small-noicon" style="margin: 0pt; left: 1654px; top: 0px;">
<em id="button-1750-btnWrap" class="">
<button id="button-1750-btnEl" class="x-btn-center" autocomplete="off" role="button" tabindex="1" hidefocus="true" type="button">
<span id="button-1750-btnInnerEl" class="x-btn-inner" style="">New Title</span>
<span id="button-1750-btnIconEl" class="x-btn-icon x-hide-display"> </span>
</button>
</em>
</div>
If you want to look for the elements under a specific div, you can use descendent axis.
Example:
//div[#id='your div']/descendant::button[contains(#class, 'x-btn-center')]/span[text()='Delete Selected']"
This will give you Deleted Selected button that is within the div with id 'your div'.
You could also use GetElements (opposed to GetElement) and this will return a List of elements that match your search criteria. Then, providing the order the buttons appear on the page never changes, you may use this List to access the button you want every time by using the associated index.
Eg.
ReadOnlyCollection<IWebElement> buttons = driver.FindElements(By.XPath("YOUR XPATH HERE"));
//If it's the 3rd button that matches your criteria
buttons[2].Click(); //or whatever you want with this button :)
I think this should work in your case:
locator = driver.find_element_by_xpath("//div/em/button/span[contains(text(),'Delete Selected')]")
You can do similar way in case of another element.
though xpath is a desired locator per your question, there are documented speed differences between xpath and css selector, here's one example: http://saucelabs.com/blog/index.php/2011/05/why-css-locators-are-the-way-to-go-vs-xpath/. to locate those elements via css selector, use the following, python example
els = driver.find_elements_by_css_selector("button[id^=button]
for eachel in els:
eachel.click()
You have to create your own xpath if the xpath of 2 elements are same
driver.findElement(By.xpath("//span[contains(text),'New Title')]")).click;