Watir finds elements by class, but elements are null? - html

I am able to find elements by class using Watir, but I can't figure out how to do additional processing with them after selection - the elements found are nil (see below).
I would love to see the html text of each element found.

You have instances of Watir::HTMLElement which at time of definition only stores the parent and selector. The #element variable which represents the object in the DOM located by Selenium through a browser driver will only be populated when you take an action on the element.
To see the text of each element, just put puts event.text inside your loop.

Related

Selenium no such element: Unable to locate element

I can locate the element via XPath in HTML page, but in selenium, it is showing unable to locate the element.
Below is my Xpath:
driver.findElement(By.xpath("//div[#class='navbar-collapse collapse']//li[#ng-class='{active:contactActive}']//span[contains(text(),'Contact Manager')]")).click();
Also, I cannot share my HTML Page.
You provided really few information regarding your problem, so i'll give general answer for general question:
precondition - you have locator
//div[#class='navbar-collapse collapse']//li[#ng-class='{active:contactActive}']//span[contains(text(),'Contact Manager')]
Possible issue 1 let's assume that locator correct - so there's possible situation that driver checks element before it appears
Solution:
a. ensure in debug mode that element is visible on step when driver is
searching for it - item is not collapsed, not overlapped, visible,
exist.
b. be sure that element is loaded when driver is actually searching
for it. Add explicit wait.
Issue 2
//div[#class='navbar-collapse collapse'] - such locator is always source of problems, because your div should have class exactly equal to navbar-collapse collapse, in the same order. Locator will fail if another class will be added, or classes will be orderer in another way.
Solution - it's better to use 'contains' locators instead of 'equals' //div[contains(#class,'navbar-collapse')]
Issue 3 - this locator tells you not really much about element you are searching for. It just says that elements should be located inside collapsible div. Same problem with li part of your locator.
Solution:
a. try to use more informative locators (classes/ids), as it will be
really easier to maintain (understand what locator is looking for and
update for correct one) when not abstract "collapse", but "userItem"(
for example) class used.
b. reduce complexity - remove unneeded part of locators. Do you really
need that part of locator //div[#class='navbar-collapse collapse'] ?
Will locator work logically/correctly if you remove this part? I
believe so). Is that important for 'Contract Manager' to be placed inside span and not div? If no - use * for tag indication. And so on.
Yes explicitly wait is only partially Working. But after using Explicit wait its showing another error called "Unable to click on an element using Selenium". Then I had to use "JavascriptExecutor" detailed below to get this working.
WebElement Importbuilding=wait.until(ExpectedConditions.elementToBeClickable((By.xpath("//div[#class='col-md-1 add_building margin_left25 col-xs-3 ng-scope']//button"))));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", Importbuilding);

HtmlUnit's DomElement can't save state of XPath result

when I search big document sometimes I need to save result of big XPath expression, but if I try to store XPath result in DomElement object and make new XPath query just on block of code that I've pointed to DomElement object, I get results based on whole document. For example:
DomElement block = page.getByXPath("//div[#class='block_of_code']");
System.out.println(block.getByXPath("//span[#class='red']"));
So, first line will fetch all divs on the page with class='block_of_code'. But when I try to print out all span elements from block object I get back all span element that are on the page, not only in that block.
Is there an alternative (in HtmlUnit package preferably) where to store small chunks of html blocks and do manipulation by xPath just on it, not whole page?
Thanks!
An XPath expression starting with a / character will always query the entire document, even if you pass a context node to the function.
To make a query relative to the context node, you can start it with a . character.
The following should achieve what you want:
DomElement block = page.getByXPath("//div[#class='block_of_code']");
System.out.println(block.getByXPath(".//span[#class='red']"));

Why does $x return items outside of the context?

