claude-code-ultimate-guide/examples/hooks/bash/test-on-change.sh
Florian BRUNIAUX 975b8019ac feat: add 4 ClaudeKit-inspired hooks (checkpoint, validation, file-guard)
- Add auto-checkpoint.sh (Stop event, git stash automation)
- Add typecheck-on-save.sh (PostToolUse, TypeScript validation)
- Add test-on-change.sh (PostToolUse, smart test detection)
- Add file-guard.sh (PreToolUse, unified file protection)
- Add ClaudeKit evaluation (3/5, patterns extracted)
- Version bump 3.21.0 → 3.21.1 (sync across all docs)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-02 21:50:48 +01:00

73 lines
1.8 KiB
Bash
Executable file

#!/bin/bash
# .claude/hooks/test-on-change.sh
# Event: PostToolUse
# Detects and runs associated tests after code changes
# Part of validation pipeline pattern
set -euo pipefail
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
# Only run after Edit/Write operations
if [[ "$TOOL_NAME" != "Edit" && "$TOOL_NAME" != "Write" ]]; then
exit 0
fi
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
# Skip if not a code file
if [[ ! "$FILE_PATH" =~ \.(ts|tsx|js|jsx|py|go|rs)$ ]]; then
exit 0
fi
# Find associated test file
TEST_FILE=""
BASENAME=$(basename "$FILE_PATH" | sed 's/\.[^.]*$//')
DIRNAME=$(dirname "$FILE_PATH")
# Common test patterns
for pattern in "${BASENAME}.test.ts" "${BASENAME}.test.js" "${BASENAME}_test.py" "${BASENAME}_test.go"; do
if [[ -f "$DIRNAME/$pattern" ]]; then
TEST_FILE="$DIRNAME/$pattern"
break
fi
done
# Try adjacent __tests__ directory
if [[ -z "$TEST_FILE" ]]; then
for pattern in "__tests__/${BASENAME}.test.ts" "__tests__/${BASENAME}.test.js"; do
if [[ -f "$DIRNAME/$pattern" ]]; then
TEST_FILE="$DIRNAME/$pattern"
break
fi
done
fi
# If test file found, run it
if [[ -n "$TEST_FILE" ]]; then
# Determine test runner
if [[ -f "package.json" ]]; then
TEST_CMD="npm test -- $TEST_FILE"
elif [[ -f "pytest.ini" || -f "pyproject.toml" ]]; then
TEST_CMD="pytest $TEST_FILE"
elif [[ -f "go.mod" ]]; then
TEST_CMD="go test $(dirname $TEST_FILE)"
else
exit 0
fi
# Run tests
TEST_OUTPUT=$($TEST_CMD 2>&1 || true)
# Check for failures
if echo "$TEST_OUTPUT" | grep -qE "(FAIL|failed|error|Error)"; then
cat << EOF
{
"systemMessage": "⚠ Tests failed in $TEST_FILE:\n\n$TEST_OUTPUT\n\nFix implementation or update tests."
}
EOF
fi
fi
exit 0