You see, sometimes in my code I need to put a global variable to set the current_page (during one step) and reuse it (in other step)
Then /^I open the "(.*?)" form$/ do |form_type|
form_page = "#{form_type}_page"
@current_page = @home_page.send(form_page.to_sym)
# here current page is not always the same page but they all have the open_form method
@current_page.open_the_form
end
Then /^I should ....$/ do
# here current_page reuse the data from the previous step
@current_page.do_something
# but sometimes, we dont know where is set the variable "current_page"
end
But I have some maintenance issue with my coworkers, because, sometimes, when we read code we dont understand what page is @current_page ?
What is the best practice in this case.
How do you use a "current_page" variable without maintenance issue or ambiguity ?
With my team, I've established a rule that our global page variable should always refer to the correct model at all times. Instead of setting the model directly, we use a few helpers.
We also established a convention that the page definition and steps go on the same file. Example some_page.rb
class SomePage < SitePrism::Page
set_url '/lol'
set_url_matcher /#{@target}\/lol/
element :button, 'button'
element :some_image, 'img'
end
Given /^I have reached SomePage$/ do
load_page SomePage
end
When /^I click a button on Some Page$/ do
@page.button.click
end
Then /^I should be on Some Page$/ do
ensure_page SomePage
end
Then /^Some Page should have an image$/ do
@page.should have_some_image
end
This might seem odd, and go against all kinds of best practices - but it's working great for my team. With the step definitions coupled together with their respective page, you always know exactly what @page refers to inside your definition, and it's a lot easier to look up and see what the elements were mapped as (or add more mappings.) You also get a quick picture of exactly what steps you have already written for any specific page, which leads to less duplicate step definitions.
On the rare case that one step definition is used for multiple pages, then we have a separate helpers file where they go.
We have a few helpers that we use for setting and using the global @page variable. Using these, another convention is to never @page = SomePage.new
or @page.should be_displayed
set_page is used for setting the global variable to an instance of the provided page. It also makes sure the expected page is displayed, and calls page#set_up. All of our pages inherit from a masterpage class, which has an empty set_up method. We can define set_up on the page to add any sort of initialization code for when specific pages load.
def set_page page_model
@page = page_model.new
# Ensure the expected page is actually displayed
ensure_page page_model
# Call the set_up method on the page
@page.set_up
end
ensure_page is used whenever we want to be sure we're on the correct page. It's used for both ensuring that the global variable refers to the correct page, and also that the page is currently displayed. This is used in place of the traditional PageModel.new.should be_displayed
def ensure_page page_model
unless @page.is_a? page_model
raise PageModelIncorrect.new "@page is a #{@page.class} when #{page_model} was expected.\nCurrent URL: #{current_url}"
end
@page.should be_displayed
end
load_page is used instead of the traditional PageModel.new.load args
. It automatically loads the page with the provided arguments, then sets the global variable with the method above, which then ensures the page is displayed.
def load_page(page_model, *args)
page = page_model.new
page.load(*args)
set_page page_model
end