appium-python-client-shadowstep


Nameappium-python-client-shadowstep JSON
Version 0.16.43 PyPI version JSON
download
home_pageNone
SummaryUI Testing Framework powered by Appium Python Client
upload_time2025-04-29 14:41:37
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseNone
keywords appium testing uiautomator2 android automation framework
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 📱 Shadowstep (in development)

> Powerful and resilient Appium-based framework for Android UI automation.

[![PyPI](https://img.shields.io/pypi/v/appium-python-client-shadowstep?color=brightgreen)](https://pypi.org/project/appium-python-client-shadowstep/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/molokov-klim/Appium-Python-Client-Shadowstep/blob/main/LICENSE)

![Shadowstep – inspired](https://hearthstone.wiki.gg/images/b/b0/EX1_144.png?6a192d=&format=original)

> [**Shadowstep**](https://www.twitch.tv/packetoff), step into the shadows and build your way
---

## 🔍 Overview
**Shadowstep** is an open-source framework, battle-tested and evolving.
It introduces powerful abstractions for Android testing: dynamic element wrappers, retry logic, visual change detection, and custom ADB terminal integration.

---

## ✨ Features

- 📲 **Robust UI Automation** – with custom `Element` class and retryable tap/click logic
- 🔁 **Automatic Session Recovery** – handles `NoSuchDriver`, `InvalidSessionId`, and reconnects
- 🎯 **Dict-to-XPath Locator DSL** – write intuitive locators like `{"class": "TextView", "text": "OK"}`
- 🎥 **Video + Screenshot Reporting** – Allure integration with visual context for failed steps
- 📷 **Visual DOM/Window Waits** – wait for or detect screen changes by screenshot diffs
- 👤 **Direct ADB Access** – push/pull/install/uninstall/interact with device via custom ADB wrapper
- 🧱 **Testable Components** – override every interaction and build new ones with ease

---

## 🚀 Quickstart

### 1. 📦 Installation

```bash
pip install appium-python-client-shadowstep
```

---

### 2. ⚙️ Integration via Composition

> ⚠️ Do **not** inherit from `Shadowstep` directly. Use composition to preserve singleton behavior.

```python
from shadowstep.shadowstep import Shadowstep

class ExamplePlatform:
    def __init__(self):
        self.app = Shadowstep.get_instance()

    def __getattr__(self, item):
        return getattr(self.app, item)
```

---

## 📚 PageObject Navigator

### ✅ Requirements for Shadowstep Pages (Auto-discovery)

### 📦 1. File Location
- Must reside in a directory named `pages`
- Filename must start with `page` and end with `.py`

> Example: `applications/android_settings/android_settings_7/pages/page_main/page_main.py`

### 🧩 2. Class Name
- Must start with `Page`, e.g. `PageMain7`

### 🧬 3. Inheritance
- Must inherit from `PageBase`:

```python
from shadowstep.page_base import PageBaseShadowstep


class PageMain7(PageBaseShadowstep): ...
```

### 🧠 4. Required: `edges` Property
Each page must define:

```python
@property
def edges(self) -> Dict[str, Callable[[], PageBase]]:   # bullshit, typing here no needed
    return {
        "PageWifi7": self.to_wifi
    }
```

Used by the navigation system to build the screen transition graph.

### 🔄 5. Navigation Methods
- Methods listed in `edges` must:
  - trigger interaction (e.g. `tap()`)
  - return the corresponding Page instance via `self.app.get_page(...)`

```python
def to_wifi(self) -> PageBase:
    self.wifi.tap()
    return self.app.get_page("PageWifi7")
```

### 🌐 6. Auto-discovery Mechanism

The `Shadowstep._auto_discover_pages()` method:

- Iterates over all paths in `sys.path`
- Looks for directories named `pages`
- Skips ignored folders (e.g. `__pycache__`, `venv`, etc.)
- Imports every module with a filename starting with `page`
- Registers each class that:
  - starts with `Page`
  - is a subclass of `PageBase`
  - is **not** the base class itself
- Stores them in `self.pages`
- Adds them to the `PageNavigator`

---

## 📄 Example Page Class

```python
from shadowstep.page_base import PageBaseShadowstep
from shadowstep.element.element import Element
from typing import Dict, Callable


class PageExample(PageBaseShadowstep):
  @property
  def edges(self) -> Dict[str, Callable[[], PageBaseShadowstep]]:
    return {"PageNext": self.to_next}

  def to_next(self) -> PageBaseShadowstep:
    self.next_button.tap()
    return self.app.get_page("PageNext")

  @property
  def next_button(self) -> Element:
    return self.app.get_element(locator={"text": "Next"})
```

---

## 🔮 Example Test

```python
def test_wifi_navigation(example_platform: ExamplePlatform):
    page = example_platform.get_page("PageMain7")
    assert page.is_current_page()

    wifi_page = page.to_wifi()
    assert wifi_page.is_current_page()
```

---

## 🔧 Under the Hood
- Supports retry logic with session recovery
- Lazy element evaluation until interaction
- ADB integration via custom wrapper
- Navigator auto-registers page transitions as a graph

---

## 🚫 Limitations
- Currently Android-only
- Web support not implemented
- Visual detection (image matching) WIP

---

## ✍️ Contributing
We welcome pull requests! Please open an issue before submitting large changes.

---

## ⚖️ License
[MIT License](LICENSE)


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "appium-python-client-shadowstep",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "appium, testing, uiautomator2, android, automation, framework",
    "author": null,
    "author_email": "Klim Molokov <klim.molokov@yandex.ru>",
    "download_url": "https://files.pythonhosted.org/packages/fa/3e/6aa8d160e72c6367f307c9ac5e42df10150133b74a3210271d3502430926/appium_python_client_shadowstep-0.16.43.tar.gz",
    "platform": null,
    "description": "# \ud83d\udcf1 Shadowstep (in development)\n\n> Powerful and resilient Appium-based framework for Android UI automation.\n\n[![PyPI](https://img.shields.io/pypi/v/appium-python-client-shadowstep?color=brightgreen)](https://pypi.org/project/appium-python-client-shadowstep/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/molokov-klim/Appium-Python-Client-Shadowstep/blob/main/LICENSE)\n\n![Shadowstep \u2013 inspired](https://hearthstone.wiki.gg/images/b/b0/EX1_144.png?6a192d=&format=original)\n\n> [**Shadowstep**](https://www.twitch.tv/packetoff), step into the shadows and build your way\n---\n\n## \ud83d\udd0d Overview\n**Shadowstep** is an open-source framework, battle-tested and evolving.\nIt introduces powerful abstractions for Android testing: dynamic element wrappers, retry logic, visual change detection, and custom ADB terminal integration.\n\n---\n\n## \u2728 Features\n\n- \ud83d\udcf2 **Robust UI Automation** \u2013 with custom `Element` class and retryable tap/click logic\n- \ud83d\udd01 **Automatic Session Recovery** \u2013 handles `NoSuchDriver`, `InvalidSessionId`, and reconnects\n- \ud83c\udfaf **Dict-to-XPath Locator DSL** \u2013 write intuitive locators like `{\"class\": \"TextView\", \"text\": \"OK\"}`\n- \ud83c\udfa5 **Video + Screenshot Reporting** \u2013 Allure integration with visual context for failed steps\n- \ud83d\udcf7 **Visual DOM/Window Waits** \u2013 wait for or detect screen changes by screenshot diffs\n- \ud83d\udc64 **Direct ADB Access** \u2013 push/pull/install/uninstall/interact with device via custom ADB wrapper\n- \ud83e\uddf1 **Testable Components** \u2013 override every interaction and build new ones with ease\n\n---\n\n## \ud83d\ude80 Quickstart\n\n### 1. \ud83d\udce6 Installation\n\n```bash\npip install appium-python-client-shadowstep\n```\n\n---\n\n### 2. \u2699\ufe0f Integration via Composition\n\n> \u26a0\ufe0f Do **not** inherit from `Shadowstep` directly. Use composition to preserve singleton behavior.\n\n```python\nfrom shadowstep.shadowstep import Shadowstep\n\nclass ExamplePlatform:\n    def __init__(self):\n        self.app = Shadowstep.get_instance()\n\n    def __getattr__(self, item):\n        return getattr(self.app, item)\n```\n\n---\n\n## \ud83d\udcda PageObject Navigator\n\n### \u2705 Requirements for Shadowstep Pages (Auto-discovery)\n\n### \ud83d\udce6 1. File Location\n- Must reside in a directory named `pages`\n- Filename must start with `page` and end with `.py`\n\n> Example: `applications/android_settings/android_settings_7/pages/page_main/page_main.py`\n\n### \ud83e\udde9 2. Class Name\n- Must start with `Page`, e.g. `PageMain7`\n\n### \ud83e\uddec 3. Inheritance\n- Must inherit from `PageBase`:\n\n```python\nfrom shadowstep.page_base import PageBaseShadowstep\n\n\nclass PageMain7(PageBaseShadowstep): ...\n```\n\n### \ud83e\udde0 4. Required: `edges` Property\nEach page must define:\n\n```python\n@property\ndef edges(self) -> Dict[str, Callable[[], PageBase]]:   # bullshit, typing here no needed\n    return {\n        \"PageWifi7\": self.to_wifi\n    }\n```\n\nUsed by the navigation system to build the screen transition graph.\n\n### \ud83d\udd04 5. Navigation Methods\n- Methods listed in `edges` must:\n  - trigger interaction (e.g. `tap()`)\n  - return the corresponding Page instance via `self.app.get_page(...)`\n\n```python\ndef to_wifi(self) -> PageBase:\n    self.wifi.tap()\n    return self.app.get_page(\"PageWifi7\")\n```\n\n### \ud83c\udf10 6. Auto-discovery Mechanism\n\nThe `Shadowstep._auto_discover_pages()` method:\n\n- Iterates over all paths in `sys.path`\n- Looks for directories named `pages`\n- Skips ignored folders (e.g. `__pycache__`, `venv`, etc.)\n- Imports every module with a filename starting with `page`\n- Registers each class that:\n  - starts with `Page`\n  - is a subclass of `PageBase`\n  - is **not** the base class itself\n- Stores them in `self.pages`\n- Adds them to the `PageNavigator`\n\n---\n\n## \ud83d\udcc4 Example Page Class\n\n```python\nfrom shadowstep.page_base import PageBaseShadowstep\nfrom shadowstep.element.element import Element\nfrom typing import Dict, Callable\n\n\nclass PageExample(PageBaseShadowstep):\n  @property\n  def edges(self) -> Dict[str, Callable[[], PageBaseShadowstep]]:\n    return {\"PageNext\": self.to_next}\n\n  def to_next(self) -> PageBaseShadowstep:\n    self.next_button.tap()\n    return self.app.get_page(\"PageNext\")\n\n  @property\n  def next_button(self) -> Element:\n    return self.app.get_element(locator={\"text\": \"Next\"})\n```\n\n---\n\n## \ud83d\udd2e Example Test\n\n```python\ndef test_wifi_navigation(example_platform: ExamplePlatform):\n    page = example_platform.get_page(\"PageMain7\")\n    assert page.is_current_page()\n\n    wifi_page = page.to_wifi()\n    assert wifi_page.is_current_page()\n```\n\n---\n\n## \ud83d\udd27 Under the Hood\n- Supports retry logic with session recovery\n- Lazy element evaluation until interaction\n- ADB integration via custom wrapper\n- Navigator auto-registers page transitions as a graph\n\n---\n\n## \ud83d\udeab Limitations\n- Currently Android-only\n- Web support not implemented\n- Visual detection (image matching) WIP\n\n---\n\n## \u270d\ufe0f Contributing\nWe welcome pull requests! Please open an issue before submitting large changes.\n\n---\n\n## \u2696\ufe0f License\n[MIT License](LICENSE)\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "UI Testing Framework powered by Appium Python Client",
    "version": "0.16.43",
    "project_urls": {
        "Repository": "https://github.com/molokov-klim/Appium-Python-Client-Shadowstep"
    },
    "split_keywords": [
        "appium",
        " testing",
        " uiautomator2",
        " android",
        " automation",
        " framework"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "aa0c0fc434b4b241d6539a2aa6d7a8071adfaca9bfb369b27d5c791b18a3c99e",
                "md5": "538f16f915d396302ddf67da14277507",
                "sha256": "d888ef139793de462c44a9a17e058065bbb051366d0b3f864e6412f7bc1dc3f4"
            },
            "downloads": -1,
            "filename": "appium_python_client_shadowstep-0.16.43-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "538f16f915d396302ddf67da14277507",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 96164,
            "upload_time": "2025-04-29T14:41:36",
            "upload_time_iso_8601": "2025-04-29T14:41:36.162014Z",
            "url": "https://files.pythonhosted.org/packages/aa/0c/0fc434b4b241d6539a2aa6d7a8071adfaca9bfb369b27d5c791b18a3c99e/appium_python_client_shadowstep-0.16.43-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "fa3e6aa8d160e72c6367f307c9ac5e42df10150133b74a3210271d3502430926",
                "md5": "0b6b52040985910c53c3b6f70c29b29b",
                "sha256": "a8159e1e45e5692e09a1e33c930d452a86540261ed44fefbe5a3438a3ce7ec36"
            },
            "downloads": -1,
            "filename": "appium_python_client_shadowstep-0.16.43.tar.gz",
            "has_sig": false,
            "md5_digest": "0b6b52040985910c53c3b6f70c29b29b",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 90372,
            "upload_time": "2025-04-29T14:41:37",
            "upload_time_iso_8601": "2025-04-29T14:41:37.451102Z",
            "url": "https://files.pythonhosted.org/packages/fa/3e/6aa8d160e72c6367f307c9ac5e42df10150133b74a3210271d3502430926/appium_python_client_shadowstep-0.16.43.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-04-29 14:41:37",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "molokov-klim",
    "github_project": "Appium-Python-Client-Shadowstep",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "appium-python-client-shadowstep"
}
        
Elapsed time: 0.56103s