# NoteFlow Testing Conventions ## Location - Python: `tests/` (pytest) - TypeScript: `client/src/**/*.test.ts` (Vitest) - Rust: `client/src-tauri/src/**/*_tests.rs` (cargo test) - E2E: `client/e2e/` (Playwright) ## Python Testing ### Running Tests ```bash pytest # Full suite pytest -m "not integration" # Skip external-service tests pytest tests/domain/ # Run specific directory pytest -k "test_segment" # Run by pattern pytest tests/quality/ # Quality gates ``` ### Markers | Marker | Purpose | |--------|---------| | `@pytest.mark.slow` | Model loading tests | | `@pytest.mark.integration` | External service tests | | `@pytest.mark.asyncio` | Async tests (auto-mode enabled) | ### Test Structure - Test files: `test_*.py` - Test functions: `test_*` - Fixtures in `tests/conftest.py` ### Quality Gates (`tests/quality/`) **Run after any non-trivial changes:** ```bash pytest tests/quality/ ``` | Test File | Enforces | |-----------|----------| | `test_test_smells.py` | No assertion roulette, no conditional logic, no loops in tests | | `test_magic_values.py` | No magic numbers in assignments | | `test_code_smells.py` | Code quality checks | | `test_duplicate_code.py` | No duplicate code patterns | | `test_stale_code.py` | No stale/dead code | | `test_decentralized_helpers.py` | Helpers consolidated properly | | `test_unnecessary_wrappers.py` | No unnecessary wrapper functions | | `test_baseline_self.py` | Baseline validation self-checks | ### Forbidden Patterns in Tests - Loops (`for`, `while`) — Use `@pytest.mark.parametrize` - Conditionals (`if`) — Use `@pytest.mark.parametrize` - Multiple assertions without messages — Add assertion messages - Empty catch blocks — All errors must be logged/handled ### Global Fixtures (DO NOT REDEFINE) | Fixture | Description | |---------|-------------| | `reset_context_vars` | Reset logging context variables | | `mock_uow` | Mock Unit of Work | | `crypto` | Crypto utilities | | `meetings_dir` | Temporary meetings directory | | `webhook_config` | Single-event webhook config | | `webhook_config_all_events` | All-events webhook config | | `sample_datetime` | Sample datetime | | `calendar_settings` | Calendar settings | | `meeting_id` | Sample meeting ID | | `sample_meeting` | Sample Meeting entity | | `recording_meeting` | Recording-state Meeting | | `sample_rate` | Audio sample rate | | `mock_grpc_context` | Mock gRPC context | | `mockasr_engine` | Mock ASR engine | | `mock_optional_extras` | Mock optional extras | | `mock_oauth_manager` | Mock OAuth manager | | `memory_servicer` | In-memory servicer | | `approx_float` | Approximate float comparison | | `approx_sequence` | Approximate sequence comparison | ## TypeScript Testing (Vitest) ### Running Tests ```bash cd client npm run test # Run all tests npm run test:watch # Watch mode npm run test:coverage # With coverage ``` ### Test Files - Unit tests: `*.test.ts` or `*.test.tsx` - Located next to source files ### Patterns ```typescript import { describe, it, expect, vi } from 'vitest'; describe('MyComponent', () => { it('should render correctly', () => { // Arrange const props = { title: 'Test' }; // Act render(); // Assert expect(screen.getByText('Test')).toBeInTheDocument(); }); }); ``` ## Rust Testing (cargo test) ### Running Tests ```bash cd client/src-tauri cargo test # All tests cargo test -- --nocapture # With output ``` ### Test Files - Test modules: `*_tests.rs` - Unit tests: `#[cfg(test)]` modules in source files ### Patterns ```rust #[cfg(test)] mod tests { use super::*; #[test] fn test_audio_capture() { // Arrange let config = CaptureConfig::default(); // Act let result = AudioCapture::new(config); // Assert assert!(result.is_ok()); } } ``` ## E2E Testing (Playwright) ### Running Tests ```bash cd client npm run test:e2e # Run all E2E tests npm run test:e2e:ui # With UI mode ``` ### Requirements - Frontend must be running on `:5173` - Backend server must be running ### Test Files - Location: `client/e2e/` - Pattern: `*.spec.ts` ## Makefile Quality Commands ```bash make quality # ALL quality checks (TS + Rust + Python) make quality-py # Python: lint + type-check + test-quality make quality-ts # TypeScript: type-check + lint + test-quality make quality-rs # Rust: clippy + lint make e2e # Playwright tests make e2e-ui # Playwright with UI make e2e-grpc # Rust gRPC integration tests ``` ## Test AAA Pattern All tests should follow **Arrange-Act-Assert**: ```python def test_create_meeting(): # Arrange service = MeetingService(mock_uow) params = MeetingCreateParams(title="Sprint Planning") # Act meeting = await service.create_meeting(params) # Assert assert meeting.title == "Sprint Planning" assert meeting.state == MeetingState.CREATED ``` ## Integration Tests ### PostgreSQL (testcontainers) ```python @pytest.fixture async def postgres_uow(): async with PostgresContainer() as postgres: engine = create_async_engine(postgres.get_connection_url()) yield SQLAlchemyUnitOfWork(engine) ``` ### gRPC Server ```python @pytest.fixture async def grpc_server(): server = await create_test_server() yield server await server.stop(grace=1.0) ``` ## Coverage Goals | Area | Target | |------|--------| | Critical business logic | 100% | | Domain entities | 90%+ | | Application services | 85%+ | | Infrastructure | 70%+ | | gRPC mixins | 80%+ | ## Forbidden in Quality Tests **NEVER modify without explicit permission:** - Adding entries to allowlists/baselines - Increasing thresholds - Adding exclusion patterns - Modifying filter functions **When quality tests fail:** 1. Fix the actual code (not the test) 2. If false positive: improve detection logic 3. NEVER add arbitrary values to allowlists