Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,5 @@
load_dotenv=True,
envvar_prefix="APPIUM",
env_switcher="ENV_FOR_APPIUM",
dotenv_path="configs/.env", # Enable env switcher
dotenv_path="configs/.env", # Enable env switcher
)


print(settings.APPIUM_SERVER)
18 changes: 11 additions & 7 deletions config/settings.yaml
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
default:
DEBUG: True
APPIUM_SERVER: "http://localhost:4723/wd/hub"

stage:
DEBUG: True
APPIUM_SERVER: "http://stage-address:4723/wd/hub"
APPIUM_SERVER: "http://127.0.0.1:4723/wd/hub"
ANDROID:
platformName: "Android"
deviceName: "emulator"
app: ""
platformVersion: "15"
newCommandTimeout: 3000
autoGrantPermissions: True
appWaitForLaunch: True
maxRetryCount: 40
noReset: True
appWaitDuration: 30000
appPackage: "io.appium.android.apis"
appActivity: "io.appium.android.apis.ApiDemos"
automationName: "uiautomator2"

IOS:
platformName: "iOS"
deviceName: "iPhone 14"
bundleId: "com.example.app"
bundleId: "ua.com.test.app"
automationName: "XCUITest"

prod:
Expand Down
60 changes: 60 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,0 +1,60 @@
import pytest

from drivers.driver_factory import Driver


@pytest.hookimpl
def pytest_addoption(parser):
"""
Adds command-line options for pytest.
"""
parser.addoption(
"--app", action="store", default="ios", help="Define App: ios or android"
)
parser.addoption(
"--device", action="store", default="emulator", help="Define Device Type"
)
parser.addoption(
"--platform", action="store", default="ios", help="Define Platform"
)
parser.addoption(
"--env",
action="store",
default="stage",
help="Define test environment (e.g., stage, prod)",
)
parser.addoption(
"--listeners",
action="store",
default="events",
help="Define listeners for the test run",
)


@pytest.fixture(scope="session")
def app(request):
"""
Retrieves the application type specified via the --app command-line option.
"""
return request.config.getoption("--app")


@pytest.fixture(scope="session")
def device(request):
"""
Retrieves the device type specified via the --device command-line option.
"""
return request.config.getoption("--device")


@pytest.fixture(scope="function")
def driver(request):
platform = request.config.getoption("--platform")
try:
driver = Driver.get_driver(platform)
except Exception as e:
pytest.fail(f"Failed to initialize driver: {e}")

yield driver

Check warning on line 58 in conftest.py

View workflow job for this annotation

GitHub Actions / Qodana Community for Python

Unbound local variables

Local variable 'driver' might be referenced before assignment
if driver is not None:
driver.quit()

Check warning on line 60 in conftest.py

View workflow job for this annotation

GitHub Actions / Qodana Community for Python

Unbound local variables

Local variable 'driver' might be referenced before assignment
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ python = "^3.12"
pytest = "^8.3.4"
dynaconf = "^3.2.10"
requests = "^2.31"
pytest-asyncio = "^0.24.0"
pytest-html = "^4.1.1"
Appium-Python-Client = "^4.5.1"

Expand All @@ -28,8 +27,8 @@ requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.pytest.ini_options]
addopts = "-rA -v --env=stage --device-type=android --listeners=events --capture=no -p no:cacheprovider --html=../reports/test_report.html --self-contained-html"
#asyncio_mode = "auto"
addopts = "-rA -v --env=stage --platform=android --device=emulator --listeners=events --capture=no -p no:cacheprovider --html=../reports/test_report.html --self-contained-html"
asyncio_default_fixture_loop_scope = "function"
markers = [
{ name = "smoke", description = "run smoke tests" },
{ name = "regression", description = "run regression tests" }
Expand Down
2 changes: 1 addition & 1 deletion src/drivers/android_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from config import settings


class AndroidCaps:

Check notice on line 6 in src/drivers/android_driver.py

View workflow job for this annotation

GitHub Actions / Qodana Community for Python

Class has no `__init__` method

Class has no __init__ method
@staticmethod
def get_caps():
"""Generate and return Android capabilities, with adding dynamic 'app' path."""
Expand All @@ -12,6 +12,6 @@
if not caps:
raise ValueError("❌ ANDROID capabilities not found in settings.yaml")

caps["app"] = str(Path(__file__).resolve().parents[2] / "data/apps/app.apk")
caps["app"] = str(Path(__file__).resolve().parents[2] / "data/apps/demo.apk")

return caps
20 changes: 16 additions & 4 deletions src/drivers/driver_factory.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
from appium.options.android import UiAutomator2Options
from appium.options.ios import XCUITestOptions
from appium import webdriver

from config import settings
from src.drivers.android_driver import AndroidCaps
from drivers.android_driver import AndroidCaps
from drivers.ios_driver import IOSCaps


class Driver:

Check notice on line 10 in src/drivers/driver_factory.py

View workflow job for this annotation

GitHub Actions / Qodana Community for Python

Class has no `__init__` method

Class has no __init__ method
@staticmethod
def get_driver(platform: str):
"""Get driver by platform, uses appropriate capabilities for Android or iOS."""
caps = (
AndroidCaps.get_caps()
if platform.lower() == "android"
else IOSCaps.get_caps()
)

if not caps:
raise ValueError(f"Capabilities not found for platform ❌: {platform}")

if platform.lower() == "android":
caps = AndroidCaps.get_caps()
options = UiAutomator2Options().load_capabilities(caps)
else:
caps = settings.iOS.to_dict()
options = XCUITestOptions().load_capabilities(caps)

driver = webdriver.Remote(settings.APPIUM_SERVER, caps)
driver = webdriver.Remote(settings.APPIUM_SERVER, options=options)
return driver
16 changes: 12 additions & 4 deletions src/drivers/ios_driver.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
from appium.webdriver import webdriver
from pathlib import Path

from config import settings


class iOSDriver:
class IOSCaps:

Check notice on line 6 in src/drivers/ios_driver.py

View workflow job for this annotation

GitHub Actions / Qodana Community for Python

Class has no `__init__` method

Class has no __init__ method
@staticmethod
def get_driver(platform: str):
return settings.iOS.to_dict()
def get_caps():
"""Generate and return Android capabilities, with adding dynamic 'app' path."""
caps = settings.iOS.to_dict()

if not caps:
raise ValueError("❌ ANDROID capabilities not found in settings.yaml")

caps["app"] = str(Path(__file__).resolve().parents[2] / "data/apps/demo.ipa")

return caps
3 changes: 3 additions & 0 deletions tests/test_p1/test_p1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Test1:
def test_1(self, driver):
pass
Loading