5.9 KiB
5.9 KiB
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
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:
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
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.tsor*.test.tsx - Located next to source files
Patterns
import { describe, it, expect, vi } from 'vitest';
describe('MyComponent', () => {
it('should render correctly', () => {
// Arrange
const props = { title: 'Test' };
// Act
render(<MyComponent {...props} />);
// Assert
expect(screen.getByText('Test')).toBeInTheDocument();
});
});
Rust Testing (cargo test)
Running Tests
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
#[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
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
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:
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)
@pytest.fixture
async def postgres_uow():
async with PostgresContainer() as postgres:
engine = create_async_engine(postgres.get_connection_url())
yield SQLAlchemyUnitOfWork(engine)
gRPC Server
@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:
- Fix the actual code (not the test)
- If false positive: improve detection logic
- NEVER add arbitrary values to allowlists