Repository navigation
Testing
Nibtree changes people's repositories, so its tests use real git, not mocks. This page explains the two test suites, the helpers behind them, and what you must run before a change counts as done. The full list of test files is on Test Suites.
flowchart TB
subgraph Rust["cargo test (src-tauri)"]
Unit["unit tests next to the code<br/>watcher, terminal, search, scripts,<br/>shelf, engine, config"]
Git["git/tests.rs<br/>readers and the CLI runner"]
Cmd["commands/tests.rs<br/>whole commands"]
Fakes["github and mcp tests<br/>fakes and local HTTP"]
Oracle["merge engine vs git merge-file"]
Script["make-conflict-repo.sh output"]
end
subgraph Vitest["bun run test"]
Pure["pure .ts modules in src/lib"]
Tools["scripts/*.test.ts"]
end
Support["test_support.rs<br/>temporary repositories<br/>isolated git config"] --> Git
Support --> Cmd
Support --> Script
Run them with cd src-tauri && cargo test --workspace (the workspace includes the command line tool's crate, cli/). Add a filter to run a few, for example cargo test watcher.
src-tauri/src/test_support.rs builds repositories in temporary folders that vanish after the test. Before any test touches git, it points git at a sandbox:
-
HOME,USERPROFILE(which Windows reads first) andXDG_CONFIG_HOMEmove to a temporary folder; -
GIT_CONFIG_GLOBALpoints at an empty file andGIT_CONFIG_NOSYSTEM=1skips the system config; -
LC_ALL=CandLANG=C, so git messages are always in English.
Why so strict? Your own ~/.gitconfig might sign commits, rebase on pull, use a different conflict style or run hooks. Any of those would make a test pass on one machine and fail on another. Each repository also gets a local config: a test identity, signing off, an empty hooks folder, merge.conflictstyle = merge and pull.rebase = false. Commit dates come from a fixed clock, so hashes and the log order are stable.
The git processes come from cli::command, the same builder the app uses. The tests therefore exercise the real environment the app sets up.
| Helper | What it gives you |
|---|---|
TestRepo::new() |
an empty repository on main with the local config above |
repo.write, repo.commit_all, repo.branch, repo.checkout
|
build history in a few lines |
repo.git(&[...]), repo.porcelain(), repo.unmerged()
|
run git and inspect the result |
merge_conflict_repo() |
a repository stopped in a merge with a both-modified file, both added, deleted by us and by them, a binary and a CRLF file |
diverged_repo() |
two branches that edit the same file |
BareRemote::new(), TestRepo::clone_from
|
a local "remote" for fetch, pull and push tests |
TestDir |
a plain folder for workspace tests, with init_repo for nested repositories |
block_on |
runs an async Tauri command in a test |
commands/tests.rs calls the command functions directly, for example block_on(merge::save_resolution(...)), and then checks the repository with git itself. git/tests.rs covers the readers and the CLI runner. Most other modules test themselves next to the code; Test Suites lists them.
-
GitHub. The network, the keychain and the
ghCLI sit behind traits insrc-tauri/src/github/, sogithub/tests.rsruns every path against fakes. The one real-transport test uses a local listener. -
MCP.
mcp/tests.rsstarts the real server on an ephemeral port on127.0.0.1and calls it over HTTP, also through thenibtree cliclient, against temporary repositories. -
Terminals.
terminal.rsstarts real shells in pseudo terminals and checks that closing hangs up and then kills them.
git/tests.rs runs scripts/make-conflict-repo.sh (with and without --rebase) and asserts the exact list of conflicts it creates, and that it refuses a folder that is not empty. The demo is what people use to try the merge tool, so it must not rot. If you change the script, update these tests.
src-tauri/src/merge/engine.rs has hand-written cases (one-sided changes, overlaps, touching changes, insertions, missing final newlines, ignore-whitespace) and a property test that uses git as an oracle. The test builds 300 random base, ours and theirs files, merges them with our engine and with git merge-file -p, and:
- when both say "clean", requires the merged text to be identical;
- requires more than 50 clean cases, so the test cannot pass by comparing nothing;
- allows fewer than 5% clean or conflict disagreements, because our diff heuristics differ slightly from git's.
It skips itself when git is not installed. The random generator is seeded, so a failure repeats every time.
Run them with bun run test, one file with bun run test src/lib/stores/tabs.test.ts, or bun run test:watch to rerun on every save. Vitest picks up src/**/*.test.ts and scripts/**/*.test.ts (see vite.config.js). Vitest blanks CSS by default, but vite.config.js keeps the UI library's styles/colors.css, so the theme tests can read its real tokens (?raw) and check the contrast of every color theme.
The suites test pure modules only: the merge model, editor helpers, stores, the menu definition, terminal and search models, the Markdown renderer, themes, MCP tool definitions and the view models of every dialog. Each folder's files are listed on Test Suites.
-
Put non-trivial logic in a pure
.tsmodule next to its component and test it there. Components are hard to test; pure functions are easy.merge/model.ts,editor/lineDiff.ts,stores/tabs.tsandstores/navHistory.tsare good examples. - Every backend change gets a Rust test with a real temporary repository.
- Every bug fix gets a test that fails without the fix, and a "Bugs we fixed" entry in the feature's chapter (see Docs and Screenshots).
A change is done when all of these pass on your machine:
bun run check # 0 errors and 0 warnings
bun run test
cd src-tauri && cargo test --workspace
cd src-tauri && cargo clippy --workspace --all-targets -- -D warnings
bun scripts/build-wiki.ts --check # when docs changed
bun scripts/version.ts check # when versions changedCI runs the same commands (with --locked for cargo), so this also keeps the pull request green. Some things no test sees, such as how a view looks or feels. When you could not check something, say so plainly in the pull request instead of calling it done.
The oracle test compared too few cases. The first version of the property test changed lines so often that almost every random case conflicted. Its guard (at least 20 clean cases) caught this: only 8 of 150 cases were clean, so the test failed instead of passing while comparing almost nothing. We made mutations rarer, doubled the cases to 300, raised the bar to 50 clean cases and added the disagreement limit. The lesson: a property test needs a check that it really tested something.
These pages are generated from docs/wiki. To correct something, open a pull request against the source file; edits made here are overwritten.
Using Nibtree
- Getting Started
- Welcome Screen
- Workspaces
- Files Panel
- File Operations
- File Icons
- Rounded Panels
- Editor and Tabs
- Pin Reorder and Wrap Tabs
- Single Tab Title
- Split Editor
- New File and Unsaved Changes
- Unload Hidden Tabs
- Editing Code
- Code Appearance
- Markdown Editor
- Image and PDF Preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and Replace
- Changes and Commits
- Sign In Prompts
- Commit Box Layout
- Repository Actions
- Commit Options
- Ignoring Files
- Diffs
- Inline Diffs
- Staging View
- Revert a Change
- Resolving Conflicts
- Merge Tool
- Blame
- History and Log
- Merge Commits
- Branches and Tags
- Branches Popup
- Remotes
- Stashes
- Shelf
- Git Menu
- Git Dialogs
- Interactive Rebase
- Worktrees
- AI Agents
- AI Tasks
- AI Usage
- Keep Computer Awake
- Submodules
- Git LFS
- GitHub
- Git Console
- Terminal
- Terminal Features
- Scripts
- Navigation
- Menus
- Settings
- Settings Search
- Color Themes
- Settings Terminal and Automation
- Settings Files
- Updates
- Status Bar and Help
- Notifications
- Memory Use
- Clear Cache
- MCP and CLI
- Git Mergetool
- Keyboard Shortcuts
- Keyboard Shortcuts Editor
- Troubleshooting
- Troubleshooting Git
Developers
- Developer Guide
- Architecture
- Project Layout
- Backend
- How Folder Watching Works
- Folder Watching Bugs We Fixed
- How Workspace Files Work
- How the Preview Scheme Works
- Backend Services
- How Terminal Features Work
- Terminal Bugs We Fixed
- Frontend
- How the Rich Markdown Editor Works
- Rich Markdown Bugs We Fixed
- Git Menu Links
- Menu Keys and Routing
- Frontend Modules
- Blame Bugs We Fixed
- Project Color And Title Bar
- One Diff View
- Diff Bugs We Fixed
- Merge Tool Layouts
- Merge Tool Bugs We Fixed
- Color Theme Bugs We Fixed
- How the Connected Diff Works
- Rounded Panels Bugs We Fixed
- Update Bugs We Fixed
- Status Bar Bugs We Fixed
- MCP and CLI Bugs We Fixed
- Repository Actions Bugs We Fixed
- How the Changes Tab Works
- CodeMirror Patterns
- How the Cursor Works
- How Editor Features Work
- How the Path Bar Works
- Commands and Events
- Settings Reference
- Commands Workspace and Changes
- Commands Branches and Remotes
- Commands History and Extras
- Commands App and Tools
- Testing
- Test Suites
- Debugging
- Debugging with MCP
- Measuring Setting Memory
- How Terminal Memory Is Measured
- How Markdown Diagrams Work
- Releases and CI
- Publishing the Wiki
- Versioning and Changelog
- Browser Version Packages
- Browser Release Checks
- Docker Image
- Platforms and Signing
- Windows Support
- Windows Bugs We Fixed
- Windows MCP and CLI
- Docs and Screenshots
- UI Library
- UI Library MCP
- UI Library Bugs
- UI Library Migration
- Contributing
How features work
- Welcome screen
- Workspaces and folders
- Files panel
- File operations
- File icons
- Editor and tabs
- Pin, reorder and wrap tabs
- Single tab title
- Split editor
- New File and unsaved changes
- Unload hidden tabs
- Editing code
- Code appearance
- Markdown editor
- Image and PDF preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and replace
- Changes and commits
- Sign-in prompts
- Commit box layout
- Repository actions
- Commit options
- Ignoring files
- Diffs
- Inline diffs
- Staging view
- Revert a change
- Resolving conflicts
- Merge tool
- Blame
- History and log
- Merge commits
- Commit tabs
- Branches and tags
- Branches popup
- Remotes
- Stashes
- Shelf
- Git menu
- Git dialogs
- Interactive rebase
- Worktrees
- AI agents
- AI usage
- Keep computer awake
- AI tasks
- Submodules
- Git LFS
- GitHub account
- Git Console
- Back and Forward
- Integrated terminal
- Scripts tool window
- Menu bar
- Settings
- Search in Settings
- Color themes
- Rounded panels
- Updates and release channels
- Status bar and help links
- Notifications
- Memory readout and memory log
- Clear Cache
- MCP server and command line tool
- git mergetool mode