Testing Strategy
Relevant source files
The following files were used as context for generating this wiki page:
The testing strategy for Ghostbird employs a combination of automated unit tests, architectural sanity checks, and manual testing to ensure code quality and prevent regressions. The primary testing framework is Vitest, which is used for running unit tests, generating coverage reports, and providing an interactive UI for development. The strategy focuses on testing core logic modules while acknowledging the need for manual verification for UI-heavy components.
The project does not aim for 100% test coverage but rather for sufficient coverage to maintain stability, particularly within the core logic modules.
Sources: doc/testing.md:1-15, README.md:210-211
Test Execution
Tests are executed via yarn scripts defined in package.json. These scripts provide different modes for development, continuous integration, and debugging.
Sources: package.json:23-48, doc/testing.md:3-7
Test Commands
The following table summarizes the available test commands:
| Command | Description |
|---|---|
yarn test | Runs the full test suite once. This is the main command used in CI. |
yarn test:watch | Runs tests continuously as files are edited. |
yarn test:ui | Opens the Vitest UI, a local webpage for interactive testing. |
yarn test:coverage | Runs tests and generates a code coverage report using v8. |
yarn test:sanity | Runs a specific set of "sanity" tests, which verify the application's dependency injection setup. |
yarn test:list | Lists all discovered tests without running them. |
Sources: package.json:33-38, doc/testing.md:3-7, doc/faq-architectural.md:11-13
Test Execution Flow
The build process integrates sanity checks to catch common mistakes early. During a development build, basic sanity tests are run by the tsdown bundler. In a release build, these are skipped as a full yarn test is expected to be run as a pre-build step.
The following diagram illustrates the test execution flow during the build process.
This diagram shows that yarn test is a prerequisite for a full build, and the tsdown build tool itself can run sanity tests during development.
Sources: package.json:41, tools/tsdown_config.ts:13-15, tools/tsdown_config.ts:85-87
Test Types and Structure
Ghostbird utilizes several types of tests, each with a specific purpose and location within the codebase.
| Test Type | Location | Purpose |
|---|---|---|
| Unit Tests | src/test/*.ts | Exercise multiple modules, often across layers, through their public APIs. The main focus is on src/ghosttext-session/ and src/ghosttext-runner/ modules, which contain most of the application logic. |
| In-source Tests | Within non-test source files (e.g., src/<module>/*.ts) | Guarded by if (import.meta.vitest), these tests are for testing individual private functions and demonstrating usage. They are removed from production builds. |
| Sanity Tests | src/test/sanity.test.ts, src/test/startup.test.ts | Verify the architectural integrity, specifically the custom dependency injection system. They ensure all auto-instantiated classes can be resolved and their dependencies are met. |
Sources: doc/testing.md:8-15, doc/faq-architectural.md:11-13, tools/tsdown_config.ts:46-49
Architectural Sanity Checks
A key part of the testing strategy is verifying the custom dependency injection (DI) mechanism, which relies on static isSingleton properties on classes. The sanity tests, located in src/test/startup.test.ts, are crucial for maintaining architectural integrity.
These tests perform the following actions:
- Collect all modules and classes that participate in the DI system.
- Attempt to "wire" the dependencies, simulating the application startup process.
- Verify that all dependencies for every class can be successfully resolved and instantiated.
- Check that all injected dependencies are actually used within the class body to prevent unused injections.
- Generate a
dependency_tree.mdfile in thebuild/test/directory, which provides a visual representation of the class dependency graph.
Sources: src/test/startup.test.ts:32-47, doc/faq-architectural.md:4-13
The process of verifying dependencies is illustrated below.
This sequence shows how the startup test validates the DI container's configuration and generates a dependency report.
Sources: src/test/startup.test.ts:43-47, src/test/util/dependency_reporter.ts:10-23
The dependency_reporter.ts utility is responsible for creating the dependency graph in Mermaid syntax and generating example startup code for documentation.
// src/test/util/dependency_reporter.ts:59-66
function* makeMermaid(modules: AnyModules, deps: [string, string[]][]): Generator<string> {
yield "flowchart LR"
yield* deps.map(([name, deps]) => `${toSnakeCase(name)}["${findModule(modules, name, deps)}<br>${name}"]`)
yield* deps.flatMap(([name, deps]) =>
deps.length === 0 ? [] : [`${toSnakeCase(name)} --> ${deps.map(toSnakeCase).join(" & ")}`],
)
}
This code snippet shows the function that generates the Mermaid diagram for the dependency tree.
Sources: src/test/util/dependency_reporter.ts:59-66
Manual Testing
For features that are difficult to automate, such as UI interactions, the project relies on manual testing. The contribution guidelines outline a manual testing workflow.
The process involves:
- Ensuring a GhostText server is running.
- Launching Thunderbird with the development version of the add-on using
yarn start. - Opening a compose window and interacting with the Ghostbird button and functionality.
- Performing unusual actions ("weird things") to test edge cases and robustness.
While there is an intention to automate these UI tests in the future, it is currently considered a significant effort and is postponed.
Sources: doc/testing.md:17-27, CONTRIBUTING.md:47-50