Testing Guide
This guide covers testing practices, patterns, and commands for the Skelenote codebase.
Test Philosophy
Testing Pyramid
Skelenote follows the testing pyramid approach:
Unit Tests (majority) - Test individual functions, utilities, and pure business logic
Integration Tests - Test module interactions, hooks with mocked contexts
Component Tests - Test React components with mocked dependencies
E2E Tests - Currently manual; future Playwright/Tauri integration
What to Test
Always test:
Pure functions (utilities, calculations, transformations)
Business logic (recurrence calculations, search algorithms, CRDT operations)
Data transformations (import/export, serialization)
Custom hooks (state management, side effects)
Component behavior (user interactions, conditional rendering)
Test selectively:
UI styling (prefer visual regression in the future)
Third-party library behavior (trust their tests)
Generated code or trivial wrappers
Skip testing:
Type definitions (TypeScript handles this)
Constants and configuration
One-line passthrough functions
Test Isolation
Each test should be independent and not rely on state from other tests
Use
beforeEachto reset mocks and stateAvoid shared mutable state between tests
Tests should pass in any order
Running Tests
Frontend Tests (Vitest)
Rust Tests (Cargo)
Coverage
Frontend coverage uses Istanbul:
Rust coverage with cargo-tarpaulin (install first):
Benchmark Suites
Performance benchmarks ensure critical operations remain fast. Run all benchmarks with:
Or run individual benchmark files:
Available Benchmark Suites
ObjectStore
src/lib/loro/__tests__/store.bench.ts
CRUD operations, bulk creation, query performance
CRDT Merge
src/lib/loro/__tests__/store.bench.ts
Loro document merge with 100-1000 objects
Fuzzy Search
src/lib/search/__tests__/search.bench.ts
Fuse.js indexing and query times (100-5000 items)
Vector Index
src/lib/semantic/__tests__/vector.bench.ts
Semantic search insert/search (100-5000 vectors)
Task Recurrence
src/lib/tasks/__tests__/recurrence.bench.ts
Next due date calculations
Markdown Import
src/lib/import/__tests__/import.bench.ts
Parsing and importing markdown files
Markdown Export
src/lib/export/__tests__/export.bench.ts
BlockNote to markdown conversion
Templates
src/lib/templates/__tests__/templates.bench.ts
Template queries and object creation
Daily Notes
src/lib/daily/__tests__/daily.bench.ts
Daily note ID generation and retrieval
Sync Operations
src/lib/sync/__tests__/sync.bench.ts
CRDT export, import, and merge
Writing Benchmarks
Test Patterns
Mocking Tauri Commands
Tauri commands are invoked via @tauri-apps/api/core. Mock the invoke function:
Testing Custom Hooks
Use @testing-library/react with renderHook:
Testing React Components
Components need MantineProvider and jsdom environment:
Testing Pure Functions
The simplest tests - no mocking needed:
Testing with ObjectStore
Create isolated stores for testing data operations:
Integration Tests
Testing Module Interactions
Integration tests verify multiple modules work together correctly:
Testing CRDT Sync
Test that documents merge correctly:
Writing Tests for New Features
Checklist
When adding a new feature, create tests for:
Core logic - Pure function unit tests
Edge cases - Null inputs, empty arrays, boundary conditions
Error handling - Invalid inputs, failed operations
Integration - How it interacts with existing modules
Performance - Add benchmarks if the feature is performance-sensitive
Test File Organization
Tests are co-located with source files:
Or alongside the file:
Naming Conventions
Test files:
*.test.tsor*.spec.tsBenchmark files:
*.bench.tsTest directories:
__tests__/
Test Structure
Follow the Arrange-Act-Assert pattern:
Test Descriptions
Write descriptive test names that explain the expected behavior:
Rust Test Patterns
Unit Tests in Rust
Rust tests live in the same file as the implementation:
Testing Tauri Commands
Test the underlying functions, not the Tauri command wrappers:
Environment Configuration
Vitest Configuration
The test configuration in vite.config.ts:
Per-File Environment Override
Use the magic comment at the top of files that need jsdom:
Troubleshooting
Common Issues
"Cannot find module" errors:
Check path aliases (
@/) are correctly resolvedVerify the import path is correct
"window is not defined":
Add
@vitest-environment jsdomcomment to the fileOr add the file pattern to
environmentMatchGlobs
Mantine components fail to render:
Wrap with
MantineProviderMock
window.matchMedia(see Component Testing section)
Tauri invoke errors:
Mock
@tauri-apps/api/corebefore importing modules that use itClear mocks in
beforeEach
Tests hang or timeout:
Check for unresolved promises
Ensure mocks return values (not
undefined)Use
vi.useFakeTimers()for time-dependent code
Debugging Tests
Last updated