-
Notifications
You must be signed in to change notification settings - Fork 45.8k
feat(backend): snapshot test responses #10039
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Swiftyos
merged 27 commits into
dev
from
swiftyos/add-pytest-snapshot-to-dev-dependencies
Jun 6, 2025
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
43b5be6
feat(backend): snapshot test responses
Swiftyos 62227dd
Merge branch 'dev' into swiftyos/add-pytest-snapshot-to-dev-dependencies
Swiftyos 8936a42
added snapshot testing
Swiftyos 3dd2690
formatting
Swiftyos 0fa20e8
fmt
Swiftyos 574f4f1
Merge branch 'dev' into swiftyos/add-pytest-snapshot-to-dev-dependencies
Swiftyos ba0f9f3
update lock file
Swiftyos d3bb799
updated lock file
Swiftyos d8b1037
updated lock file
Swiftyos 2b29f12
added testing doc to docs
Swiftyos 010adf4
Move root contributing to introduciton
Swiftyos 90e56bc
Merge branch 'dev' into swiftyos/add-pytest-snapshot-to-dev-dependencies
Swiftyos 2e4ef8f
Merge branch 'dev' into swiftyos/add-pytest-snapshot-to-dev-dependencies
Swiftyos 891e171
Merge branch 'dev' into swiftyos/add-pytest-snapshot-to-dev-dependencies
Swiftyos 05f9050
updated snapshot testing dir
Swiftyos 5c3371d
fmt
Swiftyos bc58bf8
fix(backend): Prevent test runner from wiping developer databases
Swiftyos f566b1c
refactor(backend): Comprehensive test improvements and code review fixes
Swiftyos 416b4e6
remove docs
Swiftyos d9157c9
updated poetry lock
Swiftyos e386b21
fix(backend): Fix DB_PORT environment variable handling in test infra…
Swiftyos 59ca3fc
Merge branch 'dev' into swiftyos/add-pytest-snapshot-to-dev-dependencies
Swiftyos 69b3c9c
update lock file
Swiftyos 99e74a4
Merge branch 'dev' into swiftyos/add-pytest-snapshot-to-dev-dependencies
ntindle 1f974a0
fix: lock
ntindle 3bf2c26
Merge branch 'dev' into swiftyos/add-pytest-snapshot-to-dev-dependencies
Swiftyos c8f3793
added testing docs
Swiftyos File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
# CLAUDE.md | ||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
|
||
## Repository Overview | ||
|
||
AutoGPT Platform is a monorepo containing: | ||
- **Backend** (`/backend`): Python FastAPI server with async support | ||
- **Frontend** (`/frontend`): Next.js React application | ||
- **Shared Libraries** (`/autogpt_libs`): Common Python utilities | ||
|
||
## Essential Commands | ||
|
||
### Backend Development | ||
```bash | ||
# Install dependencies | ||
cd backend && poetry install | ||
|
||
# Run database migrations | ||
poetry run prisma migrate dev | ||
|
||
# Start all services (database, redis, rabbitmq) | ||
docker compose up -d | ||
|
||
# Run the backend server | ||
poetry run serve | ||
|
||
# Run tests | ||
poetry run test | ||
|
||
# Run specific test | ||
poetry run pytest path/to/test_file.py::test_function_name | ||
|
||
# Lint and format | ||
poetry run format # Black + isort | ||
poetry run lint # ruff | ||
``` | ||
More details can be found in TESTING.md | ||
|
||
#### Creating/Updating Snapshots | ||
|
||
When you first write a test or when the expected output changes: | ||
|
||
```bash | ||
poetry run pytest path/to/test.py --snapshot-update | ||
``` | ||
|
||
⚠️ **Important**: Always review snapshot changes before committing! Use `git diff` to verify the changes are expected. | ||
|
||
|
||
### Frontend Development | ||
```bash | ||
# Install dependencies | ||
cd frontend && npm install | ||
|
||
# Start development server | ||
npm run dev | ||
|
||
# Run E2E tests | ||
npm run test | ||
|
||
# Run Storybook for component development | ||
npm run storybook | ||
|
||
# Build production | ||
npm run build | ||
|
||
# Type checking | ||
npm run type-check | ||
``` | ||
|
||
## Architecture Overview | ||
|
||
### Backend Architecture | ||
- **API Layer**: FastAPI with REST and WebSocket endpoints | ||
- **Database**: PostgreSQL with Prisma ORM, includes pgvector for embeddings | ||
- **Queue System**: RabbitMQ for async task processing | ||
- **Execution Engine**: Separate executor service processes agent workflows | ||
- **Authentication**: JWT-based with Supabase integration | ||
|
||
### Frontend Architecture | ||
- **Framework**: Next.js App Router with React Server Components | ||
- **State Management**: React hooks + Supabase client for real-time updates | ||
- **Workflow Builder**: Visual graph editor using @xyflow/react | ||
- **UI Components**: Radix UI primitives with Tailwind CSS styling | ||
- **Feature Flags**: LaunchDarkly integration | ||
|
||
### Key Concepts | ||
1. **Agent Graphs**: Workflow definitions stored as JSON, executed by the backend | ||
2. **Blocks**: Reusable components in `/backend/blocks/` that perform specific tasks | ||
3. **Integrations**: OAuth and API connections stored per user | ||
4. **Store**: Marketplace for sharing agent templates | ||
|
||
### Testing Approach | ||
- Backend uses pytest with snapshot testing for API responses | ||
- Test files are colocated with source files (`*_test.py`) | ||
- Frontend uses Playwright for E2E tests | ||
- Component testing via Storybook | ||
|
||
### Database Schema | ||
Key models (defined in `/backend/schema.prisma`): | ||
- `User`: Authentication and profile data | ||
- `AgentGraph`: Workflow definitions with version control | ||
- `AgentGraphExecution`: Execution history and results | ||
- `AgentNode`: Individual nodes in a workflow | ||
- `StoreListing`: Marketplace listings for sharing agents | ||
|
||
### Environment Configuration | ||
- Backend: `.env` file in `/backend` | ||
- Frontend: `.env.local` file in `/frontend` | ||
- Both require Supabase credentials and API keys for various services | ||
|
||
### Common Development Tasks | ||
|
||
**Adding a new block:** | ||
1. Create new file in `/backend/backend/blocks/` | ||
2. Inherit from `Block` base class | ||
3. Define input/output schemas | ||
4. Implement `run` method | ||
5. Register in block registry | ||
|
||
**Modifying the API:** | ||
1. Update route in `/backend/backend/server/routers/` | ||
2. Add/update Pydantic models in same directory | ||
3. Write tests alongside the route file | ||
4. Run `poetry run test` to verify | ||
|
||
**Frontend feature development:** | ||
1. Components go in `/frontend/src/components/` | ||
2. Use existing UI components from `/frontend/src/components/ui/` | ||
3. Add Storybook stories for new components | ||
4. Test with Playwright if user-facing |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
# Backend Testing Guide | ||
|
||
This guide covers testing practices for the AutoGPT Platform backend, with a focus on snapshot testing for API endpoints. | ||
|
||
## Table of Contents | ||
- [Overview](#overview) | ||
- [Running Tests](#running-tests) | ||
- [Snapshot Testing](#snapshot-testing) | ||
- [Writing Tests for API Routes](#writing-tests-for-api-routes) | ||
- [Best Practices](#best-practices) | ||
|
||
## Overview | ||
|
||
The backend uses pytest for testing with the following key libraries: | ||
- `pytest` - Test framework | ||
- `pytest-asyncio` - Async test support | ||
- `pytest-mock` - Mocking support | ||
- `pytest-snapshot` - Snapshot testing for API responses | ||
|
||
## Running Tests | ||
|
||
Swiftyos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
### Run all tests | ||
```bash | ||
poetry run test | ||
Swiftyos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
### Run specific test file | ||
```bash | ||
poetry run pytest path/to/test_file.py | ||
``` | ||
|
||
### Run with verbose output | ||
```bash | ||
poetry run pytest -v | ||
``` | ||
|
||
### Run with coverage | ||
```bash | ||
poetry run pytest --cov=backend | ||
``` | ||
|
||
## Snapshot Testing | ||
|
||
Snapshot testing captures the output of your code and compares it against previously saved snapshots. This is particularly useful for testing API responses. | ||
|
||
### How Snapshot Testing Works | ||
|
||
1. First run: Creates snapshot files in `snapshots/` directories | ||
2. Subsequent runs: Compares output against saved snapshots | ||
3. Changes detected: Test fails if output differs from snapshot | ||
|
||
### Creating/Updating Snapshots | ||
|
||
When you first write a test or when the expected output changes: | ||
|
||
```bash | ||
poetry run pytest path/to/test.py --snapshot-update | ||
``` | ||
|
||
⚠️ **Important**: Always review snapshot changes before committing! Use `git diff` to verify the changes are expected. | ||
|
||
### Snapshot Test Example | ||
|
||
```python | ||
import json | ||
from pytest_snapshot.plugin import Snapshot | ||
|
||
def test_api_endpoint(snapshot: Snapshot): | ||
response = client.get("/api/endpoint") | ||
|
||
# Snapshot the response | ||
snapshot.snapshot_dir = "snapshots" | ||
snapshot.assert_match( | ||
json.dumps(response.json(), indent=2, sort_keys=True), | ||
"endpoint_response" | ||
) | ||
``` | ||
|
||
### Best Practices for Snapshots | ||
|
||
1. **Use descriptive names**: `"user_list_response"` not `"response1"` | ||
2. **Sort JSON keys**: Ensures consistent snapshots | ||
3. **Format JSON**: Use `indent=2` for readable diffs | ||
4. **Exclude dynamic data**: Remove timestamps, IDs, etc. that change between runs | ||
|
||
Example of excluding dynamic data: | ||
```python | ||
response_data = response.json() | ||
# Remove dynamic fields for snapshot | ||
response_data.pop("created_at", None) | ||
response_data.pop("id", None) | ||
|
||
snapshot.snapshot_dir = "snapshots" | ||
snapshot.assert_match( | ||
json.dumps(response_data, indent=2, sort_keys=True), | ||
"static_response_data" | ||
) | ||
``` | ||
|
||
## Writing Tests for API Routes | ||
|
||
### Basic Structure | ||
|
||
```python | ||
import json | ||
import fastapi | ||
import fastapi.testclient | ||
import pytest | ||
from pytest_snapshot.plugin import Snapshot | ||
|
||
from backend.server.v2.myroute import router | ||
|
||
app = fastapi.FastAPI() | ||
app.include_router(router) | ||
client = fastapi.testclient.TestClient(app) | ||
|
||
def test_endpoint_success(snapshot: Snapshot): | ||
response = client.get("/endpoint") | ||
assert response.status_code == 200 | ||
|
||
# Test specific fields | ||
data = response.json() | ||
assert data["status"] == "success" | ||
|
||
# Snapshot the full response | ||
snapshot.snapshot_dir = "snapshots" | ||
snapshot.assert_match( | ||
json.dumps(data, indent=2, sort_keys=True), | ||
"endpoint_success_response" | ||
) | ||
``` | ||
|
||
### Testing with Authentication | ||
|
||
```python | ||
def override_auth_middleware(): | ||
return {"sub": "test-user-id"} | ||
|
||
def override_get_user_id(): | ||
return "test-user-id" | ||
|
||
app.dependency_overrides[auth_middleware] = override_auth_middleware | ||
app.dependency_overrides[get_user_id] = override_get_user_id | ||
``` | ||
|
||
### Mocking External Services | ||
|
||
```python | ||
def test_external_api_call(mocker, snapshot): | ||
# Mock external service | ||
mock_response = {"external": "data"} | ||
mocker.patch( | ||
"backend.services.external_api.call", | ||
return_value=mock_response | ||
) | ||
|
||
response = client.post("/api/process") | ||
assert response.status_code == 200 | ||
|
||
snapshot.snapshot_dir = "snapshots" | ||
snapshot.assert_match( | ||
json.dumps(response.json(), indent=2, sort_keys=True), | ||
"process_with_external_response" | ||
) | ||
``` | ||
|
||
## Best Practices | ||
|
||
### 1. Test Organization | ||
- Place tests next to the code: `routes.py` → `routes_test.py` | ||
- Use descriptive test names: `test_create_user_with_invalid_email` | ||
- Group related tests in classes when appropriate | ||
|
||
### 2. Test Coverage | ||
- Test happy path and error cases | ||
- Test edge cases (empty data, invalid formats) | ||
- Test authentication and authorization | ||
|
||
### 3. Snapshot Testing Guidelines | ||
- Review all snapshot changes carefully | ||
- Don't snapshot sensitive data | ||
- Keep snapshots focused and minimal | ||
- Update snapshots intentionally, not accidentally | ||
|
||
### 4. Async Testing | ||
- Use regular `def` for FastAPI TestClient tests | ||
- Use `async def` with `@pytest.mark.asyncio` for testing async functions directly | ||
|
||
### 5. Fixtures | ||
Create reusable fixtures for common test data: | ||
|
||
```python | ||
@pytest.fixture | ||
def sample_user(): | ||
return { | ||
"email": "[email protected]", | ||
"name": "Test User" | ||
} | ||
|
||
def test_create_user(sample_user, snapshot): | ||
response = client.post("/users", json=sample_user) | ||
# ... test implementation | ||
``` | ||
|
||
## CI/CD Integration | ||
|
||
The GitHub Actions workflow automatically runs tests on: | ||
- Pull requests | ||
- Pushes to main branch | ||
|
||
Snapshot tests work in CI by: | ||
1. Committing snapshot files to the repository | ||
2. CI compares against committed snapshots | ||
3. Fails if snapshots don't match | ||
|
||
## Troubleshooting | ||
|
||
### Snapshot Mismatches | ||
- Review the diff carefully | ||
- If changes are expected: `poetry run pytest --snapshot-update` | ||
- If changes are unexpected: Fix the code causing the difference | ||
|
||
### Async Test Issues | ||
- Ensure async functions use `@pytest.mark.asyncio` | ||
- Use `AsyncMock` for mocking async functions | ||
- FastAPI TestClient handles async automatically | ||
|
||
### Import Errors | ||
- Check that all dependencies are in `pyproject.toml` | ||
- Run `poetry install` to ensure dependencies are installed | ||
- Verify import paths are correct | ||
|
||
## Summary | ||
|
||
Snapshot testing provides a powerful way to ensure API responses remain consistent. Combined with traditional assertions, it creates a robust test suite that catches regressions while remaining maintainable. | ||
|
||
Remember: Good tests are as important as good code! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
"""Common test fixtures for server tests.""" | ||
|
||
import pytest | ||
from pytest_snapshot.plugin import Snapshot | ||
|
||
|
||
@pytest.fixture | ||
def configured_snapshot(snapshot: Snapshot) -> Snapshot: | ||
"""Pre-configured snapshot fixture with standard settings.""" | ||
snapshot.snapshot_dir = "snapshots" | ||
return snapshot | ||
|
||
|
||
# Test ID constants | ||
TEST_USER_ID = "test-user-id" | ||
ADMIN_USER_ID = "admin-user-id" | ||
TARGET_USER_ID = "target-user-id" |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.