Monday 31 May 2021

Python Appium - Desired Capabilities - Importance of noReset in Script

 What if you don't include noReset option of desired capabilities?

By default this capability is set to false.

desired_caps = {
'platformName': 'android',
'udid': 'emulator-5554',
'deviceName': 'Pixel 2 API 28',
'platformVersion': '9.0',
'appPackage': 'com.flipkart.android',
'appActivity': 'com.flipkart.android.activity.HomeFragmentHolderActivity'

}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)

So what exactly it does that if noReset is set to false, each time your test select capabilities, it will clear the cache, data for the application under test.

Lets take an actual test scenario of flipkart app. If user want to land on home screen, they have to first select the language, enter number or skip the page and then user is landed on home screen.

Select Language

Enter Number

On HomeScreen

If noReset : true, It will not clear the cache, data and user is landed on home screen. So selecting language and entering contact number would be a one time activity in this case.

desired_caps = {
'platformName': 'android',
'udid': 'emulator-5554',
'deviceName': 'Pixel 2 API 28',
'platformVersion': '9.0',
'noReset': 'true',
'appPackage': 'com.flipkart.android',
'appActivity': 'com.flipkart.android.activity.HomeFragmentHolderActivity'

}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
On Home Screen







Python Appium - Multiple scroll


Difference between single scroll and multiple scroll


Let us implement multiple scroll for flipkart app
For multiple scroll you have to use TouchAction class as below.
import pytest
from appium import webdriver
from utilities.BaseClass import BaseClass
from time import sleep
from appium.webdriver.common.touch_action import TouchAction

def __init__(self, driver):
self.driver = driver

def test_flipkart_homescreen():
desired_caps = {
'platformName': 'android',
'udid': 'emulator-5556',
'deviceName': 'Pixel 3 API 24',
'platformVersion': '7.0',
'noReset': 'true',
'appPackage': 'com.flipkart.android',
'appActivity': 'com.flipkart.android.activity.HomeFragmentHolderActivity'

}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)

log = BaseClass().get_logger()
log.info("-------------- Launching Flipkart App --------------")
sleep(5)
log.info("-------------- User is on Flipkart home screen --------------")
touch = TouchAction(driver)
touch.press(x=41, y=1576).move_to(x=44, y=1453).release().perform()

for i in range(4):
touch = TouchAction(driver)
touch.press(x=41, y=1576).move_to(x=44, y=1453).release().perform()
sleep(5)


So the basic difference is multiple scroll can be done multiple times using for loop. such scenarios arises when you want to scroll the items on page till last element is displayed. Sometime "scroll to top" such text is displayed once user reaches to the end of page.



Thursday 27 May 2021

Python Appium - How to handle list of Elements

 How to handle list of Elements

There are situations where all the elements on a particular page have same attribute however we have to extract a unique one and click on it.

So let us take a simple example for this SMS a native app on device


Here I want to click on settings So I need to find an unique locator for the same. So let us see how we can capture the it

For this open new session in appium and click on screenshot


So if you see all the elements have same attribute, its a list which have common attribute and here we have to find a unique one

ist_of_values = driver.find_elements_by_xpath(
"//android.widget.TextView[@resource-id='com.google.android.apps.messaging:id/title']")
expected_list =['Archived','Blocked contacts','Messages for web','Settings','Help&feedback']
actual_list = []

print(len(list_of_values))
for values in list_of_values:
ele = values.get_attribute("text")
actual_list.append(ele)

print(actual_list)

So we can identify elements by xpath. Once the element is identified wee can iterate through list of values. Before that we can get the length of list of values. Later append the text in actual_list[].

Let us see what is the output for this.


So from output we can see that length of list is 5 and the actual list is displayed. So let us get back to the point that we want to click on settings now. How to click on that

#Tap on Settings options
driver.find_element_by_xpath("//android.widget.TextView[@text='Settings']").click()

So you need to pass text= Settings

Complete code as below:

import pytest
from appium import webdriver
from pageObject.message.message_app import Message
from utilities.BaseClass import BaseClass
from time import sleep


def __init__(self, driver):
self.driver = driver


