├── README.md ├── driver ├── Appium.py └── __init__.py ├── page ├── __init__.py ├── base_page.py ├── portfolio.py ├── search.py ├── stock.py ├── stock_group.py └── xueqiu.py ├── temp ├── 1 │ ├── 11 │ │ ├── conftest.py │ │ └── test_demo.py │ ├── conftest.py │ └── test_demo1.py ├── __init__.py ├── demo2 │ ├── BaseDemo.py │ └── __init__.py └── demo22 │ ├── 1.yaml │ ├── __init__.py │ └── test_children.py ├── test_apidemo.py ├── test_h5.py ├── test_ios.py ├── test_uicatalog.py ├── test_xueqiu.py └── testcase ├── __init__.py ├── test_portfolio.py ├── test_stock_group.py ├── test_ut.py └── test_xueqiu.py /README.md: -------------------------------------------------------------------------------- 1 | # AppiumDemo8_Android 2 | -------------------------------------------------------------------------------- /driver/Appium.py: -------------------------------------------------------------------------------- 1 | from appium import webdriver 2 | from appium.webdriver.webdriver import WebDriver 3 | 4 | 5 | class Appium(object): 6 | 7 | 8 | driver =None 9 | "@type driver: WebDriver" 10 | 11 | #这个办法只适合python3.5以上 12 | #driver: WebDriver = None 13 | 14 | @classmethod 15 | def getDriver(cls): 16 | return cls.driver 17 | 18 | @classmethod 19 | def initDriver(cls): 20 | print("setup") 21 | caps = {} 22 | caps["platformName"] = "android" 23 | caps["deviceName"] = "demo" 24 | caps["udid"]="192.168.59.101:5555" 25 | caps["appPackage"] = "com.xueqiu.android" 26 | caps["appActivity"] = ".view.WelcomeActivityAlias" 27 | caps["autoGrantPermissions"] = True 28 | caps["automationName"] = "UiAutomator2" 29 | 30 | cls.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps) 31 | cls.driver.implicitly_wait(6) -------------------------------------------------------------------------------- /driver/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seveniruby/AppiumDemo8_Android/7a2ed3be27ed6cb27bd4e30e13d48cc8f34aa654/driver/__init__.py -------------------------------------------------------------------------------- /page/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seveniruby/AppiumDemo8_Android/7a2ed3be27ed6cb27bd4e30e13d48cc8f34aa654/page/__init__.py -------------------------------------------------------------------------------- /page/base_page.py: -------------------------------------------------------------------------------- 1 | from appium.webdriver import WebElement 2 | from appium.webdriver.common.mobileby import MobileBy 3 | from lxml.html import Element 4 | from selenium.webdriver.common.by import By 5 | 6 | from driver.Appium import Appium 7 | from lxml import etree 8 | 9 | class BasePage(object): 10 | 11 | def __init__(self): 12 | pass 13 | 14 | @classmethod 15 | def byAndroid(self, text=None, id=None): 16 | text_selector="" 17 | 18 | if(text!=None): 19 | text_selector="@text='" + text + "'" 20 | if (id != None): 21 | id_selector = "contains(@resource-id, '" + id + "')" 22 | return (MobileBy.ANDROID_UIAUTOMATOR, 'new UiSelector().resourceId("' + id + '").text("' + text + '")') 23 | #return "//*[" + text_selector + " and " + id_selector + "]" 24 | else: 25 | return (MobileBy.ANDROID_UIAUTOMATOR,'new UiSelector().text("'+text+'")') 26 | #return "//*[" + text_selector + "]" 27 | 28 | 29 | @classmethod 30 | def byAttribute(self, text=None, id=None): 31 | text_selector="" 32 | 33 | if(text!=None): 34 | text_selector="@text='" + text + "'" 35 | if (id != None): 36 | id_selector = "contains(@resource-id, '" + id + "')" 37 | #return 'new UiSelector().resourceId("' + id + '").text("' + text + '")' 38 | return "//*[" + text_selector + " and " + id_selector + "]" 39 | else: 40 | #return 'new UiSelector().text("'+text+'")' 41 | return "//*[" + text_selector + "]" 42 | 43 | 44 | def findBy(self, by=By.ID, value=None): 45 | try: 46 | return Appium.getDriver().find_element(by, value) 47 | except: 48 | self.exception_handle2() 49 | return Appium.getDriver().find_element(by, value) 50 | 51 | def find(self, locate) -> WebElement: 52 | return self.findBy(*locate) 53 | 54 | def findAll(self, locate) -> []: 55 | return Appium.getDriver().find_elements(*locate) 56 | 57 | def exception_handle(self): 58 | self.black_words = [self.byAttribute(text="好的"), self.byAttribute(text="下次再说")] 59 | 60 | for w in self.black_words: 61 | elements = Appium.getDriver().find_elements(By.XPATH, w) 62 | if len(elements) > 0: 63 | elements[0].click() 64 | return Appium.getDriver().find_element(By.XPATH, w) 65 | 66 | 67 | def exception_handle2(self): 68 | self.black_words = [self.byAttribute(text="好的"), self.byAttribute(text="下次再说")] 69 | 70 | #todo: 优化弹框处理逻辑,发现toast,自动发现兼容性问题等。。。 71 | page_source=Appium.getDriver().page_source 72 | print(page_source) 73 | #parser = etree.XMLParser(encoding='utf-8') 74 | xml=etree.XML(str(page_source).encode("utf-8")) 75 | for w in self.black_words: 76 | print(w) 77 | if(len(xml.xpath(w))>0): 78 | Appium.getDriver().find_element(By.XPATH, w).click() 79 | -------------------------------------------------------------------------------- /page/portfolio.py: -------------------------------------------------------------------------------- 1 | from selenium.webdriver.common.by import By 2 | 3 | from page.base_page import BasePage 4 | from page.search import Search 5 | 6 | 7 | class Portfolio(BasePage): 8 | _search_button=(By.ID, "action_create_cube") 9 | def toSearch(self): 10 | self.find(self._search_button).click() 11 | return Search() -------------------------------------------------------------------------------- /page/search.py: -------------------------------------------------------------------------------- 1 | from appium.webdriver.common.mobileby import MobileBy 2 | 3 | from driver.Appium import Appium 4 | from page.base_page import BasePage 5 | 6 | 7 | class Search(BasePage): 8 | _user=(MobileBy.XPATH, "//*[@text='用户']") 9 | _username=(MobileBy.ID, "user_name") 10 | _stockName = (MobileBy.ID, "stockName") 11 | _search = (MobileBy.ID, "search_input_text") 12 | _cancel=(MobileBy.XPATH, "//*[@text='取消']") 13 | 14 | _follow=(MobileBy.ID, "com.xueqiu.android:id/follow_btn") 15 | _followed = (MobileBy.ID, "com.xueqiu.android:id/followed_btn") 16 | 17 | def search(self, keyword): 18 | self.find(self._search).send_keys(keyword) 19 | return self 20 | 21 | def getUserName(self): 22 | self.find(self._user).click() 23 | self.find(self._username).text 24 | 25 | 26 | 27 | def getStocks(self): 28 | return self.find(self._stockName).text 29 | 30 | def cancel(self): 31 | self.find(self._cancel).click() 32 | 33 | def followFirst(self): 34 | elements=self.findAll(self._follow) 35 | if len(elements)==2: 36 | elements[0].click() 37 | 38 | return self 39 | -------------------------------------------------------------------------------- /page/stock.py: -------------------------------------------------------------------------------- 1 | from appium.webdriver.common.mobileby import MobileBy 2 | from appium.webdriver.common.touch_action import TouchAction 3 | from selenium.webdriver.common.by import By 4 | 5 | from driver.Appium import Appium 6 | from page.portfolio import Portfolio 7 | 8 | 9 | class Stock(Portfolio): 10 | 11 | _name=(By.ID, "com.xueqiu.android:id/portfolio_stockName") 12 | _us=(By.XPATH, "//*[@text='美股' and contains(@resource-id, 'text')]") 13 | 14 | _all=Portfolio.byAndroid(text="全部") 15 | 16 | def getNameByUS(self): 17 | self.find(self._us).click() 18 | x=[] 19 | for e in self.findAll(self._name): 20 | x.append(e.text) 21 | return x 22 | 23 | def getNameByAll(self): 24 | self.find(self._all).click() 25 | x=[] 26 | for e in self.findAll(self._name): 27 | x.append(e.text) 28 | return x 29 | 30 | def getNameByGroup(self, name): 31 | pass 32 | 33 | 34 | def delete(self, name, group_name=""): 35 | if group_name!="": 36 | self.find((By.XPATH, self.byAttribute(text=group_name))).click() 37 | 38 | print(Appium.getDriver().page_source) 39 | element=self.find((MobileBy.ANDROID_UIAUTOMATOR, 40 | 'new UiSelector().resourceId("com.xueqiu.android:id/portfolio_stockName").text("'+name+'")')) 41 | TouchAction(Appium.getDriver()).long_press(el=element).perform() 42 | self.find((By.XPATH, self.byAttribute(text='删除'))).click() 43 | 44 | 45 | -------------------------------------------------------------------------------- /page/stock_group.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class StockGroup(object): 4 | 5 | def add(self, name): 6 | 7 | return self 8 | 9 | def delete(self,name ): 10 | return self 11 | 12 | def sort(self, name=[]): 13 | return self 14 | 15 | def getGroups(self): 16 | return ["n1", "n2"] 17 | 18 | def toGroup(self, group): 19 | return self 20 | -------------------------------------------------------------------------------- /page/xueqiu.py: -------------------------------------------------------------------------------- 1 | from selenium.webdriver.common.by import By 2 | 3 | from driver.Appium import Appium 4 | from page.base_page import BasePage 5 | from page.portfolio import Portfolio 6 | from page.search import Search 7 | from page.stock import Stock 8 | 9 | 10 | class Xueqiu(BasePage): 11 | _search=(By.ID, "home_search") 12 | _portfolio=(By.XPATH,"//*[@text='自选' and contains(@resource-id, 'tab_name')]") 13 | def __init__(self): 14 | self.loaded() 15 | 16 | def toSearch(self): 17 | self.find(self._search).click() 18 | return Search() 19 | 20 | def toPortfolio(self): 21 | self.find(self._portfolio).click() 22 | return Stock() 23 | 24 | def loaded(self): 25 | locations = ["x", "y"] 26 | while locations[-1] != locations[-2]: 27 | element = self.find(self._portfolio) 28 | print(element) 29 | locations.append(element.location) 30 | print(locations) -------------------------------------------------------------------------------- /temp/1/11/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import logging 3 | 4 | logging.basicConfig(level=logging.DEBUG) 5 | 6 | 7 | @pytest.fixture(scope="class") 8 | def username11(): 9 | print("username 11 module 11") 10 | return "module username 11" -------------------------------------------------------------------------------- /temp/1/11/test_demo.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import logging 3 | 4 | class TestDemo(object): 5 | def test_demo1(self, username): 6 | print(username) 7 | 8 | def test_demo2(self, username11): 9 | logging.getLogger().info('boo %s', 'arg') 10 | print(username11) 11 | logging.info("xxxxx") 12 | logging.debug("ddd") -------------------------------------------------------------------------------- /temp/1/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | @pytest.fixture(scope="module") 4 | def username(): 5 | print("username module 1") 6 | return "module username 1" -------------------------------------------------------------------------------- /temp/1/test_demo1.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import logging 3 | import time 4 | 5 | logging.basicConfig(level=logging.DEBUG) 6 | loger=logging.getLogger("xxx") 7 | class TestDemo(object): 8 | 9 | def test_1(self): 10 | log = logging.getLogger('test_1') 11 | time.sleep(1) 12 | log.debug('after 1 sec') 13 | time.sleep(1) 14 | log.debug('after demo2 sec') 15 | time.sleep(1) 16 | log.debug('after 3 sec') 17 | assert 1, 'should pass' 18 | 19 | 20 | -------------------------------------------------------------------------------- /temp/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | logging.basicConfig(level=logging.DEBUG) -------------------------------------------------------------------------------- /temp/demo2/BaseDemo.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import logging 3 | 4 | class BaseDemo(object): 5 | def setup(self): 6 | logging.basicConfig(level=logging.DEBUG) 7 | print("setup BaseDemo") 8 | 9 | -------------------------------------------------------------------------------- /temp/demo2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seveniruby/AppiumDemo8_Android/7a2ed3be27ed6cb27bd4e30e13d48cc8f34aa654/temp/demo2/__init__.py -------------------------------------------------------------------------------- /temp/demo22/1.yaml: -------------------------------------------------------------------------------- 1 | - [1, 2] 2 | - [3, 4] -------------------------------------------------------------------------------- /temp/demo22/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seveniruby/AppiumDemo8_Android/7a2ed3be27ed6cb27bd4e30e13d48cc8f34aa654/temp/demo22/__init__.py -------------------------------------------------------------------------------- /temp/demo22/test_children.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from temp.demo2.BaseDemo import BaseDemo 4 | import yaml 5 | import logging 6 | 7 | 8 | def get_data(): 9 | return yaml.load(open("1.yaml", 'r')) 10 | 11 | 12 | class TestChildren(BaseDemo): 13 | def setup(self): 14 | super().setup() 15 | print("setup Children") 16 | self.data=[(1, 2), (3, 4)] 17 | 18 | def test_demo(self): 19 | print("demo") 20 | 21 | @pytest.mark.parametrize("a, b", get_data()) 22 | def test_data(self, a, b): 23 | logging.info(b) 24 | print(a) 25 | 26 | 27 | -------------------------------------------------------------------------------- /test_apidemo.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import unittest 3 | from appium import webdriver 4 | from time import sleep 5 | 6 | from appium.webdriver.common.touch_action import TouchAction 7 | from selenium.webdriver.support.wait import WebDriverWait 8 | 9 | 10 | class TestApiDemo(unittest.TestCase): 11 | def setUp(self): 12 | print("setup") 13 | caps = {} 14 | caps["platformName"] = "android" 15 | caps["deviceName"] = "demo" 16 | #caps["appPackage"] = "com.example.android.apis" 17 | caps["appPackage"] = "io.appium.android.apis" 18 | caps["appActivity"] = ".ApiDemos" 19 | caps["autoGrantPermissions"] = "true" 20 | caps["automationName"] = "UiAutomator2" 21 | caps["newCommandTimeout"] = 600 22 | 23 | self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps) 24 | self.driver.implicitly_wait(10) 25 | 26 | 27 | def test_toast(self): 28 | self.driver.find_element_by_accessibility_id("Views").click() 29 | #self.driver.find_element_by_accessibility_id("Popup Menu").click() 30 | self.driver.find_element_by_android_uiautomator( 31 | 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).getChildByText(new UiSelector().className("android.widget.TextView"), "Popup Menu")' 32 | ).click() 33 | self.driver.find_element_by_accessibility_id("Make a Popup!").click() 34 | self.driver.find_element_by_xpath("//*[@text='Search']").click() 35 | print(self.driver.find_element_by_xpath("//*[@class='android.widget.Toast']").text) 36 | print(self.driver.find_element_by_xpath("//*[@package='com.android.settings']").text) 37 | print(self.driver.find_element_by_xpath("//*[contains(@text, 'Clicked')]").text) 38 | 39 | def test_toast_not_found(self): 40 | self.driver.find_element_by_accessibility_id("Views").click() 41 | #self.driver.find_element_by_accessibility_id("Popup Menu").click() 42 | self.driver.find_element_by_android_uiautomator( 43 | 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).getChildByText(new UiSelector().className("android.widget.TextView"), "Popup Menu")' 44 | ).click() 45 | self.driver.find_element_by_accessibility_id("Make a Popup!").click() 46 | self.driver.find_element_by_xpath("//*[@text='Search']").click() 47 | 48 | 49 | def test_webview_sim_simple(self): 50 | self.driver.find_element_by_accessibility_id("Views").click() 51 | self.driver.find_element_by_android_uiautomator( 52 | 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).getChildByText(new UiSelector().className("android.widget.TextView"), "WebView")' 53 | ).click() 54 | self.driver.find_element_by_accessibility_id("Hello World! - 1").click() 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /test_h5.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from appium import webdriver 3 | 4 | class TestH5(unittest.TestCase): 5 | def setUp(self): 6 | caps={} 7 | caps["platformName"]="android" 8 | caps["deviceName"]="seveniruby" 9 | #caps["browserName"]="chrome" 10 | caps["browserName"]="Browser" 11 | caps["noReset"]="true" 12 | caps["fullReset"]="false" 13 | caps["forceMjsonwp"]="true" 14 | caps["dontStopAppOnReset"]="true" 15 | 16 | self.driver=webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps) 17 | self.driver.implicitly_wait(10) 18 | 19 | def test_main(self): 20 | 21 | self.driver.get("https://danjuanapp.com/my-money?channel=1300100158&refer=xq_trade") 22 | self.driver.find_element_by_css_selector(".btns .blank").click() 23 | self.driver.find_element_by_css_selector(".pass_switch").click() 24 | self.driver.find_element_by_name("telno").send_keys("15600534760") 25 | self.driver.find_element_by_name("pass").send_keys("password") 26 | self.driver.find_element_by_id("next").click() 27 | -------------------------------------------------------------------------------- /test_ios.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import unittest 3 | from appium import webdriver 4 | from time import sleep 5 | 6 | from appium.webdriver.common.touch_action import TouchAction 7 | from selenium.webdriver.support.wait import WebDriverWait 8 | 9 | 10 | class TestIOS(unittest.TestCase): 11 | loaded = False 12 | 13 | def setUp(self): 14 | pass 15 | 16 | 17 | def test_uicatalog_sim(self): 18 | 19 | print("setup") 20 | caps = {} 21 | caps["platformName"] = "ios" 22 | caps["platformVersion"] = "12.1" 23 | caps["deviceName"] = "iPhone X" 24 | caps["app"] = '/Users/seveniruby/Library/Developer/Xcode/DerivedData/UICatalog-ftyzdbgapjmxxobezrnrxsshpdqh/' \ 25 | 'Build/Products/Debug-iphonesimulator/UICatalog.app' 26 | 27 | if TestIOS.loaded == True: 28 | caps["noReset"] = "true" 29 | 30 | self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps) 31 | self.driver.implicitly_wait(10) 32 | loaded = True 33 | 34 | 35 | print(self.driver.page_source) 36 | self.driver.find_element_by_id("Buttons").click() 37 | self.driver.back() 38 | self.driver.find_element_by_accessibility_id("Buttons").click() 39 | 40 | def test_uicatalog_real_by_url(self): 41 | caps = {} 42 | caps["platformName"] = "ios" 43 | caps["automationName"] = "xcuitest" 44 | caps["deviceName"] = "Uzumaki的iPhone" 45 | caps["udid"]="auto" 46 | caps["app"] = '/Users/seveniruby/Library/Developer/Xcode/DerivedData/UICatalog-dfavfehsvaabuqdpmxouzqphclvl/' \ 47 | 'Build/Products/Debug-iphoneos/UICatalog.app' 48 | caps["xcodeOrgId"]="96NJEQL7Y2" 49 | caps["xcodeSigningId"]="iPhone Developer" 50 | caps["webDriverAgentUrl"]="http://192.168.0.102:8100" 51 | 52 | self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps) 53 | self.driver.implicitly_wait(10) 54 | print(self.driver.page_source) 55 | 56 | def test_uicatalog_real(self): 57 | caps = {} 58 | caps["platformName"] = "ios" 59 | caps["automationName"] = "xcuitest" 60 | caps["deviceName"] = "Uzumaki的iPhone" 61 | caps["udid"]="auto" 62 | caps["app"] = '/Users/seveniruby/Library/Developer/Xcode/DerivedData/UICatalog-dfavfehsvaabuqdpmxouzqphclvl/' \ 63 | 'Build/Products/Debug-iphoneos/UICatalog.app' 64 | caps["xcodeOrgId"]="96NJEQL7Y2" 65 | caps["xcodeSigningId"]="iPhone Developer" 66 | #加速,绕过构建 67 | caps["usePrebuiltWDA"]="true" 68 | 69 | self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps) 70 | self.driver.implicitly_wait(10) 71 | print(self.driver.page_source) 72 | 73 | -------------------------------------------------------------------------------- /test_uicatalog.py: -------------------------------------------------------------------------------- 1 | # This sample code uses the Appium python client 2 | # pip install Appium-Python-Client 3 | # Then you can paste this into a file and simply run with Python 4 | 5 | import unittest 6 | from appium import webdriver 7 | from appium.webdriver.webelement import WebElement 8 | 9 | 10 | class TestUicatalog(unittest.TestCase): 11 | def setUp(self): 12 | caps = {} 13 | caps["platformName"] = "ios" 14 | caps["platformVersion"] = "12.1" 15 | caps["deviceName"] = "iPhone X" 16 | caps["app"] = "/Users/seveniruby/Library/Developer/Xcode/DerivedData/UICatalog-dfavfehsvaabuqdpmxouzqphclvl/Build/Products/Debug-iphonesimulator/UICatalog.app" 17 | 18 | self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps) 19 | 20 | def test_buttons(self): 21 | el2 = self.driver.find_element_by_accessibility_id("Buttons") 22 | el2.click() 23 | print(self.driver.page_source) 24 | self.driver.find_element_by_accessibility_id("UICatalog").click() 25 | 26 | def tearDown(self): 27 | self.driver.quit() -------------------------------------------------------------------------------- /test_xueqiu.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from time import sleep 3 | 4 | from appium.webdriver.common.mobileby import MobileBy 5 | from appium.webdriver.common.touch_action import TouchAction 6 | from selenium.webdriver.support.wait import WebDriverWait 7 | from selenium.webdriver.support import expected_conditions 8 | 9 | from page.search import Search 10 | from driver.Appium import Appium 11 | from page.xueqiu import Xueqiu 12 | 13 | 14 | class TestXueqiu(unittest.TestCase): 15 | loaded = False 16 | 17 | def setUp(self): 18 | Appium.initDriver() 19 | print(Appium.driver) 20 | 21 | 22 | def test_add_stock(self): 23 | self.driver.find_element_by_id("tv_search").click() 24 | self.driver.save_screenshot("screenshot/tv_search.png") 25 | self.driver.find_element_by_id("search_input_text").send_keys("pdd") 26 | self.driver.save_screenshot("screenshot/search_input_text.png") 27 | 28 | print(self.driver.find_element_by_id("add_attention") \ 29 | .find_element_by_class_name("android.widget.TextView") \ 30 | .get_attribute("resourceId")) 31 | 32 | if len(self.driver.find_elements_by_id("follow_btn")) > 0: 33 | self.driver.find_element_by_id("follow_btn").click() 34 | self.driver.find_element_by_xpath("//*[@text='下次再说']").click() 35 | 36 | def test_check_stock(self): 37 | for i in range(1, 5): 38 | element = self.driver.find_element_by_xpath( 39 | "//*[@text='自选' and contains(@resource-id, 'tab_name')]") 40 | print(element.location) 41 | element.text 42 | element.get_attribute("text") 43 | self.driver.find_element_by_xpath( 44 | "//*[@text='自选' and contains(@resource-id, 'tab_name')]").click() 45 | assert 1 == len(self.driver.find_elements_by_xpath( 46 | "//*[contains(@resource-id, 'portfolio_stockName') and @text='拼多多']")) 47 | 48 | def test_mobile(self): 49 | # self.driver.start_activity("com.android.calculator2", ".Calculator") 50 | print(self.driver.is_locked()) 51 | self.driver.lock(5) 52 | self.driver.unlock() 53 | # self.driver.shake() 54 | 55 | def test_touch(self): 56 | self.loaded() 57 | self.driver.find_element_by_xpath( 58 | "//*[@text='自选' and contains(@resource-id, 'tab_name')]").click() 59 | 60 | element = self.driver.find_element_by_xpath("//*[@text='拼多多']") 61 | TouchAction(self.driver).long_press(element).perform() 62 | self.driver.find_element_by_xpath("//*[@text='删除']").click() 63 | 64 | def test_main_swipe(self): 65 | self.loaded() 66 | for i in range(1, 10): 67 | sleep(1) 68 | self.driver.swipe(start_x=1340, start_y=2000, end_x=200, end_y=600, duration=1000) 69 | 70 | def find(self, by, locator): 71 | 72 | try: 73 | self.driver.find_element(by, locator) 74 | except: 75 | keywords=[] 76 | for key in keywords: 77 | elements=self.driver.find_elements(key) 78 | if len(elements)>0: 79 | elements[0].click() 80 | 81 | 82 | def loaded(self): 83 | locations = ["x", "y"] 84 | while locations[-1] != locations[-2]: 85 | element = self.driver.find_element_by_xpath( 86 | "//*[@text='自选' and contains(@resource-id, 'tab_name')]") 87 | locations.append(element.location) 88 | print(locations) 89 | 90 | def test_battery(self): 91 | print(self.driver.execute_script("mobile:batteryInfo")) 92 | 93 | def test_shell(self): 94 | print(self.driver.execute_script("mobile:shell", 95 | {"command": "am", 96 | "args": ["start", "-n", "com.android.calculator2/.Calculator"]})) 97 | 98 | def test_webview_sim_image(self): 99 | self.loaded() 100 | self.driver.find_element_by_xpath("//*[@text='交易']").click() 101 | self.driver.find_element_by_accessibility_id("15da75b0b28c2b23feda8fe7").click() 102 | 103 | 104 | def test_webview_sim_h5(self): 105 | self.loaded() 106 | self.driver.find_element_by_xpath("//*[@text='交易']").click() 107 | WebDriverWait(self.driver, 10).until( 108 | expected_conditions.visibility_of_element_located( 109 | (MobileBy.ACCESSIBILITY_ID, "基金开户"))) 110 | self.driver.switch_to.context("WEBVIEW_com.xueqiu.android") 111 | print(self.driver.current_context) 112 | print(self.driver.page_source) 113 | self.driver.find_element_by_css_selector(".trade_home_agu_3ki").click() 114 | 115 | def test_search(self): 116 | xueqiu=Xueqiu() 117 | search=xueqiu.toSearch() 118 | search.search("pdd") 119 | assert search.getStocks() == "拼多多" 120 | 121 | def test_search_username(self): 122 | xueqiu=Xueqiu() 123 | search=xueqiu.toSearch() 124 | search.search("seveniruby") 125 | assert search.getUserName() == "seveniruby" 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /testcase/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seveniruby/AppiumDemo8_Android/7a2ed3be27ed6cb27bd4e30e13d48cc8f34aa654/testcase/__init__.py -------------------------------------------------------------------------------- /testcase/test_portfolio.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import unittest 3 | 4 | from driver.Appium import Appium 5 | from page.xueqiu import Xueqiu 6 | 7 | 8 | class TestPortfolio(unittest.TestCase): 9 | 10 | def setUp(self): 11 | #todo: 数据的初始化 12 | Appium.initDriver() 13 | self.xueqiu=Xueqiu() 14 | self.stock=self.xueqiu.toPortfolio() 15 | 16 | def test_list(self): 17 | print(self.stock.getNameByUS()) 18 | 19 | 20 | def test_add(self): 21 | self.stock.toSearch().search("alibaba").followFirst().cancel() 22 | assert "阿里巴巴" in self.stock.getNameByUS() 23 | 24 | def test_delete(self): 25 | self.stock.delete("拼多多", "美股") 26 | assert "拼多多" not in self.stock.getNameByUS() 27 | 28 | def test_delete_all(self): 29 | 30 | #todo: xpath定位bug 确认是8.0系统上的android Uiautomator2 server的bug 31 | #todo: 使用接口清理数据是更高效的办法 32 | 33 | stocks=[] 34 | while True: 35 | stocks=self.stock.getNameByAll() 36 | if len(stocks)==0: 37 | break 38 | stock=stocks[0] 39 | print(stock) 40 | self.stock.delete(stock) 41 | #Appium.initDriver() 42 | #self.xueqiu = Xueqiu() 43 | #self.stock = self.xueqiu.toPortfolio() 44 | 45 | assert len(self.stock.getNameByAll())==0 46 | -------------------------------------------------------------------------------- /testcase/test_stock_group.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from page.stock_group import StockGroup 4 | import pytest 5 | 6 | from page.xueqiu import Xueqiu 7 | 8 | 9 | class TestStockGroup(object): 10 | 11 | def setup(self): 12 | # todo: 删除所有分组 13 | self.group = StockGroup() 14 | pass 15 | 16 | def test_add(self): 17 | self.group.add("demo") 18 | assert "demo" in self.group.getGroups() 19 | 20 | @pytest.mark.parametrize("group,name", [ 21 | ("g1", "n1"), 22 | ("g2", "n2"), 23 | ("g3", "n3") 24 | ]) 25 | def test_add(self, group, name): 26 | self.group.toGroup(group) 27 | self.group.add(name) 28 | assert name in self.group.getGroups() 29 | 30 | @pytest.mark.parametrize("name", ["1", "demo2", "中文名"]) 31 | def test_delete(self, name): 32 | name = "demo2" 33 | assert name in self.group.add(name).getGroups() 34 | self.group.delete(name) 35 | assert name not in self.group.getGroups() 36 | -------------------------------------------------------------------------------- /testcase/test_ut.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from lxml import etree 4 | 5 | def test_xpath(): 6 | import xml.etree.ElementTree as ET 7 | 8 | root = ET.fromstring('') 9 | 10 | # Top-level elements 11 | print(len(root.findall("//node"))) 12 | 13 | def test_lxml(): 14 | 15 | text = ''' 16 |
17 | 24 |
25 | ''' 26 | html = etree.HTML(text) 27 | print(html) 28 | print(len(html.xpath("//ul"))) 29 | 30 | def test_encode(): 31 | page_source=""" 32 | 33 | """ 34 | print(etree.HTML(page_source)) -------------------------------------------------------------------------------- /testcase/test_xueqiu.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from time import sleep 3 | 4 | from appium.webdriver.common.mobileby import MobileBy 5 | from appium.webdriver.common.touch_action import TouchAction 6 | from selenium.webdriver.support.wait import WebDriverWait 7 | from selenium.webdriver.support import expected_conditions 8 | 9 | from page.search import Search 10 | from driver.Appium import Appium 11 | from page.xueqiu import Xueqiu 12 | 13 | 14 | class TestXueqiu(unittest.TestCase): 15 | 16 | def setUp(self): 17 | Appium.initDriver() 18 | print(Appium.driver) 19 | 20 | def test_search(self): 21 | assert Xueqiu().toSearch().search("pdd").getStocks() == "拼多多" 22 | 23 | def test_search_username(self): 24 | assert Xueqiu()\ 25 | .toSearch()\ 26 | .search("seveniruby")\ 27 | .getUserName() == "seveniruby" 28 | 29 | 30 | 31 | 32 | 33 | 34 | --------------------------------------------------------------------------------