How to find element within fieldset with no class or id - capybara

I have two field-set on my page. None of them have any id or class.
Now i want to fill specific field in second field-set.
Currently i a doing something like this which is not working:
within_fieldset('fieldset') do
fill_in 'app_answers_attributes_0_answer', with: 'My First Answer'
end
click_on 'Submit'
And it is giving error:
Capybara::ElementNotFound: Unable to find fieldset "fieldset"
Any idea on how to do that?

within_fieldset takes the id or legend text of the fieldset - http://www.rubydoc.info/gems/capybara/Capybara/Session#within_fieldset-instance_method - so it's not really surprising within_fieldset('fieldset') isn't working for you. How you can do what you want really depends on how you're HTML is structured. For instance if you're fieldsets have legends
<fieldset>
<legend>Something</legened>
...
</fieldset>
<fieldset>
<legend>Other thing</legened>
...
</fieldset>
You can do
within_fieldset('Other thing') do
...
end
If you don't have legends, but have wrapping elements
<div id="first_section">
...
<fieldset>...</fieldset>
<div>
<div id="second_section">
<fieldset>...</fieldset>
</div>
then you can just scope using CSS to the correct fieldset
within('#second_section fieldset') do
...
end
If instead the fieldsets are siblings
<div>
<fieldset>...</fieldset>
<fieldset>...</fieldset>
</div>
then you can just scope to the second fieldset with a CSS sibling selector
within("fieldset + fieldset") do
...
end

Related

Capybara - usage of applying has_xpath? on an apath with variable

There is the structure like:
<div class="parent">
<div>
<div class="fieldRow">...</div>
</div>
<div>
<div class="fieldRow">
<div class="CheckBox">
</div>
</div>
<div>
<div class="fieldRow">...</div>
</div>
<div>
<div class="fieldRow">...</div>
</div>
</div>
In my script I am writing a loop for each of the 4 div's under div[#class='parent'] and aiming to click the checkbox if there is, i.e.
members = page.all(:xpath, '//div[#class='parent'])
members.each do |a|
if **page.has_xpath?(a).find(:xpath, "div[#class='fieldRow']/div[#class='CheckBox']")**
a.find(:xpath, "div[#class='fieldRow']/div[#class='CheckBox']").click
end
end
However I can't look for the correct usage of has_xpath? with xpath including variable.
Please advice? Thank you!
has_xpath? takes an XPath expression (not an element) and returns a boolean (true/false) based on whether there are any elements that match that expression within the current scope - http://www.rubydoc.info/gems/capybara/Capybara/Node/Matchers#has_xpath%3F-instance_method. Since it returns true/false you can't then call find on it. For the example you posted there's no need for XPath or checking for the existence of the elements, just find all the matching elements and call click on them. Something like
page.all('div.parent div.fieldRow div.Checkbox').each { |cb| cb.click }
or
page.all('div.parent div.Checkbox').each { |cb| cb.click }
if the fieldRow class isn't something you really need to check.
Note: this assumes clicking the elements doesn't invalidate any of the other matched elements/change the page.
If you REALLY need to do it with the whole members and looping on them , using XPath, and checking for presence then it would be something like
members = page.all(:xpath, './/div[#class='parent'])
members.each do |a|
if a.has_xpath?(:xpath, ".//div[#class='fieldRow']/div[#class='CheckBox']")
a.find(:xpath, ".//div[#class='fieldRow']/div[#class='CheckBox']").click
end
end
Note: the .// at the beginning of the XPath expressions is needed for scoping to work correctly - see https://github.com/teamcapybara/capybara#beware-the-xpath--trap - which is an issue using CSS selectors doesn't have, so you should really prefer CSS selectors whenever possible.

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

Grails nested taglibs that use templates?

I want to create taglibs to simplify a webpage that represents a user dashboard. There are 2 taglibs I want to create. The first is a generic panel that will be used elsewhere, the second is a more specific version of the panel.
The GSP is called from a controller with the following model:
def index() {
def timelineItems = [
[details: "Some text"],
[details: "Some other text"]
]
render(view: "index", model: [timelineItems: timelineItems])
}
My desired GSP looks like this:
<dash:panel panelClass="col-lg-8" panelTitle="Service History">
<p>Some text in the body here</p>
<dash:timelinePanel timelineItems="$timelineItems" />
</dash:panel>
I want to put my HTML code in templates to make editing it simpler, so I call render from inside the tag lib and pass a data model. The taglibs look like this (within a namespace called dash):
def panel = {attrs, body ->
out << render(template: "/dashboard/dashboardPanel", model:[panelClass: attrs.getAt("panelClass"), panelTitle: attrs.getAt("panelTitle"), body: body()])
}
def timelinePanel = { attrs ->
out << render(template: "/dashboard/dashboardTimelinePanel", model: [timelineItems: attrs.getAt("timelineItems")])
}
This is my generic panel template: it should render the data in the top divs and then simply render the body passed to it in the model:
<div class="${panelClass}">
<div class="panel panel-default">
<div class="panel-heading">
${panelTitle}
</div>
<div class="panel-body">
${body}
</div>
</div>
</div>
This is my timeline template: it should render the details of each of the timeline variables passed in the model by the controller.
<g:each in="${timelineItems}">
<p>${it.details}</p>
</g:each>
I'm expecting to see a div which includes something like:
Some text in the body here
<p>Some text</p>
<p>Some other text</p>
However, I get the following error:
Error evaluating expression [it.details] : No such property: details for class: java.lang.String
My map appears to be being converted to a string and I can't access the map. What am I doing wrong please? I want to define multiple tags which can be used inside one another. How do I do this?

How do I make dynamic ids in Haml?

#item
creates a div with id="item"
.box#item
creates a div with class="box" and id="item"
.box#="item "+x
creates a div with class="box" and a comment '#="item"+x'
.box#
="item"+x
throws "Illegal element: classes and ids must have values."
How do I get set the id to a variable?
There are two ways:
The long form way (define the id as if it were a regular attribute):
.box{:id => "item_#{x}"}
produces this (x is what ever x.to_s evaluates to):
<div class="box" id="item_x">
The short form way:
.box[x]
produces the following assuming x is an instance of item:
<div class="box item" id="item_45">
See the HAML reference for more information.
You can set the id and class in HAML the following ways
The normal way
.box.item#item
<div id="item" class="box item"></div>
If you need to interpolation you can use this format
.box{id: "item_#{123}", class: "item_#{123}"}
<div id="item_123" class="box item_123"></div>
This format generates the class and id using the object reference
# app/controllers/items_controller.rb
#item = Item.find(123)
.box[#item]
<div id="item_123" class="box item"></div>
If you need to prefix something
.box[#item, :custom]
<div id="custom_item_123" class="box custom_item"></div>
If you need a custom class and id generation you need to add the following method to model.
class CrazyUser < ActiveRecord::Base
def haml_object_ref
"customized_item"
end
end
And then you will get the customized class
.box[#item]
<div id="customized_item_123" class="box customized_item"></div>
Refer:
http://haml.info/docs/yardoc/file.REFERENCE.html#object-reference-
http://haml.info/docs/yardoc/file.REFERENCE.html

Resources