Making dynamic code in Cucumber with the Page Object Model - selenium

Is there a way perform actions dynamically using Cucumber?
Example:
Feature File:
Scenario: Click all the boxes
Given On the checkbox page
When Click checkboxA
And Click checkboxB
Step Definition:
#When("Click checkboxA")
public void clickCheckBoxA()
{
pageObject.checkBoxA.click();
}
#And("Click checkboxB")
public void clickCheckBoxB()
{
pageObject.checkBoxB.click();
}
In this scenario, there are two very similar step definitions. The reason why there are two different definitions is because each WebElement is defined in the pageObject Class. Is there a way to dynamically pass which checkbox we want to click, rather than having two separate methods performing the same action?
The only way I can think to do this is by passing a selector as a parameter in the feature step and instantiating the webElement within the step definition method. But that seems like bad practice to me.

Click is your step. It should not be unique for each item you may want to click. You should match what you want to click with a regular expression. The following combines your two steps into one.
#When("^Click (.*)$")
public void clickElement(String elementToClick) {
switch (elementToClick) {
case "checkBoxA":
pageObject.checkBoxA.click();
case "checkBoxB":
pageObject.checkBoxB.click();
}
}
I'd suggest using a smarter regex match (this one is lazy and sloppy) and you could also create a new variable for the element to be clicked, assign its value to your existing element in each case and have a single call to click() after the switch statement.
Regarding your question of doing this "dynamically," you cannot do so in Java (I think you were thinking of having a single line in the example I gave above of pageObject.elementToClick.click();?) because it's a compiled programming language; your code can't be altered at runtime.

I would prefer to use #mike's solution, but in some cases I tend to create a locator as string in POM so that it reduces lines of code in the step definition.
Feature File:
Scenario: Click all the boxes
Given On the checkbox page
When Click checkbox A
And Click checkbox B
POM:
private String checkBox = "//input[text()='checkBox%s']";
Step Definition:
#When("Click checkbox (.*)")
public void handleCheckBox(String checkBoxName) {
driver.findElement(By.xpath(String.format(checkBox, checkBoxName))).click();
}

Related

Can we use click() functionality along with sendKeys()?

Can we use Click() functionality along with sendKeys()??
I just read a drop-down value using xpath and now i need to click on the particular value i have read. Actually its possible to use in two steps. But is there any option to read and click in a single code??
Thanks,
SK
Kindly try with this. I have used Enter key as a substitute for clicking.
driver.findElement(By.xpath("xpath")).sendKeys("Talk-Talk",K‌​eys.ENTER);
Hope this helps. Thanks.
If your requirement is to select some specific option in dropdown then use select class.
Go though this article for more info
But if you want to click on some element and then send some text, then you can user Action class.
WebElement wb = driver.findElement(By.xpath("your xpath"));
Actions action = new Actions(driver);
action.moveToElement(wb).click().moveToElement(wb,200, 0).sendkeys("text").build().perform();//you need to specify where you need to send text 200,0 is just as an example
Actions action = new Actions(driver);
WebElement MobileNumber = driver.findElement(By.xpath("yourxpath"));
action.moveToElement(MobileNumber).click().sendKeys("your text").build().perform();
Following the Java Docs, click() method returns void as follows:
void click()
Similarly, sendKeys() method also returns void as follows :
void sendKeys(java.lang.CharSequence... keysToSend)
So as per best programming practice we must not try to club-up click() method with sendKeys() method or vice versa. It would be ideal to achieve the intended task in two separate steps.

Selenium Web driver - loop over elements and click if matches

