appium automation -- pageobject mode 02

Keywords: Selenium Android emulator Mobile

Directory structure changes:

1. The Android client.py script has no changes:

#AndroidClient.py
from appium.webdriver.webdriver import WebDriver
from appium import webdriver

class AndroidClient(object):
    driver:WebDriver
    @classmethod
    def installApp(cls)->WebDriver:
        caps={}
        #These are written to the configuration file
        #caps['app']=''
        caps['platformName']='android'
        caps['deviceName']='hogwarts'
        caps['appPackage']='com.xueqiu.android'
        caps['appActivity']=".view.WelcomeActivityAlias"
        #Solve the authorization problem of the first startup
        caps['autoGrantPermissions']='true'


        cls.driver=webdriver.Remote("http://localhost:4723/wd/hub",caps)
        cls.driver.implicitly_wait(15)
        return cls.driver

    @classmethod
    def restartApp(cls)->WebDriver:

        caps = {}
        # caps['app']=''
        caps['platformName'] = 'android'
        caps['deviceName'] = 'hogwarts'
        caps['appPackage'] = 'com.xueqiu.android'
        caps['appActivity'] = ".view.WelcomeActivityAlias"
        # Solve the authorization problem of the first startup
        caps['autoGrantPermissions'] = 'true'
        # In order to start faster and keep the previous data, the status of the last case can be saved.
        #caps['noReset']=True
        #When there are multiple devices, you need to specify the uuid of the device.
        # caps["udid"]="emulator-5554"
        caps['unicodeKeyboard']=True  #Support Chinese input
        caps['resetKeyboard'] = True

        cls.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
        cls.driver.implicitly_wait(15)
        return cls.driver

pages bag:

App.py implements the function of APP startup:

#App.py
from page_objects.driver.AndroidClient import AndroidClient
from page_objects.pages.Mainpage import MainPage
from page_objects.pages.basepage import Basepage


class App(Basepage):

    @classmethod
    def main(cls):
        cls.getClient().restartApp()
        return MainPage()  

Basepage.py: some common basic operations of page

#basepage.py
from selenium.webdriver.common.by import By
from page_objects.driver.AndroidClient import AndroidClient
from page_objects.driver.SeleniumClient import SeleniumClient
from selenium.webdriver.remote.webelement import WebElement
from appium.webdriver.webdriver import WebDriver

class Basepage(object):

    def __init__(self):
        self.driver=self.getDriver()  #driver in each instance

    @classmethod
    def getDriver(cls):
        #todo:
        #{multi platform testing: 1. When using method 1 and multi platform, call the unused Client according to the configuration item in the configuration file. 2. Method 2: write a web page - > selenium web, and let the web page test inherit this. 3. Step back to selenium. All driver s inherit selenium.
        # if True:
        #     cls.driver=AndroidClient.driver
        # else:
        #     cls.driver=SeleniumClient.driver
        #}
        cls.driver = AndroidClient.driver
        return cls.driver

    @classmethod
    def getClient(cls):
        return AndroidClient

    def find(self,kv)->WebElement:  #Without return value, there is no way to reverse click and sendkeys when calling find.
        #todo: handle pop ups
        return self.driver.find_element(*kv)

    def findByText(self,text)->WebElement:
        return self.find((By.XPATH, "//*[@text='%s']" %text))

Mainpage.py: some operations of snowball APP Homepage

#Mainpage.py
from page_objects.pages.SelectedPage import SelectedPage
from page_objects.pages.basepage import Basepage
from selenium.webdriver.common.by import By
from page_objects.pages.Searchpage import Searchpage
from page_objects.pages.ProfilePage import ProfilePage
import time


