I am using nightwatch with chrome driver for UI-Testing. I have come across an issue when trying to click on 'primary-btn' in the web-page. First the waitForElement returns a warning "Warn: WaitForElement found 2 elements for selector "#primary-btn". Only the first one will be checked" and the subsequent .click('#primary-btn') does not yield the desired result.
I checked the web-page to see if actually there are 2 elements with the name "#primary-btn" using document.getElementById('primary-btn'). However the function listed only 1 element with id 'primary-btn'
I am not sure why this happens. Does nightwatch support wait for animation to finish.
You should try this
document.querySelectorAll("div[id='primary-btn']:nth-child(1)")
In nightwatch :
browser.waitForElementPresent("div[id='primary-btn']:nth-child(1)")
It means that you have 2 elements in you page with an identical id. While the standard impose a unique name, it is not enforced in the browser. You can verify it by executing this command in your browser:
document.querySelectorAll("[id='primary-btn']")
Or:
$x("//*[#id='primary-btn']")
So to get the expected element, you need to extend your selector with another condition. It could be for example:
'#container-id #primary-btn'
Related
Selenium FindElement:
driver.FindElement(By.XPath($"//*[contains(text(), '{text}')]"));
Throws:
no such element: Unable to locate element:
{
"method":"xpath",
"selector":"//*[contains(text(), '269424ae-4d74-4a68-91e0-1603f2d674a0')]"
}
(Session info: chrome=74.0.3729.169)
(Driver info:
chromedriver=74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729#{#29}),
platform=Linux 4.18.0-20-generic x86_64)
But it's definitely there and the xpath is valid because I can use AngleSharp to parse the driver's page source with the same xpath expression:
new HtmlParser()
.ParseDocument(driver.PageSource)
.SelectSingleNode($"//*[contains(text(), '{text}')]");
The target element is a div containing a guid:
<div class="home-project-title-text"> 269424ae-4d74-4a68-91e0-1603f2d674a0 </div>
This is with
dotnet core 2.2
chrome webdriver
Chrome 74
Ubuntu 18.04
EDIT1
Interestingly the document.evaluate in the browser console also fails with this xpath expression. I use this as a helper function for running xpath:
selectSingle = xpath => document.evaluate(xpath, document).iterateNext()
and then find that this returns null:
> selectSingle("//*[contains(text(), '269424ae-4d74-4a68-91e0-1603f2d674a0')]")
> null
but it's definitely there and has the expected text, e.g. I can use a different xpath expression to manually locate and check it's text content:
> selectSingle("//*[#id='app']/div/div[1]/div[3]/div/div[1]/div/div[1]/div")
.textContent
.trim()
== "269424ae-4d74-4a68-91e0-1603f2d674a0"
> true
EDIT2
So the cause was that the div was being created in react like this:
React.createElement(
"div",
{className = "home-project-title-text"},
" ",
"269424ae-4d74-4a68-91e0-1603f2d674a0",
" ");
I think this roughly means that the div has three textnodes as children (is that valid?). The result looks 100% normal - it renders perfectly and inspecting the element with devtools looks like a single text node and .textContent returns the concatenated string.
Now that you gave some more information (how this element is created):
Yes, it is possible that an XML element has as its children several separate text nodes. However, this is usually not the case if the text nodes are adjacent to each other, instead of separated by child elements.
If '269424ae-4d74-4a68-91e0-1603f2d674a0' is indeed the second text node, then
//*[contains(text(), '269424ae-4d74-4a68-91e0-1603f2d674a0')]
will indeed not return this div element. You should not think of this as "breaking XPath", it is just that the precise semantics of the expression are:
Find an element with any name whose first text node contains '269424ae-4d74-4a68-91e0-1603f2d674a0'.
text() actually selects all text nodes of an element, but XPath functions such as contains() silenty select only the first one.
What you actually would like to select is
an element with any name where any text node contains '269424ae-4d74-4a68-91e0-1603f2d674a0'
And an expression to achieve exactly that is:
//*[text()[contains(.,'269424ae-4d74-4a68-91e0-1603f2d674a0')]]
You can test those expressions with a small toy document such as:
<div className="home-project-title-text">
<other/>
269424ae-4d74-4a68-91e0-1603f2d674a0
<other/>
</div>
Where other elements are forcing the div element to contain three separate text nodes, two of them containing whitespace only.
Finally, if you already know that the element you are looking for is a div, then you should look specifically for that:
//div[text()[contains(.,'269424ae-4d74-4a68-91e0-1603f2d674a0')]]
It might be the case the element lives in an iframe, if this is the case - you will have to use IWebDriver.SwitchTo() function in order to switch to the required iframe prior to attempting locating the element.
It might be the case the element is not immediately available, i.e. it's being loaded by an AJAX request, in that case you will need to use WebDriverWait class so Selenium could wait till the element appears in DOM prior to interacting with it.
Try the following xpath.See if you get any luck.
//div[#class='home-project-title-text'][contains(.,'269424ae-4d74-4a68-91e0-1603f2d674a0')]
EDIT
//div[contains(.,'269424ae-4d74-4a68-91e0-1603f2d674a0')]
I am tring to find a button in a webpage using find elements, the page can contain one of the below button ID's.
driver.findElements(By.xpath("//*[contains(#id,'topBtn')]"))
driver.findElements(By.xpath("//*[contains(#id,'WSMplasticTop')]"))
driver.findElements(By.xpath("//*[contains(#id,'bottomApplyBtn')]"))
The above code is working as expected when i use the Firefox Driver, where as getting the below error when i run in Chrome Driver.
org.openqa.selenium.InvalidSelectorException: invalid selector: Unable to locate an element with the xpath expression //*[contains(#id='bottomApplyBtn')] because of the following error:
SyntaxError: Failed to execute 'evaluate' on 'Document': The string '//*[contains(#id='bottomApplyBtn')]' is not a valid XPath expression.
Just wanted to know whether i have done any mistake
Try to use
'//*[contains(#id,'bottomApplyBtn')]'
instead of
'//*[contains(#id='bottomApplyBtn')]'
When you are using contains method in your XPath expression, you basically are using an inbuilt method to find the element.
This method takes 2 parameters.
First the tag you in which you want to search.
Second is the actual text value which you are looking for inside the above tag.
Basically you have to call the method with 2 parameters and that 2 parameters should be comma separated.
So //*[contains(#id='bottomApplyBtn')] is wrong you should instead remove this = sign.
//*[contains(#id, 'bottomApplyBtn')]
|_______|____________________ Parameter 1
|__________________________________Parameter 2
Hope it helps!
I am trying to run test cases to perform reset password and I am facing this issue.
WebDriverException Element must be user-editable in order to clear it.
Basically i am accessing the page for entering the new password and doing this:
browser.$("#newPassword").text("password");
where execution of the above line throws the error.
I had the same problem and it was because there was another element with the same id which was not an input field so it could not be cleared.
We can try the following:
WebElement.sendKeys(Keys.DELETE);
WebElement.sendKeys("Test");
It might be a case of using the wrong method for the input type.
In CodeCeption at least, fillField should be used on input elements and selectOption should be used on select elements and mixing them up will give invalid element state: Element must be user-editable in order to clear it.
I had this problem with a Primefaces autoComplete element. Primefaces 6.0 renders a span with the ID you pass, and within that an input with a "_input" appended to the ID. If you just use the ID you added in your source code, you tell Selenium to enter into the span (which fails with the "element must be user-editable" error). Add the "_input" to the ID if you select by ID in selenium.
I have to test some complicated web service using Selenium.
Problem is that ids of elements are changing from session to session.
For example there is bunch of inputs each have id with prefix textf_id_DComboBox_ and ends with a consecutive numbers, starting number is random (session dependent).
Those inputs doesn't have a common parent so nth-child doesn't work.\
I can find first input by using selector: css=input[id^='textf_id_DComboBox_'] but I have no idea how to find next items (1-7) which match this selector.
I've found some suggestions on stackoverflow that xpath selector should be used, but I was unable to adopt examples for my use case.
Update:
I have also alternative selector which captures first input: css=td.DForm_treeGridNoWrap input.
You can use this XPath in order to select all inputs that contain a common id:
string comboBoxXPath = "//input[contains(#id, 'textf_id_DComboBox')]";
List<WebElement> comboBoxElements = driver.findElements(By.XPath(comboBoxXPath));
At this point, you can iterate through the entire collection, or you can select which one you'd like to interact with by using an index:
comboBoxElements[1]
comboBoxElements[2]
comboBoxElements[3]
etc...
Well, that descrption does not help that much. You can try these tricks:
You can call findElement on WebElement This trick will probably not work, because those IDs do not have common parent. But if they are wrapped, say, in table, you can find the table first:
WebElement table = driver.findElement(By.id("the-table"));
And then to find all input in such table:
List<WebElement> inputs = table.findElements(By.tagName("input"));
Install Selenium IDE to your firefox and try record testcase by using it. You can play with target in Selenium IDE.
Dirty approach
List<WebElement> allInputs = driver.findElements(By.tagName("input"));
Will find all inputs in such page.
Footnote: The code is Java and driver variable is considered as healthy instance of WebDriver
I am getting different results for the same locator. For example
//table[#id='foo']
returns true when testing ElementPresent, but returns 0 for XpathCount. In Selenium v1.0.10 IDE the Find button highlights the correct element for both functions. Any ideas on what could be causing this?
Notes:
We have frames on the page EDIT: This is probably the problem. Bounty to verification.
There are many tables on the page, but only one with #id of "foo"
Firefox 3.6
Happens in both IDE and Java RC
Well, this is not a verification more of a non-verification.
I use Selenium to test a GUI with frames. To make isElementPresent and getXpathCount to work I always have to select a frame first with selectFrame (even to get isElementPresent to work correctly). By just opening an URL no frame at all seems to be selected.
This is what the HTML and corresponding selectFrame code looks like:
<frameset id="mainframeset"><frame name="nav" id="nav" src....
selenium.selectFrame("nav");
Use these XPath expressions:
boolean(//table[#id='foo'])
and
count(//table[#id='foo'])
In case there is a table element whose id attribute's value is "foo", then the first expression above should evalute to true() and the second expression above should evalute to a positive integer.
Not really a direct answer to the question, but a workaround if you are reading this and want to loop over the elements. Use isElementPresent in the for loop like this:
for(int i = 2; selenium.isElementPresent("//table[#id='foo']//tr["+i+"]"); i++)
{
selenium.getText("//table[#id='foo']//tr["+i+"]//td["+columnNum+"]");
}
Note that we start i at 2 since XPath is indexed from 1 and we want to skip the header