Last active
August 29, 2015 13:56
-
-
Save Juraci/8849035 to your computer and use it in GitHub Desktop.
Page Object Standards 1# - Avoid long procedures inside the page objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Here is an example of procedures that should be avoided inside the page objects | |
it "can create the server" do | |
server = DataSetup::Servers::Server.new(server_name) | |
server_details_view = server_list_view.create_server(server) | |
# ^ this create_server method above is hiding the flow of the test inside the page object | |
server_details_view.info_section.wait_to_load | |
server_details_view.root_admin_password_modal_exist.should be_true | |
server_details_view.server_name.should == server_name | |
server_details_view.info_section.image_name.should include(server.image) | |
server_details_view.info_section.flavor_name.should == '512MB Standard Instance' | |
server_details_view.info_section.disk_config.should == 'Automatic' | |
server_details_view.info_section.region.should include(server.region) | |
end | |
# look at the method implementation bellow | |
# it starts in the list_view, calls a method inside CreateView | |
module Servers | |
class SshKeyListView < Base::Pages::View | |
def create_server(server) | |
create_server_view = go_create_server | |
create_server_view.create_server(server) | |
PageObjects::Servers::DetailsView.new @selenium | |
end | |
end | |
end | |
# it ends up in a procedural set of actions inside the create view, full of conditionals | |
def fill_information_from_server(server) | |
region = server.region | |
type_server_name(server.name) | |
select_region(region) | |
if image_table.displayed? | |
select_image(server.image) | |
else | |
select_image_from_cascade_widget(server.image_description) | |
end | |
if size_table.displayed? | |
select_size(server.size) | |
else | |
select_flavor_from_flavor_panel(server.flavor_class, server.size) | |
end | |
if not server.first_gen? | |
modify_network("PublicNet", server.hasPublicNet?) | |
end | |
if disk_config_selector_shown? | |
select_disk_config(server.disk_config) | |
end | |
if ssh_key_section_shown? && !server.ssh_key.nil? | |
select_ssh_key(server.ssh_key) | |
end | |
end | |
# Why this should be avoided? | |
# Here are the arguments | |
# 1 - this method has basically 2 code smells | |
# Long method code smell: | |
## this method is breaking the single responsibility principle | |
## creating a server has lots of behavior that cannot fit in one method | |
## it's also doing several actions in a procedural way. Long methods are hard to maintain. | |
# Spaghetti code smell: | |
## Not all servers are created in the same way | |
## That is why there is so many conditionals inside this method like region based conditions. | |
# 2 - it is bad for the test readability | |
## because it hides part of the flow of the test inside this method | |
## which makes it hard to know what this test is really doing just by reading it | |
## What if I need to create several servers in my tests, this would be too much code repetition right? | |
## That is why UiSetup is for so you can abstract repetitive procedures there | |
## while keeping the page objects clean and simple. | |
# Just to recap | |
# Page object should be only an interface between the tests and the web elements | |
# The flow of actions must belong to the test body not to the page objects | |
# If a given procedure must be used several times you should abstract it on UiSetup | |
# The page objects should be like a box of building blocks; | |
# you can select just the pieces you need and assemble them in unanticipated ways (the tests) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment