A page object is an object that represents a single screen (page) in your application. For mobile, “screen object” would possibly be a better word, but Page Object is an established term that we’ll stick with.
A page object should abstract a single screen in your application. It should expose methods to query the state and data of the screen as well as methods to take actions on the screen.
Example: “login screen” – basically consisting of username and password and a Login button could expose a method login(user,pass)
method that would abstract the details of entering username, password, touching the “Login” button, as well as ‘transitioning’ to another page (after login).
A screen with a list of talks for a conference could expose a talks()
method to return the visible talks and perhaps a details(talk)
method to navigate to details for a particular talk.
The most benefit of this is abstraction and reuse. If you have several steps needing to navigate to details, the code for details(talk)
is reused. Also, callers of this method need not worry about the details (e.g. query and touch) or navigating to this screen.
Example Calabash:
login_steps.rb
Given(/^I am about to login$/) do
@current_page = page(LoginPage).await(timeout: 30)
@current_page.self_hosted_site
end
When(/^I enter invalid credentials$/) do
user = CREDENTIALS[:invalid_user]
@current_page = @current_page.login(user[:username],
user[:password],
CREDENTIALS[:site])
end
When(/^I enter valid credentials$/) do
user = CREDENTIALS[:valid_user]
@current_page = @current_page.login(user[:username],
user[:password],
CREDENTIALS[:site])
end
Then(/^I am successfully authenticated$/) do
unless @current_page.is_a?(SitePage)
raise "Expected SitePage, but found #{@current_page}"
end
end
When(/^I can see posts for the site$/) do
@current_page.to_posts
end
android/login_page.rb
require 'calabash-android/abase'
class LoginPage < Calabash::ABase
def trait
"android.widget.TextView text:'Sign in'"
end
def self_hosted_site
hide_soft_keyboard
tap_when_element_exists(add_self_hosted_site_button)
end
def login(user,pass,site)
enter_text(user_field, user)
enter_text(pass_field, pass)
enter_text(site_field, site)
hide_soft_keyboard
touch(sign_in)
wait_for_login_done
end
def sign_in
"android.widget.TextView text:'Sign in'"
end
def user_field
field('nux_username')
end
def pass_field
field('nux_password')
end
def site_field
field('nux_url')
end
def field(field_id)
"android.widget.TextView id:'#{field_id}'"
end
def add_self_hosted_site_button
"android.widget.TextView text:'Add self-hosted site'"
end
def wait_for_login_done
result = nil
wait_for(timeout: 120) do
if element_exists("android.widget.TextView {text BEGINSWITH 'The username or'}")
result = :invalid
elsif element_exists("* marked:'Posts'")
result = :valid
end
end
case result
when :invalid
self
else
page(SitePage)
end
end
end
ios/login_page.rb
require 'calabash-cucumber/ibase'
class LoginPage < Calabash::IBase
def trait
"button marked:'Sign In'"
end
def self_hosted_site
touch("* marked:'Add Self-Hosted Site'")
wait_for_none_animating
end
def login(user,pass,site)
enter_text(user_field, user)
enter_text(pass_field, pass)
enter_text(site_field, site)
touch(add_site)
wait_for_login_done
end
def enter_text(query_string, text)
touch(query_string)
wait_for_keyboard
keyboard_enter_text text
end
def sign_in
trait()
end
def add_site
"button marked:'Add Site'"
end
def user_field
"* marked:'Username / Email'"
end
def pass_field
"* marked:'Password'"
end
def site_field
"* marked:'Site Address (URL)'"
end
def wait_for_login_done
result = nil
site_page = page(SitePage)
wait_for(timeout: 60) do
if element_exists("label text:'Need Help?'")
result = :invalid
elsif element_exists(site_page.trait)
result = :valid
end
end
case result
when :invalid
self
else
site_page.await(timeout:10)
end
end
end
So, you can see that everything of login screen is inside the same class (login – android and other for ios) and you need use only one time. So you will avoid to repeat your code and it will be easier to maintain 🙂
Fonts: https://github.com/calabash/x-platform-example
http://developer.xamarin.com/guides/testcloud/calabash/xplat-best-practices/