I am having few overlay's and some elements , where I should check the the visibility of these element. Is that possible to achieve through page object?My intention here is I have a method in my page and it should return the visibility true or false.
Here is my page file
class HomePage
include PageObject
span(:text1, :text=>'text1') #this has 10+matches on my page
def getAvailabilityOf text
return send("#{text}.visible?")
end
end
This is how I am calling from my step definition.
Then(/^I should verify the visibility of "(.*?)" on images$/) do |text|
puts on(HomePage).getAvailabilityOf text
end
Below is the HTML.
<div class="box col2 review-box featured masonry-brick" style="height: 360px; background-image: url("https://stagingfiles.gamestakers.com/images/204/medium.jpg?1408991647"); background-repeat: no-repeat; position: absolute; top: 0px; left: 0px;">
<a href="/interviews/jeremy-spillmann">
<div class="gradient-fade">
<div class="featured-box">Featured</div>
<div class="title">
<span>text1</span>
<h2>Jeremy Spillmann</h2>
</div>
</div>
</a>
</div>
Below is the error I am getting .
Then I should verify the visibility of "text1" on images
undefined method `text1.visible?' for #<HomePage:0x35798b8> (NoMethodE rror)
./features/support/pages/HomePage_page.rb:67:in `getAvailabilityOf'
./features/step_definitions/homepage.rb:45:in `/^I should verify the visib ility of "(.*?)" on images$/'
features\RINavigation.feature:6:in `Then I should verify the visibility of "interview" on images'
I am expecting true or false to be printed on console.
In brief I am expecting page object way of implementing
#browser.span(:text => "text1").visible?
Suggest me some work around
Regards,
Avinash
The problem is that in the line:
return send("#{text}.visible?")
The page-object is looking for a single method called "text1.visible?", which does not exist. send is for making a single method call. It does not evaluate the string - ie it will not determine that you actually want to call a method and then with the returned value call a second method.
You could do the following:
def getAvailabilityOf text
return send("#{text}_element").visible?
end
Note that send("text1") would just return the text of the span element. send("#{text}_element") returns the page object element, which would have the visible? method.
Depending on how you are going to use the method, perhaps you actually want the following, which allows looking for the text without the need to also create the accessor.
def getAvailabilityOf text
return span_element(:text => text).visible?
end
I noticed something subtle in your question.
You indicated in a comment in your sample code:
span(:text1, :text=>'text1') #this has 10+matches on my page
You also added this requirement:
I should check the the visibility of these element(s)
Justin's answer is exactly what you need to do to validate a single, unique element, but when you have multiple elements that have the same attributes and text, then the locator you want to use is span_elements, like so:
def getAvailabilityOf text
return span_elements(:text => text)
end
Presumably you would do some sort of validation on this
Then /^I should verify the visibility of (.*?) on images$/ do |text|
spans = getAvailabilityOf text
spans.each do |s|
#Your validation code goes here
end
end
This validation is not very granular as you don't exactly know which span element you are validating, so make sure to take that into consideration.
Related
Lets say I have a simple page that has less IDs than I'd like for testing
<div class="__panel_body">
<div class="__panel_header">Real Estate Rating</div>
<div class="__panel_body">
<div class="__panel_header">Property Rating Info</div>
<a class="icon.edit"></a>
<a class="icon.edit"></a>
</div>
<div class="__panel_body">
<div class="__panel_header">General Risks</div>
<a class="icon.edit"></a>
<a class="icon.edit"></a>
</div>
<div class="__panel_body">
<div class="__panel_header">Amenities</div>
<a class="icon.edit"></a>
<a class="icon.edit"></a>
</div>
</div>
I'm using Jeff Morgan's Page Object gem and I want to make accessors for the edit links in any given section.
The challenge is that the panel headers differentiate what body I want to choose. Then I need to access the parent and get all links with class "icon.edit". Assume I can't change the HTML to solve this.
Here's a start
module RealEstateRatingPageFields
div(:general_risks_section, ....)
def general_risks_edit_links
general_risks_section_element.links(class: "icon.edit")
end
end
How do I get the general_risks_section accessor to work, though?
I want that to represent the parent div to the panel header with text 'General Risks'...
There are a number of ways to get the general risk section.
Using a Block
The accessors can take a block where you can more programatically describe how to locate the element. This allows you to locate a distinguishing element and then traverse the DOM to the element you actually want. In this case, you can locate the header with the matching text and navigate to its parent.
div(:general_risks_section) { div_element(class: '__panel_header', text: 'General Risks').parent }
Using XPath
While harder to read and write, you could also use an XPath locator. The concept and thought process is the same as using the block. The only benefit is that it reduces the number of element calls, which slightly improves performance.
div(:general_risks_section, xpath: './/div[#class="__panel_body"][./div[#class="__panel_header" and text() = "General Risks"]]')
The XPath is saying:
.//div # Find a div element that
[#class="__panel_body"] # Has the class "__panel_body" and
[./div[ # Contains a div element that
#class="__panel_header" and # Has the class "__panel_header" and
text() = "General Risks" # Has the text "General Risks"
]]
Using the Body Text
Given the HTML, you could also just locate the section directly based on its text.
div(:general_risks_section, class: '__panel_body', text: 'General Risks')
Note that this assumes that the HTML given was not simplified. If there are actually other text nodes, this probably would not be the best option.
How do I interact with a file_field thats hidden by its parent?
<span class="btn button-large fileinput-button">
Select files...
<input accept="image/png, image/gif, image/jpeg" id="gallery_files" multiple="multiple" name="gallery_files" type="file">
</span>
The button overlays the input, therefore it's not visible.
Edit
For the record, here's my code:
data[:photos].each do |photo|
$browser.file_field.set photo
end
and the error: Watir::Wait::TimeoutError: timed out after 20 seconds, waiting for {:tag_name=>"input", :type=>"file"} to become present
Workable example in a Gist
I was a bit suprised, but I was able to set the file field in the sample HTML without any issue using:
browser.file_field.set('path/to/file.txt')
From the code, it looks like setting the file field only requires the input to exist. It does not require it to be visible (or present).
Given that you are getting a Watir::Wait::TimeoutError exception, I would guess that your code is actually failing before the file_field.set. As it looks like the page has the input in a dialog, I am guessing your code actually looks more like:
$browser.file_field.wait_until_present
data[:photos].each do |photo|
$browser.file_field.set photo
end
It would be the wait_until_present method that is actually throwing the exception.
Solution 1
Assuming that an explicit wait method is being called for the file field, you should be able to just remove the wait.
If you have the wait because the dialog is being loaded by Ajax, you could try waiting for a different element instead - eg the parent span.
Solution 2
If for some reason you need the file field to be present, you will need to change its CSS. In this case, the opacity:
p $browser.file_field.present?
#=> false
$browser.execute_script('arguments[0].style.opacity = "1.0";', browser.file_field)
p $browser.file_field.present?
#=> true
For my situation, this worked:
$browser.execute_script("jQuery(function($) {
$('.fileinput-button').css('visibility', 'hidden')
$('#gallery_files').css('visibility', 'visible').css('opacity', '1').css('width', '100').css('height', '50')
})")
I had to hide the parent span, then show, resize, and change the opacity of the input
In cases when we have a dynamic content population in a span tag,
for e.g.,
.detail
%label Sku:
%span.#sku.detail= #deal.sku
When the deal in the above example doesn't have sku associated, the span element in the html will be as below
without any content in it.
<div class="detail">
<label>Sku:</label>
<span id="sku" class="detail"></span>
</div>
If the SitePrism element is defined to look for this for e.g.,
element :sku, "#sku"
and if "#sample_page" is reference to my Site Prism page, and I refer sku as
#sample_page.sku.text
we will get Capybara::ElementNotFound Exception
To avoid this we can check as below
#sample_page.has_sku?
and if the element is available then proceed with the actions as required.
This will omit Capybara::ElementNotFound Exception
When the span has no content it is not visible and thus not found. If you still want to find it, change your element to something like:
element :sku, "#sku", visible: false
How can i enter a text into a Editinplace element as shown below using PageObject:-
New Rule Name
as right now i have to click on the class="editInPlace" and sendkeys to it to enter some text into it
<div id="ruleContainer">
<div class="splitPanel basicInfo">
<div class="subPanel">
<div id="ruleName" class="editInPlace">New Rule Name</div>
</div>
Based on the example you provided you simply need to change the call to use the *_element generated method. Try this:
def name_rule
rule_name_element.send_keys "Test"
end
All element declarations will generate a method that has the pattern "name you provided"_element. This method will return the actual underlying html element that you can make calls on.
Is it possible to return a map of hidden links using watir? I have been trying to find some useful documentation, but have been most unsuccessful.
I need it to be generic enough to return any link thats hidden on page regardless of class, id, etc
style=display: none;
This currently returns me all visible links
full_list = #driver.links.map{|a| a.href}
i'd like to do something like (my syntax is probably way off):
hidden_list = #driver.hiddens.map{:style, a => 'display: none;'}
Please, please let me know if there is a way!
Thanks!
You could find all the links that are not visible? and collect their href attributes:
For example, given the following html:
asdf
<a style="display:none;" href="somewhere/invisible">asdf</a>
<a style="display:none;" href="somewhere/invisible2">asdf</a>
You can do:
hidden_list = #driver.links.find_all{ |a| !a.visible? }.collect(&:href)
#=> ["somewhere/invisible", "somewhere/invisible2"]