Testing Strategy
Relevant source files
The following files were used as context for generating this wiki page:
The Keynobi project employs a multi-layered testing strategy designed to validate a cross-platform application built with a Rust backend (Tauri) and a SolidJS frontend. The strategy covers unit testing for both domains, integration testing for complex workflows like Android builds, and performance benchmarking for critical file system and log processing operations.
Testing is integrated into the development lifecycle, with specific mandates for regenerating TypeScript bindings after Rust model changes and utilizing automated CI workflows for type checking and test execution.
Sources: AGENTS.md:1-15, package.json:7-25
Frontend Testing Framework
The frontend testing environment utilizes Vitest for unit and component testing. It focuses on validating utility functions, state management stores, and UI component logic.
Unit Testing Patterns
Frontend tests are typically co-located with the source code or placed in a dedicated test directory. For example, path helpers and language detection utilities are validated using Vitest's describe and it blocks to ensure correct string manipulation and file extension mapping.
describe("joinPath", () => {
it("joins parent and name with a slash", () => {
expect(joinPath("/project/src", "Main.kt")).toBe("/project/src/Main.kt");
});
});
Sources: src/lib/file-utils.test.ts:74-78, package.json:44-55
Pure Logic Validation
For complex UI features like the LogViewer, the strategy involves testing pure filtering functions and data derivation (like unique source extraction) independently of the DOM. This ensures that the underlying logic for logcat filtering and level-based visibility is accurate.
Sources: src/components/common/LogViewer.test.ts:7-12
Backend Testing Framework
The Rust backend leverages standard #[test] and #[tokio::test] attributes for unit and asynchronous testing. High-performance requirements for logcat and build log processing are addressed through dedicated benchmarks.
Unit and Integration Tests
Backend tests are categorized into:
- Service Unit Tests: Validating internal logic like the
log_pipelineparsing andbuild_runnerresult recording. - Integration Tests: Located in
src-tauri/tests, these simulate real process execution using mock environments, such as a mockgradlewscript to verify build lifecycle handling.
The diagram shows the relationship between different Rust testing layers, where integration tests utilize mock environments to trigger core service logic.
Sources: AGENTS.md:43-48, src-tauri/tests/build_integration.rs:16-30
Performance Benchmarking
Critical paths, particularly file system operations and recursive directory walking, are benchmarked using Criterion. These are defined in the [[bench]] section of the Cargo configuration and target the fs_benchmarks.
Sources: src-tauri/Cargo.toml:60-65, AGENTS.md:47-48
Build System Integration Testing
A significant portion of the testing strategy is dedicated to the Android build orchestration. This involves complex state transitions and output parsing.
Build Output Parsing
The system uses regex-based parsers to extract structured data from raw Gradle output. Tests verify that the system correctly identifies:
- Kotlin and Java compiler errors.
- Task start and end outcomes (e.g.,
UP-TO-DATE,FAILED). - Build duration and success summaries.
Sources: src-tauri/src/services/build_runner.rs:410-500, src-tauri/tests/build_integration.rs:100-130
State Machine Validation
Integration tests ensure the BuildState inner state machine correctly transitions through phases such as Running, Cancelled, Success, and Failed. This includes verifying that PIDs are cleared and results are persisted to the history ring buffer.
| Test Case | Target Component | Expected Outcome |
|---|---|---|
record_build_result_success | BuildState | History length increments; status becomes Success. |
cancel_build | ProcessManager | Process is killed; status becomes Cancelled. |
history_limit_enforcement | VecDeque | Oldest records are evicted when MAX_HISTORY is reached. |
Sources: src-tauri/src/services/build_runner.rs:560-620, src-tauri/tests/build_integration.rs:150-180
Cross-Domain Consistency
Because the project relies on ts-rs to share types between Rust and TypeScript, a critical part of the strategy is maintaining binding integrity.
Binding Generation
Developers are required to run npm run generate:bindings whenever a Rust model changes. This is enforced by a CI check (npm run check:bindings) which executes cargo test and verifies that the generated TypeScript files in src/bindings/ match the current git state.
Sources: AGENTS.md:52-54, package.json:15-16
Test Execution Commands
The following table summarizes the primary commands used to execute the testing suite across different domains.
| Command | Domain | Description |
|---|---|---|
npm run test | Frontend | Runs Vitest unit tests once. |
npm run test:ui | Frontend | Opens the Vitest browser UI for interactive debugging. |
cargo test | Backend | Runs all Rust unit and integration tests. |
cargo bench | Backend | Executes Criterion benchmarks for performance measurement. |
npm run perf:collect | Project | Captures a snapshot of current performance metrics. |
Sources: AGENTS.md:38-50, package.json:13-18
Conclusion
The Keynobi testing strategy balances granular unit tests with broad integration tests to manage the complexity of a multi-language, process-heavy application. By utilizing mocks for the Android environment and performance benchmarks for core data pipelines, the project ensures reliability in build management and log processing while maintaining strict type safety across the IPC boundary.