test-api-x 0.3.0
Async API testing framework with pluggable authentication for Python 3.12+
License: MIT
Requires Python: >=3.12

# test-api-x

[![PyPI version](https://badge.fury.io/py/test-api-x.svg)](https://badge.fury.io/py/test-api-x)
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Tests](https://github.com/JamesPBrett/test-api-x/actions/workflows/test.yml/badge.svg)](https://github.com/JamesPBrett/test-api-x/actions/workflows/test.yml)
[![Coverage](https://img.shields.io/badge/coverage-96.50%25-brightgreen.svg)](https://github.com/JamesPBrett/test-api-x)

Async API testing framework with pluggable authentication for Python 3.12+

## Requirements

- Python 3.12 or higher
- Poetry 1.5+ (for development)

## Installation

```bash
pip install test-api-x
```

## Features

- **Async HTTP Client**: Built on httpx with automatic retries and timeout handling
- **Secure Logging**: Automatic credential masking with correlation IDs for request tracing
- **Fluent Assertions**: Chainable assertions for response validation
- **Enhanced Response**: Rich response objects with JSON path queries and validation
- **Pluggable Authentication**: Support for Basic Auth and Auth0 with automatic session management
- **User Registry**: Multi-persona authentication with pool-based organization and environment variable substitution
- **Factory Methods**: Ergonomic client creation with built-in authentication
- **Plugin System**: Extensible architecture for custom fixtures and authentication providers

## Quick Start

### Basic Usage

```python
from test_api_x import Client, assert_that

async with Client(base_url="https://api.example.com") as client:
    response = await client.get("/users")
    assert_that(response).has_status(200).has_json_path("users")
```

### With Authentication

```python
from test_api_x import Client

# Basic Authentication
async with Client.with_basic_auth(
    username="admin",
    password="secret123",
    base_url="https://api.example.com"
) as client:
    response = await client.get("/protected")
    assert_that(response).has_status(200)

# Auth0 Authentication
async with Client.with_auth0(
    domain="your-tenant.auth0.com",
    client_id="your-client-id",
    client_secret="your-client-secret",
    username="user@example.com",
    password="password",
    base_url="https://api.example.com"
) as client:
    response = await client.get("/protected")
    assert_that(response).has_status(200)
```

### With User Registry

```python
from test_api_x import UserRegistry, Client

# Load users from YAML
registry = UserRegistry.from_yaml("users.yaml")

# Get client for specific persona
async with Client.from_registry(
    registry=registry,
    persona="admin",
    base_url="https://api.example.com"
) as client:
    response = await client.get("/admin/users")
    assert_that(response).has_status(200)
```

## Logging

test-api-x includes secure logging with automatic credential masking to prevent sensitive data leaks.

### Basic Usage

```python
from test_api_x import get_logger

logger = get_logger("my_module")
logger.info("Starting test execution")
```

### Automatic Request/Response Logging

The Client automatically logs all HTTP requests and responses with correlation IDs for tracing:

```python
import os
os.environ["TESTAPIX_LOG_LEVEL"] = "DEBUG"

async with Client(base_url="https://api.example.com") as client:
    # Automatically logs request/response with correlation ID
    response = await client.post("/auth", json={
        "username": "admin",
        "password": "secret123"  # Automatically masked in logs
    })
```

### Credential Masking

Sensitive data is automatically detected and masked in:
- HTTP headers (Authorization, X-API-Key, etc.)
- Request/response bodies (password, token, api_key fields)
- URLs (query parameters and basic auth)

Masked data appears as `***REDACTED***` in logs.

### Log Levels

Set the log level via environment variable:

```bash
export TESTAPIX_LOG_LEVEL=DEBUG  # DEBUG, INFO, WARNING, ERROR
```

## User Registry

Manage multiple test users with different personas and authentication methods.

### Basic YAML Structure

```yaml
users:
  - user_id: admin_user
    persona: admin
    auth_method: basic
    username: admin
    password: admin123

  - user_id: auth0_user
    persona: standard_user
    auth_method: auth0
    domain: your-tenant.auth0.com
    client_id: your-client-id
    client_secret: your-client-secret
    username: user@example.com
    password: password
```

### Pool-Based Organization

Organize users into pools for different environments:

```yaml
pools:
  dev:
    users:
      - user_id: dev_admin
        persona: admin
        auth_method: basic
        username: dev_admin
        password: dev_pass

  staging:
    users:
      - user_id: staging_admin
        persona: admin
        auth_method: basic
        username: staging_admin
        password: staging_pass
```

Usage:

```python
# Get user from specific pool
async with Client.from_registry(
    registry=registry,
    persona="admin",
    pool="staging",
    base_url="https://staging-api.example.com"
) as client:
    response = await client.get("/users")
```

### Environment Variable Substitution

Use environment variables for sensitive credentials:

```yaml
users:
  - user_id: admin_user
    persona: admin
    auth_method: basic
    username: ${ADMIN_USERNAME}
    password: ${ADMIN_PASSWORD}
```

The registry automatically substitutes `${VAR_NAME}` with environment variable values.

## Plugin System

Extend test-api-x with custom fixtures and authentication providers.

### Using Plugins

```python
from test_api_x.plugins import PluginManager

# Automatically discover installed plugins
manager = PluginManager()
manager.discover_plugins()

# Use plugin fixtures
helper = manager.get_fixture("example_helper")()
result = helper.greet("World")
```

### Creating Plugins

```python
from test_api_x.plugins import Plugin

class MyPlugin(Plugin):
    @property
    def name(self) -> str:
        return "my_plugin"

    def register_fixtures(self) -> dict:
        return {"my_helper": self._my_helper_fixture}

    def register_auth_providers(self) -> dict:
        return {}

    def _my_helper_fixture(self):
        return MyHelper()
```

See [Plugin Development Guide](docs/plugins/plugin-development.md) for details.

## Response Assertions

Validate API responses with fluent assertions:

```python
# Status code assertions
assert_that(response).has_status(200)
assert_that(response).has_status_in_range(200, 299)

# JSON assertions
assert_that(response).has_json_matching({"status": "success"})
assert_that(response).has_json_path("data.users[0].id")

# Header assertions
assert_that(response).has_header("Content-Type", "application/json")

# Response time assertions
assert_that(response).responded_within(1000)  # milliseconds
```

## Development

### Setup

```bash
# Clone the repository
git clone https://github.com/yourusername/test-api-x.git
cd test-api-x

# Install dependencies
poetry install
```

### Running Quality Checks

```bash
# Run all tests (285 tests, 96.50% coverage)
poetry run pytest

# Run only unit tests (up to 198 tests)
poetry run pytest -m unit

# Run only integration tests (21 tests)
poetry run pytest -m integration

# Run tests with coverage report
poetry run pytest --cov=src/test_api_x --cov-report=html

# Format code
poetry run black src/ tests/

# Lint code
poetry run ruff check src/ tests/

# Type check
poetry run mypy src/
```

### Development Workflow

The project includes a pre-commit hook that automatically runs:
- Black code formatting check
- Ruff linting
- MyPy type checking

All checks must pass before commits are accepted.

## Project Status

**Phase 3 In Progress** - Plugin system implemented

Completed:
- Core HTTP client with retries and timeout handling
- Enhanced response objects with JSON path queries
- Fluent assertion API
- Secure logging with automatic credential masking
- Correlation IDs for request tracing
- Pluggable authentication system (Basic Auth, Auth0)
- Session management with automatic caching
- User registry with multi-persona support
- Pool-based user organization
- Environment variable substitution
- Factory methods for ergonomic client creation
- Plugin system with entry point discovery
- 96.50% test coverage (285 tests: 198 unit, 21 integration)

Coming Soon:
- Official plugins (AWS, Database, Mocking)
- Enhanced retry strategies
- Request/response middleware
- Performance optimizations

## License

MIT