# Functional Tests

High-level pytest tests focused on endpoint behavior and integration.

## Conventions

- Use pytest.
- Patch external integrations (e.g., S3) with `@mock_s3` or `@patch`.
- Use fixtures: `fixture_client`, `faker`.
- Assert:
  - HTTP status codes (e.g., `assert res.status_code == 200`)
  - Response content (e.g., `assert res.json.items() >= expected.items()` — checks `expected` is a subset of the response)

## Required cases per resource

- GET on a soft-deleted record returns 404
- DELETE success returns 204 with empty body
- Second DELETE on the same id returns 404

## Example

```python
@mock_s3
def test_create_or_update_report_update_success(fixture_client, faker) -> None:
    """PUT /reports/<target_type>/<target_id>/ update success."""
    existing_report = ReportPaymentFactory.create()
    payload = {
        'report_type': existing_report.report_type,
        'report_export_url': faker.uri(),
    }
    expected = {
        'target_type': existing_report.target_type,
        'target_id': existing_report.target_id,
        **payload,
    }
    url = (
        f'/reports/{expected["target_type"].replace("_", "-")}/{expected["target_id"]}/'
    )

    res = fixture_client.put(url, json=payload)

    assert res.status_code == 200
    assert res.json.items() >= expected.items()
```
