Sachi_1

Advertisements

‘Scroll’ in Mobile using Appium

Oh! this was definitely one of the difficult tasks to automate in Mobile (Android) and strangely I did find it sooner rather than later! But spent hours looking for it on the internet. Below is the code which one can use it to scroll in android apps. It takes an argument, specifically the text one wants to search for. And it works like a charm!

Courtesy: Appium discussion forum

def scroll_to(text)
   # This is a workaround for Appium issue 4311,
   # It can and should be replaced by the following when the issue is resolved
   # appium.driver.scroll_to text
   text = %Q("#{text}")
   args = Appium::Android::scroll_uiselector("new UiSelector().text(#{text})")
   find_element :uiautomator, args
end

How to use the above method?

if the above code is defined in a class then do –

<@class_instance>.scroll_to(<text you want to search for>).click

Mobile Testing using Appium

In this article, we will study on how to do Mobile Automation using tools like Appium, we will use Ruby and RSpec BDD framework to write the test scripts. But before diving into the details of it let’s learn why do we need to do Mobile Testing?

As we all are confused sometimes to choose our favorite mobile device and we expect that the one we choose should be flawless in every aspect. Well, to make this happen TESTING is necessary but with so many devices available today, is it humanly possible to test the applications on each and every device? The answer is a big no, and this is where the mobile automation comes into picture which gives the tester an ability to run tests on any device without spending a penny! the answer to this is mobile emulators/simulators available. These are the software that mimics the real device and helps in running the automated tests on them.

In this blog, I will help you in setting up the required environment for mobile testing and also provide you with a simple script of testing an application on Android OS.

Appium – The reason for choosing this software for mobile automation over others is:

  • It is open source (free!)
  • It is compatible with both iOS and Android (Need to install only one software!)
  • Support for vast client libraries like Python, Ruby, Java, C# etc.
  • No need to install any agents to talk with Android apps.

Download the software from Appium downloads page (OS X and Windows) and install it. Make sure you installed Ruby, Android SDK, Java JDK. Launch the Appium server (Note: Appium is an HTTPServer written in Node.js if you get error while launching then install Node.js and try again)

appium_launch_1

After launching the Appium, you will get a UI and click on ‘Play’ button to start the Appium server.

appium_launch_2

Let’s try to launch Android SDK Manager from command line. Go to command prompt and enter ‘android’ and press enter. Android SDK Manager GUI should be launched without error.

android_sdk_launch.gif

If you get an error then make sure you have set the PATH variable for Android executables as below.

Go to Windows Run and type in ‘PATH’, select ‘Edit the System environment variables’.  You will be taken to the below window.

android_sdk_PATH.gif

Install the ‘appium_lib’ and ‘selenium-webdriver’ gems by following the command:

gem install appium_lib
gem install selenium-webdriver

Woah! that’s a lot of effort to set up the things! One more thing, since we will be using a real Android device to test, let’s connect the Android device and from the command prompt give the command, adb devices’, to see the connected devices to the system and also if any emulator is launched. And important thing: Make sure to enable the developer option on your Android device by following the steps:

Enable USB debugging in your phone to be able to run your test scripts. For this, you need to enable “Developer options” by navigating to Settings/About Phone and tapping build number seven times. You will get a notification saying that you’re now a developer. Ignore it. Then navigate to “Developer options” and enable the USB debugging option.

android_sdk_adb_devices.gif

Awesome! We have set up our environment. But how do we launch the application? Well, applications are launched by giving the Package Name and the Activity, to know this without any fuss, install ‘Application Reader’ app by visiting the Play store.

The app we will be testing is , ‘ATP/WTA Live’. From our recently installed app we can find the package name and the activity details of the app under test.

Application_Reader

To inspect the elements of an Android app, we will use ‘UI Automator Viewer’ tool from Android SDK, it is located in ‘tools’ directory of the Android SDK.

UI_Automator.png

Let’s start scripting in RSpec directly. We need to say beforehand that which package we will be launching, follow the below code:

server_url = 'http://localhost:4723/wd/hub'

