diff --git a/README.md b/README.md index b2fd4f9..f69ed59 100644 --- a/README.md +++ b/README.md @@ -37,18 +37,37 @@ prepare remote adb connection and starts appium server that tests could utilize ## Usage example Test script: sample.py + ```python -def test_create(selected_phone): - device, adb, appium = selected_phone + +from appium.webdriver.webdriver import WebDriver + + +def test_create(appium_client): + client, appium, adb, phone = appium_client # device is dictionary of device metadata # adb: AdbServer instance, that is already connected # appium: AppiumServer instance that provide server address for appium client - print(device) - print(f'wd_hub: {appium.get_wd_hub_uri()}') + print(phone) + print(f'wd_hub: {appium.get_api_path()}') + client: WebDriver + client, *_ = appium_client + URL = 'https://google.com' + client.get(URL) + url = client.current_url + assert url == URL, 'Wrong URL' ``` Execution ``` > pytest sample/test_samples.py --stf_host localhost --stf_token $TOKEN --phone_requirements platform=Android ``` + + +See more examples from [sample/test_samples.py](sample/test_samples.py). + +custom capabilities: +``` +> pytest --appium_capabilities cab=val1&cab=val2 +``` diff --git a/pytest_stf/plugin.py b/pytest_stf/plugin.py index 19ae3b0..118409e 100644 --- a/pytest_stf/plugin.py +++ b/pytest_stf/plugin.py @@ -1,9 +1,11 @@ import os import pytest -from stf_appium_client import StfClient +from stf_appium_client.StfClient import StfClient from stf_appium_client.tools import parse_requirements from stf_appium_client.AdbServer import AdbServer -from stf_appium_client.Appium import Appium +from stf_appium_client.AppiumServer import AppiumServer +from stf_appium_client.AppiumClient import AppiumClient +from appium.webdriver.webdriver import WebDriver def pytest_addoption(parser): @@ -29,9 +31,13 @@ def pytest_addoption(parser): ) group.addoption( "--stf_allocation_timeout", - default=10, + default=1000, help="Allocation timeout", ) + group.addoption( + "--appium_capabilities", + help="Appium capabilities" + ) def pytest_configure(config): @@ -58,11 +64,28 @@ def pytest_unconfigure(config): del config._openstf # pylint: disable=protected-access -@pytest.fixture(name="selected_phone", scope="session") -def fixture_selected_phone(pytestconfig): +@pytest.fixture(name='allocated_phone', scope="session") +def fixture_allocated_phone(pytestconfig): """ - Allocate required phone, create ADB tunnel to phone via STF and start appium server for tests. - Yields tuple (device: dict, adb: AdbServer, appium: Appium) + Allocate required phone via STF. + Yields device details as dict. + e.g. + { + "abi": "arm64-v8a", + "airplaneMode": false, + "battery": {...}, + "browser": {...}, + "cpuPlatform": "...", + "manufacturer": "...", + "marketName": "Pixel 4", + "model": "Pixel 4", + "network": {...}, + "platform": "Android", + "sdk": "32", + "serial": "...", + "version": "12", + ... + } """ assert hasattr(pytestconfig, '_openstf'), 'stf_host or stf_token missing' @@ -74,6 +97,53 @@ def fixture_selected_phone(pytestconfig): requirements = parse_requirements(requirements) with stf.allocation_context(requirements, timeout_seconds=timeout) as device: - with AdbServer(device['remote_adb_url']) as adb: - with Appium() as appium: - yield device, adb, appium + yield device + + +@pytest.fixture(name='phone_with_adb', scope="session") +def fixture_phone_with_adb(allocated_phone): + """ + Allocate required phone and create ADB tunnel to phone via STF. + Yields tuple (adb: AdbServer, device: dict) + """ + with AdbServer(allocated_phone['remote_adb_url']) as adb: + yield adb, allocated_phone + + +@pytest.fixture(name='appium_args', scope='session') +def fixture_appium_args(): + # overridable list of appium server args + return [] + +@pytest.fixture(name="appium_server", scope="session") +def fixture_appium_server(phone_with_adb, appium_args): + """ + Allocate required phone, create ADB tunnel to phone via STF and start appium server for tests. + Yields tuple (appium: Appium, adb: AdbServer, device: dict ) + """ + adb, phone = phone_with_adb + with AppiumServer(appium_args) as appium: + yield appium, adb, phone + + +@pytest.fixture(name='capabilities', scope='session') +def fixture_capabilities(pytestconfig, allocated_phone): + kwargs = { + "desired_capabilities": { + 'platformName': allocated_phone['platform'] + } + } + extra_capabilities = pytestconfig.getoption('appium_capabilities') + if extra_capabilities: + extra_capabilities = parse_requirements(extra_capabilities) + kwargs['desired_capabilities'].update(extra_capabilities) + yield kwargs + + +@pytest.fixture(name="appium_client", scope="session") +def fixture_appium_client(appium_server, capabilities): + appium, adb, phone = appium_server + client = AppiumClient(command_executor=appium.get_api_path(), **capabilities) + with client as driver: + driver: WebDriver + yield driver, appium, adb, phone diff --git a/sample/test_samples.py b/sample/test_samples.py index 7e51469..4958616 100644 --- a/sample/test_samples.py +++ b/sample/test_samples.py @@ -1,4 +1,66 @@ -def test_create(selected_phone): - device, adb, appium = selected_phone - print(device) - print(f'wd_hub: {appium.get_wd_hub_uri()}') +import pytest +from appium.webdriver.webdriver import WebDriver + +from stf_appium_client import AppiumServer, AdbServer + + +def test_allocated_phone(allocated_phone: dict): + # allocated_phone is dictionary of phone metadata + print(allocated_phone) + + +def test_adb(phone_with_adb): + # allocated phone with adb proxy + adb, phone = phone_with_adb + adb: AdbServer + response = adb._execute('shell getprop ro.build.version.release', 10) + assert response.stdout == phone.get('version'), 'Wrong Android version' + + +def test_appium(appium_server): + # allocated phone with adb and appium server + appium, adb, phone = appium_server + appium: AppiumServer + print(f'wd_hub: {appium.get_api_path()}') + + +@pytest.fixture(scope='session') +def fixture_capabilities(pytestconfig): + values = pytestconfig.getoption('appium_capabilities') + + +@pytest.fixture(name='appium_args', scope='session') +def fixture_appium_args(): + # overridable list of appium server args + # https://appium.io/docs/en/writing-running-appium/server-args/ + return [] + + +@pytest.fixture(name='capabilities', scope='session') +def fixture_capabilities(pytestconfig, allocated_phone): + # Allows to overwrite WebDriver arguments + # Under the hoods these are used like `WebDriver(**kwargs)` + kwargs = { + "desired_capabilities": { + 'platformName': allocated_phone['platform'], + #'udid': '', #allocated_phone['serial'], + 'automationName': 'UiAutomator2', + 'browserName': 'Chrome', + } + } + yield kwargs + + +def test_client(appium_client): + # allocated phone with adb+appium server + appium client (WebDriver) + driver, appium, adb, phone = appium_client + + # adb: AdbServer instance, that is already connected + # appium: AppiumServer instance that provide server address for appium client + # + driver: WebDriver + test_url = 'https://www.google.com/' + + driver.get(test_url) + url = driver.current_url + assert url == test_url, 'Wrong URL' diff --git a/setup.py b/setup.py index e6b7975..d7650ad 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ install_requires=[ "pytest>=5.0", "pytest-metadata", - "stf-appium-client==0.7.0"], + "stf-appium-client==0.9.0"], # List additional groups of dependencies here (e.g. development # dependencies). Users will be able to install these using the "extras" # syntax, for example: