Skip to content

Use Page Object On Any HTML Fragment Or Page (with WatirNokogiri)

pvmeerbe edited this page Jun 17, 2016 · 1 revision

Goal

Page Object works very well for testing your web application using different browsers. But would't it be nice to recycle all the effort done while creating and maintaining the different Page Objects into other non-browser based test (for example View testing or RSpec request tests)?

This is perfectly possible by adding an additional driver platform to Page Object, called WatirNokogiri.

This is in fact nothing new as Capybara provides a similar solution:

Setup

Install gems

Add the following gems to your project

Map the retrieved HTML into a PageObject

For example, in case of an RSpec request test the HTML will be in the body of the returned response

get "/comments/1"
expect(response).to render_template(:show)

@browser = WatirNokogiri::Document.new(response.body)
my_page = on_page(CommentShowPageObject)
expect(my_page.author).to eql 'Jos Smos'

This code can now be extracted to an 'on_page' routine similar to the one provided by PageFactory

def on_page(page_class, &block)
  raise "Response is #{response.content_type}. No page object available." unless response.content_type.to_s =~ /html/
  raise "Response body is empty!" if response.body.blank?

  @browser = WatirNokogiri::Document.new(response.body)
  @current_page = page_class.new(@browser)
  block.call @current_page if block
  @current_page
end

For RSpec with Rails only

Unfortunately rspec-rails currently is tightly coupled to capybara, the following patch will allow you to use PageObject with WatirNokogiri as a replacement

# Taken from rspec-rails 3.2.1 /lib/rspec/rails/example/feature_example_group.rb
# Ensure page-object/selenium-webdriver visit method is not overruled

module RSpec
  module Rails
    module FeatureExampleGroup

      remove_method :visit

    end
  end
end



# Taken from capybara 2.4.4  /capybara-2.4.4/lib/capybara/rspec/features.rb
# required by rspec-rails 3.2.1

if RSpec::Core::Version::STRING.to_f >= 3.0
  RSpec.shared_context "Capybara Features", :capybara_feature => true do
    instance_eval do
      alias background before
      alias given let
      alias given! let!
    end
  end

  RSpec.configure do |config|
    config.alias_example_group_to :feature, :capybara_feature => true, :type => :feature
    config.alias_example_to :scenario
    config.alias_example_to :xscenario, :skip => "Temporarily disabled with xscenario"
    # config.alias_example_to :fscenario, :focus => true
  end
else
  module Capybara
    module Features
      def self.included(base)
        base.instance_eval do
          alias :background :before
          alias :scenario :it
          alias :xscenario :xit
          alias :given :let
          alias :given! :let!
          alias :feature :describe
        end
      end
    end
  end


  def self.feature(*args, &block)
    options = if args.last.is_a?(Hash) then args.pop else {} end
    options[:capybara_feature] = true
    options[:type] = :feature
    options[:caller] ||= caller
    args.push(options)

    #call describe on RSpec in case user has expose_dsl_globally set to false
    RSpec.describe(*args, &block)
  end

  RSpec.configuration.include Capybara::Features, :capybara_feature => true
 end