I am attempting to use an xpath locator within a context for a Codeception test using the Selenium driver with Firefox. Specifically, I am trying to click the second link in the message body of an email, viewed with roundcube.
The body of the email is in the div with xpath //div[#class="rcmBody"]
I can get the link with this path: (//div[#class="rcmBody"]//a)[2]
But for some reason when I try //a[2] within the context of the body div, it returns all a elements within the iframe.
An example from codeception: (after selecting the correct iframe)
$I->click('//a[2]', '//div[#class="rcmBody"]')
This causes the web driver to click the second link in the iframe which comes before the body div begins.
I can also test this from directly in chrome:
$x('//a', $x('//div[#class="rcmBody"]')[0])
This returns a list of all a elements within the iframe, not within the context.
How can I get the context part to work?
Add a dot to the beginning of XPath to make it context-specific:
$I->click('(.//a)[2]', '//div[#class="rcmBody"]')
HERE^
Note that the parenthesis here are also important to get the desired a descendant of the parent.

Data binding between two Polymer-elements

I have two polymer elements like
<moviegrep-element></moviegrep-element>
<custom-card-element></custom-card-element>
In moviegrep-element I got an array of objects called results. I want to use the results in my custom-card-element. How does it work?
Use Polymers data-binding:
<moviegrep-element results="{{sharedResults}}"></moviegrep-element>
<custom-card-element results="{{sharedResults}}"></custom-card-element>
This assumes that both of your elements publish the results property as an attribute. Changes to the results property in one element are then propagated to the results property in the other element.
This also assumes that your elements are itself inside a Polymer element. Otherwise you need an auto-binding template element

How can I access an element by using its DOM hierarchy(parent element)?

I want to access an element using a DOM hierarchy Node structure, through its parent nodes.I am trying to find the DOM hierarchy through firebug; want something like, <parent_node1>.<child_node1>.<child_node2> (not by document.getElementByID, getElementbyname) to access an element.
I want to automate a scenario like, I have column headers and corresponding values. Want to test, whether the values present under each column header, is correct...
I am thinking of using DOM as a method of automating this case...But, how can I find the DOM hierarchy...?
What I see through Inspect Element in Firebug is something like, list of events, elements and is not looking like a hierarchy node structure...Can somebody help in this regard please?
As discussed, you probably mean the DOM Element properties like element.childNodes, element.firstChild or similar.
Have a look at the DOM Element property reference over at JavaScriptKit, you'll get a good overview there how to access the hierarchy.
var currentTD = document.getElementsByTagName("td")[0];
var currentTable = document.getElementsByTagName("table")[0];
currentTD.parentNode // contains the TR element the TD resides in.
currentTable.childNodes // contains THEAD TBODY and TFOOT if present.
DOM Tables even have more properties like a rows collection and a cells collection.
A reminder of caution: Beware that these collections are live collections, so iterating over them and accessing collection.length in each iteration can be really slow because to get the length, the DOM has to be queried each time.
document.getElementById and document.getElementByTagname are using the DOM. They take an object within the DOM (specifically the document object, though you can also call both of those on elements) and return an object which is a single element or a collection of zero or more elements, respectively. That's a DOM operation. From there you can do other DOM operations on the results like getting children, parents or siblings, changing values etc.
All DOM operations come down to:
Take a starting point. This is often document though it's so often that the first thing we do is call document.getElementById or document.getElementByTagname and then work from the result that we could really consider that the starting point.
Find the element or elements we are interested in, relative to the starting point whether through startingPoint.getElementById* or startingPoing.getElementByTagname perhaps combined with some test (e.g. only working on those with a particular classname, if they have children of particular types, etc.
Read and/or change certain values, add new child nodes and/or delete nodes.
In a case like yours the starting point will be one or more tables found by document.getElementById(someID), document.getElementById(someID).getElementsByTagname('table')[0], or similar. From that table, myTable.getElementsByTagname('th') will get you the column headings. Depending on the structure, and what you are doing with it, you could just select corresponding elements from myTable.getElementsByTagname('td') or go through each row and then work on curRow.getElementsByTagname('td').
You could also just use firstChild, childNodes etc. though it's normally more convenient to have elements you don't care about filtered out by tagname.
*Since there can only be one element with a given id in a document, this will return the same if called on any element higher in the document hierarchy, so we normally just call this on document. It can be useful to call it on an element if we want to do something if the element is a descendant of our current element, and not otherwise.