i'm in day 2 of my selenium class, need help in finding an efficient way of looping over elements and if matches click the link address.
I want to navigate from classFrame to navList and loop over to find the match and click.
public void switchFrames() {
driver.navigate().to("https://seleniumhq.github.io/selenium/docs/api/java/");
driver.switchTo().frame("classFrame");
/* List<WebElement> elements = driver.findElements(By.className("navList"));
for (WebElement element : elements) {
System.out.println(element.findElement(By.xpath(".//li/a")).getText());
}
*/
List<WebElement> items = driver.findElements(By.cssSelector("ul li"));
if ( items.size() > 0 ) {
for ( WebElement we: items ) {
we.findElement(By.linkText("Deprecated")).click();
}
}
driver.findElement(By.linkText("Deprecated")).click();
driver.close();
}
The main part you are missing and the reason you can't find the element you are looking for is because it's in a frame. In order to access elements in a frame with Selenium, you need to switch the driver context to the frame. You do that using driver.switchTo().frame(). Once you are done interacting with the frame, switch back to the default context using driver.switchTo().defaultContent().
Having said that... let me offer you some more advice since you are just starting out. There are several ways to do this. One way is like what you attempted... grab an element, find a child, loop through those children looking for the link you want. I prefer the more direct approach since we can search for the exact link using an XPath. What you want to do is to click the DEPRECATED link on the navbar. You could just use the By.linkText() locator and that will work but you want to be careful, especially with a page like this that has so many links, to not click on a link you didn't intend to. The way you do that is to narrow the search to the specific area you expect the link to be in, the navbar. Once you narrow the search there, you can quickly and safely find the link you are looking for. I prefer to do it in a single search using an XPath but you could use say a CSS selector to find the navbar area and then use By.linkText() to find the link, e.g.
driver.findElement(By.cssSelector("ul[title='Navigation']").findElement(By.linkText("Deprecated").click();
In that case, you will be scraping the page twice. It's not likely a big performance hit, I just prefer to use a single locator when it makes sense. I would suggest that since you are likely to use this code over and over that you put it in a function and pass it the link name, e.g.
public void clickNavbar(String linkName)
{
driver.switchTo().frame(driver.findElement(By.cssSelector("frame[name='classFrame']")));
driver.findElement(By.xpath("//ul[#title='Navigation']//a[.='" + linkName + "']")).click();
driver.switchTo().defaultContent();
}
Then you can call it like, clickNavbar("Deprecated");

Not able to locate a class in Selenium

I want to locate a drop down arrow using this line of code:
driver.findElement(By.className("icon-caret-down")).click();
There is nothing wrong with the code but the same class name is used for another drop down arrow which resides before it. My script points to that drop down arrow in spite me wanting it to point to this one.
I cannot use id or xpath as these are dynamically changed
Xpaths can be used if if the elements change dynamically but if you left with no other options, below snippet should help
List<WebElement> commonElem=driver.findElements(By.className("icon-caret-down"));
for(i=0;i<commonElem.size();i++){
if(i=1){ //instead you can also use commonElem.getText()=="TextVal";
commonElem.click();
break;
}
}

Selenium Webdriver - using isDisplayed() in If statement is not working

I am creating a script that involved searching for a record and then updating the record. On the search screen, the user has the option of viewing advanced search options. To toggle showing or hiding advanced search is controlled by one button.
<a title="Searches" href="javascript:expandFilters()"><img border="0" align="absmiddle" alt="Advanced" src="****MASKED URL****"></a>
The only difference between the properties of the search button when it is showing or hiding the advanced search is the img src:
When advanced search is hidden the IMG src ends with "/Styles/_Images/advanced_button.jpg", when advanced search is visible, the IMG src ends with "/Styles/_Images/basic_button.png"
When I open the page, sometimes the Advanced search options are showing, sometimes they aren't. The value that I want to search on appears in the Advanced section, so for my script to work I have added an IF statement.
<input type="text" value="" maxlength="30" size="30" name="guiSystemID">
The IF statement looks for the fields that I need to enter data into, and if the field does not exist then that would indicate that the Advanced options are not visible I need to click on the button to expand the search option.
I created the following IF statement.
if (!driver.findElement(By.name("guiSystemID")).isDisplayed()) {
driver.findElement(By.cssSelector("img[alt='Advanced']")).click();
}
When I run the script and the Advanced search is expanded then the script runs successfully. However, when I run the script and the Advanced search is not expanded, the script fails, advising me that it could not find the object "guiSystemID". This is frustrating because if it can't find it then I want the script to continue, entering into the True path of the IF statement.
Has anyone got any suggestions about how else I could assess if the field is appearing without having the script fail because it can't find the field.
Thanks in advance
Simon
I might be late in answering this, but it might help someone else looking for the same.
I recently faced a similar problem while working with isDisplayed(). My code was something like this
if(driver.findElement(By.xpath(noRecordId)).isDisplayed() )
{
/**Do this*/
}
else
{
/**Do this*/
}
This code works pretty well when the element that isDisplayed is trying to find is present. But when the element is absent, it continues looking for that and hence throws an exception "NosuchElementFound". So there was no way that I could test the else part.
I figured out a way to work with this(Surround the {if, else} with try and catch block, say something like this.
public void deleteSubVar() throws Exception
{
try
{
if(driver.findElement(By.xpath(noRecordId)).isDisplayed() )
{
/**when the element is found do this*/
}
}
catch(Exception e)
{
/**include the else part here*/
}
}
Hope this helps :)
I've had mixed results with .isDisplayed() in the past. Since there are various methods to hide an element on the DOM, I think it boils down to a flexibility issue with isDisplayed(). I tend to come up with my own solutions to this. I'll share a couple things I do, then make a recommendation for your scenario.
Unless I have something very specific, I tend to use a wrapper method that performs a number of checks for visibility. Here's the concept, I'll leave the actual implementation approach to you. For general examples here, just assume "locator" is your chosen method of location (CSS, XPath, Name, ID, etc).
The first, and easiest check to make is to see if the element is even present on the DOM. If it's not present, it certainly isn't visible.
boolean isPresent = driver.findElements(locator).size() > 0;
Then, if that returns true, I'll check the dimensions of the element:
Dimension d = driver.findElement(locator).getSize();
boolean isVisible = (d.getHeight() > 0 && d.getWidth() > 0);
Now, dimensions, at times, can return a false positive if the element does in fact have height and width greater than zero, but, for example, another element covers the target element, making it appear hidden on the page (at least, I've encountered this a few times in the past). So, as a final check (if the dimension check returns true), I look at the style attribute of the element (if one has been defined) and set the value of a boolean accordingly:
String elementStyle = driver.findElement(locator).getAttribute("style");
boolean isVisible = !(elementStyle.equals("display: none;") || elementStyle.equals("visibility: hidden;"));
These work for a majority of element visibility scenarios I encounter, but there are times where your front end dev does something different that needs to be handled on it's own.
An easy scenario is when there's a CSS class that defines element visibility. It could be named anything, so let's assume "hidden" to be what we need to look for. In this case, a simple check of the 'class' attribute should yield suitable results (if any of the above approaches fail to do so):
boolean isHidden = driver.findElement(locator).getAttribute("class").contains("hidden");
Now, for your particular situation, based on the information you've given above, I'd recommend setting a boolean value based on evaluation of the "src" attribute. This would be a similar approach to the CSS class check just above, but used in a slightly different context, since we know exactly what attribute changes between the two states. Note that this would only work in this fashion if there are two states of the element (Advanced and Basic, as you've noted). If there are more states, I'd look into setting an enum value or something of the like. So, assuming the element represents either Advanced or Basic:
boolean isAdvanced = driver.findElement(locator).getAttribute("src").contains("advanced_button.jpg");
From any of these approaches, once you have your boolean value, you can begin your if/then logic accordingly.
My apologies for being long winded with this, but hopefully it helps get you on the right path.
Use of Try Catch defies the very purpose of isdisplayed() used as If condition, one can write below code without using "if"
try{
driver.findElement(By.xpath(noRecordId)).isDisplayed();
//Put then statements here
}
Catch(Exception e)
{//put else statement here.}

zend framwwork 2 inArray element validator boring

How to disable the inArray validator of Zend\Element\Select ?
I can not remove this standard validator select element.
Edit:
What I'm trying to do is populate a select element so dynamic with ajax. So that way the inArray loses the reference field value.
Does anyone know what is the right way to populate this element with ajax?
It actually does not look like it is possible at this point in time to disable the validator; however, you can override the select element to be able to remove the validator for this specific case:
use Zend\Form\Element\Select;
class MySelect extends Select {
public function getValidator() {
return $this->validator;
}
}
Basically the key issue with the current select element is that if the validator does not exist; it will create it. The other option you have here is to set a validator manually; which you should likely be doing is manually creating an InArrayValidator and populating it with the potential options that would be coming from your AJAX call. In which case you would need to add a setter above.
Since version 2.2, Zend Framework provide the ability to disable inArray validator calling:
$element->setDisableInArrayValidator(false);
or passing option to an element:
'disable_inarray_validator' => false