Unable to define siteprism element from a given label text - capybara

I'm using a cucumber/ruby/capybara/siteprism framework and I'm having problems identifying elements as either we're missing the ids, names, etc or they create them with a in real time.
I was mainly trying to define some of those elements in a siteprism page object model. For example, I was trying to enter some data in the 'input' field for 'First Name' below:
<div class="control-group">
<label class="control-label" for="input_field_dec_<random_number>">
First Name
<span class="required"></span>
</label>
<div class="controls">
<input id="input_field_dec_<random_number>" class=" span5" type="text" value="" scripttofire="SetUserFirstName('input_field_dec_<random_number>')" required="required" name="input_field_dec_<random_number>" data-val-required="First Name is required" data-val-regex-pattern="^[a-zA-Z0-9_ \-\']*$" data-val-regex="Only alphabetic and numeric characters allowed" data-val="true">
<span class="field-validation-valid help-inline" data-valmsg-for="input_field_dec_<random_number>" data-valmsg-replace="true"></span>
</div>
</div>
Is there a way to pass the label text (eg: 'First Name' - ignoring the spaces around, something like - contains='First Name') and then find the input element inside to set it up?
I was thinking something along the lines of:
element :first_name_field, :xpath, "//label[contains(text()='Continue'])/<and here something to find the input field?>" but cannot figure it out...

