Reputation: 3229
Im writing a framework using Capybara and the Page Object Model for a web application. It's my first time writing my own framework and using PoM for automation.
My base "Page Object" essentially initializes the driver and is used in every other page object child class (for the individual pages)
class PageObject
include Capybara::DSL
BASE_URL = 'https://www.atesturl.com'
Capybara.default_max_wait_time = 5
def initialize
Capybara.register_driver :selenium_chrome do |app|
Capybara::Selenium::Driver.load_selenium
browser_options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts|
# Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
opts.args << '--disable-site-isolation-trials'
end
Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
end
Capybara.register_driver :selenium_chrome_headless do |app|
Capybara::Selenium::Driver.load_selenium
browser_options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts|
opts.args << '--headless'
opts.args << 'window-size=2880,1800'
opts.args << '--disable-gpu' if Gem.win_platform?
#opts.args << '--remote-debugging-port=9222'
# Workaround https://bugs.chromium.org/p/chromedriver/issues/detail?id=2650&q=load&sort=-id&colspec=ID%20Status%20Pri%20Owner%20Summary
opts.args << '--disable-site-isolation-trials'
end
Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
end
Capybara.current_driver = :selenium_chrome
end
def visit_url
visit BASE_URL
end
end
In most examples of PoM I see the methods returning an instance of that page object, but generally they use some @browser
instance variable that is passed around. Within my test scripts I simple call an instance of the Base page object class via let(:p) {PageObject.new}
and then p.visit_url
then make new instances of the other page objects via new
....but this seems like the wrong way to do it.
How exactly do I return a instance of the @browser
or driver that I can pass around? And how should I be calling it in my spec?
Upvotes: 0
Views: 857
Reputation: 49890
You don't want to be registering your drivers in the initialize for the base PageObject since that means every object created will be registering new driver configs - which isn't desirable.
When you include Capybara::DSL into your class you're including methods that end up calling methods on Capybara.current_session
. ie visit
=> Capybara.current_session.visit
. The result of Capybara.current_session
is the "@browser" instance you're asking about since it encapsulates the driver/browser instance. The issue with the way you've currently implemented that is that if any code changes the current session then all your objects will suddenly refer to the new session. If instead you store a reference to the session you want the object to use in each object and call the Capybara methods on that session rather than using Capybara::DSL (@session.visit ...
) then you can be sure the session an object is using doesn't change unexpectedly.
Also note that things like Capybara.default_max_wait_time
, `Capybara.current_driver', etc are global settings so setting them inside your PageObject class isn't a great idea.
Upvotes: 1