How to Run Python Unit Tests for i-have-adhd Hooks: A Complete Guide
Use python3 -m unittest discover -s tests -v to run the full test suite, or python3 -m unittest tests.test_always_on_hooks for hook-specific validation.
The i-have-adhd repository provides SessionStart hooks for Claude and Codex that automatically inject an ADHD ruleset into every session when users opt in. To ensure these cross-platform hooks work reliably, the project maintains a Python unit test suite in tests/test_always_on_hooks.py. This guide covers how to run Python unit tests for i-have-adhd hooks locally, what the tests verify, and how to interpret the results.
Prerequisites: Install Required Runtimes
The hook tests exercise three runtime environments: Node.js, Bash, and PowerShell. Install these before running tests.
On Linux/macOS:
# Node.js (required for the primary hook)
sudo apt-get install nodejs # Debian/Ubuntu
brew install node # macOS
# PowerShell (optional but tested)
sudo apt-get install powershell
On Windows:
# Using Chocolatey
choco install nodejs
# PowerShell is built-in; Bash available via WSL or Git Bash
Verify installations:
node --version
bash --version
pwsh --version
Clone and Navigate to the Repository
git clone https://github.com/ayghri/i-have-adhd.git
cd i-have-adhd
The test suite expects this directory structure:
i-have-adhd/
├── hooks/
│ ├── always-on.mjs
│ ├── always-on.sh
│ ├── always-on.ps1
│ └── hooks.json
├── skills/i-have-adhd/SKILL.md
└── tests/
└── test_always_on_hooks.py
Run All Python Unit Tests
Execute the complete test discovery to validate the entire codebase:
python3 -m unittest discover -s tests -v
The -v (verbose) flag shows individual test names and results. Expect output like:
test_flag_absent_hooks_silent (tests.test_always_on_hooks.TestAlwaysOnHooks) ... ok
test_flag_present_shows_ruleset (tests.test_always_on_hooks.TestAlwaysOnHooks) ... ok
test_frontmatter_stripping (tests.test_always_on_hooks.TestAlwaysOnHooks) ... ok
...
----------------------------------------------------------------------
Ran 5 tests in 2.34s
OK
Run Only the Hook Tests
For rapid iteration during hook development, target the specific test module:
python3 -m unittest tests.test_always_on_hooks
Or with verbosity:
python3 -m unittest tests.test_always_on_hooks -v
What the Python Unit Tests Validate
The test_always_on_hooks.py suite performs comprehensive validation of the i-have-adhd hook system:
Temporary Environment Setup
- Creates a mock plugin directory structure
- Copies
hooks/andskills/folders to isolated temp locations - Configures
$CLAUDE_CONFIG_DIRpointing to a temporary path
Flag File Behavior
- Absent flag: Verifies all three hook runtimes (
node always-on.mjs,sh always-on.sh,pwsh always-on.ps1) produce no output - Present flag: Creates
.i-have-adhd-alwaysin the temp config directory and confirms the ADHD ruleset prints to stdout
Front-Matter Processing
The tests verify skills/i-have-adhd/SKILL.md parsing handles edge cases:
- Standard YAML front-matter delimiters (
---) are stripped correctly - Stray whitespace around delimiters doesn't break parsing
- Unclosed delimiters are handled gracefully
Codex Launcher Configuration
Cross-references hooks/hooks.json against the actual hooks/always-on.mjs implementation:
- Confirms the
commandfield invokes the shared Node launcher - Validates environment variable references like
$CLAUDE_CONFIG_DIR
Manual Hook Testing Outside Python
To observe hook behavior directly without the test framework:
# Without opt-in flag: silent
node hooks/always-on.mjs
# Enable opt-in
mkdir -p ~/.claude
touch ~/.claude/.i-have-adhd-always
# Now produces output
node hooks/always-on.mjs
Test Bash and PowerShell variants:
sh hooks/always-on.sh # Unix fallback
pwsh hooks/always-on.ps1 # Windows fallback
Remove the flag to silence output again:
rm ~/.claude/.i-have-adhd-always
Key Files in the Test System
| File | Purpose |
|---|---|
tests/test_always_on_hooks.py |
Main Python unittest suite with TestAlwaysOnHooks class |
hooks/always-on.mjs |
Primary Node.js hook implementation |
hooks/always-on.sh |
Bash implementation for Unix compatibility |
hooks/always-on.ps1 |
PowerShell implementation for Windows |
hooks/hooks.json |
Claude/Codex hook configuration schema |
skills/i-have-adhd/SKILL.md |
Source content injected by hooks |
Troubleshooting Common Test Failures
Missing Runtime Errors
If you see FileNotFoundError or subprocess failures, verify the runtime is in your PATH:
which node
which pwsh
Permission Denied on Hooks
Ensure hook scripts are executable:
chmod +x hooks/always-on.sh
chmod +x hooks/always-on.mjs # if directly executed
Windows-Specific Issues
PowerShell execution policy may block scripts. Adjust as needed:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Summary
Running Python unit tests for i-have-adhd hooks ensures cross-platform reliability of the SessionStart injection system:
- Full suite:
python3 -m unittest discover -s tests -v - Hook-only:
python3 -m unittest tests.test_always_on_hooks - The tests in
tests/test_always_on_hooks.pyvalidate Node, Bash, and PowerShell runtimes - Flag file behavior, front-matter stripping, and launcher configuration are all verified
- Manual testing requires the
.i-have-adhd-alwaysopt-in flag in~/.claude/
Frequently Asked Questions
What Python version is required to run the i-have-adhd hook tests?
The tests use standard unittest from the Python standard library, compatible with Python 3.7+. No external test dependencies are required.
Why do the tests need Node.js and PowerShell installed?
The test suite invokes actual hook scripts via subprocess.run to verify real-world behavior. Since hooks/always-on.mjs, hooks/always-on.sh, and hooks/always-on.ps1 target different platforms, the tests exercise each runtime to catch environment-specific regressions.
Can I run the tests without PowerShell?
Yes, but tests targeting the PowerShell hook will be skipped or fail. The Node.js hook is the primary implementation; Bash and PowerShell serve as fallbacks. For full coverage on Linux/macOS, install PowerShell via your package manager.
What does "front-matter stripping" mean in the test context?
The skills/i-have-adhd/SKILL.md file contains YAML front-matter (metadata between --- delimiters) that Claude uses for skill discovery. The hooks must output only the ruleset content, not this metadata. The tests verify this stripping works correctly even with malformed delimiters.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →