Selenium CSS selector :visible is not a valid selector - css

I'm using Page Objects to map elements in a page, something like that:
public class MyPage {
protected WebDriver driver;
#FindBy(css = "a[data-code=panel]:visible")
private WebElement cpaneladmin;
public MyPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(this.driver, this);
}
}
The problem is this :visible CSS selector. Aparently, Selenium does not support it. Is there a way to select only visible elements using xpath or another kind of CSS selector?
Thanks

#FindBy(css = "a[data-code=panel]")
private List<WebElement> cpaneladmin;
Then iterate through the elements until you find the one that is displayed.
public WebElement FindDisplayed(WebElements elements)
{
foreach (WebElement element in elements)
{
if (element.isDisplayed()) // correct method: isDisplayed()
return element;
}
}

This should answer your question.
If you want to verify the element is visible another way, use element.IsDisplayed(), or use ExpectedConditions.

This might solve your problem,
List<WebElement> list = driver.findElements(By.cssSelector("selector_that_matches_one__or_more_elements"));
//do what ever you want with the elements in list
The above code will store all the visible elements that can be located by the provided selector.
Try using an implicit wait at the start of your code, for the above statements to be more effective.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
When implicitly waiting, findElements() method will return as soon as there are more than 0 items in the found collection, or will return an empty list if the timeout(30 secs in the above case) is reached.

I came on this question a bit late, but here's how I resolved it in C#:
private void AssertAdminIsVisible(OpenQA.Selenium.IWebDriver wd)
{
OpenQA.Selenium.Support.UI.WebDriverWait wait = new OpenQA.Selenium.Support.UI.WebDriverWait(wd, TimeSpan.FromSeconds(60));
var cpaneladmin = wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementIsVisible(OpenQA.Selenium.By.CssSelector("a[data-code=panel]")));
Assert.IsNotNull(cpaneladmin);
}
And for.NET, it comes from the "DotNetSeleniumExtras.WaitHelpers" NuGet package:

you can also use :not([style*="display: none"]) as a workaround.

Related

How to use the Vaadin Testbench with Rich Text Area?

I am using Vaadin Testbench (4.1.0-alpha) for designing some integration test for my application (designed in Vaadin 7.6.1).
In a window, I use a rich test area. The idea is to design a test where the value of this rich text element is changed simulating some user behaviour. But now I realize I cannot find any method for change the value of this element, neither get the current value of the element.
I have tested some methods.getHTML() gets the HTML for the component, no the HTML of the designer. getText() gets the list of elements (font colour, background and other options of the element, but not the content).
Then I expect to have specific class methods for retrieving the value. If I explore the class RichTextAreaElement, seems that no method is implemented. All code in this class is:
#ServerClass("com.vaadin.ui.RichTextArea")
public class RichTextAreaElement extends AbstractFieldElement {
}
As you can see, no method is declared.
How can I do a test where a user change the value of this rich text area? It is not implemented?
Hmm yeah, that looks like some work in progress, probably because it's a complex component with all the features it provides. Nonetheless we can workaround the limitations a bit, again making use of chrome developer tools (or similar) and some custom classes to select the components by (actually it's just the gwt-RichTextArea).
Of course this serves just as a starting point and can be further enhanced. Also I'd be very interested to see a more elegant solution if someone finds one...
Structure inspection
Test class
public class RichTextAreaTest extends TestBenchTestCase {
#Before
public void setUp() throws Exception {
System.setProperty("webdriver.chrome.driver", "D:\\Kit\\chromedriver_win32\\chromedriver.exe");
setDriver(new ChromeDriver());
}
#After
public void tearDown() throws Exception {
// TODO uncomment below once everything works as expected
//getDriver().quit();
}
#Test
public void shouldModifyRichTextArea() throws InterruptedException {
// class to identify the editor area by
String editorClass = "gwt-RichTextArea";
// open the browser
getDriver().get("http://localhost:8080/");
// select the first rich text
RichTextAreaElement richTextArea = $(RichTextAreaElement.class).first();
// get the editor section which is where we're writing
WebElement richTextEditorArea = richTextArea.findElement(By.className(editorClass));
// click inside to make it "editable"
richTextEditorArea.click();
// send some keystrokes
richTextEditorArea.sendKeys(" + something else added by selenium");
}
}
Result:
Update for getting the value
If you simply want to get the text, the code below will do the trick:
// switch to the editor iframe
getDriver().switchTo().frame(richTextEditorArea);
// get the <body> section where the text is inserted, and print its text
System.out.println("Text =[" + findElement(By.xpath("/html/body")).getText() + "]");
Output
Text =[Some predefined text + something else added by selenium]
At the end, I was able to obtain the content of the element selecting the first iframe of the page, and searching for the body content. The final code looks like:
String currentWindow = getDriver().getWindowHandle();
getDriver().switchTo().frame(getDriver().findElement(By.tagName("iframe")));
WebElement webelement = this.findElement(By.xpath("/html/body"));
String text = webelement.getText();
getDriver().switchTo().window(currentWindow);
return text;
As I need to switch between the iframe and the window, I am only able to obtain the content of the element, not the element itself. If I return directly the element for future use, an org.openqa.selenium.StaleElementReferenceException: Element belongs to a different frame than the current one - switch to its containing frame to use it exception is obtained.
For changing the text, the solutions is very similar, only use the sendKey functions to first remove existing characters and later add the new text:
String currentWindow = getDriver().getWindowHandle();
getDriver().switchTo().frame(getDriver().findElement(By.tagName("iframe")));
WebElement webelement = this.findElement(By.xpath("/html/body"));
// Remove any previous text.
String previousText = webelement.getText();
for (int i = 0; i < previousText.length(); i++) {
webelement.sendKeys(Keys.DELETE);
}
// Set text.
webelement.sendKeys(text);
getDriver().switchTo().window(currentWindow);

Is there a way to filter out hidden elements with css?

as an example some html has several elements which have the css path table.class1.class2[role="menu"] but only one of these elements will be visible at any given time, so I want to get only the one that is visible.
can I adjust my css path to narrow it down?
Possibly use Linq to get the list. I am not sure which language you are using. But, similar concept can be applied using any of them. Using Linq
to accomplish this kind of scenario is very simple in C#
public IWebElement Test()
{
//selector
By bycss = By.CssSelector("table.class1.class2[role='menu']");
return Driver.FindElements(bycss).ToList().FirstOrDefault(d => d.Displayed);
}
And, make sure to import
using System.Linq; if you are using C#
In Java you can do something like this[not using lambdas]
List<WebElement> visibleList = null;
//selector
By byCss = By.cssSelector("table.class1.class2[role='menu']");
//list of visible and hidden elements
Iterator<WebElement> iterator = driver.findElements(byCss).iterator();
while (iterator.hasNext()){
WebElement element = iterator.next();
if (element.isDisplayed()){
//building the list of visible elements
visibleList.add(element);
}
}
//get the first item of the list
//you can return all if needed
return visibleList.get(0);
In Java, you can use WebElement.isDisplayed().

Webdriver: expose selector/by/location of existing element

The problem:
.Click()-ing a radio button webdriver element stales it(no control over the page that does this). The DOM element itself is still the same.
The goal:
I want to reset the existing webdriver element using its own original selector method so that it is no longer stale. I want a general solution that does not require knowing ahead of time how the element was found. I want to use the existing stale element to do the work. Ideal case would look something like this(using the following C# extension method just for sake of example):
IWebElement refreshedElement = driver.FindElement(staleElement.By());
The question:
Is there a way to expose the existing elements location? Is the 'address' of the element available anywhere? It doesn't even have to be the original method of addressing the element when it was found, I don't care about that. I'd just rather not have to make a subclass just to capture this information.
No, Selenium does not keep track of 'how' you found an element, and frankly I don't think that should be Selenium's responsibility.
I would wrap it into a new class, which inherits from RemoteWebElement, and has a method called RefindElement.
I might suggest considering adding the concept of a "Page Class". Basically, instead of adding the element to the test itself, I create a separate class that has methods that return elements.
For example, a login page would have three elements therefore 3 methods:
public class LoginPage
{
private IWebDriver driver { get; set; }
public CSCView_SalesAspx(IWebDriver driver) { this.driver = driver; }
public IWebElement Id { get { return driver.FindElement(By.Id("login_id")); } }
public IWebElement Pw { get { return driver.FindElement(By.Id("login_pw")); } }
public IWebElement SubmitBtn { get { return driver.FindElement(By.Id("submitBtn")); } }
}
Now all you have to do is instantiate the class then interact with the method. Your element should always be "fresh" since you're doing the lookup every time (without any extra work).
LoginPage loginPage = new LoginPage(driver);
loginPage.Id.SendKeys("myName");
loginPage.Pw.SendKeys("myPw");
loginPage.SubmitBtn.Click();
The best thing about this is if a page changes, instead of having to rewrite every test, you only change one page class and that fixes your broken tests.

Flex: Expand AdvancedDataGrid Tree Column programmatically

Does anyone know how to programmatically expand the nodes of an AdvancedDataGrid tree column in Flex? If I was using a tree I would use something like this:
dataGrid.expandItem(treeNodeObject, true);
But I don't seem to have access to this property in the AdvancedDataGrid.
AdvancedDataGrid has an expandItem() method too:
http://livedocs.adobe.com/flex/3/langref/mx/controls/AdvancedDataGrid.html#expandItem()
Copy the sample found at the aforementioned url and call this function:
private function openMe():void
{
var obj:Object = gc.getRoot();
var temp:Object = ListCollectionView(obj).getItemAt(0);
myADG.expandItem(temp,true);
}
You could also open nodes by iterating through the dataProvider using a cursor. Here is how I open all nodes at a specified level:
private var dataCursor:IHierarchicalCollectionViewCursor;
override public function set dataProvider(value:Object):void
{
super.dataProvider = value;
/* The dataProvider property has not been updated at this point, so call
commitProperties() so that the HierarchicalData value is available. */
super.commitProperties();
if (dataProvider is HierarchicalCollectionView)
dataCursor = dataProvider.createCursor();
}
public function setOpenNodes(numLevels:int = 1):void
{
dataCursor.seek(CursorBookmark.FIRST);
while (!dataCursor.afterLast)
{
if (dataCursor.currentDepth < numLevels)
dataProvider.openNode(dataCursor.current);
else
dataProvider.closeNode(dataCursor.current);
dataCursor.moveNext();
}
dataCursor.seek(CursorBookmark.FIRST, verticalScrollPosition);
// Refresh the data provider to properly display the newly opened nodes
dataProvider.refresh();
}
Would like to add here that the AdvancedDataGrid, in spite of having an expandAll() method, has a property called displayItemsExpanded, which set to true will expand all the nodes.
For expanding particular children, the expandChildrenOf() and expandItem() methods can be used, as can be verified from the links given above.

How do you add a row listener to a Flextable in GWT?

How do you add a row listener to a specific row, or all rows in a table? I need to add a type of "onMouseOver" listener to the rows so that when you hover over them, it changes the background color of the row, much like getRowFormatter will allow you to do.
// this is click
final FlexTable myTable = new FlexTable();
myTable.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
Cell cell = myTable.getCellForEvent(event);
int receiverRowIndex = cell.getRowIndex(); // <- here!
}
});
Supposing GWT 1.5.3:
CLICK EVENT HANDLING
If you are using FlexTable and you wanted a click event handler, you could use the FlexTable.addTableListener() and register your own TableListener. The TableListener object will need to implement the onCellClicked callback which would give you the row number.
OTHER EVENTS HANDLING (e.g. HOVER)
If you need to handle other type of events other than click (say, hover), GWT currently doesn't have a ready interface for that. You pretty much left on your own to implement them yourself. There's two ways of doing it that I can think of now:
The quick and dirty way, is probably by exploiting JSNI, which provides a means for you to inject Javascript into your GWT code. I didn't use much JSNI (apart from really hard workarounds which is not worth the effort writing it in pure GWT) in my code so I can't show you an example; but frankly I won't recommend this as it reduces maintainability and extensibility.
If you wanted a native, GWT interface, you can create a new class that inherits HTMLTable or FlexTable. At the constructor, call the sinkEvents function with your needed events. (e.g. for hover, you'll probably need sinkEvents(Event.ONMOUSEOVER)). Then you'll need the onBrowserEvent function that handles the mouseover.
A quick template of how the code should look like:
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FlexTable;
public class FlexTableWithHoverHandler
extends FlexTable
{
public FlexTableWithHoverHandler()
{
super();
sinkEvents(Event.ONMOUSEOVER);
}
#Override
public void onBrowserEvent(Event event)
{
switch(DOM.eventGetType(event))
{
case Event.ONMOUSEOVER:
// Mouse over handling code here
break;
default:
break;
}
}
}
The best of learning how to code this is by looking at the GWT source code itself (search for sinkEvent) and getting the feel on how to do it the GWT way.
I found it much simple to add javascript directly to the TR element. My code assumes that a widgets DOM parent is a TD and the grandparent is the TR so you need to be sure you know your DOM.
Here's my code. Nice and simple, no JSNI or GWT DOM event management required.
TableRowElement rowElement = (TableRowElement) checkbox.getElement().getParentElement().getParentElement();
rowElement.setAttribute("onMouseOver", "this.className='" + importRecordsResources.css().normalActive() + "'");
rowElement.setAttribute("onMouseOut", "this.className='" + importRecordsResources.css().normal() + "'");
I just did it this simple way:
protected void handleRowsSelectionStyles(ClickEvent event) {
int selectedRowIndex = fieldTable.getCellForEvent(event).getRowIndex();
int rowCount = fieldTable.getRowCount();
for (int row = 0; row < rowCount; row++) {
Element rowElem = fieldTable.getRowFormatter().getElement(row);
rowElem.setClassName(row == selectedRowIndex ? "row selected" : "row");
}
}
You call this method from the cells you want to be clickable
int row = 0;
for (final RowDataProxy rowData : rowDataList) {
Label fieldName = new Label(rowData.name());
fieldName.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
handleRowsSelectionStyles(event);
}
});
fieldTable.setWidget(row++, 0, fieldName);
}
Best Regards,
Zied Hamdi

Resources