Capybara provides a bunch of built-in "selectors" that can be used for this, and you can add your own if you find it necessary. You can see the provided selectors by either building the Capybara docs yourself (rubydocs doesn't run the custom yard code used to generate that part of the docs) or by browsing the file where they are implemented - https://github.com/teamcapybara/capybara/blob/master/lib/capybara/selector.rb#L47
For your original example you can use the :field selector
element :first_name_field, :field, 'First Name'
which will match on the inputs associated label text. For you second example (from the comments) where the input and label have no connection (wrapped or for attribute) you should be able to do something like
element :some_field, :xpath, ".//label[contains(normalize-space(string(.)), 'label text')]/following-sibling::*[1]/self::input"
If you wanted to make that reusable you could add your own "selector" like
Capybara.add_selector(:sibling_input) do
label "Label adjacent sibling input"
xpath do |locator|
XPath.descendant(:label)[XPath.string.n.is(locator)].next_sibling(:input)
end
end
which could then be used as
element :some_field, :sibling_input, 'label text'

Related

Capybara doesn't want to select an input node

My HTML/ERB looks like this
<fieldset class="row notifications">
<legend>
<hr class="dash blue inline">
<%= t :my_notifications %>
</legend>
<label>
<%= f.check_box(:subscribed_to_news) %>
<span></span>
<span class="checkbox-text"><%= t :accepts_to_receive_news %></span>
<br>
</label>
</fieldset>
When I debug my Cucumber test with Capybara, I do find the notification checkbox f.check_box(:subscribed_to_news) in this mess
page.find('.notifications label')['innerHTML']
# => "\n\t\t<input name=\"user[subscribed_to_news]\" type=\"hidden\" value=\"0\"><input type=\"checkbox\" value=\"1\" checked=\"checked\" name=\"user[subscribed_to_news]\" id=\"user_subscribed_to_news\">\n\t\t<span></span>\n\t\t<span class=\"checkbox-text\">blahblahblah</span>\n\t\t<br>\n\t"
But for some reason I cannot find the nested inputs nor find them by ID
page.find('.notifications label input')
# => Capybara::ElementNotFound Exception: Unable to find css ".notifications label input"
page.find('.notifications label #user_subscribed_to_news') # => Capybara::ElementNotFound Exception: Unable to find css ".notifications label #user_subscribed_to_news"
Selecting the label does work though
page.find('.notifications label')
# => #<Capybara::Node::Element tag="label" path="//HTML[1]/BODY[1]/DIV[1]/MAIN[1]/SECTION[1]/FORM[1]/FIELDSET[3]/LABEL[1]">
What am I doing wrong ? I just want to check the damn checkbox :'(
Most likely reason is the checkbox is actually hidden by CSS and then replaced with images to enable identical styling of checkboxes across different browsers. If you're using the latest Capybara you can have it click it the label when the checkbox is hidden by calling
page.check('user_subscribed_to_news', allow_label_click: true) # you can also set Capybara.automatic_label_click = true to default to this behavior
or if using an older capybara you would need to click the label yourself
page.find(:label, "blahblahblah").click #match on labels text
or
page.find(:label, for: 'user_subscribed_to_news').click #match on labels for attribute if set
It would seem that the checkbox is unreachable via normal css /xpath...
I got away using some javascript
page.execute_script(%Q{document.querySelector('#{area} input##{selector}').click()})

Capybara: how to retrive the Test Services code value(F603YPW) of an element from below html page

I want to retrieve the value of Test Services code
<p>
<span class="floatLeft w30p">Test Services code:</span>
<span> <strong>F603YPW</strong> </span>
</p>
The rest of the page will really affect what selector(s) you would need to use to get that text, however given only the HTML specified you can use the css adjacent sibling selector to get the element
value = find(:css, 'span.floatLeft.w30p + span').text
if there are a bunch of other elements with the floatLeft and w30p classes then you could get more complicated using xpath selectors and do something along the lines of
value = find(:xpath, XPath.descendant(:span)[XPath.string.n.is('Test Services code:')].next_sibling).text
or with multiple finds
value = find(:css, 'span', text: 'Test Services code:').find(:xpath, XPath.next_sibling).text
If you are able to edit the HTML to
<p>
<span class="floatLeft w30p">Test Services:</span>
<span class="your_class"> <strong>F603YPW</strong> </span>
</p>
(so by adding a class to the span),
you will be able to find its value doing
value = page.find('.your_class').text
If you are not able to edit the HTML, do
value = find(:css, 'the css selector').text

Minitest assert can't see date value

I'd asked a question about this date field a few days ago but was able to test against the ID though the text label of the field was not being found even though the source clearly shows it.
Now I'm testing the actual value of the date. My test is simple:
assert page.has_content?("2015-02-26"), "Content - 2015-02-26 not available."
Here's the source of the page loaded in the browser:
<div class="form-group date required visit_date_of_visit">
<label class="date required control-label" for="visit_date_of_visit_1i">
<abbr title="required">*</abbr> Date of visit</label>
<input class="date required form-control" value="2015-02-26" type="date" name="visit[date_of_visit]" id="visit_date_of_visit" /></div>
As you see, the value is there.
Now, this is the source. In the actual browser this is 02/26/2015 as I have it formatted that way and the actual code works. Even though it shows this as the value, the code itself shows something else. But the test does not find this OR that.
Any ideas?
Why don't be more specific? and instead searching in all page content just search for fields:
page.has_field?('name_of_filed', :with => 'filed_value')
In your case
page.has_field?('visit[date_of_visit]', :type => 'date', :with => '2015-02-26')
For more options visit Capybara documentation

Rails - Add HTML attribute without setting a value

I'm trying to create an image_tag and specify a data- attribute that does not have any value set to it. I'm trying to add data-tooltip, for use with Foundation 5 tooltips. It seems that if any value is actually set to this, Foundation uses the same tooltip text every time and ignores the title attribute of that element (so every tooltip will say whatever the first one you hovered on was... which seems buggy in and of itself on Foundation's part also)
This is what I need to generate:
<img src="[whatever]" title="My Tooltip" data-tooltip />
This will not work for me:
<img src="[whatever]" title="My Tooltip" data-tooltip="[insert anything here]" />
I have tried a number of different combinations, and read documentation, but it seems no matter what I put as the value, it ends up generating it like data-tooltip="null", or true, or false, or any string I pass.
image_tag(my_image, class: 'has-tip', title: "My Title Here", data: { tooltip: true })
Try to pass in empty string as follows:
image_tag(my_image, class: 'has-tip', title: "My Title Here", data: { tooltip: "" })
In Rails 4.1.4 using above tip :"data-tooltip" => '' renders data-tooltip without value.
For an attribute with no value like multiple <input multiple type="file">, you can override the attribute default name, by uppercasing and setting an empty string. For example input_html: { Multiple: '' } But this is a hack.
In rails 5, I was trying to add itemscope attribute with no value in the following link tag scenario:
<%= link_to example_path(#example) do %>
<span>
<%= #example.name %>
</span>
<% end %>
I needed the resulting html a tag to show the itemscope attribute without any value like so:
<a itemscope href="example/path">
<span>
some text
</span>
</a>
Notice the itemscope has no ="" or itemscope="itemscope".
I tried solutions from SO and other places and the only thing that worked for me was adding the following to the link_to tag: " itemscope" => ''. Notice the space between the first double quote and the word itemscope.
This seems to generate the desired outcome and also validated as schema.org tag on google (that is what i used the tag for).

Grails RadioGroup, how to bind labels to radio name

I'm struggling arround with the g:radioGroup tag -- I want to create some radios and some labels correspondig to the radios:
<g:radioGroup name="stateOfHealth" value="${review.stateOfHealth}" id="stammp"
labels="['1','2','3','4','5']"
values="['bad','suboptimal','well','veryWell','excellent']">
<span class="radioSpan"> ${it.radio}</span>
<label for="${ ???? }">${it.label}</label>
</g:radioGroup>
What do I need to do to insert in the label's "for" attribute to match the right radio?
You don't need to set the for attribute, just wrap the radio with the label, like this:
<g:radioGroup name="stateOfHealth" value="${review.stateOfHealth}" id="stammp"
labels="['1','2','3','4','5']"
values="['bad','suboptimal','well','veryWell','excellent']">
<label>
<span class="radioSpan">${it.radio}</span>
${it.label}
</label>
</g:radioGroup>

Resources