cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm
leaflet
readability
golang
1# Testing Documentation
2
3This document outlines the testing patterns and practices used in the `noteleaf` application.
4
5## Overview
6
7The codebase follows Go's standard testing practices with specialized testing utilities for complex scenarios. Tests use the standard library along with carefully selected dependencies like faker for data generation and BubbleTea for TUI testing. This approach keeps dependencies minimal while providing robust testing infrastructure for interactive components and complex integrations.
8
9### Organization
10
11Each package contains its own test files alongside the source code. Test files are organized by functionality and mirror the structure of the source code they test. The codebase includes four main test utility files that provide specialized testing infrastructure:
12
13- `internal/services/test_utilities.go` - HTTP mocking and media service testing
14- `internal/repo/test_utilities.go` - Database testing and data generation
15- `internal/ui/test_utilities.go` - TUI testing framework and interactive component testing
16- `internal/handlers/test_utilities.go` - Handler testing with database isolation and input simulation
17
18## Patterns
19
20### Handler Creation
21
22Tests create real handler instances using temporary databases to ensure test isolation. Factory functions handle both database setup and handler initialization, returning both the handler and a cleanup function.
23
24### Database Isolation
25
26Tests use temporary directories and environment variable manipulation to create isolated database instances. Each test gets its own temporary SQLite database that is automatically cleaned up after the test completes.
27
28The `setupCommandTest` function creates a temporary directory, sets `XDG_CONFIG_HOME` to point to it, and initializes the database schema. This ensures tests don't interfere with each other or with development data.
29
30### Resource Management
31
32Tests properly manage resources using cleanup functions returned by factory methods. The cleanup function handles both handler closure and temporary directory removal. This pattern ensures complete resource cleanup even if tests fail.
33
34### Error Handling
35
36Tests use `t.Fatal` for setup errors that prevent test execution and `t.Error` for test assertion failures. Fatal errors stop test execution while errors allow tests to continue checking other conditions.
37
38### Context Cancellation
39
40Error case testing frequently uses context cancellation to simulate database and network failures. The pattern creates a context, immediately cancels it, then calls the function under test to verify error handling. This provides a reliable way to test error paths without requiring complex mock setups or external failure injection.
41
42### Command Structure
43
44Command group tests verify cobra command structure including use strings, aliases, short descriptions, and subcommand presence. Tests check that commands are properly configured without executing their logic.
45
46### Interface Compliance
47
48Tests verify interface compliance using compile-time checks with blank identifier assignments. This ensures structs implement expected interfaces without runtime overhead.
49
50## Test Infrastructure
51
52### Test Utility Frameworks
53
54The codebase provides comprehensive testing utilities organized by layer and functionality. Each test utility file contains specialized helpers, mocks, and test infrastructure for its respective domain.
55
56#### Database Testing Utilities
57
58`internal/repo/test_utilities.go` provides comprehensive database testing infrastructure:
59
60- **In-Memory Database Creation**: `CreateTestDB` creates isolated SQLite databases with full schema
61- **Sample Data Factories**: Functions like `CreateSampleTask`, `CreateSampleBook` generate realistic test data
62- **Faker Integration**: Uses jaswdr/faker for generating realistic fake data with `CreateFakeArticle`
63- **Test Setup Helpers**: `SetupTestData` creates a full set of sample data across all models
64- **Custom Assertions**: Generic assertion helpers like `AssertEqual`, `AssertContains`, `AssertNoError`
65
66#### HTTP Service Testing
67
68`internal/services/test_utilities.go` provides HTTP mocking and media service testing:
69
70- **Mock Configuration**: `MockConfig` structure for configuring service behavior
71- **Function Replacement**: `SetupMediaMocks` replaces service functions with controllable mocks
72- **Sample Data Access**: Helper functions that use embedded HTML samples for realistic testing
73- **Specialized Scenarios**: Pre-configured mock setups for success and failure scenarios
74- **Assertion Helpers**: Domain-specific assertions for movies, TV shows, and error conditions
75
76#### TUI Testing Framework
77
78`internal/ui/test_utilities.go` provides a comprehensive BubbleTea testing framework:
79
80- **TUITestSuite**: Complete testing infrastructure for interactive TUI components
81- **Controlled I/O**: `ControlledOutput` and `ControlledInput` for deterministic testing
82- **Message Simulation**: Key press simulation, message queuing, and timing control
83- **State Verification**: Model state checking and view content assertions
84- **Timeout Handling**: Configurable timeouts for async operations
85- **Mock Repository**: Test doubles for repository interfaces
86
87#### Handler Testing Infrastructure
88
89`internal/handlers/test_utilities.go` provides end-to-end handler testing:
90
91- **Environment Isolation**: `HandlerTestHelper` creates isolated test environments
92- **Input Simulation**: `InputSimulator` for testing interactive components that use `fmt.Scanf`
93- **HTTP Mocking**: Comprehensive HTTP server mocking for external API testing
94- **Database Helpers**: Database corruption and error scenario testing
95- **Editor Mocking**: `MockEditor` for testing file editing workflows
96- **Assertion Helpers**: Handler-specific assertions and verification functions
97
98### Advanced Testing Patterns
99
100#### Input Simulation for Interactive Components
101
102Interactive handlers that use `fmt.Scanf` require special testing infrastructure with an `io.Reader` implementation.
103
104The `InputSimulator` provides controlled input sequences that prevent tests from hanging while maintaining coverage of interactive code paths.
105
106#### TUI Testing with BubbleTea Framework
107
108The TUI testing framework addresses the fundamental challenge of testing interactive terminal applications in a deterministic, concurrent environment. BubbleTea's message-passing architecture creates unique testing requirements that standard Go testing patterns cannot adequately address.
109
110The framework implements a controlled execution environment that replaces BubbleTea's typical program loop with a deterministic testing harness. Rather than running an actual terminal program, the "testing suite" directly manages model state transitions by simulating the Update/View cycle. This approach eliminates the non-deterministic behavior inherent in real terminal interactions while preserving the exact message flow patterns that production code experiences.
111
112State verification relies on function composition patterns where test conditions are expressed as closures that capture specific model states. The `WaitFor` mechanism uses polling with configurable timeouts, addressing the async nature of BubbleTea model updates without creating race conditions. This pattern bridges imperative test assertions with BubbleTea's declarative update model.
113This is inspired by front-end/TS/JS testing patterns.
114
115The framework's I/O abstraction layer replaces terminal input/output with controlled buffers that implement standard Go interfaces.
116This design maintains interface compatibility while providing complete control over timing and content. The controlled I/O system captures all output for later verification and injects precise input sequences, enabling complex interaction testing without external dependencies.
117
118Concurrency management uses channels and context propagation to coordinate between the testing framework and the model under test.
119The suite manages goroutine lifecycle and ensures proper cleanup, preventing test interference and resource leaks. This architecture supports testing of models that perform background operations or handle async events.
120
121#### HTTP Service Mocking
122
123Service testing uses HTTP mocking with request capture. A `MockServer` is instantiated, and its URL is used in test scoped services.
124
125#### Database Schema Testing
126
127Database tests use comprehensive schema setup with (automatic) cleanup
128
129#### Environment Manipulation
130
131Environment testing utilities provide controlled environment manipulation. Environment variables are restored after instantiation.
132
133## Test Organization Patterns
134
135### Single Root Test
136
137The preferred test organization pattern uses a single root test function with nested subtests using `t.Run`. This provides clear hierarchical organization and allows running specific test sections while maintaining shared setup and context. This pattern offers several advantages: clear test hierarchy with logical grouping, ability to run specific test sections, consistent test structure across the codebase, and shared setup that can be inherited by subtests.
138
139### Integration vs Unit Testing
140
141The codebase emphasizes integration testing over heavy mocking by using real handlers and services to verify actual behavior rather than mocked interactions. The goal is to catch integration issues while maintaining test reliability.
142
143### Static Output
144
145UI components support static output modes for testing. Tests capture output using bytes.Buffer and verify content using string contains checks rather than exact string matching for better test maintainability.
146
147### Standard Output Redirection
148
149For testing functions that write to stdout, tests use a pipe redirection pattern with goroutines to capture output. The pattern saves the original stdout, redirects to a pipe, captures output in a separate goroutine, and restores stdout after the test. This ensures clean output capture without interfering with the testing framework.
150
151## Utilities
152
153### Test Data Generation
154
155The codebase uses sophisticated data generation strategies:
156
157- **Factory Functions**: Each package provides factory functions for creating valid test data
158- **Faker Integration**: Uses `jaswdr/faker` for generating realistic fake data with proper randomization
159- **Sample Data Creators**: Functions like `CreateSampleTask`, `CreateSampleBook` provide consistent test data
160- **Embedded Resources**: Services use embedded HTML samples from real API responses for realistic testing
161
162### Assertion Helpers
163
164Custom assertion functions provide clear error messages and reduce test code duplication:
165
166- **Generic Assertions**: `AssertEqual`, `AssertNoError`, `AssertContains` for common checks
167- **Domain-Specific Assertions**: `AssertMovieInResults`, `AssertNoteExists` for specialized verification
168- **TUI Assertions**: `AssertViewContains`, `AssertModelState` for BubbleTea model testing
169- **HTTP Assertions**: `AssertRequestMade` for verifying HTTP interactions
170
171### Mock Infrastructure
172
173Each layer provides specialized mocking capabilities:
174
175- **Service Mocking**: Function replacement with configurable behavior and embedded test data
176- **HTTP Mocking**: `HTTPMockServer` with request capture and response customization
177- **Input Mocking**: `InputSimulator` for deterministic interactive component testing
178- **Editor Mocking**: `MockEditor` for file editing workflow testing
179- **Repository Mocking**: `MockTaskRepository` for TUI component testing
180
181### Environment and Resource Management
182
183Testing utilities provide comprehensive resource management:
184
185- **Environment Isolation**: `EnvironmentTestHelper` for controlled environment variable manipulation
186- **Database Isolation**: Temporary SQLite databases with automatic cleanup
187- **File System Isolation**: Temporary directories with automatic cleanup
188- **Process Isolation**: Handler helpers that create completely isolated test environments
189
190## Testing CLI Commands
191
192Command group tests focus on structure verification rather than execution testing. Tests check command configuration, subcommand presence, and interface compliance. This approach ensures command trees are properly constructed without requiring complex execution mocking.
193
194### CommandGroup Interface Testing
195
196The CommandGroup interface enables testable CLI architecture. Tests verify that command groups implement the interface correctly and return properly configured cobra commands. This pattern separates command structure from command execution.
197
198Interface compliance is tested using compile-time checks within the "Interface Implementations" subtest, ensuring all command structs properly implement the CommandGroup interface without runtime overhead.
199
200## Performance Considerations
201
202Tests avoid expensive operations in setup functions. Handler creation uses real instances but tests focus on structure verification rather than full execution paths. This keeps test suites fast while maintaining coverage of critical functionality.
203
204The single root test pattern allows for efficient resource management where setup costs can be amortized across multiple related test cases.
205
206## Interactive Component Testing
207
208The codebase provides comprehensive testing infrastructure for interactive components, including both terminal UI applications and command-line interfaces that require user input.
209
210### Input Simulation Framework
211
212Interactive handlers that use `fmt.Scanf` require specialized testing infrastructure:
213
214- **InputSimulator**: Provides controlled input sequences that implement `io.Reader`
215- **Menu Selection Helpers**: `MenuSelection`, `MenuCancel`, `MenuSequence` for common interaction patterns
216- **Handler Integration**: Handlers can accept `io.Reader` for input, enabling deterministic testing
217- **Cleanup Management**: Automatic cleanup prevents resource leaks in test environments
218
219### TUI Testing with BubbleTea
220
221The TUI testing framework provides complete testing infrastructure for interactive terminal interfaces:
222
223- **TUITestSuite**: Comprehensive testing framework for BubbleTea models
224- **Message Simulation**: Key press simulation, window resize events, and custom message handling
225- **State Verification**: Model state checking with custom condition functions
226- **View Assertions**: Content verification and output capture
227- **Timing Control**: Configurable timeouts and delay handling for async operations
228- **Mock Integration**: Repository mocking for isolated component testing
229
230### Interactive Test Scenarios
231
232Interactive handlers should test comprehensive scenarios:
233
234- **Valid user selections** - User chooses valid menu options and inputs
235- **Cancellation flows** - User chooses to cancel operations (option 0 or escape keys)
236- **Invalid choices** - User selects out-of-range options or provides invalid input
237- **Navigation patterns** - Keyboard navigation, scrolling, and multi-step interactions
238- **Error handling** - Network errors, service failures, and data validation errors
239- **Empty states** - Search returns no results, empty lists, and missing data
240- **Edge cases** - Boundary conditions, malformed input, and resource constraints
241
242### TUI Component Testing Patterns
243
244BubbleTea components use specialized testing patterns:
245
246- **Key Sequence Testing**: Simulate complex user interactions with timing
247- **State Transition Testing**: Verify model state changes through user actions
248- **View Content Testing**: Assert specific content appears in rendered output
249- **Async Operation Testing**: Handle loading states and network operations
250- **Responsive Design Testing**: Test different terminal sizes and window resize handling
251
252This comprehensive testing approach ensures interactive components work reliably in automated environments while maintaining full coverage of user interaction paths.
253
254## Errors
255
256Error coverage follows a systematic approach to identify and test failure scenarios:
257
2581. **Context Cancellation** - Primary method for testing database and network timeout scenarios
2592. **Invalid Input** - Malformed data, empty inputs, boundary conditions
2603. **Resource Exhaustion** - Database connection failures, memory limits
2614. **Constraint Violations** - Duplicate keys, foreign key failures
2625. **State Validation** - Testing functions with invalid system states
2636. **Interactive Input** - Invalid user choices, cancellation handling, input simulation errors