capybarasite-prism

With site_prism I dont know how the best practice if I want to use a variable called @current_page


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 ?


Solution

  • 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