---
estimated_steps: 31
estimated_files: 3
skills_used: []
---

# T02: Add integration tests for search and public API endpoints

## Description

Write integration tests for all new S05 backend endpoints: search (with mocked embedding API and Qdrant), techniques list/detail, topics hierarchy, and enhanced creators (randomized sort, genre filter, counts). Tests run against real PostgreSQL with the existing conftest.py fixtures. All 40 existing tests must continue to pass.

## Negative Tests

- **Malformed inputs**: Empty search query returns empty results. Invalid technique slug returns 404. Invalid topic category returns empty list.
- **Error paths**: Search with mocked embedding failure → keyword fallback results returned. Search with mocked Qdrant failure → keyword fallback.
- **Boundary conditions**: Search with no matching results → empty items list. Topics with no technique pages → zero counts. Creators list with no creators → empty list.

## Steps

1. Create `backend/tests/test_search.py`:
   - Fixture: seed DB with 2 creators, 3 technique pages (different categories/tags), 5 key moments
   - Test search endpoint with mocked SearchService that returns canned results → verify response shape (items, total, query, fallback_used)
   - Test search with empty query → returns empty results or validation error
   - Test search keyword fallback: mock embedding to return None → verify keyword results returned and fallback_used=true
   - Test search scope filtering (scope=topics returns only technique_page type results)

2. Create `backend/tests/test_public_api.py`:
   - Test GET /api/v1/techniques — returns list of technique pages, supports category filter
   - Test GET /api/v1/techniques/{slug} — returns full detail with key_moments, creator info, related links
   - Test GET /api/v1/techniques/{slug} with invalid slug → 404
   - Test GET /api/v1/topics — returns category hierarchy with counts matching seeded data
   - Test GET /api/v1/creators?sort=random — returns creators (verify all returned, order may vary)
   - Test GET /api/v1/creators?sort=alpha — returns creators in alphabetical order
   - Test GET /api/v1/creators?genre=Bass+music — returns only matching creators
   - Test GET /api/v1/creators/{slug} — returns detail with technique_count, video_count

3. Run full test suite: `cd backend && python -m pytest tests/ -v` — all 40 existing + new tests pass

## Must-Haves

- [ ] test_search.py with ≥4 tests covering happy path, empty query, keyword fallback, scope filter
- [ ] test_public_api.py with ≥8 tests covering techniques list/detail/404, topics hierarchy, creators sort/filter/detail
- [ ] All 40 existing tests still pass (regression)
- [ ] Tests use real PostgreSQL with seeded data (not mocked DB)

## Verification

- `cd backend && python -m pytest tests/test_search.py tests/test_public_api.py -v` — all new tests pass
- `cd backend && python -m pytest tests/ -v` — all tests pass (40 existing + new)

## Inputs

- ``backend/search_service.py` — SearchService class to mock for search tests`
- ``backend/routers/search.py` — search endpoint under test`
- ``backend/routers/techniques.py` — techniques endpoints under test`
- ``backend/routers/topics.py` — topics endpoint under test`
- ``backend/routers/creators.py` — enhanced creators endpoint under test`
- ``backend/schemas.py` — response schemas for assertion shapes`
- ``backend/models.py` — ORM models for seeding test data`
- ``backend/tests/conftest.py` — existing test fixtures (db_engine, client)`
- ``config/canonical_tags.yaml` — expected tag structure for topics test assertions`

## Expected Output

- ``backend/tests/test_search.py` — ≥4 integration tests for search endpoint`
- ``backend/tests/test_public_api.py` — ≥8 integration tests for techniques, topics, creators endpoints`
- ``backend/tests/conftest.py` — possibly extended with shared seed fixtures for S05 tests`

## Verification

cd backend && python -m pytest tests/test_search.py tests/test_public_api.py -v && python -m pytest tests/ -v
