Reputation: 3231
So i've been implementing PoM on a new project, it'll be my first time doing so. Im using Capybara with Rspec (Selenium) to write my framework.
One thing I keep running into is how "discrete" I should make the methods in my Page Object Classes. I see two trains of thought when it comes to this:
Lets take a page that makes a widget:
Option 1 (Generalized, more focused on what a user would do)
class WidgetPage
def click_widgets_tab
click_on('Widgets')
end
def create_widget_button
click_on('Add Widget')
end
def enter_widget_name(name)
fill_in 'Widget Name', with: name
end
def enter_widget_type(type)
fill_in 'Widget Type', with: type
end
def widget_success?
expect(page).to have_content('.alert', text: 'Widget Successfully created!')
end
end
(The "Fill in" methods could probably be even combined in the above case
or option 2:
class WidgetPage
def click_widgets_tab
widget_tab_link.click
end
def create_widget_button
widget_add_element.click
end
def enter_widget_name(name)
widget_form_name.fill_in(name)
end
def enter_widget_type(type)
widget_form_type.fill_in(type)
end
def widget_success?
widget_success_alert.has_text? 'Widget successfully created!'
end
private
def widget_add_element
find_button('Widget')
end
def widget_form_name
find_field('Widget Name')
end
def widget_form_type
find_field('Widget Type')
end
def widget_tab_link
find_link('Widgets')
end
def widget_success_alert
find(.alert, text: "Widget successfully created!")
end
end
I feel like I see most Page Object tutorials use option 2...but it seems like a lot of extra code for little return on investment. Having methods to return elements makes sense to me if they are being used in multiple methods...but not for every method.
Also as far as assertions go, option 1 makes more sense. But i've also heard that you shouldn't have assertions in a page object. So maybe it makes more sense to just have a method that returns whether an alert for example is visible or not? Still not sure the best way to handle that.
Upvotes: 1
Views: 166
Reputation: 564
I think this is a fair question, a lot of it does come down to preference, but there are some pretty real pitfalls you can get into if you choose the wrong "preference" for your situation, so I think it's worth talking about.
page.element.click()
calls in the step defs that all need to be updated because the app changes to require a hover before every click. If that action is wrapped in the page object as page.clickElement()
then you have a single place to make that update (or implement the workaround).click_on
/fill_in
methods restrict you to using their concept of a locator (name, id, or label). I always found this to be so restrictive, compared to arbitrary CSS, that I avoided using them.Something like
def get_widget_alert
find(.alert).get_text()
end
Called from the step def as
expect(widget_page.get_widget_alert).to eq('Widget Successfully created!')
Will fail with a helpful message if someone decides to change the punctuation or case of the message down the road.
Upvotes: 1