How to simulate a selection from a SELECT control in sfTestBrowser - testing

In a functional test in symfony, sfTestBrowser provides methods
click() "Simulates a click on a link or button."
select() "Simulates selecting a checkbox or radiobutton."
and unselect().
But I have not found a way to simulate making a selection from a <select> element.
Does anybody know a way to do this?

This has troubled me too. I'm assuming you just want to set the value for form submission? If you know the value, you can of course just do
$browser->click('Save', array(
'theselectfield' => 'desired_value'
));
But usually I don't know the value I want posted, because it's from a database-driven select box. So my solution is
$theOption = $browser->getResponseDomCssSelector()->matchAll('select[name*=name_of_select_field] option:contains(TheOptionTextYouWant)')->getNode();
$browser->setField('theselectfield', $theOption->getAttribute('value'));
... or use $browser->click() instead ...
Frustrating because you have to break out of the $browser call chain, in order to use getResponseDomCssSelector(), but I haven't found an easier way.

Related

Copy-paste using Capybara?

I would love to do something like this:
div = find '#some-div'
copy_to_clipboard(div)
input = find '#my-input'
paste_from_clipboard(input)
I do not want to simulate this with send_keys and using Ctrl+C and Ctrl+V; I want this to work cross-browser (especially on mobile).
Does this API exist?
The most simple way I've found:
element.send_keys [:control, 'c']
element.send_keys [:control, 'v']
There is no Capybara copy/paste API - If all you want to do is copy the visible text into an input then you could do
div_text = find('#some-div').text()
find('#my-input').set(div_text)
If that's not correct for what you want, then you could use #execute_script to create a selection range like
var range = document.createRange();
range.setStart( <start node>, <start node character offset> );
range.setEnd( <end node>, <end node character offset> );
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
then find your target element and set it's value to window.getSelection().toString(). Note that's not really emulating what a user would do, so if you are actually using this for testing an app I would still recommend using the ctrl/cmd-c/v after setting the selection range for browsers that support it since it emulates user behavior better.
It's an old one, however you don't need to use capybara however the workaround would to use this incredibly simple gem:
https://github.com/janlelis/clipboard
There is no API to do it.
You can get element from one browser
div = page.find('#some-div')
Then you can pass it to another browser
fill_in '#some-other-div' with => div
You can read more about capybara here: https://github.com/jnicklas/capybara

Capybara, selecting 1st option from dropdown?

I've done a search and most of the related google results have returned just in general selecting an element from a dropdown. However the ID's in this case for the elements in the dropdown are dynamically generated unfortunately.
This is for a base test case, so I basically just need to select for example the first one. The text is also the same for the elements in the dropdown (not sure if that helps).
Is there such an example of this?
Im using cucumber with caybara(using selenium driver) integration
You can find the first option element and then use the select_option method to select it.
For example, if the select list has an id "select_id", you can do:
first('#select_id option').select_option
As #TomWalpole mentions, this will not wait for the element to appear. It would be safer to do one of the following:
first('#select_id option', minimum: 1).select_option
or
find('#select_id option:first-of-type').select_option
Alternatively you can get the first element text then select it by select function:
first_element = find("#id_of_dropdown > option:nth-child(1)").text
select(first_element, :from => "id_of_dropdown")
After two days of searching and reading, this article was amongst one of a few that was helpful. Hopefully, this can help someone else!
I created a few methods like so, excuse the naming..I changed it.
def some_dropdown(id, text)
dropdown = find(id).click
dropdown.first('option', text: text).select_option
end
def select_form
within 'content#id' do
some_dropdown('#id', text)
click_link_or_button 'Submit'
end
end
I also referenced this.
I've tried to select an option from a modal dropdown. After trying all listed methods, and many other from other threads - I totally gave up and instead of using clicks or select_option just used keyboard keys
find(:select, "funding").send_keys :enter, :down, :enter
In case it still complains - try:
find(:select, "funding", visible: false).send_keys :enter, :down, :enter
Worked like a charm, selecting first option from a dropdown.

Dynamic xpath handling

Below is my xpath
driver.findElement(By.xpath("html/body/div[9]/div/a/div")).click();
In above code value of div[6] is keep changing.
Sometimes it will
driver.findElement(By.xpath("html/body/div[6]/div/a/div")).click();
or
driver.findElement(By.xpath("html/body/div[1]/div/a/div")).click();
Please provide solution.
We faced this issue with dynamic page content making XPath identification basically useless. We took the decision to make sure everything that needed to be identified in a test would have an id set. So:
driver.findElement(By.xpath("html/body/div[6]/div/a/div")).click();
becomes:
driver.findElement(By.id("myDivId")).click();
Use div 'id' or 'class' instead of div[6].
like:
/html/body/div[#id='div_id']/div/a/div
(or)
/html/body/div[#class='div_className']/div/a/div

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.}

Edit individual radio buttons in zend form view script

I have a zend form which is using a view script. I want to get access to the individual radio button items but I'm not sure how to do so. Right now, I just print them all out using:
echo $this->element->getElement('myRadio');
That prints them all out vertically. I need a little more control. I need to be able to print the first 5 options in one column then the next 5 in a second column.
I have the same issue. There is no nice way to do this that I have found (circa ZF 1.10.8)
Matthew Weier O'Phinney had some advice on this page:
http://framework.zend.com/issues/browse/ZF-2977
But I find that approach cumbersome in practice. The original poster on that ticket had a good idea, and I think they should ultimately incorporate some nice way to do this along those lines.
But since there is no better way at the moment, I just follow Matthew's suggestion for now.
For my form I was working on, to render just one single radio button out of the group, I had to do this:
In my form class:
$radio = new Zend_Form_Element_Radio('MYRADIO');
$radio->addMultiOption('OPTION1', 'Option One')
->addMultiOption('OPTION2', 'Option Two');
$this->addElement($radio);
In my view script, just rendering OPTION1:
echo $this->formRadio(
$this->form->MYRADIO->getFullyQualifiedName(),
$this->form->MYRADIO->getValue(),
null,
array('OPTION1' => $this->form->MYRADIO->getMultiOption('OPTION1'))
);
That will render a <input type="radio" /> element, and an associated <label>. No other decorators will be rendered, which is a pain.
For your case, you will probably want to render your radio elements and other elements using the ViewScript view helper - so you can line all of the elements up amongst your own custom table markup as you described.
Figured this one out too. Just use
$this->element->getElment('myRadio')->getMultiOptions();
and it will return an array of the key/value options.