Hi i am trying to select input field and add value into stripe's iframe, based on element name.
this won't work
page.find(:name, 'exp-date')
i was able to select root div with id selector, but i can't select input field which is child node somewhere in root div
find(:id, "root")
Any idea how to target those fields
Use the capybara find_field method to find field inputs. Checkout the docs here:
http://www.rubydoc.info/github/jnicklas/capybara/Capybara/Node/Finders#find_field-instance_method
Would look something like: find_field('attributes[form_field_attribute_you_need]')
Not sure if this works with an iframe, but you should be able to use:
within('#target_form_id') do #or another selector
fill_in 'field_name_or_id', with: 'value'
fill_in 'another_field', with: 'another_value'
end
You can use a CSS selector here:
find('input[name="exp-date"]', match: :first).set('my value')
Related
For some reason im running into problems with Select2 and Firefox w/Geckodriver.
Select2 fields I used to be able to just say page.select 'Text', from: 'Label' however that no longer works I just get a Element <option> could not be scrolled into view (Despite being scrolled into view). Right now im doing something similar to this:
select2Fields = page.all('.select2-selection')
select2Fields[0].click
page.find('.select2-search__field').set('Text To Set')
within('.select2-results') do
page.find('li', text: 'Text To Click').click
end
It's ugly and doesn't fit with my Page Object Model method, since I have to sorta know which select2 field it is. It doesn't seem to be when finding it with a label.
Any ideas? It's very frustrating since it worked with Chrome but the latest chromedriver has issues with the newest capybara versions.
Not sure what you were using that you were able to ever use select with a select2 widget, it never should have worked, and the fact it did would have been a bug. The reason is the actual <select> element (which is what Capybaras select method works with) is non-visible on the page, and select2 replaces it with a JS driven widget. You need to do exactly what a user would do, which is click to make the widget show up then click on the <li> element which represents the correct entry. This can all be moved into a helper method and potentially some custom selectors which boils down to something like this
Capybara.add_selector(:select2) do
xpath do |locator, **options|
xpath = XPath.descendant(:select)
xpath = locate_field(xpath, locator, options)
xpath = xpath.next_sibling(:span)[XPath.attr(:class).contains_word('select2')][XPath.attr(:class).contains_word('select2-container')]
xpath
end
end
Capybara.add_selector(:select2_option) do
xpath do |locator|
# Use anywhere to escape from the current scope since select2 appends
# the choices to the end of the document
xpath = XPath.anywhere(:ul)[XPath.attr(:class).contains_word('select2-results__options')][XPath.attr(:id)]
xpath = xpath.descendant(:li)[XPath.attr(:role) == 'treeitem']
xpath = xpath[XPath.string.n.is(locator.to_s)] unless locator.nil?
xpath
end
end
def select_from_select2(value, from: nil, **options)
select2 = if from
find(:select2, from, options.merge(visible: false))
else
select = find(:option, value, options).ancestor(:css, 'select', visible: false)
select.find(:xpath, XPath.next_sibling(:span)[XPath.attr(:class).contains_word('select2')][XPath.attr(:class).contains_word('select2-container')])
end
select2.click
find(:select2_option, value).click
end
That should let you call select_from_select2 just like you would call select and it will find the select2 widget associated with the given <select> element (hidden by select2) and choose the correct entry from it.
I had tested the Thomas´ answer but it doesn´t work for me. When Capybara click in the desired option, the select2 box close itself and set the 0 option. Finnaly, I made a walkaround as I check the option I want as selected and trigger the change.select2 event. I know that I dont really test the select2 box.
def self.select2 (page, datos)
page.execute_script("$('##{datos[:from]}').select2('open')")
if page.find(".select2-results li", text: datos[:texto]).click
page.execute_script("$('##{datos[:from]} option[value=\"#{datos[:valor]}\"]').prop('selected', true)")
page.execute_script("$('##{datos[:from]}').trigger('change.select2')")
end
page.find(:css, '#' + datos[:from]).value
end
As I keep my module Helper without include it in tests, I needed to include self in the name of the method and take 'page' from the capybara´test as parameter.
The variable 'datos' is a hash with the selector, the text of the option and its value.
As select2 box close when capybara click on it, I wrap the walkaround inside the if clause to be sure that some parts of the select2 box were working.
Finally, I returned the current value of the select to test it (really, it doesnt needed as I set the option with that value as 'selected')
I hope it would help anyone.
I have a number field, that takes a :product_quantity with a button after it saying "Add to Cart". My test works without adjusting the number_field but when I uncomment this line:
product_from_shop.fill_in 'quantity', with: 5
Stuff blows up. Capybara::ElementNotFound
It's about this line in my view:
<%= f.number_field :product_quantity, value: booking.product_quantity, min: 1, max: 999, title: 'quantity' %>
I tried several approaches, also searching for the class or id. Non work. There is no label, that would clutter my view.
title worked fine in other cases, without a form.
Also: I am using capybara webkit, because it uses JS.
fill_in uses the :fillable_field selector which will find any visible input or textarea area element except of type submit, image, radio, checkbox, or file. It will find those elements id, name or placeholder attributes or by the text in an associated label element. Since you don't have an associated label you're down to id, name or placeholder attribute. Assuming product_from_shop is a wrapper element on the page you're using to scope this fill_in then
product_from_shop.fill_in '<something>_product_quantity', with: 5
should find and fill_in the element by id - will depend on what model type the form is for (just look at the actual HTML to see what id was assigned).
If the product quantity field is the only fillable field inside product_from_shop you could also do
product_from_shop.fill_in with: 5 # same as product_from_shop.fill_in nil, with: 5
If none of those will work for you, you can move to using something like
product_from_shop.find(<more complicated query>).set '5'
To clarify your comment about title working previously - The title attribute is only matched when finding links and buttons.
Assuming you are using form_for in Rails for this, then it should be generating an id that you can use. I am not familiar with the product_from_shop.fill_in form, I typically use page, but try one of these:
page.fill_in :product_from_shop_product_quantity, with: 5
or
page.fill_in "product_from_shop_product_quantity", with: 5
I was just starting with SitePrism and I've got a site where elements get added dynamically to the page and don't have any kind of id, name, etc... the easiest I could think of is finding them by their 'text', eg. a CONTINUE button
I was trying:
element :continue_b, :button, 'Continue'
and SitePrism fails with the following:
Capybara::Ambiguous: Ambiguous match, found 4 elements matching button "Continue"
Is there a way for me to specify with SitePrism the element I want to click? I've found a few ways to do it with Capybara itself but I didn't manage to see the equivalent with SitePrism.
If there really is no difference between any of the button elements and you can't/don't want to move the element definition to a scoped section of the page, you can use the match argument to return just the first. Since all the parameters after the SitePrism element name are passed through to Capybara as find arguments it would be
element :continue_b, :button, 'Continue', match: :first
How do I select a link in a list to click on for an rspec acceptance test. The code for the view is (in html):
%ul.exports
%li.model
.name
Model 1
.control
link_to 'Export', export_model_path(:model1)
I've tried
(page.find("a")[:href] = "/admin/export/users").click
and the response is 'Capybara Ambiguous match'. I've also tried variations on
page.find(".exports li:nth-child(3) control a").click
and the response is 'unable to find css'. All the items in the list are identical except for the href value.
You've only got a single a tag in your Haml example, so I'm guessing your example is incomplete. If you want to retrieve a link by it's href value you could try this:
find(:xpath, "//a[#href='/admin/export/users']").click
I'm unable to test a Tokeninput field in a form using selenium. The situation is when we type something, it gives a list to options to select but those options aren't part of the DOM. The text fills the field but doesn't select the item.
The code which I have written is:
Given admin user is on schedule interview page
And he select "obie[1]" and "DHH[1]" from the candidate name(s) auto sugget field
**step defination**
Given /^he select "([^"]*)" and "([^"]*)" from the candidate name\(s\) auto sugget field$/ do |arg1, arg2|
within(:css, "#interview_template_candidate_names_input") do
fill_in('tmp',:with => arg1) --tmp is name of the token input field
find("li:contains('obie[1])'").click
save_and_open_page
end
end
I finally succeeded in making this work. Here's the gist: https://gist.github.com/1229684
The list is part of the dom (div.token-input-dropdown), it's added as the last child of the body element, which is probably why you didn't see it.
If you understand what the tokeninput plugin is doing, you can get a better idea of what you need to do. For each tokeninput you create, the plugin:
creates a ul.token-input-list (immediately before input#your_input_id)
creates a ul.token-input-list input#token-input-your_input_id
hides the input#your_input_id
creates a div.token-input-dropdown
So the most challenging part is finding the correct ul.token-input-list, because you have to find it based on its position relative to the original input, and the selenium webdriver doesn't let you navigate the dom.
After that, you just fill in the input#token-input-your_input_id and "click" on the div.token-input-dropdown li option that matches what you're looking for.