Search code examples
rubycucumberbddpageobjects

Support for the Page Object pattern in Ruby


In Ruby-land we have Capybara and Webrat to drive our web browsers during functional testing with Cucumber.

What I can't find is something like Geb in Groovy/Java-land which seems like it works on one level of abstraction higher than Capybara. This is the description of Geb from the Geb website.

Geb is a browser automation solution.

It brings together the power of WebDriver, the elegance of jQuery content selection, the robustness of Page Object modelling and the expressiveness of the Groovy language.

Capybara already brings together WebDriver (usually Selenium) and jQuery-style content selection. But it doesn't have any support for the Page Object idea. (You create classes to represent the pages under test, so the steps carry out actions upon them rather than look at the DOM directly all the time. Like a mini-API for your page.)

To give an example of the kind of useful feature I'm looking for, I understand from a colleague that Geb can automatically assert that the page under test matches the attributes in the virtual page object which represents the page to your Cucumber tests.


Solution

  • I've made use of Site Prism for page-objects in a fairly large application. Cheezy's page-object gem was the other gem that I considered at the time but it didn't make use of Capybara (which when used correctly can aid with timing issues). The page-object gem has it's own "wait" mechanism.

    There's also another gem but I suspect it's abandoned.

    The page-object gem will give you test code along these lines:

    class LoginPage
      include PageObject
    
      page_url "http://example.com/login"
      text_field(:username, :id => 'username')
      text_field(:password, :id => 'password')
      button(:login, :id => 'login')
    
      def login_with(username, password)
        self.username = username
        self.password = password
        login
      end
    end
    
    # in your tests
    visit_page LoginPage do |page|
    page.login_with('testuser1@example.com', 'incorrect')
    page.wait_until do # using default of 30s for this asynch call
      page.text.include? 'invalid user or password'
    end
    expect(page).to have_content 'invalid user or password'
    

    More examples can be seen in this project: https://github.com/JonKernPA/pageobject and on the wiki https://github.com/cheezy/page-object/wiki/Elements

    Site Prism looks like this:

    class LoginPage < SitePrism::Page
      set_url '/login'
    
      element :username_field, '#username'
      element :password_field, '#password'
      element :login_button, '#login'
    
      def login_with(username, password)
        username_field.set username
        password_field.set password
        login_button.click # this uses capybara to find('#login').click
      end
    end
    
    # in your tests
    @page = LoginPage.new
    @page.load
    @page.login_with('testuser1@example.com', 'incorrect')
    # capybara automatically waits for us
    expect(@page).to have_content 'invalid user or password'
    

    The Site Prism README has a lot of good examples. Everything else you need to know is in Capybara's excellent README and documentation.

    There are of course far more differences than these small example shows.
    I would advise you to take a look at both and decide what your requirements are.