capabilities =
    {
        platformName: 'Android',
        deviceName: 'XT1063',
        appPackage: 'atpwta.live', # Package Name of the app
        appActivity: '.activity.Main',
        appWaitActivity: '.activity.root.TournamentList'
    }
@driver = Selenium::WebDriver.for(:remote, :desired_capabilities=>capabilities, :url=>server_url)

The above will launch the app in the real device once it is executed. Appium is a wrapper around the Selenium-webdriver and hence it is easy to follow up and write the scripts if one is familiar with it.

Now, what would one test after launching an app? Title! let’s start by verifying it.

it 'Check for homepage title', main_title: true do
  # Go to the navigation bar in the UI Automator Viewer and see the ID.
  expect(@driver.find_element(:id, 'atpwta.live:id/NavBarTitleTextView').text).to eq 'ATP/WTA Live'
end

Awesome, this is our first script in Mobile testing that verify’s the title of an app.

Let’s dive deeper and try to verify the Rankings in ATP Singles category, below is the step by step process to navigate through the contents and verifying them. After doing it manually in our app, let’s try to automate it.

android_app_operations.gif

Below is the RSpec code to test the application and asserting if elements are present.

Android_spec.rb

require 'rspec'
require 'watir-webdriver'
require 'selenium-webdriver'
require 'appium_lib'

describe 'WTA Rankings' do
  before(:each) do
    server_url = 'http://localhost:4723/wd/hub'

    capabilities =
        {
            platformName: 'Android',
            deviceName: 'XT1063',
            appPackage: 'atpwta.live',
            appActivity: '.activity.Main',
            appWaitActivity: '.activity.root.TournamentList'
        }
    @driver = Selenium::WebDriver.for(:remote, :desired_capabilities=>capabilities, :url=>server_url)
  end

  after(:each) do
    @driver.quit
  end

  it 'Check for homepage title', main_title: true do
    expect(@driver.find_element(:id, 'atpwta.live:id/NavBarTitleTextView').text).to eq 'ATP/WTA Live'
  end

  it 'Should check for Title', title: true do
    @driver.find_element(:xpath, "//android.widget.Spinner[@resource-id='atpwta.live:id/NavBarMainMenuSpinner']").click
    @driver.find_element(:name, 'Rankings').click
    @driver.find_element(:name, 'ATP Singles').click
    expect(@driver.find_element(:id, 'atpwta.live:id/NavBarTitleTextView').text).to eq 'Rankings'
  end

  it 'Should check for Rank 1 and corresponding Name', rank: true do
    @driver.find_element(:xpath, "//android.widget.Spinner[@resource-id='atpwta.live:id/NavBarMainMenuSpinner']").click
    @driver.find_element(:name, 'Rankings').click
    @driver.find_element(:name, 'ATP Singles').click
    expect(@driver.find_element(:id, 'atpwta.live:id/RankTV').text).to eq '1'
    expect(@driver.find_element(:id, 'atpwta.live:id/Player1TV').text).to eq 'Novak Djokovic'
  end

  it 'Should check for details for the Rank 1', rank_page: true do
    @driver.find_element(:xpath, "//android.widget.Spinner[@resource-id='atpwta.live:id/NavBarMainMenuSpinner']").click
    @driver.find_element(:name, 'Rankings').click
    @driver.find_element(:name, 'ATP Singles').click
    @driver.find_element(:id, 'atpwta.live:id/RankingItemViewRoot').click
    expect(@driver.find_element(:id, 'atpwta.live:id/NavBarTitleTextView').text).to eq 'Players'
  end

  it 'Should check the table contents and display them', rank_details: true do
    @driver.find_element(:xpath, "//android.widget.Spinner[@resource-id='atpwta.live:id/NavBarMainMenuSpinner']").click
    @driver.find_element(:name, 'Rankings').click
    @driver.find_element(:name, 'ATP Singles').click
    @driver.find_element(:id, 'atpwta.live:id/RankingItemViewRoot').click
    table = @driver.find_element(:class, 'android.widget.TableLayout')
    rows = table.find_elements(:class, 'android.widget.TableRow')
    table_contents = []
    rows.each do |row|
      cols = row.find_elements(:class, 'android.widget.TextView')
      cols.each do |col|
        table_contents.push(col.text)
      end
    end
    expect(table_contents.include? 'Belgrade, Serbia').to eq true
  end

  it 'Should take to previous menu/page', back: true do
    @driver.find_element(:xpath, "//android.widget.Spinner[@resource-id='atpwta.live:id/NavBarMainMenuSpinner']").click
    @driver.find_element(:name, 'Rankings').click
    @driver.find_element(:name, 'ATP Singles').click
    @driver.find_element(:id, 'atpwta.live:id/RankingItemViewRoot').click
    @driver.find_element(:name, 'Back').click
    expect(@driver.find_element(:id, 'atpwta.live:id/NavBarTitleTextView').text).to eq 'Rankings'
  end

