Metadata-Version: 2.4
Name: qa-insight
Version: 1.0.0
Summary: Official QA Insight SDK for Python. Sends test run events (pytest, Robot Framework, behave) to the QA Insight Collector without changing your tests.
Author-email: QA Insight <qainsight.io@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/QA-Insight/qa-insight
Project-URL: Repository, https://github.com/QA-Insight/qa-insight
Project-URL: Bug Tracker, https://github.com/QA-Insight/qa-insight/issues
Keywords: qa,testing,playwright,selenium,pytest,robot,behave,observability
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: pytest
Requires-Dist: pytest>=7.0; extra == "pytest"
Provides-Extra: robot
Requires-Dist: robotframework>=6.0; extra == "robot"
Provides-Extra: behave
Requires-Dist: behave>=1.2.6; extra == "behave"
Provides-Extra: examples
Requires-Dist: pytest>=7.0; extra == "examples"
Requires-Dist: pytest-playwright>=0.4; extra == "examples"
Requires-Dist: playwright>=1.30; extra == "examples"
Requires-Dist: selenium>=4.10; extra == "examples"
Requires-Dist: robotframework>=6.0; extra == "examples"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Dynamic: license-file

# qa-insight (Python SDK)

SDK oficial de [QA Insight](https://github.com/QA-Insight/qa-insight) para **Python**.

Envía automáticamente el ciclo de vida de tus pruebas (inicio/fin de ejecución y de tests) al **Collector** de QA Insight, sin modificar tus tests. Compatible con **pytest** (incluido Selenium WebDriver 4 y Playwright), **Robot Framework**, **behave** (BDD) y un **importador de JUnit XML** post-run.

- **Cero dependencias runtime** (solo stdlib: `urllib`, `threading`, `queue`, `subprocess`, `re`). Las integraciones (pytest, robotframework, behave) son dependencias opcionales.
- Python **3.9+**.
- Nunca altera el resultado de tus pruebas; si el Collector no responde, registra una advertencia y continúa.

## Instalación

```bash
pip install -e .            # desde el repo (desarrollo)
pip install -e ".[examples]" # con pytest + Playwright + Selenium + Robot para los ejemplos
```

## Configuración por variables de entorno

| Variable | Default | Descripción |
|---|---|---|
| `QAI_ENDPOINT` | `http://localhost:3000/collector/v1/events` | URL del Collector de QA Insight |
| `QAI_API_KEY` | — | API key de QA Insight (proyecto + ambiente) |
| `QAI_ENABLED` | `true` | `false` desactiva el envío |
| `QAI_TIMEOUT_MS` | `2000` | Timeout por request HTTP |
| `QAI_RETRY_MAX` | `3` | Reintentos para errores transitorios (5xx, 429, red) |
| `QAI_FLUSH_TIMEOUT_MS` | `5000` | Máximo de espera del flush al terminar |
| `QAI_RUN_NAME` | `python-run-<ts>` | Nombre de la ejecución |
| `QAI_RUN_ID` | UUID generado | `externalRunId` (idempotencia del run) |
| `QAI_FRAMEWORK` | `pytest`/`robot`/`behave`/`junit` | Framework reportado a la columna framework |
| `QAI_BROWSER` | — | Browser/proyecto (chromium, firefox, webkit, chrome, ...) |

## pytest

El plugin se auto-registra (entry point `pytest11`). Solo necesitas las variables de entorno:

```bash
export QAI_ENDPOINT=http://localhost:3000/collector/v1/events
export QAI_API_KEY=qai_...
export QAI_FRAMEWORK=playwright   # o selenium, o pytest
pytest
```

- `pytest_sessionstart` → `RUN_STARTED`
- Cada test → `TEST_STARTED` / `TEST_FINISHED` (con `retryIndex` si usás `pytest-rerunfailures`)
- `pytest_sessionfinish` → `RUN_FINISHED`
- Los tests parametrizados generan nodeids únicos → no colapsan en el backend.

Para reportar el browser por test (badges de browser en la UI), setealos en un `conftest.py`:

```python
# conftest.py (Playwright)
import pytest
from qa_insight import QaiContext

@pytest.fixture(autouse=True)
def qai_browser(browser):
    QaiContext.set_browser(browser.browser_type.name)
```

```python
# conftest.py (Selenium 4)
import pytest
from qa_insight import QaiContext

@pytest.fixture
def driver():
    from selenium import webdriver
    d = webdriver.Chrome()  # Selenium Manager descarga el driver automáticamente
    QaiContext.set_webdriver(d)
    yield d
    d.quit()
```

El plugin resuelve el browser en este orden: `QaiContext.browser` → `QAI_BROWSER` → capabilities del `QaiContext.webdriver`.

### Cross-browser

- **Playwright**: `pytest --browser chromium --browser firefox --browser webkit` (cada browser genera su ejecución con sus badges).
- **Selenium 4**: `pytest --selenium-browser chrome` / `pytest --selenium-browser firefox` (ver ejemplo).
- **Robot Framework**: exporta `QAI_BROWSER=chrome|firefox` al correr con `--variable BROWSER:...`.

## Robot Framework

El SDK incluye un **library listener** (`QaiInsightLibrary`) que se auto-registra, de modo que no hace falta
pasar `--listener` en la línea de comandos. Solo importá la librería (idealmente en un resource compartido):

```robotframework
*** Settings ***
Library    qa_insight.robot_library.QaiInsightLibrary
```

Al importarse, la librería carga el `.env` del proyecto, emite `RUN_STARTED`, registra el listener para
toda la ejecución (tags, suites, tests específicos o archivos individuales) y, al terminar, emite
`RUN_FINISHED` de forma garantizada vía su método `close()`.

Configuración vía `.env` (sin necesidad de `export`):

```bash
QAI_API_KEY=qai_...
QAI_ENDPOINT=http://localhost:3000/collector/v1/events
QAI_FRAMEWORK=robot
QAI_BROWSER=chrome   # opcional: badges de browser + Open Browser de SeleniumLibrary
HEADLESS=True        # opcional: modo headless/visible del navegador
```

Ejecutá tus tests como siempre:

```bash
robot tests/                     # todo
robot --include smoke tests/     # por tags
robot --suite my_suite tests/    # por suite
robot --test "my test" tests/    # por test
```

> Alternativa (CLI listener): `robot --listener qa_insight.robot_listener.QaiInsightListener tests/`

## behave (BDD)

```python
# features/environment.py
from qa_insight.behave_env import *  # noqa
```

## Importador de JUnit XML (post-run)

```bash
export QAI_API_KEY=qai_...
qa-insight-import junit.xml --framework pytest
# o para cualquier framework que emita JUnit XML
```

## Uso manual / sin runner

```python
from qa_insight import QaiInsight

insight = QaiInsight({"api_key": "qai_...", "framework": "selenium"})
insight.start_run()
insight.start_test("test_login", suite="tests/test_auth.py")
insight.finish_test("test_login", suite="tests/test_auth.py", status="PASSED", duration_ms=1200)
insight.finish_run()
```

## Comportamiento ante fallos de red

- Buffer no bloqueante en un hilo de fondo + flush acotado (`QAI_FLUSH_TIMEOUT_MS`) al terminar.
- Errores transitorios (timeout, red, 5xx, 429) se reintentan con backoff exponencial (50 ms·2^n, cap 1 s).
- Errores permanentes (4xx) no se reintentan.
- La API key **nunca** se imprime ni se incluye en los payloads; `errorMessage`/`stacktrace` se redactan antes de enviar (authorization, bearer, cookie, password, secret, api-key, token, `qai_`, `xox*` + literales custom).
- Payload limitado a 100 KB (se trunca el stacktrace si excede).

## Desarrollo

```bash
pip install -e ".[dev]"
ruff check src tests
pytest
```

## Licencia

MIT
