Metadata-Version: 2.4
Name: snakeoil-web
Version: 0.1.21
Summary: Plain English web test automation using Selenium and Playwright. No code. No maintenance.
License: MIT
Project-URL: Homepage, https://github.com/snakeoiltool/snakeoil-web
Keywords: testing,automation,plain-english,selenium,playwright,web
Classifier: Development Status :: 1 - Planning
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: playwright>=1.40.0
Requires-Dist: pytest-html>=4.0.0

# snakeoil-web

[![PyPI version](https://badge.fury.io/py/snakeoil-web.svg)](https://pypi.org/project/snakeoil-web/)
[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**Selector-free, self-healing web test automation.**

No XPaths. No CSS selectors. No waiting. Tests that describe what users see, not how developers built it.

---

## Install

```bash
pip install snakeoil-web
```

---

## Your first test

```python
from snakeoil_web import WebAgent

agent = WebAgent()
agent.click("Sign in")
agent.type("harish@example.com", into="Email")
agent.type("password123", into="Password")
agent.click("Sign in")
agent.verify_text("Dashboard")
```

That's it. No selectors. No waits. No maintenance.

---

## Why snake-oil?

Most test automation breaks when a developer renames a CSS class or moves an element.
**snakeoil-web** finds elements by what users actually see — visible text, labels, and
position on screen — not by how the DOM is built.

```python
# Selenium — breaks when developer renames the class
driver.find_element(By.XPATH, '//button[@data-testid="login-btn"]').click()

# snakeoil-web — works regardless of how the DOM changes
agent.click("Sign in")
```

When the DOM changes, your tests don't.

---

## Two ways to write tests

**Pythonic — IDE guided, autocomplete friendly:**
```python
agent = WebAgent()
agent.click("Sign in")
agent.type("harish@example.com", into="Email")
agent.verify_text("Dashboard")
```

**English — human readable, shareable with non-developers:**
```python
agent = WebAgent()
agent.run([
    'click "Sign in"',
    'type "harish@example.com" into "Email"',
    'verify text "Dashboard" is present',
])
```

---

## Using variables

**Pythonic — pass variables directly:**
```python
email    = "harish@example.com"
password = "secret123"

agent.type(email, into="Email")
agent.type(password, into="Password")
agent.click("Sign in")
```

**English — embed variables with f-strings:**
```python
email    = "harish@example.com"
password = "secret123"

agent.run([
    f'type "{email}" into "Email"',
    f'type "{password}" into "Password"',
    'click "Sign in"',
])
```

---

## Mix Pythonic and English freely

Use whichever style fits each step — they work together in the same test:

```python
from snakeoil_web import WebAgent

# Get test data from your API
user = api.create_test_user()

agent = WebAgent()

# English for readable setup steps
agent.run([
    'click "Sign in"',
    f'type "{user.email}" into "Email"',
    f'type "{user.password}" into "Password"',
    'click "Sign in"',
])

# Pythonic for assertions — IDE helps you get it right
agent.verify_text("Dashboard")
balance = agent.extract_text(next_to="Balance")

# Back to Python for logic
assert balance == user.expected_balance

# English for teardown
agent.run([
    'click "Settings"',
    'click "Sign out"',
])
```

---

## Spatial targeting

No visible text on that icon button? Use its position instead.

```python
agent.click("button", below="Total Price")
agent.click("icon", next_to="Search")
agent.click("button", index=2)
agent.extract_text(next_to="Balance")
agent.verify_text("$0.00", next_to="Balance")
```

---

## Mix with Python

Use Python for data setup, snakeoil for the UI steps.

```python
from snakeoil_web import WebAgent

user = api.create_test_user()

agent = WebAgent()
agent.type(user.email, into="Email")
agent.type(user.password, into="Password")
agent.click("Sign in")
agent.verify_text("Dashboard")

balance = agent.extract_text(next_to="Balance")
assert balance == user.expected_balance
```

---

## Quick start with pytest

```bash
pip install snakeoil-web
snakeoil init
pytest web-tests/
```

`snakeoil init` creates everything — config, conftest, sample tests, installs pytest and pytest-html. Results saved to `report.html`.

---

## pytest integration

```python
# web-tests/test_checkout.py

username = "standard_user"
password = "secret_sauce"

def test_login(agent):
    agent.run([
        f'type "{username}" into "Username"',
        f'type "{password}" into "Password"',
        'click "Login"',
        'verify text "Products" is present',
    ])

def test_add_to_cart(agent):
    agent.type(username, into="Username")
    agent.type(password, into="Password")
    agent.click("Login")
    agent.click("Add to cart")
    agent.verify_text("1")
```

Each test gets its own isolated browser session. `verify_*` failures raise `AssertionError` — pytest handles reporting.

---

## Configuration

`snakeoil.web.config.py` in your project root:

```python
URL        = "https://yourapp.com"
BROWSER    = "chromium"   # chromium | firefox | webkit | msedge
HEADLESS   = False
MAXIMIZED  = True
TIMEOUT    = 30_000       # milliseconds
RESULT_DIR = "."          # where report.html is saved
```

---

## Supported browsers

| Browser | Support |
|---|---|
| Chrome / Chromium | ✅ |
| Firefox | ✅ |
| Safari / WebKit | ✅ |
| Edge | ✅ |

---

## Related packages

- [snakeoil-mobile](https://pypi.org/project/snakeoil-mobile/) — Mobile browser automation on real Android and iOS devices
- [snakeoil-native](https://pypi.org/project/snakeoil-native/) — Native app automation for Android and iOS

---

## Status

Early development. Feedback and contributions welcome.

[GitHub](https://github.com/harish2323/snakeoil) · [PyPI](https://pypi.org/project/snakeoil-web/)