end

Results:

android_result.png

Running Specific Test Cases:

android_specific_tc

Hope you enjoyed it!

RSpec, Capybara for Web Automation – Part II

Continuing the automation of the-internet, below is the updated Ruby Code and RSpec. Refer to this to learn more.

File: the_heroku_app.rb
class The_Heroku_App

  def start_browser
    @session = Capybara::Session.new (:selenium)
  end

  def tear_down
    @session.execute_script('window.close();')
  end

  def go_to(site)
    @session.visit site
  end

  def click_on_link(name)
    @session.click_link name
  end

  def checkbox_clicked?
    @session.find(:css, 'input:nth-child(1)[type="checkbox"]').checked?
  end

  def click_checkbox
    @session.find(:css, 'input:nth-child(1)[type="checkbox"]').click
  end

  def clear_checkbox
    @session.find(:css, 'input:nth-child(1)[type="checkbox"]').clear
  end

  def drag_and_drop_script
    dnd_javascript = File.read('C:\...Sachin_Test_Automation' + '\dnd.js')
    dnd_javascript+"$('#column-a').simulateDragDrop({ dropTarget: '#column-b'});"
  end

  def by_id(name)
    @session.find_by_id(name)
  end

  def find_all_drop_down
    #@session.select(option, from: 'dropdown')
    @session.find('#dropdown').all('option').collect(&:text)
  end

  def select_dropdown(x)
    @session.select(x, from: 'dropdown')
  end

  def switch_frames(parent, child)
    @session.within_frame(parent){@session.within_frame(child){@session.text}}
  end

  def single_frame(parent)
    @session.within_frame(parent){@session.text}
  end

end
File: the_heroku_spec.rb

require 'rspec'
require 'capybara'
require 'C:\...\the_heroku_app.rb'

RSpec.configure do |c|
  c.filter_run_excluding valid: true
  c.filter_run_excluding invalid: true
end

