We had a discussion between several automation engineers on page object design, specifically about how many layers it should have and what are the responsibilities of the layers. I hope you guys could provide some insight about which way you prefer and why. Below you can find some examples we discussed in simplified Pseudo Python.
Which should I use in which circumstances, and why?
Case1:
Most popular case, based on examples found via Google/SQA exchange. Screen class has two responsibilities: element location & functional logic.
login_screen.xyz
class LoginScreen(BaseScreen):
username_input = find_element(By.ID, 'username')
password_input = find_element(By.ID, 'password')
submit_button = find_element(By.ID, 'submit')
def login(self, credentials):
username_input.send_keys(credentials.username)
password_input.send_keys(credentials.password)
submit_button.click
end
test_login.xyz
def test_login:
credentials = { 'username': 'asdf', 'password': 'asdf'}
login_screen = LoginScreen(self.driver)
login_screen.login(credentials)
end
Case2:
Screen class has only one responsibility: element location. Interactions with elements are performed directly from the tests.
login_screen.xyz
class LoginScreen(BaseScreen):
def login_input(self):
self.find_element(By.ID, 'username')
end
def password_input(self):
self.find_element(By.ID, 'password')
end
def submit_button(self):
self.find_element(By.ID, 'submit')
end
test_login.xyz
def test_login:
login_screen = LoginScreen(self.driver)
login_screen.login_input.send_keys('asdf')
login_screen.password_input.send_keys('asdf')
login_screen.submit_button.click
end
Case3:
3 layer structure where we have element definitions, interactions with elements and tests that work only with interactions.
login_screen.xyz
class LoginScreen(BaseScreen):
def login_input(self):
self.find_element(By.ID, 'username')
end
def password_input(self):
self.find_element(By.ID, 'password')
end
def submit_button(self):
self.find_element(By.ID, 'submit')
end
login_steps.xyz
class LoginSteps(LoginScreen):
def fill_username(self, username):
self.login_input.send_keys(text)
end
def fill_password(self, password)
self.password_input.send_keys(password)
end
def click_submit(self)
self.submit_button.click
end
test_login.xyz
class TestLoginScreen:
def test_login:
login_screen = LoginSteps(self.driver)
login_screen.fill_username('asdf')
login_screen.fill_password('asdf')
login_screen.click_submit
end