I have a simple link_to_function in my view template
<%= link_to_function "add new category", "$('#category_name').focus()" %>
and I want to test this with capybara using request specs. Basically the spec should look something like this
it "focuses category form when I click 'add new category'" do
visit new_article_path
click_link "add new category"
# unfortunately there's nothing like 'has_focus?'
find_field("category_name").should have_focus
end
the problem is, I wasn't able to find anything, that would check if the element has focus.
The only thing I did find was this
page.evaluate_script('document.focus')[:id]
which however isn't supported by the capybara-wekbit driver, which I'm using to avoid opening browser for each test run.
I just used the following code (with phantomjs driver, but I believe that it works with webkit also):
page.evaluate_script("document.activeElement.id") == "some_id"
P.S. One year question without an answer. Should they give me a badge? :)
You should use the :focus selector, e.g:
page.should have_selector('#category_name:focus')
With the Selenium driver you can get the focused element:
page.driver.browser.switch_to.active_element
Then you can do what you like with it
page.driver.browser.switch_to.active_element.send_keys "some text"
Note that it returns a Selenium::WebDriver::Element whereas find returns a Capybara::Node::Element so be careful when comparing them
expect(page.driver.browser.switch_to.active_element).to eql(find('#some-element').native)
Related
I am having issues with selenium using the next xpath "./preceding-sibling::text()"
I don't understand why, my first thought was that IE wasn't supporting that xpath statement but it didnt work on chrome neither.
What I am trying to do is to verify if a radio button have a certain text "near" it. For example if a radio button is like this
<div>
<label> Yes <input name='radioBtn'></input></label>
<label> No <input name='radioBtn'></input></label>
</div>
This is a simplified scenario where I need to check the "yes" radio button, so what I am doing is to search for the radiobutton and check if it preceding-sibling::text(), but selenium is cant find any element. I know the Xpath works because I test it on chrome developer tools and it returns the text "Yes".
I can't do something like 'input[1]' because I can't be sure that the first one will be always that have the Yes text.
Any idea why isn't this working on selenium? and if there is any work around?
I got to a work around but is kind of specific to the problem. But let's answer the questions 1 at the time.
Any idea why isn't this working on selenium?
It's not working because selenium don't support text elements, so even when selenium find the element it cant map it to a selenium object, i didn't see it because my code hided the selenium exception. The Exception throw is the next one:
An unhandled exception of type
'OpenQA.Selenium.InvalidSelectorException' occurred in WebDriver.dll
Additional information: invalid selector: The result of the xpath
expression "./preceding-sibling::text()" is: [object Text]. It should
be an element
Is there any work around?
Yes it is. What I did was to run a java script using the selenium IJavaScriptExecutor. With the script I revised the preceding sibling text and return it as a string so if the text was equal to the thing I was looking for (i.e Yes) trhat means that is the radio button I was looking for.
The code looks is similar to this (it can have some sintax errors since I didn't copied from the source):
string script = "function GetPrecedingText(node){"+
"var result = document.evaluate('./preceding-sibling::text()[1]', node, null, XPathResult.STRING_TYPE, null);"+
"return (result==null) ? '' : result.stringValue.trim();}"+
"return GetPrecedingText(arguments[0])";
string result = ((driver as IJavaScriptExecutor).ExecuteScript(script, SeleniumElement)).toString();
Hope someone can find this useful :) and thanks for all that tried to help me :)
I'm using capybara-webkit driver for my JS enabled tests. However when I try to fill in the form fields for the stripe checkout iframe, I'm not able to do it using the capybara fill_in helper in both the drivers. Selenium driver provides methods that facilitates in achieving this task though.
4.times {page.driver.browser.find_element(:id, 'card_number').send_keys('4242')}
page.driver.browser.find_element(:id, 'cc-exp').send_keys '5'
page.driver.browser.find_element(:id, 'cc-exp').send_keys '18'
page.driver.browser.find_element(:id, 'cc-csc').send_keys '123'
page.driver.browser.find_element(:id,'billing-zip').send_keys '600004'
If I use the fill_in helper, I'm not able to input the details fully. For example for a 16 digit card number, the input field gets filled only with 4 digits & in the date field I'm able to input only the month and not the year.
I want to know if there are helpers in the webkit driver that would enable me to fill in forms in the Stripe checkout form. Any heads up on this would be great! Thanks in advance.
I was having similar problems with Selenium that both
find(:css, "input[id$='card_number']").set("4242 4242 4242 4242")
fill_in('card_number', with: "4242 4242 4242 4242")
stopped working. I had find(:css, ...) earlier, which still worked a few months ago, but I guess changes in checkout.js made it so that it didn't work any more. With the help of Capybara cannot fill Stripe Checkout.js fields I managed to get it working. It's not a pretty (or really behavior-driven) solution, but it does the job:
stripe_iframe = all('iframe[name=stripe_checkout_app]').last
Capybara.within_frame stripe_iframe do
page.execute_script(%Q{ $('input#card_number').val('4242 4242 4242 4242'); })
page.execute_script(%Q{ $('input#cc-exp').val('12/16'); })
#rest of the Stripe-capybara
end
I am not sure if it works with Webkit though.
It looks like Stripe has changed the IDs on the checkout elements. Many have dynamic IDs that aren't matched by some of the other examples here.
What worked for me is matching elements by the placeholder text. Here's a working snippet as of 12/06/16:
stripe_card_number = '4242424242424242'
within_frame 'stripe_checkout_app' do
find_field('Card number').send_keys(stripe_card_number)
find_field('MM / YY').send_keys "01#{DateTime.now.year + 1}"
find_field('CVC').send_keys '123'
find('button[type="submit"]').click
end
page.has_content?('Success!', wait: 30)
For completeness, here's working code.
Capybara.within_frame stripe_iframe do
page.find_field('Email').set 'foo#bar.com'
page.find_field('Card number').set '4242 4242 4242 4242'
page.find_field('MM / YY').set '12/42'
page.find_field('CVC').set '123'
find('button[type="submit"]').click
end
You can always find the latest working version in
https://github.com/dblock/slack-gamebot/blob/master/spec/integration/update_cc_spec.rb
I had exactly the same issue, and found that the following solution works with capybara-webkit as well as with selenium-chrome:
page.find_field('Email').set "test#gmail.com"
page.find_field('Card number').set ('4242424242424242')
The "Email" and "Card number" here are the placeholders. The reason it works this way and doesn't with find('#email') is because there's no element with id='email' on the page. Capybara correctly can't find this element, it doesn't exist many times. The reason there's no element is because sometimes stripe's iframe is rendered without proper id, like so:
element-with-dynamic-id
find_field searches by id, name, or placeholder, and in this case, placeholder is the only attribute that doesn't change in both situations and that can be found by capybara (for ex. "type" doesn't change either, but I couldn't find the way to make capybara search by type and also the test would be much less readable then).
Why does Stripe's iframe sometimes miss these correct ids and replaces them with dynamic ids? No idea.
If you're using Stripe from an iframe (perhaps https://www.paymentiframe.com/?), you should be able to change the scope of your tests to the frame using Capybara's within_frame method:
within_frame('stripe-iframe') do
fill_in 'card_number', :with => '4242'
end
If you give your iframe a name (stripe-iframe in that example) then that should do it.
Hope that's of help!
I made it similar to #humpah, but without evil JS code.
form_iframe = all('iframe.wysihtml5-sandbox').last
within_frame form_iframe do
page.find('body').set('SomeContent')
end
Make sure you:
Wrap your query method in a Capybara.within_frame block
Use the placeholder value in Stripe's input fields to fill in the field.
Example that is currently working for me:
Capybara.within_frame first("iframe") do
fill_in "Card number", with: "4242424242424242"
fill_in "MM / YY", with: "12 / #{ (Time.now.year + 1).to_s[-2..-1] }"
fill_in "CVC", with: "123"
fill_in "ZIP", with: "12345"
end
I am testing a scenario for the site "https://www.freecrm.com/index.html"
login credentials [ john2013 / john2013 ]
Scenario :
1 open the site https://www.freecrm.com/index.html
2 login with valid credentials
3 click on the "New Contacts" link
4 Add new contacts
using Selenium ide i am able to login and click on the "New Contact" link , but when i am trying to do the same thing using Webdriver [ java] i am not able to click the "New Contact" link
the code i have written is given below
driver.findElement(By.name("username")).clear()
driver.findElement(By.name("username")).sendKeys("john2013");
driver.findElement(By.name("password")).clear();
driver.findElement(By.name("password")).sendKeys("john2013");
driver.findElement(By.cssSelector("input[type=\"image\"]")).click();
The code up to the above is working fine but clicking the "New Contact" link
driver.findElement(By.xpath("//div[#class='noprint']/span[#class='headertext']/a[3]/")).click();
is not working though the same xpath is working in IDE.
i have tried with expected condition option , sleep but nothing is working.
can any one help me in this regard.
The problem is that your page uses a frameset. You should tell your webdriver which frame to use when it will search for your element. So try this:
driver.findElement(By.name("username")).clear()
driver.findElement(By.name("username")).sendKeys("john2013");
driver.findElement(By.name("password")).clear();
driver.findElement(By.name("password")).sendKeys("john2013");
driver.findElement(By.cssSelector("input[type=\"image\"]")).click();
//switch the driver to use one of the frames on your page. Potentially wait for a bit till the page is loaded
driver.switchTo().frame("mainpanel");
driver.findElement(By.xpath("//*[text()='New Contact']")).click();
Please change the xpath of link to
xpath=//a[contains(text(),'<whatevertext>')]
Incase if the same text link is already present in some part o the page we can proceed with occurences. Example if it is repeating second time:
xpath=(//a[contains(text(),'<whatevertext>')])[2]
If Nothing is working the best way is through java script executor.
First get the webelement of the link.
Then use the following code"
webelement=driver.findElement(by.xpath("=//a[contains(text(),'')]
"))
(JavaScriptExecutor)driver.executescript("argument[0].click();",webelement)
Actually Speaking //div[#class='noprint']/span[#class='headertext']/a[3]/ is absolute XPath.
as it ends with a[3] the position will vary always so it is advisable to use relative XPath/CSS
Suggested CSS:css=.noprint > .headertext > a.classname
Another Suggested CSS: css=.noprint > .headertext > a[attribute='value']
So we can use either of the above format.
I am writitng request spec for my rails app with capybara. In my code I have something like:
%table
%tbody
%tr{"on_click" => "location.href='some_link'"}
%td="Some attribute"
%td="Some attribute"
%td="Some attribute"
%td="Some attribute"
This way I make the entire row clickable. I want to write a request spec with capybara for this feature but I don't know how. Can anyone help me on this ?
Thank you
May be you should first get to know the testing in rails. Check this out! http://railscasts.com/episodes/275-how-i-test it is really helpful. You can give your tr a class (say) .tr and do
page.find(:css, ".tr").click()
I hope this works, worked in my case!
I found this works without requiring a class:
page.find(:xpath, "//table/tbody/tr").click
I believe your row-click requires JavaScript, so you'll need to add :js => true to your test's header. Setting up testing with JavaScript is a challenge. I found these resources helpful:
ASCIIcast #257 Request Specs and Capybara - see info on database-cleaner
Capybara readme - see “Transactions and Database Setup"
Here is a more complete test example:
# Note that opening page by clicking on row requires JavaScript
describe "when user clicks on first row", :js => true do
let(:first_account_listed) { Account.order(:name).first }
before { page.find(:xpath, "//table/tbody/tr").click }
it { should have_selector('title', text: 'Account Details') }
end
In Capybara 3+ you can go with a more elegant way by using the :table_row selector and match against a td value like:
page.find(:table_row, ["Some attribute"]).click
If you have table headers defined you can also pass a Hash instead of an Array that will match the cell against its corresponding table header like this:
page.find(:table_row, { "Header" => "Cell value" }).click
To dive into how this actually works, here's a link to the latest Capybara selector definition: https://github.com/teamcapybara/capybara/blob/master/lib/capybara/selector/definition/table_row.rb
I'm working on a Rails 3 application with Cucumber 1.1.1 and I'm trying to select multiple checkboxes in my cucumber scenarios.
Here is my multiple checkboxes in haml:
- for diocese in Diocese.all
= check_box_tag "clergy[diocese_ids][]", diocese.id, #clergy.dioceses.include?(diocese)
= f.label diocese.name
%br
Here is my cucumber step
When /^I check the (\d+)(st|nd|rd|th) of the "([^"]*)" checkboxes$/ do |index, junk, group|
page.all("input[id=\"clergy_diocese_ids_\"]")[index.to_i - 1].check('clergy_diocese_ids_')
end
Here is my cucumber test:
#wip
Scenario: New Clergy
Given I am on the clergies page
When I follow "New Clergy"
And I fill in "Surname" with "Wells"
And I fill in "Given names" with "Robin"
And I check the 1st of the "diocese" checkboxes
And I check the 2nd of the "diocese" checkboxes
And I press "Create Clergy"
Then I should see "Clergy was successfully created."
The error I get when running my test:
And I check the 1st of the "diocese" checkboxes # fea
tures/step_definitions/clergy_steps.rb:37
cannot check field, no checkbox with id, name, or label 'clergy_diocese_ids_' found (C
apybara::ElementNotFound)
./features/step_definitions/clergy_steps.rb:38:in `/^I check the (\d+)(st|nd|rd|th) of
the "([^"]*)" checkboxes$/'
features/clergy_new.feature:17:in `And I check the 1st of the "diocese" checkboxes'
I've tried playing around with the page.all selector but I cannot work it out.
As I understand it, its not the job of Cucumber to select checkboxes and interact with the UI. Cucumber parses the feature files and executes the corresponding step definitions that match. What you put in each step definition block is up to you.
Since your step definition code appears to be using Capybara, I suggest viewing this solution.