def test_send_message_delivery_on():
desired_caps = {
'platformName': 'android',
'udid': 'emulator-5554',
'deviceName': 'Pixel 2 API 28',
'platformVersion': '9.0',
'appPackage': 'com.google.android.apps.messaging',
'appActivity': 'com.google.android.apps.messaging.ui.ConversationListActivity',
'new/commandTimeout': 600
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
driver.find_element_by_xpath("//android.widget.ImageView"
"[@content-desc='More options']").click()
sleep(7)
list_of_values = driver.find_elements_by_xpath(
"//android.widget.TextView[@resource-id='com.google.android.apps.messaging:id/title']")
expected_list = ['Archived','Blocked contacts',
'Messages for web','Settings','Help & feedback']
actual_list = []
print("\n ")
print(len(list_of_values))
for values in list_of_values:
ele = values.get_attribute("text")
actual_list.append(ele)

print(actual_list)

assert expected_list == actual_list, "List did not matched..."

#Tap on Settings options
driver.find_element_by_xpath("//android.widget.TextView[@text='Settings']").click()

Here Attaching with video of our scenario.




Monday 24 May 2021

Python Appium - How to automate gestures - Tap, long press and swipes/scroll

So above gestures are the part of TouchAction class of appium. So let us go in details of this class

TouchActions:
TouchAction objects contains chain of actions. TouchAction class have only one method perform and we should always end our touchAction sequence with .perform() method.

MultiTouch:
MultiTouch object are collection of TouchActions. MultiTouch have add() and perform() methods.

So let us see a real time example.

tap(): You need to pass x and y co-ordinates where you want to tap.
You can find the tap co ordinates from appium session. Give the desired capabilities and it will launch the session screen for you.

On top of screen there is an option swipe by co ordinates. Place the mouse over the item for which you want to tap. At top left corner you could see x and y coordinate values.




And we have the code which we implemented for tap and swipe up and down on Settings app
from appium import webdriver
from appium.webdriver.common.touch_action import TouchAction
import time

def __init__(self, driver):
self.driver = driver

def test_tap_example():
desired_caps = {
'platformName': 'android',
'udid': 'emulator-5554',
'deviceName': 'Pixel_3_API_24',
'platformVersion': '7.0',
'appPackage': 'com.android.settings',
'appActivity': 'com.android.settings.Settings'
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)

driver.find_element_by_id("android:id/title").get_attribute("text")

# Tap example
# Tap on Notification option given under settings
user_actions = TouchAction(driver)
user_actions.tap(x=253, y=1107).perform()
time.sleep(5)
driver.back()

#Swipe/Scroll up and down example
time.sleep(5)
user_actions.press(x=434, y=872).move_to(x=437, y=656).release().perform()
time.sleep(5)
user_actions.press(x=468, y=1165).move_to(x=465, y=1401).release().perform()
time.sleep(5)

Let us see the implementation for long press on dialer app



So here you can record the actions for swipe and then the co ordinated appear . You can select the programming language as well whatever is required by you.

from appium import webdriver
from appium.webdriver.common.touch_action import TouchAction
import time

def __init__(self, driver):
self.driver = driver


def test_long_press_example():
desired_caps = {
'platformName': 'android',
'udid': 'emulator-5554',
'deviceName': 'Pixel_3_API_24',
'platformVersion': '7.0',
'appPackage': 'com.android.dialer',
'appActivity': 'com.android.dialer.DialtactsActivity'
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
# Long press for sending the number
user_actions = TouchAction(driver)
user_actions.tap(x=543, y=1890).perform()
time.sleep(5)

number = driver.find_element_by_id("com.android.dialer:id/digits")
number.send_keys("810000000")
user_actions.long_press(number)
time.sleep(5)


Thursday 20 May 2021

Python Appium - Parallel Test execution on mobile devices

 Why there is requirement for Parallel execution of test script on multiple devices?

Having single script and executing them parallel on multiple devices can actually reduce the efforts, resources and mainly the "TIME".

So let us start with parallel test execution script. first we would need below package. For info refer https://pypi.org/project/pytest-xdist/

pip install pytest-xdist

Once the package is installed, we can make sure that our test will run on multiple devices in parallel

For that I have considered pytest framework. Lets start the code

@pytest.mark.parametrize("udid,platformVersion,deviceName,systemPort,",[('emulator-5554','7.0','Pixel API 24','8201'),('emulator-5556','7.0','Pixel 3 API 24','8202')]) 

Basically you have to use parameterize annotation here to pass multiple device info, which it will pick at the time of creation of thread. Two parameters means two threads will be created for parallel execution.

import pytest
from appium import webdriver
from pageObject.calculator.calculator_app import Calculator
from utilities.BaseClass import BaseClass


def __init__(self, driver):
self.driver = driver


@pytest.mark.parametrize("udid,platformVersion,deviceName,systemPort,",[('emulator-5554',
'7.0','Pixel API 24','8201'),('emulator-5556','7.0','Pixel 3 API 24','8202')])
def test_calculator_add_number(udid, platformVersion, deviceName, systemPort):
desired_caps = {
'platformName': 'android',
'udid': udid,
'deviceName': deviceName,
'platformVersion': platformVersion,
'appPackage': 'com.android.calculator2',
'appActivity': 'com.android.calculator2.Calculator',
'systemPort': int(systemPort)
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
cal = Calculator(driver)
cal.add_numbers(2, 2)

In above code you can pass as many as device details that will run in parallel. But make sure you pass unique system port.

To run this you have to give below command




Python Appium - Step by step procedure for capturing screenshot

 Why To capture screenshot?

It is as important as your logs. If there is any failure for any test scenario, we can provide screenshot for the same. Its part of good practice to include in your test framework for each scenarios. Later point of time we will discuss about how to accommodate same in your framework.

Let us see how we can capture screenshot

1. Get the current activity name

2. Get the current time stamp

3. capture and save the screenshot at specified location

import pytest
from appium import webdriver
from login import Login
import time
import os
import base64
from calculator_app import Calculator


def __init__(self, driver):
self.driver = driver

def test_calculator_add_number():
desired_caps = {
'platformName': 'android',
'udid': 'emulator-5556',
'deviceName': 'Pixel 2 API 28',
'platformVersion': '9.0',
'appPackage': 'com.android.calculator2',
'appActivity': 'com.android.calculator2.Calculator'
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
cal = Calculator(driver)
cal.add_numbers(2, 2)
file_name = driver.current_activity + time.strftime("%Y_%m_%d_%H%M%S")
filepath = os.path.join("C:/Data/2021/May/Sample/", file_name + ".png")
driver.save_screenshot(filepath)


This the result from above script.






Python Appium - Procedure for Video/Screen Recording

 Why Screen/Video recording is required?

When there are complex test scenarios and if there is any failure it becomes easy to identify where exactly is the failure. As a tester point of view, it is always necessary to provide logs, video recording and screenshots (This may vary project to project). 

So let us start how to accommodate video recording in your appium framework.

Basically you would need three steps here,

1. start video recording

2. stop video recording

3. convert the captured video to mp3or mp4 format

So to record video you would need

driver.start_recording_screen()

To Stop video you would need to call

driver.start_recording_screen()

So here I will explain you with calculator example,

from appium import webdriver
from login import Login
import time
import os
import base64


def __init__(self, driver):
self.driver = driver

def test_calculator_click_number():
desired_caps = {
'platformName': 'android',
'udid': 'emulator-5556',
'deviceName': 'Pixel 2 API 28',
'platformVersion': '9.0',
'appPackage': 'com.android.calculator2',
'appActivity': 'com.android.calculator2.Calculator'
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
driver.start_recording_screen()
login = Login(driver)
login.login_in_to_app()
video_rawdata = driver.stop_recording_screen()
video_name = driver.current_activity + time.strftime("%Y_%m_%d_%H%M%S")
filepath = os.path.join("C:/Data/2021/May/Sample/", video_name+".mp4")


with open(filepath,"wb+") as vd:
vd.write(base64.b64decode(video_rawdata))


Here whatever video has been recorded is stored in video_rawdata variable. Later at this point

with open(filepath,"wb+") as vd:
vd.write(base64.b64decode(video_rawdata))

It is been converted. In below code, video_name is the variable with current activity name and current time of video recording

video_name = driver.current_activity + time.strftime("%Y_%m_%d_%H%M%S")

In below code snippet we have stored the video at specified location

filepath = os.path.join("C:/Data/2021/May/Sample/", video_name+".mp4")


Feature Posts

Python Appium - Step by step procedure for capturing screenshot

 Why To capture screenshot? It is as important as your logs. If there is any failure for any test scenario, we can provide screenshot for th...