behat fillField xpath giving error? - behat

This line of code:
$this->fillField('xpath','//fieldset[#id="address-container"]/input[#name="address_add[0][city]"]', "Toronto");
Is giving me this error
Form field with id|name|label|value|placeholder "xpath" not found. (Behat\Mink\Exception\ElementNotFoundException)
The reason I want to use xpath in my fillField is because there are actually multiple input[#name="address_add[0][city]"] in my html document. I figure an xpath will let me target specifically the field I want to populate.
What's the best way to fill out just the input[#name="address_add[0][city]"] that is a descendant of fieldset[#id="address-container"] ?

You are not using the method in the wright way.
As i see here xpath is taken as selector.
The method expects 2 parameters:
identifier - value of one of attributes 'id|name|label|value'
value - the string you need to set as value
If you want to use css|xpath then you need to use find method first.
For example:
$this->find('xpath', 'your_selector')->setValue('your_string');
Please note that find might return null and using setValue will result in a fatal exception.
You should have something like this:
$field = find('xpath', 'your_selector');
if ($field === null) {
// throw exception
}
$field->setValue('your_string');
Also your selector could be written as:
#address-container input[name*=city] - this with css
or
//fieldset[#id="address-container"]//input[contains(#name, 'city')] - this with xpath
Make sure you take advantage of your IDE editor when you have any doubts using a method and you should find a php doc with what parameters are expected and what the method will return.
If you are using css/xpath a lot you could override find method to detect automatically the type of selector and to use it like $this->find($selector);
Also you could define another method to wait for the element and to handle the exception in one place, for example waitForElement($selector) that could contain a conditional wait up to 10 seconds and that throws exception if not found.

Related

Robot Framework variable attribute in seperate file not storing attribute to be used elsewhere

Variable attribute not getting passed into other file.
I have my variables for element locators stored in one file and I have assertions done in another file which has worked fine until now and separates things out nicely. I am doing an assertion to check that an element exists and its attribute(value) is not blank. If I write it on one page as follows it works perfectly. This use the selenium library keywords should not be equal and Get Element Attribute just to note.
${EXAMPLE} get element attribute class=test test-data
should not be equal ${EXAMPLE} ${EMPTY}
But If I separate them out into different files. So a locators.robot file:
#Locater File
${EXAMPLE} get element attribute class=test[test-data]
And an Assertions.robot:
#Assertion File
should not be equal ${EXAMPLE} ${EMPTY}
It stops working. If I use a selenium library assertion like page should contain element then it works, so I know I am pulling in the other Resource correctly. I have a feeling I may need to store the attribute in another variable somehow and actually assert against that. Any ideas would be great. Thanks in advance.
Suppose you have html code like this as you given in other question -
<div id="top-list">
<div data-version="12345" data-list="1" data-point="10">
Way 1 - Less recommended -
This is how my assertion.robot looks like -
*Settings
Library SeleniumLibrary
Resource Locator.robot
*Test Cases
Test attributes Locator
Open Browser file:///C:Desktop/testxpath.html chrome
${attribute_value}= Get Element attribute ${Datalist_locator_with_all_attribt} data-list
should not be equal ${attribute_value} ${EMPTY}
The locators are in locator.robot file. I'm not calling Get Element Attribute keyword in the locators because doing so there will be no link of directly executing it and referencing back the return value of it in testcase... So just keeping the locators in the locator file nothing else. This locators are accessible when I did Resource Locator.robot in my assertion.robot file. As you can see the Get Element Attribute element take first argument locator of element and second argument is nothing but the attribute name of which value you need. And this keyword returns value of attribute that supplied as second argument. -
*Variables
${Datalist_locator_with_all_attribt} xpath://div[#data-version='12345' and #data-list='1' and #data-point='10']
${locator_with_single_attribute} xpath://div[#data-version='12345']
Output
Way 2 - More Recommended -
Wrap the Get Element Attribute and Should Not Be Equal keywords in one single keyword. and dump it in another keyword file or create *keywords section in locator.robot file itself. Doing this your assertion.robot file will look like this -
*Test Cases
Test attributes Locator
Open Browser file:///C:/Desktop/testxpath.html chrome
Attribute values should not be empty
and locator.robot will look like this. You can make it more generic though -
*** Variables
${Datalist_locator_with_all_attribt} xpath://div[#data-version='12345' and #data-list='1' and #data-point='10']
${locator_with_single_attribute} xpath://div[#data-version='12345']
*** Keywords
Attribute values should not be empty
${attribute_value}= Get Element attribute ${Datalist_locator_with_all_attribt} data-list
should not be equal ${attribute_value} ${EMPTY}
Output

How to select one from duplicate tag in page in java in selenium webdriver

I am using Selenium WebDriver and I have number of items on a page and each item on page is a separate form type.
I have saved all of these form elements in a list and I am iterating over every item in an attempt to get the name of the element by using the "alt" attribute.
However when I try to get the "name" attribute from the input element it is always returning the first input tag found on that page, not the name attribute of the element I have currently selected.
The syntax I am using is:
((Webdriver imgtags.get(i)).findelement(By.xpath("//input[#name='qty']")).sendKeys ("100");
I have also tried to get the id from the tag by using:
((Webdriver imgtags.get(i)).getAttribute("id");
It's returning a blank value, but it should return the value of the id attribute in that input tag.
I also tried to get the id by using .bytagname but as id is an attribute it is not accessible
Try:
(driver) findElement(By.xpath("//*[contains(local-name(), 'input') and contains(#name, 'qty')]")).sendKeys("100");
To answer the comment by #rrd: to be honest, I have no idea why OP uses ((Webdriver imgtags.get(i)). I don't know what that is. Normally, I just use driver.findElement[...]
Hoping that he knows what works in his framework :D
Selenium Xpath handling is not fully compliant and it does not always treat // as a synonym of descendant-or-self.
Instead try tweaking your code to use the following Xpath:
((Webdriver imgtags.get(i)).findElement(By.xpath("./descendant-or-self::input[#name='qty']")).sendKeys("100");
This will base your search off the currently selected WebElement and then look for any descendants that have a name attribute with a value of "qty".
I would also suggest storing your imgtags array as an array of WebElement e.g.
List<WebElement> imgtags = new ArrayList<>();
This is a much better idea than casting to WebDriver to be able to use .findElement(). This will cause you problems at some point in the future.

How to make geb throw error when element not found instead of returning EmptyNavigator

in my page object I have simple method
def clickSomething(byName) {
$("a.name", text: contains(byName)).click()
}
and during execution it does not find required element and goes further.
it happens because, according to documentation, $() returns EmptyNavigator if element not found.
I want for test to fail with some kind of "ElementNotFoundException" or "NullPointerException" on trying to make click on null element.
I also do not want to add additional checks for returned element (because I would need to add that for every element identification).
Is there an elegant workaround for that ?
e.g. for elements declared within "content" there is performed such a check. But what is the best practice for elements found outside content block ?
The issue that you've encountered which is click() not throwing an error when called on en empty navigator has been fixed recently and will be released in the next version of Geb.
If you need to get an error when a selector results in an empty navigator then you can either:
wrap your selector in a content definition with the required template option set to true which is the default
call verifyNotEmpty() on your navigator

How to use variable, which value should be set in keyword or test, in XPATH?

I need to click on element based on what value it contains..but I want to set this value in test run or keyword definition (best option is in the test I guess)
How should I do it?
the variable containing xpath should look like that:
${DROPDOWN ITEMS} xpath=//*[contains(#class,'listitem-element')]/span[contains(text(),'${second_number}')]
This locator works when I replace the variable with actual number like '002', but I want to have it more general..
In keyword definition I use it like:
Choose Value From Dropdown
focus ${DROPDOWN ITEMS}
click element ${DROPDOWN ITEMS}
and in test I just call the keyword
my question is where and how to set the variable value of ${second_number} variable used in xpath?
PS:the xpath definition, keyword and test are each in separate files
thank you!
I use similar approach in my SUT, as it works with fairly complex objects, both precreated and dynamically generated during the tests executions - and their main user-identifiable attribute is the displayed name. Here's simplified version of my flow, and it's based around string substitution.
Starting off from the variables file - a simple collection of selenium locators, the value of the locator has a "special" string, which will later be substituted:
*** VARIABLES ***
${DROPDOWN ITEMS} xpath=//*[contains(#class,'listitem-element')]/span[contains(text(),'SELENIUM_PLACEHOLDER_CHANGE_ME')]
Then, in the keyword files there are private keywords for returning the proper locators, for example for this one:
*** KEYWORDS ***
_Return Selenium Locator For The Dropdown Item Named
[Documentation] Verifies the desired dropdown item is valid, ando returns its locator (not Webelements!!)
[Arguments] ${name}
# change the placeholder with the actual UI name
${loc}= Replace String ${DROPDOWN ITEMS} SELENIUM_PLACEHOLDER_CHANGE_ME ${name}
# why? Rationale explained below
Element Should Be Visible ${loc} message=The dropdown does not have an item called ${name}
[Return] ${loc}
Why the visibility check? Simple - to fail as early as possible if there's no such object currently in the SUT, and to have uniform error message, independent of how is the element further used (clicked on, checked for presence, attribute retrieval, etc.)
Then, a follow up user keyword for performing actions on the element uses the previous one:
# the user keywords
Choose Value From Dropdown
[Documentation] It does what it does :)
[Arguments] ${the value}
${loc}= _Return Selenium Locator For The Dropdown Item Named ${the value}
# as you can see, no checks is the element real - that'she offloaded to the helper keyword ^
Focus Element ${loc}
Click Element ${loc}
Finally, the test cases use the keyword to work with any data you deem neaded:
*** TESTCASE ***
The dropdown should do X
[Documentation] Steps: 1, 2, 3, etc
# do the normal steps you'do do
Choose Value From Dropdown my current value
This approach applies fairly well for negative tests also - for example, to check a value is not present, a test case would contain:
Run Keyword And Expect Error The dropdown does not have an item called no_such_element Choose Value From Dropdown no_such_element
Thus we're both using selenium checks for the absence of the element, and keeping the test case close to real-life expression - a description of what should happen, with no special syntax and SE keywords.
please excuse any typos and minor syntax omissions - it's not easy to type on a mobile that much, next time I'd think twice before taking it on :D
You can define variables when you fire off your test suite by using arguments.
Here is the documentation for it
Right now, you would leave your xpath as it is. Keeping the ${second_number} inside. Now you can either define it within the argument or within the argument file. They do the exact same thing, but one is neater. Just to get it working I would just worry about putting it directly in the console.
pybot -v second_number:002 nameOfTestFile.robot
This will tell pybot to create a variable called ${second_number} with the value of 002. It does not save this inside the test, so after the test is completed, it will forget the variable.
Once this works, you can then move this into a Argument file Or if you want you can even define it inside a Variable file where you can store all of your variables and then call them within the argument file / within the console.
Any questions do ask and ill try to help out
how about using the set suite variable keyword?
we can use Evaluate keyword for framing dynamically changing xpath
*** Variable ***
${common xpath} xpath=//label[contains(text(), '{0}')]
${text to be replaced} my name
*** Keyword ***
Frame xpath based on user input
${final xpath} Evaluate "${common xpath}".format("${text to be replaced}")
log ${final xpath}
RESULT
In ${final xpath}, you will have the "xpath=//label[contains(text(), 'my name')]"

Getting org.openqa.selenium.InvalidSelectorException only for Chrome

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!