Using Cheezy's page-object gem I've come across the ability to have dynamic element locators. (Noted at this github issue: https://github.com/cheezy/page-object/issues/203).
So for example I can do span_element(id: 'some id'), div_element(class: 'some_class'), etc. However what can I do if I need to locate a generic element? For example I could be working on a page that has angular so the elements are not traditional (like instead of a traditional html select control with options, it is a custom angular dropdown). I've tried element_element(class: 'class_name') and just element(class: 'class_name') but ruby says method missing
The generic dynamic element locator is defined in PageObject::ElementLocators#element as:
def element(tag, identifier={:index => 0})
platform.element_for(tag, identifier.clone)
end
The first argument is the element's tag name. If you don't know the tag name, you can specify "element" for any tag. For example:
class MyPage
include PageObject
def do_stuff
element('element', class: 'class_name').text
end
end
Related
I use page-object gem with RSpec and I want to create an element with a custom parameter like
link(:derect_link, text: "#{custom_text}"
Because I want to get the link to text and this text was changed every time when I starting the test.
How can I use it in spec scenario?
The accessor methods do not support custom parameters at run time. You will have to manually create the methods for the link. The equivalent of the methods created by the link accessor would be:
class MyPage
include PageObject
def derect_link_element(text)
link_element(text: text)
end
def derect_link(text)
derect_link_element(text).click
end
def derect_link?(text)
derect_link_element(text).exists?
end
end
This would be used like the standard methods, except that you would specify the text of the link:
# Click the link
page.derect_link('custom_text')
# Check if the link exists
page.derect_link?('custom_text')
# Get the link element to perform other actions (eg inspect attribute values)
link = page.derect_link_element('custom_text')
link.attribute('href')
A DEPRECATION WARNING appears when I run following code:
class MatchingPage
include PageObject
include Watir
div(:choose_competitor_dialog, :class => 'dijitDialogPaneContentArea pf-matching-competitors-dlg')
def competitor_name_select (name)
self.choose_competitor_dialog_element.label(:text => name).parent.checkbox(:class => 'dijitReset dijitCheckBoxInput').set
end
end
on(MatchingPage) do |matching_page|
matching_page.competitor_name_select 'shop.com'
end
The warning says:
* DEPRECATION WARNING
You are calling a method named label at /home/spoonest/workspace/csv_ui_checker/pages.rb:77:in
`competitor_name_select'.
This method does not exist in page-object so it is being passed to the driver.
This feature will be removed in the near future.
Please change your code to call the correct page-object method.
* If you are using functionality that does not exist in page-object please request it be added.
How can I locate the label element without getting this warning?
If a Page Object element does not know a method called, in this case label, the method is delegated to the underlying Watir (or Selenium) element. When this happens, you will get the warnings.
To locate a child label element, the method is called label in Watir. However, to avoid the warning in the page object gem, it should be label_element:
def competitor_name_select (name)
self.choose_competitor_dialog_element.label_element(:text => name).parent.checkbox(:class => 'dijitReset dijitCheckBoxInput').set
end
I have the following step definitions with Page Object Pattern gem 'site_prism':
class Main < SitePrism::Page
element :login_link, "a.log-in-link"
element :login_field, "input[name='userLogin']"
element :pass_field, "input[name='userPassword']"
element :enter_button, ".button_pretty"
end
If /I'm log in as "([^"]*)" with password "([^"]*)"$/ do |login, pass|
#main = Main.new
#main.login_link.click
#main.login_field.set login
#main.pass_field.set pass
#main.enter_button.click
end
It works fine but looks very heavy and unbeautiful. Is there any way to write it like capybara 'within' method? The following isn't work (Error: "can't convert Main into String (TypeError)")
within #main do
login_link.click
login_field.set login
pass_field.set pass
enter_button.click
end
You can hack support for a with statement into Ruby:
http://www.ruby-forum.com/topic/128781#574402
(I've seen this in VBScript, not sure if any other languages support it out of the box).
No, you can't use capybara's within functionality with site_prism.
On my rails3 application I want to use redcarpet to handle user's posts and the user comment section. As such I'd like to extend redcarpet to support turning #username into a link to a user on my site. I know redcarpet is written in C but is there anyway easy way to extend it in ruby? How hard would it be to write it in C? Should I just do this outside of redcarpet?
Also I'm intrested in some other extensions of redcarpet that would be shorthand for linking to other models in my app. I'm not sure the syntax yet but I'm guessing it would be similar to how github handles linking to issues.
I found it pretty easy to extend redcarpet's parser in Ruby for my rails 3 app. It wasn't scary at all.
First, start by deriving a class from Redcarpet's HTML renderer and override the preprocess method as recommended in the docs. In Rails 3.2 and Rails 4, this file can go anywhere and you don't need to require it. I use a 'services' folder to hold code like this.
# app/services/my_flavored_markdown.rb
class MyFlavoredMarkdown < Redcarpet::Render::HTML
def preprocess(text)
text
end
end
Next step is to add methods that do text substitutions you want. Here I use regex to wrap text that looks like "#mention" in an HTML span tag with a css class 'mention'.
# app/services/my_flavored_markdown.rb
class MyFlavoredMarkdown < Redcarpet::Render::HTML
def preprocess(text)
wrap_mentions(text)
end
def wrap_mentions(text)
text.gsub! /(^|\s)(#\w+)/ do
"#{$1}<span class='mention'>#{$2}</span>"
end
text
end
end
You could just as easily look up a user's profile page and wrap the #mention in an anchor tag instead. In my case, I also made methods for emoticons and hashtags that worked the same way and chained the methods together.
The last step is to add a helper that accepts some text, creates an instance of your Redcarpet-derived class, passes the text into that for processing, and returns the html result.
# app/helpers/application_helper.rb
def flavored_markdown_to_html(text)
renderer = MyFlavoredMarkdown.new()
# These options might be helpful but are not required
options = {
safe_links_only: true,
no_intra_emphasis: true,
autolink: true
}
Redcarpet::Markdown.new(renderer, options).render(text)
}
In your views you can call it like this:
<%= flavored_markdown_to_html("This is something worth #mentioning") %>
The output would then be:
This is something worth <span class='mention'>#mentioning</span>.
I once tried to extend redcarpet, but found it very difficult. If there are no other dependencies on redcarpet I'd recommend you try rpeg-markdown which is a (somewhat outdated) Ruby gem providing bindings to the excellent peg-markdown.
peg-markdown is a markdown interpreter written as a formal grammar. This means that it is very easy to extend it with own syntax. I've successfully extended peg-markdown for my own projects (see my fork here) and I found it to be much simpler than fiddling with redcarpet's custom parser code.
I also found peg-markdown to have fewer bugs.
The Ruby bindings may have to be made current by updating the git submodule. (I'm planning to submit a pull request to update rpeg-markdown to the latest version of peg-markdown.)
I'm a newbie to programmer so excuse my noviceness. So I'm using Nokogiri to scrape a police crime log. Here is the code below:
require 'rubygems'
require 'nokogiri'
require 'open-uri'
url = "http://www.sfsu.edu/~upd/crimelog/index.html"
doc = Nokogiri::HTML(open(url))
puts doc.at_css("title").text
doc.css(".brief").each do |brief|
puts brief.at_css("h3").text
end
I used the selector gadget bookmarklet to find the CSS selector for the log (.brief). When I pass "h3" through brief.at_css I get all of the h3 tags with the content inside.
However, if I add the .text method to remove the tags, I get NoMethod error.
Is there any reason why this is happening? What am I missing? Thanks!
To clarify if you look at the structure of the HTML source you will see that the very first occurrence of <div class="brief"> does not have a child h3 tag (it actually only has a child <p> tag).
The Nokogiri Docs say that
at_css(*rules)
Search this node for the first occurrence of CSS rules. Equivalent to css(rules).first See Node#css for more information.
If you call at_css(*rules) the docs states it is equivalent to css(rules).first. When there are items (your .brief class contains a h3) then an Nokogiri::XML::Element object is returned which responds to text, whereas if your .brief does not contain a h3 then a NilClass object is returned, which of course does not respond to text
So if we call css(rules) (not at_css as you have) we get a Nokogiri::XML::NodeSet object returned, which has the text() method defined as (notice the alias)
# Get the inner text of all contained Node objects
def inner_text
collect{|j| j.inner_text}.join('')
end
alias :text :inner_text
because the class is Enumerable it iterates over it's children calling their inner_text method and joins them all together.
Therefore you can either perform a nil? check or as #floatless correctly stated just use the css method
You just need to replace at_css with css and everything should be okay.