public
Last active

  • Download Gist
2013-07-22.md
Markdown

PageObject + SimpleDelegator = Awesome Capybara Helpers

I've always liked using the Page Object pattern to write concise, namespaced, and composeable capybara helpers:

When /^I register as a new user$/ do
  NewUserPage.new(self).tap do |page|
    page.visit!
    page.form.fill
    page.form.submit!
  end
end

class PageObject
  attr_reader :page

  def initialize(page)
    @page = page
  end
end

class NewUserPage < PageObject
  def visit!
    page.visit new_user_path
  end

  def form
    @form ||= UserForm.new(self)
  end
end

class UserForm < PageObject
  attr_reader :parent

  def initialize(parent)
    @parent = parent
  end

  def fill
    page.find('[name$="[name]"]').set 'George'
    page.find('[password$="[password]"]').set 'password'
  end

  def page
    parent.page
  end

  def submit!
    page.find('input[type=submit]').click
  end
end

However, with this PORO implementation, constantly calling page in the PageObject classes can be annoying. It would be nice to call the Capybara helpers directly without having to mix in Capybara::DSL and all those rspec/capybara helpers into PageObject.

Turns out there is. And it's in the standard Ruby library.

SimpleDelegator "provides the means to delegate all supported method calls to the object passed into the constructor". So if I subclass the NewUserPage class from SimpleDelegator:

class NewUserPage < SimpleDelegator
end

And I instantiate it with the the test suite itself:

When /^I register as a new user$/ do
  new_page = NewUserPage.new(self)
  # ...
end

Then Capybara helpers like visit or find automatically become available to new_page! So now I can write the PageObject classes like this:

class NewUserPage < SimpleDelegator
  def visit!
    visit new_user_path
  end

  def form
    @form ||= UserForm.new(self)
  end
end

class UserForm < SimpleDelegator
  def fill
    find('[name$="[name]"]').set 'George'
    find('[password$="[password]"]').set 'password'
  end

  def submit!
    find('input[type=submit]').click
  end
end

There is a gem for Capybara which uses this pattern https://github.com/natritmeyer/site_prism, it has a lot of other cool feature.

@nestd Thanks for the link! It looks like a very nice gem :)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.