class MainPage(Basepage):
    _profile_button=(By.ID,"user_profile_icon")
    _search_button = (By.ID, "home_search")

    def gotoSelected(self):

        #Calling global driver object and using webdriver api to manipulate app
        #{original method
        #Self.driver.find'element'by'xpath ("/ / * [@ text ='optional '])
        # Self.driver.find'element (by.xpath, "/ / * [@ text = 'optional'])
        # Self.driver.find'element'by'xpath ("/ / * [@ text ='optional ']). click()
        #}
        #{find() method
        #zixuan=(By.XPATH, "//*[@text = 'optional'])
        #self.find(zixuan)
        #self.find(zixuan).click()
        #}

        #{findByText() method
        zixuan="Optional"
        self.findByText(zixuan)
        self.findByText(zixuan).click()
        #}

        return SelectedPage()

    def gotohangqing(self):
        self.driver.find_element_by_xpath("//*[@ text = 'market'] ")
        self.driver.find_element_by_xpath("//*[@ text = 'market'] "). click()
        time.sleep(10)
        return hangqingpage()

    def gotoSearch(self) -> Searchpage:

        self.find(self._search_button).click()
        return Searchpage()

    def gotoprofile(self) ->ProfilePage:
        self.find(MainPage._profile_button).click()
        return ProfilePage()

Element positioning and operation of LoginPage.py landing page:

#LoginPage.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions

from page_objects.pages.basepage import Basepage


class LoginPage(Basepage):  #The same set of test scripts tests different platforms, web and app.
    #todo:read form yaml, dynamically read different locators from yaml files according to different platforms

    _close_locator=(By.ID,"iv_close")
    _other_locator=(By.ID,"tv_login_by_phone_or_others")
    _weixin_locator=(By.ID,"rl_login_by_wx")
    _register_phone_number=(By.ID,"register_phone_number")
    _register_code=(By.ID,"register_code")
    _button_next=(By.ID,"button_next")
    _tv_login_with_account=(By.ID,"tv_login_with_account")
    _login_account=(By.ID,"login_account")
    _login_password=(By.ID,"login_password")
    _close2_locator=(By.ID,"iv_action_back")
    _error_msg=(By.ID,"md_content")
    _error_sure_btn=(By.ID,"md_buttonDefaultPositive")
    _back_locator=(By.XPATH,"//*[contains(@resource-id,'iv_close')or contains(@resource-id,'iv_action_back')]")

    def loginByWX(self):#WeChat landing
        return self

    def loginByMSG(self,phone,code): #Mobile phone or other location
        pass

    def loginByPassword(self,account,password):
        self.find(self._other_locator).click()
        self.find(self._tv_login_with_account).click()
        self.find(self._login_account).send_keys(account)
        self.find(self._login_password).send_keys(password)
        self.find(self._button_next).click()
        return self

        pass
    def loginSuccessByPassword(self,account,password):
        from page_objects.pages.Mainpage import MainPage
        return MainPage()

    def back(self):
        self.find(self._back_locator).click()
       #WebDriverWait(self.driver,5).until(expected_conditions.presence_of_element_located(self._close_locator))
        from page_objects.pages.ProfilePage import ProfilePage
        return ProfilePage()

    def getErrorMsg(self):
        msg=self.find(self._error_msg).text
        self.find(self._error_sure_btn).click()
        return msg

ProfilePage.py click the login page

#ProfilePage.py click the login page
from selenium.webdriver.common.by import By
from page_objects.pages.LoginPage import LoginPage
from page_objects.pages.basepage import Basepage




class ProfilePage(Basepage):

    def gotoLogin(self):
        clicklog=(By.ID,"tv_login")
        self.find(clicklog).click()
        return LoginPage()

Search page: search page.py

#Searchpage.py
from selenium.webdriver.common.by import By
from page_objects.pages.basepage import Basepage


class Searchpage(Basepage):
    _edit_locator=(By.CLASS_NAME, "android.widget.EditText")

    def search(self,key):
        self.find(self._edit_locator).send_keys(key)
        return self  #It can be called in chain, and always use....

    def addToSelected(self,key):
        follow_button = (By.XPATH, "//*[contains(@resource-id,'stockCode')and contains(@text,'%s')]" % key +
                         "/../../..//*[contains(@resource-id,'follow_btn')]")
        self.find(follow_button).click()
        return self

    def removeFromSelected(self,key):
        follow_button = (By.XPATH, "//*[contains(@resource-id,'stockCode')and contains(@text,'%s')]" % key +
                         "/../../..//*[contains(@resource-id,'followed_btn')]")
        self.find(follow_button).click()
        return self

    def isExisted(self,key):
        follow_button=(By.XPATH,"//*[contains(@resource-id,'stockCode')and contains(@text,'%s')]"%key+
                                "/../../..//*[contains(@resource-id,'follow')]")
        id=self.find(follow_button).get_attribute("resourceId")
        print(id)
        return "followed_btn" in id

    def cancel(self):
        self.findByText("cancel").click()

    def searchByUser(self,key):
        pass

    def isFollowed(self):
        pass