describe 'Verifying the components of the_heroku_app' do

  before(:each) do
    @cls_instance = The_Heroku_App.new
    @browser = @cls_instance.start_browser
    @cls_instance.go_to 'https://the-internet.herokuapp.com'
  end

  after(:each) do
    @cls_instance.tear_down
  end

  context 'Title and Body' do

    it 'Check for title of the page', page_title: true  do
      expect(@browser.title).to eq('The Internet')
    end

    it 'Check for the body of page', page_body: true  do
      expect(@browser).to have_content('Welcome to the Internet')
    end

  end

  context 'Checkbox' do

    it 'Verification of Checkbox', chk_box: true  do
      expect(@browser).to have_content('Welcome')
      @cls_instance.click_on_link 'Checkboxes'
      checkbox_1 = @cls_instance.checkbox_clicked?

      if !checkbox_1
        @cls_instance.click_checkbox
        expect(@cls_instance.checkbox_clicked?).to eq TRUE
      else
        @cls_instance.clear_checkbox
        expect(@cls_instance.checkbox_clicked?).to eq FALSE
      end
    end

  end

  context 'Credentials' do

    it 'Verify Basic Auth with VALID credentials', valid: true do
      @cls_instance.click_on_link 'Basic Auth'
      @browser.visit 'http://admin:admin@the-internet.herokuapp.com/basic_auth'
      expect(@browser).to have_content 'Congratulations! You must have the proper credentials.'
    end

    it 'Verify Basic Auth with INVALID credentials', invalid: true  do
      @cls_instance.click_on_link 'Basic Auth'
      @browser.visit 'http://admin:123@the-internet.herokuapp.com/basic_auth'
      expect(@browser).to have_content 'Not authorized'
    end

  end

  context 'Drag and Drop' do

    it 'Should drag and drop Column A to Column B', dnd: true  do
      @cls_instance.click_on_link 'Drag and Drop'
      @browser.execute_script(@cls_instance.drag_and_drop_script)
      expect(@cls_instance.by_id('column-a').text).to eq 'B'
      expect(@cls_instance.by_id('column-b').text).to eq 'A'
    end

  end

  context 'Dropdown box/Select box' do

    it 'Should select all options', drop_down: true  do
      @cls_instance.click_on_link 'Dropdown'
      values = @cls_instance.find_all_drop_down
      nw_vals = values[1..values.length]
      #results = [] #firefox
      #nw_vals.each {|x| results << @cls_instance.select_dropdown(x) == 'ok' ? true: false}#firefox
      #results.each{|x| expect(x).to eq 'ok'}#firefox
      nw_vals.each{|x| @cls_instance.select_dropdown(x)}
    end

  end

  context 'Upload a file' do

    it 'Should upload a file', upload_file: true do
      file = 'Hello.cpp'
      path = File.join(Dir.pwd, file)
      @cls_instance.click_on_link 'File Upload'
      upload_id = @cls_instance.by_id('file-upload')
      upload_id.send_keys path
      @browser.click_button 'Upload'
      uploaded = @cls_instance.by_id('uploaded-files').text
      expect(uploaded).to eq file

    end

  end

  context 'Switch between FRAMES' do

    it 'Should switch to LEFT frame and verify text', left_frame: true do
      @cls_instance.click_on_link 'Nested Frames'
      expect(@cls_instance.switch_frames('frame-top', 'frame-left')).to eq 'LEFT'
    end

    it 'Should switch to MIDDLE frame and verify text', middle_frame: true do
      @cls_instance.click_on_link 'Nested Frames'
      expect(@cls_instance.switch_frames('frame-top', 'frame-middle')).to eq 'MIDDLE'
    end

    it 'Should switch to RIGHT frame and verify text', right_frame: true do
      @cls_instance.click_on_link 'Nested Frames'
      expect(@cls_instance.switch_frames('frame-top', 'frame-right')).to eq 'RIGHT'
    end

    it 'Should switch to BOTTOM frame and verify text', bottom_frame: true do
      @cls_instance.click_on_link 'Nested Frames'
      expect(@cls_instance.single_frame('frame-bottom')).to eq 'BOTTOM'
    end

    it 'Should switch to LEFT frame and verify text', not_left_frame: true do
      @cls_instance.click_on_link 'Nested Frames'
      expect(@cls_instance.switch_frames('frame-top', 'frame-left')).not_to eq '123'
    end

    it 'Should switch to MIDDLE frame and verify text', not_middle_frame: true do
      @cls_instance.click_on_link 'Nested Frames'
      expect(@cls_instance.switch_frames('frame-top', 'frame-middle')).not_to eq 'CENTER'
    end

    it 'Should switch to RIGHT frame and verify text', not_right_frame: true do
      @cls_instance.click_on_link 'Nested Frames'
      expect(@cls_instance.switch_frames('frame-top', 'frame-right')).not_to eq 'LEFT'
    end

    it 'Should switch to BOTTOM frame and verify text', not_bottom_frame: true do
      @cls_instance.click_on_link 'Nested Frames'
      expect(@cls_instance.single_frame('frame-bottom')).not_to eq 'TOP'
    end

  end

end
The result after running the code:

Final

To be updated...