Reputation: 223
In a cucumber/Watir-webdriver/page-object environment, I need to verify the presence and functionality of common header and footer links. While these should all be the same, and work, I'd like to include them on all of the relevant pages.
I'm trying to keep up on DRY coding, and want to minimize the amount of times I need to identify Header/Footer elements that are shared on a web application.
I thought I could do this by including somethings 'common_links.rb' in the support/ folder:
module CommonLinks
include PageObject
# Header links
link(:log_out_header_link, :text => "Log Out")
link(:logo, :id => "logo")
#Logged in nav links
div(:nav, :id => "globalnav_wrapper")
nav.link(:nav_activities, :href => "/activities/")
# Footer Links
link(:contact_us_footer, :text => "CONTACT US")
# Social Media Links
link(:social_twitter, :id => "soc_twitter")
link(:social_facebook, :id => "soc_fb")
link(:social_pinterest, :id => "soc_pin")
link(:social_google_plus, :id => "soc_gplus")
link(:social_youtube, :id => "soc_yt")
end
I'm trying to include the above in support/pages/activities_page.rb
. When I attempt to load a cucumber feature that calls this, I get the following error:
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/gems/page-object-0.8.6.1/lib/page-object/accessors.rb:1110:in `block (2 levels) in <module:Accessors>'
/Users/user_name/svn/watir/cukes/client/features/support/common_links.rb:12:in `<module:CommonLinks>'
/Users/user_name/svn/watir/cukes/client/features/support/common_links.rb:1:in `<top (required)>'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/gems/cucumber-1.2.1/lib/cucumber/rb_support/rb_language.rb:129:in `load'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/gems/cucumber-1.2.1/lib/cucumber/rb_support/rb_language.rb:129:in `load_code_file'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/gems/cucumber-1.2.1/lib/cucumber/runtime/support_code.rb:171:in `load_file'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/gems/cucumber-1.2.1/lib/cucumber/runtime/support_code.rb:83:in `block in load_files!'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/gems/cucumber-1.2.1/lib/cucumber/runtime/support_code.rb:82:in `each'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/gems/cucumber-1.2.1/lib/cucumber/runtime/support_code.rb:82:in `load_files!'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/gems/cucumber-1.2.1/lib/cucumber/runtime.rb:175:in `load_step_definitions'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/gems/cucumber-1.2.1/lib/cucumber/runtime.rb:40:in `run!'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/gems/cucumber-1.2.1/lib/cucumber/cli/main.rb:43:in `execute!'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/gems/cucumber-1.2.1/lib/cucumber/cli/main.rb:20:in `execute'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/gems/cucumber-1.2.1/bin/cucumber:14:in `<top (required)>'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/bin/cucumber:23:in `load'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/bin/cucumber:23:in `<main>'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/bin/ruby_noexec_wrapper:14:in `eval'
/Users/user_name/.rvm/gems/ruby-2.0.0-p0/bin/ruby_noexec_wrapper:14:in `<main>'
I have also attempted to create a 'CommonPage' class, and inherit from that, but I'm getting an unitialized constant error. The CommonPage class is identical to the module.
class CommonPage
include PageObject
#Header links
link(:log_out_header_link, :text => "Log Out")
link(:logo, :id => "logo")
#Logged in nav links
div(:nav, :id => "globalnav_wrapper")
nav.link(:nav_activities, :href => "/activities/")
# Footer Links
link(:contact_us_footer, :text => "CONTACT US")
# Social Media Links
link(:social_twitter, :id => "soc_twitter")
link(:social_facebook, :id => "soc_fb")
link(:social_pinterest, :id => "soc_pin")
link(:social_google_plus, :id => "soc_gplus")
link(:social_youtube, :id => "soc_yt")
end
Attempting to use either of these approaches has not resulted in success.
Has anyone had success declaring common links (like header/footer) in one file/module/class and then using them from another class?
Any direction will be appreciated.
Upvotes: 3
Views: 1267
Reputation: 6660
This is a standard feature of the Test-Factory gem. It's designed for supporting page objects and data objects with Watir-webdriver. It's a bit more streamlined since there is no support for selenium. I'm using it with the cucumber tests I'm creating for climate.com
Here's an example ripped from my code (shared with permission)
base_page.rb
class BasePage < PageFactory
class << self
def header_elements
element(:logo) { |b| b.link(:id => "logo") }
element(:session_links) { |b| b.ul(:id => "session-links")}
element(:logout_link) { |p| p.session_links.link(:text => "Log Out") }
element(:login_link) { |p| p.session_links.link(:text => "Login") }
value(:current_user) { |p| p.session_links.li.text }
action(:login) { |p| p.login_link.click }
action(:logout) { |p| p.logout_link.click }
end
def footer_elements
#todo add all the footer elements once we have tests that need them
#climate_dot_com_link
#about_twi_link
#about_tcc_link
#legal_tou_link
end
def grower_nav
element (:grower_appnav) {|b|b.div(:class => "appnav-container")}
element (:dashboard_link) { |p|p.grower_appnav.link(:text => /Dashboard/)}
action (:dashboard) { |p|p.dashboard_link.click}
element (:field_weather_link) { |p|p.grower_appnav.link(:text => /Field Weather/)}
action (:field_weather) { |p|p.field_weather_link.click}
element (:forecast_link) { |p|p.grower_appnav.link(:text => /Forecast/)}
action (:forecast) { |p|p.forecast_link.click}
element (:toolbox_link) { |p|p.grower_appnav.link(:text => /Toolbox/)}
action (:toolbox) { |p|p.toolbox_link.click}
element (:crop_impact_link) { |p|p.grower_appnav.link(:text => /Crop Impact/)}
action (:crop_impact) { |p|p.crop_impact_link.click}
element (:policies_link) { |p|p.grower_appnav.link(:text => /Policies/)}
action (:policies) { |p|p.policies_link.click}
element (:settings_link) { |p|p.grower_appnav.link(:text => /Settings/)}
action (:settings) { |p|p.settings_link.click}
element (:help_link) { |p|p.grower_appnav.link(:text => /Help/)}
action (:help) { |p|p.help_link.click}
end
def agent_nav
element (:tcc_appnav) { |b| b.div(:id => "tcc_appnav")}
element (:home_link) { |p|p.tcc_appnav.link(:text => /Home/)}
action (:home) { |p|p.home_link.click}
element (:clients_link) { |p| p.tcc_appnav.link(:text => /Clients/)}
action (:clients) { |p| p.clients_link.click}
element (:policies_link) { |p|p.tcc_appnav.link(:text => /Policies/)}
action (:policies) { |p|p.policies_link.click}
element (:quotes_link) { |p|p.tcc_appnav.link(:text => /Quotes/)}
action (:quotes) { |p|p.quotes_link.click}
element (:sales_tools_link) { |p|p.tcc_appnav.link(:text => /Sales Tools/)}
action (:sales_tools) { |p|p.sales_link.click}
element (:marketing_hub_link) { |p|p.tcc_appnav.link(:text => /Marketing Hub/)}
action (:marketing_hub) { |p|p.marketing_hub.click}
element (:agents_link) { |p|p.tcc_appnav.link(:text => /Agents/)}
action (:agents) { |p|p.agents_link.click}
element (:policy_docs_link) { |p|p.tcc_appnav.link(:text => /Policy Docs/)}
action (:policy_docs) { |p|p.policy_docs.click}
element (:users_link) { |p|p.tcc_appnav.link(:text => /Users/)}
action (:users) { |p|p.users_link.click}
element (:licenses_link) { |p|p.tcc_appnav.link(:text => /Licenses/)}
action (:licenses) { |p|p.licenses_link.click}
end
def notifications
element (:agent_notification_bar) { |b|b.div(:class => "agent-notification-bar")}
value (:agent_notification_header) { |p|p.agent_notification_bar.h4.text}
value (:agent_notification_message) { |p|p.agent_notification_bar.text}
action (:return_to_client_details) { |p|p.agent_notification_bar.link(:text => "Return to Client Details").click}
element (:modal_dialog) { |b|b.div(:class => "modal-inner-wrapper")}
value (:modal_header) { |p|p.modal_dialog.div(:class => "modal-header").text}
value (:modal_body) { |p|p.modal_dialog.div(:class => "modal-body").text}
end
end
end
register.rb a self registration page, has footer elements, but not header or nav
class Register < BasePage
page_url "#{$test_site}/preso/register.html"
footer_elements
element(:first_name) { |b|b.text_field(:id => "first_name")}
element(:last_name) { |b|b.text_field(:id => "last_name")}
element(:email) { |b|b.text_field(:id => "email")}
element(:phone) { |b|b.text_field(:id => "phone")}
element(:zip_code) { |b|b.text_field(:id => "zip_code")}
element(:password) { |b|b.text_field(:id => "self_reg_password")}
element(:confirm_password) { |b|b.text_field(:id => "self_reg_confirm_password")}
element(:has_agent) { |b|b.select(:id => "has_agent")}
element(:agents_name) { |b|b.text_field(:id => "source")}
element(:contact_me) { |b|b.checkbox(:id => "contact_me")}
element(:agree_to_terms) { |b|b.checkbox(:id => "terms")}
button ("Create Account")
element(:spinner) { |b|b.div(:class => "spinner")}
action(:wait_on_spinner) { |p|p.spinner.wait_while_present}
element(:agree_to_terms_required_message) {|b|b.div(:class => "terms-error")}
end
agent_clients.rb a page accessable to 'agent' class users
class AgentClients < BasePage
page_url "#{$test_site}/apps/admin/named_insureds?q[enabled_eq]=true"
header_elements
footer_elements
agent_nav
expected_element :session_links
element (:client_list_table) { |b|b.table(:id => "named_insureds")}
end
dashboard.rb a page accessable to 'grower' class users (different nav)
class Dashboard < BasePage
page_url "#{$test_site}/apps/preso/growerapps/dashboard.html"
header_elements
footer_elements
grower_nav
notifications
expected_element :session_links
element(:sort_by_precip) { |b| b.button(:text => "Precip 7d") }
element(:sort_by_soil_moiosture) { |b| b.button(:text => "Soil Moisture") }
element(:sort_by_growth_stage) { |b| b.button(:text => "Growth Stage") }
element(:fields_list) { |b|b.divs(:class => "field-group-card")}
end
Upvotes: 1
Reputation: 46836
It is possible to inherit from a parent class or include a module.
For example, I did the following test where the page object inherited from a parent class. It ran as expected.
test.feature
Feature: Search
Scenario: Set google search field
When google search field set
support\pages.rb
require 'watir-webdriver'
require 'page-object'
class CommonPage
include PageObject
text_field(:search, :name => 'q')
end
class PageA < CommonPage
end
steps\steps.rb
When /google search field set/ do
b = Watir::Browser.new
b.goto 'www.google.ca'
page = PageA.new(b)
page.search = 'test'
end
Similar worked when including CommonPage as a module in PageA.
Possible Issues
The exceptions do not match what I would expect, but it is possible it is due to the line:
nav.link(:nav_activities, :href => "/activities/")
As far as I know and have tried, this will not work. nav
will be undefined. I think you want to do (note that I think you also want a regex instead of a string):
link(:nav_activities){ search.link(:href => /activities/) }
Upvotes: 5