Testing guide
Testing Philosophy
Section titled “Testing Philosophy”Privatefolio’s testing approach focuses on maintaining high code quality and reliability through comprehensive test coverage across the monorepo’s packages. The project emphasizes functional correctness, particularly in the backend services that handle critical financial data processing. Tests are designed to validate functionality at multiple levels, from unit to integration tests, with a preference for snapshot testing to prevent regressions. The project aims to ensure that all core functionality remains stable across updates and that new features are thoroughly tested before integration.
Testing Tools & Frameworks
Section titled “Testing Tools & Frameworks”Core Testing Stack
Section titled “Core Testing Stack”- Vitest: Primary testing framework used across the project, providing a Jest-compatible API with TypeScript support out of the box
- Bun Test: Used for specific SQLite compatibility tests that need to run in the Bun runtime
- Snapshots: Extensive use of inline snapshots for regression testing
- CI Integration: Tests run automatically as part of the GitHub Actions CI workflow
Package-specific Tools
Section titled “Package-specific Tools”- Backend:
- Custom diff visualization configuration in
vitest.diff.ts - Environment flags to enable/disable Bun SQLite testing (
BUN_SQL=true/false)
- Custom diff visualization configuration in
- Frontend:
- Utilizes Vitest within the context of the Vite build system
- Electron:
- Limited direct testing, relies on the testing of its constituent parts in backend and frontend packages
Test Types & Organization
Section titled “Test Types & Organization”Backend Package
Section titled “Backend Package”Test Directory Structure
Section titled “Test Directory Structure”The backend package has a well-organized test directory structure:
/test /__snapshots__/ # Generated snapshot files /assets/ # Tests for asset-related functionality /backend-relayer/ # Tests for the backend relayer service /backup/ # Tests for backup/restore functionality /balances/ # Tests for balance tracking /bun/ # Bun-specific tests for SQLite compatibility /connections/ # Tests for external API connections /daily-prices/ # Tests for price history functionality /database/ # Database-related tests /file-imports/ # Tests for file import functionality /files/ # File handling tests /networth/ # Net worth calculation tests /server-tasks/ # Server task processing tests /tags/ # Tag management tests /trades/ # Trade tracking tests /utils/ # Utility function testsTests follow a clear naming convention with .test.ts suffix for each test file.
Test Categories
Section titled “Test Categories”- Unit Tests: Focused on testing individual functions and modules in isolation
- Integration Tests: Test the interaction between multiple components
- SQLite Compatibility Tests: Special tests that run in the Bun environment to ensure SQLite compatibility
- API Tests: Test the backend API endpoints functionality
Key Test Fixtures & Mocks
Section titled “Key Test Fixtures & Mocks”- Random account names generated per test run to ensure test isolation
- Test-specific transaction and audit log IDs
- Snapshot-based assertions for complex data structures
Frontend Package
Section titled “Frontend Package”The frontend package uses Vitest for testing, though it has less extensive test coverage compared to the backend. Testing focuses primarily on utility functions and critical UI components.
Electron Package
Section titled “Electron Package”The Electron package does not have dedicated tests in its own directory. Functionality is primarily tested through the backend and frontend packages that it integrates.
Running Tests
Section titled “Running Tests”Common Commands
Section titled “Common Commands”To run all tests across the monorepo:
yarn testFor CI-specific test runs (including all test suites):
yarn test:ciPackage-specific Commands
Section titled “Package-specific Commands”Or navigate to the specific package directory:
# For backend testscd packages/backendyarn test # Run standard tests (without Bun SQLite)yarn test:bun # Run Bun-specific SQLite testsyarn test <test-file> # Run a specific test file, e.g., yarn test test/tags/tags-api.test.tsTesting in Watch Mode
Section titled “Testing in Watch Mode”When developing, you can run tests in watch mode in the backend package:
cd packages/backendyarn test --watchThis will rerun the tests automatically when files change.
Debugging Tests
Section titled “Debugging Tests”If tests fail, the output includes detailed error messages and diff comparisons. For snapshot test failures, you can update snapshots with:
yarn test -uFor more complex debugging scenarios:
- Add
console.logstatements or use thedebugoption in Vitest - Run a specific test file to isolate the issue
- Use
it.onlyto run just one test case within a file
CI/CD Integration
Section titled “CI/CD Integration”Testing is integrated into the Continuous Integration pipeline via GitHub Actions in the .github/workflows/continuous-integration.yml file.
The CI process:
- Checks out the code
- Sets up Node.js and Bun
- Installs dependencies
- Builds the project
- Runs linting checks
- Checks TypeScript types
- Runs all tests in CI mode
Tests are a critical gate for accepting pull requests and merging code into the main branch.
Best Practices
Section titled “Best Practices”Testing Patterns to Follow
Section titled “Testing Patterns to Follow”-
AAA Pattern: Structure tests using the Arrange-Act-Assert pattern:
it("should create and retrieve tags", async () => {// arrangeconst tagNames = ["defi", "staking", "trading"]// actconst tags = await upsertTags(accountName, tagNames)const allTags = await getTags(accountName)// assertexpect(tags).toMatchInlineSnapshot(`...`)expect(allTags).toMatchInlineSnapshot(`...`)}) -
Isolation: Ensure tests are isolated by using random identifiers for account names and test data:
const accountName = Math.random().toString(36).substring(7)const transactionId = "test_transaction_" + Math.random().toString(36).substring(7) -
Descriptive Test Names: Use descriptive
it()statements that clearly indicate what’s being tested -
Snapshots for Complex Data: Use snapshots for testing complex data structures
Common Pitfalls to Avoid
Section titled “Common Pitfalls to Avoid”- Hard-coded Data: Avoid hard-coded account names or IDs that could lead to test interference
- Global State: Beware of tests that change global state without restoring it
- Time Dependencies: Tests that rely on specific timestamps may be fragile
- Incomplete Assertions: Ensure you’re asserting all relevant aspects of the test result
Guidelines for Writing New Tests
Section titled “Guidelines for Writing New Tests”- Place tests in the appropriate subdirectory based on functionality
- Follow existing naming conventions:
feature-name.test.ts - Use descriptive test names in the format “should do something”
- Include tests for both success and failure cases
- Use snapshots for complex data structures, but be careful not to overuse them
- When adding new APIs, include tests for all endpoints and edge cases
- Structure tests using the AAA pattern (Arrange-Act-Assert)
- Add appropriate comments to explain test setup and assertions