Next time someone ask what is Page Object Model

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/

15 Expert Tips for Using Cucumber

Hey guys, I found these excellent tips to who are working with Cucumber and Calabash. Try follow each one to get more performance and use the best practices always 🙂

1. Feature Files Should Actually be Features, Not Entire Portions of an App

One feature per well named file, please, and keep the features focused.

2. Avoid Inconsistencies with Domain Language

You’ll get the most benefit out of using Cucumber when your customers are involved. To that end, make sure you use their domain language when you write stories. The best course of action is to have them involved in writing the stories.

3. Organize Your Features and Scenarios with the Same Thought You Give to Organizing Your Code

One useful way to organize things is by how fast they run. Use 2-3 levels of granularity for this:

  • Fast: scenarios that run very fast, e.g. under 1/10 of a second
  • Slow: scenarios that are slower but not painfully so, maybe under one second each
  • Glacial: scenarios that take a really long time to run

You can do this separation several different ways (and even some combination):

  • Put them in separate features
  • Put them in separate subdirectories
  • Tag them

4. Use Tags

Tags are a great way to organize your features and scenarios in non functional ways. You could use @small, @medium and @large, or maybe @hare, @tortoise, and @sloth. Using tags let you keep a feature’s scenarios together structurally, but run them separately. It also makes it easy to move features/scenarios between groups, and to have a given feature’s scenarios split between groups.

The advantage of separating them this way is that you can selectively run scenarios at different times and/or frequencies, i.e. run faster scenarios more often, or run really big/slow scenarios overnight on a schedule.

Tagging has uses beyond separating scenarios into groups based on how fast they are:

  • When they should be run: on @checkin, @hourly, @daily
  • What external dependencies they have: @local, @database, @network
  • Level: @functional, @system, @smoke
  • Etc.

5. Use Rake Tasks to Run Features

This provides a consistent environment for running features: this way each run uses the same set of options and parameters. This goes a long way toward maintaining deterministic results.

Another benefit is that this makes for easy integration with continuous integration tools. There is a single point of entry into the spec run, with all options/parameters encapsulated.

6. Don’t Get Carried Away with Backgrounds (Stick to Givens)

The larger the background, the greater the load of understanding for each scenario. Scenarios that contain all the details are self-contained and as such, can be more understandable at a glance.

7. Make Scenarios Independent and Deterministic

There shouldn’t be any sort of coupling between scenarios. The main source of such coupling is state that persists between scenarios. This can be accidental, or worse, by design. For example one scenario could step through adding a record to a database, and subsequent scenarios depend on the existence of that record.

This may work, but will create a problem if the order in which scenarios run changes, or they are run in parallel. Scenarios need to be completely independent.

Each time a scenario runs, it should run the same, giving identical results. The purpose of a scenario is to describe how your system works. If you don’t have confidence that this is always the case, then it isn’t doing its job. If you have non-deterministic scenarios, find out why and fix them.

8. Write Scenarios for the Non-Happy-Path Cases As Well

Happy path tests are easy; edge cases and failure scenarios take more thought and work. Here’s where having some good (and yet pathological) testers on the team can reap rewards.

Use rcov with your full Cucumber runs to find holes in coverage.

9. Be DRY: Refactor and Reuse Step Definitions

Especially look for the opportunity to make reusable step definitions that are not feature specific. As a project proceeds, you should be accumulating a library of step definitions. Ideally, you will end up with step definitions that can be used across projects.

10. Use a Library (Such as Chronic) for Parsing Time in Your Step Definitions

This allows you to use time in scenarios in a natural way. This is especially useful for relative times.

Background:
  Given a user signs up for a 30 day account

Scenario: access before expiry
  When they login in 29 days
  Then they will be let in

Scenario: access after expiry
  When they login in 31 days
  Then they will be asked to renew

11. Revisit, Refactor, and Improve Your Scenarios and Steps

Look for opportunities to generalize your steps and reuse them. You want to accumulate a reusable library of steps so that writing additional features takes less and less effort over time.

12. Refactor Language and Steps to Reflect Better Understanding of Domain

This is an extension of the previous point; as your understanding of the domain and your customer’s language/terminology improves, update the language used in your scenarios.

13. Use Compound Steps to Build Up Your Language

Compound steps (calling steps from steps) can help make your features more concise while still keeping your steps general—just don’t get too carried away. For example:

Given /^the user (.*) exists$/ do |name|
  # ...
end

Given /^I log in as (.*)$/ do |name|
  # ...
end

Given /^(.*) is logged in$/ do |name|
  Given "the user #{name} exists"
  Given "I log in as #{name}"
end

14. Use Parallel Step Definitions to Support Different Implementations for Features

For example, running features against Webrat and Selenium. Put these step definitions somewhere where they won’t be auto-loaded, and require them from the command line or rake task.

15. Avoid Using Conjunctive Steps

Each step should do one thing. You should not generally have step patterns containing “and.” For example:

Given A and B

should be split into two steps:

Given A
And B

 

Bye 🙂

Font: https://blog.engineyard.com/2009/15-expert-tips-for-using-cucumber/