Stock price information of optional page: SelectedPage.py

#SelectedPage.py
from selenium.webdriver.common.by import By

from page_objects.driver.AndroidClient import AndroidClient
from page_objects.pages.basepage import Basepage

class SelectedPage(Basepage):

    def addDefault(self):
        return self

    def getPriceByName(self,name):
        #price=self.driver.find_element_by_xpath("//*[contains(@resource-id,'portfolio_stockName') and (@text='"+name+"')]/../../..//*[contains(@resource-id,'portfolio_currentPrice')]").text
        priceLocate=(By.XPATH,"//*[contains(@resource-id,'portfolio_stockName') and (@text='%s')]/../../..//*[contains(@resource-id,'portfolio_currentPrice')]" %name)
        price=self.find(priceLocate).text
        return float(price)

    def gotohs(self):
        self.findByText("Shanghai and Shenzhen").click()
        return self

testcase: package of test case:

Test added stock: test selected page.py

#test_selected_page.py
from page_objects.pages import Mainpage
from page_objects.pages.App import App
import pytest

class TestSelected(object):

    mainPage:Mainpage
    @classmethod
    def setup_class(cls):
        cls.mainPage=App.main()

    def setup_method(self):
        self.mainPage: Mainpage =TestSelected.mainPage
        self.searchPage=self.mainPage.gotoSearch()


    def test_is_selected_stock(self):
        searchpage= self.searchPage.search("alibaba")
        assert searchpage.isExisted("BABA")==True
        assert searchpage.isExisted("1688") == False

    def test_is_follow_user(self):
        pass

    @pytest.mark.parametrize("key,code",[    #Data driven
        ("China Merchants Bank","SH60036"),
        ("Ping An Bank","SZ0001"),
        ("pingan","SH601318")
    ])
    def test_is_selected_stock_hs(self,key,code):
        searchPage=self.searchPage.search(key)
        assert searchPage.isExisted(code)==False


    def teardown_method(self):
        self.searchPage.cancel()


    def test_add_stock_hs(self):
        key="China Merchants Bank"
        code="SH600036"
        self.searchPage.search(key)
        if self.searchPage.isExisted(code)==True:
            self.searchPage.removeFromSelected(code)
        self.searchPage.addToSelected(code)
        assert self.searchPage.isExisted(code)==True

Test login function: Test login.py

#test_login.py
from page_objects.pages.App import App
import pytest

class TestLogin(object):
    @classmethod
    def setup_class(cls):
        cls.profilePage=App.main().gotoprofile()  #Execute once to the profile page

    def setup_method(self):
        self.loginPage=self.profilePage.gotoLogin()#Execute once to loginpage page

    @pytest.mark.parametrize("user,pw,msg",[
        ("150265983481","123456","Phone number"),
        ("15026598348", "123456", "Password error")
    ])
    def test_login_password(self,user,pw,msg):
        self.loginPage.loginByPassword(user,pw)
        assert msg in self.loginPage.getErrorMsg()




    def teardown_method(self):
        self.loginPage.back()

Test selected page stock price: test selected page.py

#test_selected_page.py
from page_objects.pages import Mainpage
from page_objects.pages.App import App
import pytest

class TestSelected(object):

    mainPage:Mainpage
    @classmethod
    def setup_class(cls):
        cls.mainPage=App.main()

    def setup_method(self):
        self.mainPage: Mainpage =TestSelected.mainPage
        self.searchPage=self.mainPage.gotoSelected()

    def test_price(self):
        assert self.searchPage.gotohs().getPriceByName("Erie shares")==32.10


    def teardown_method(self):
        self.searchPage.cancel()

 

Posted by hossfly007 on Fri, 18 Oct 2019 07:51:28 -0700