ms-ai-architect/tests/test-hooks.sh
Kjell Tore Guttormsen dc0b627e98 feat(ms-ai-architect): C2.1 lib/user-data resolver + ambient org-injeksjon + C1 config bakoverkompat (TDD) [skip-docs]
Bæreren i C2 onboarding-redesign (#26). TDD: test FØR kode.

- lib/user-data.mjs (NY, ren, SKRIVER ALDRI; kun node:os/path):
  resolveUserDataDir/resolveOrgDir/resolveConfigPath peker ~/.claude/ms-ai-architect/
  (uavhengig av pluginRoot -> overlever reinstall, K2). CONFIG_FILENAME delt med C1
  (en sannhetskilde). buildOrgSummary: deterministisk, lengde-kappet H2-ekstraksjon.
- detection-schedule.mjs: loadScheduleConfig(pluginRoot, home=homedir()) leser
  bruker-sti FORST, fallback plugin-rot. Lokal CONFIG_FILENAME -> importeres fra resolver.
  Alle 3 kallere bruker ett-arg-kall (uendret oppforsel).
- session-start-context.mjs: injiserer buildOrgSummary ambient (K1) som egen
  Virksomhetskontekst-blokk; status-nudge beholdt nar org tom.

Verifisert: user-data 16/16 · detection-schedule 23/23 · test-hooks 10/10 ·
kb-update 191 · kb-eval 100 · validate PASSED.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 13:34:05 +02:00

146 lines
4.1 KiB
Bash

#!/bin/bash
# test-hooks.sh — Unit tests for ms-ai-architect hook scripts
# Usage: bash tests/test-hooks.sh
set -euo pipefail
PLUGIN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
SCRIPTS_DIR="$PLUGIN_ROOT/hooks/scripts"
PASS=0
FAIL=0
pass() { echo -e "\033[0;32m ✓ $1\033[0m"; PASS=$((PASS + 1)); }
fail() { echo -e "\033[0;31m ✗ $1\033[0m"; FAIL=$((FAIL + 1)); }
echo "=== Hook Script Tests ==="
echo ""
# NB: the pre-edit-secrets.mjs hook was removed in v1.7.0 (secrets scanning
# consolidated to the llm-security plugin — see CHANGELOG). Its tests were
# removed with it; secrets-scanning coverage now lives in llm-security.
# -------------------------------------------------------
# session-start-context.mjs
# -------------------------------------------------------
echo "--- session-start-context.mjs ---"
OUTPUT=$(CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" node "$SCRIPTS_DIR/session-start-context.mjs" 2>/dev/null)
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
pass "Runs without error (exit 0)"
else
fail "Expected exit 0, got $EXIT_CODE"
fi
if echo "$OUTPUT" | grep -q "Architect:"; then
pass "Output contains 'Architect:' prefix"
else
fail "Output missing 'Architect:' prefix"
fi
# C2.1: ambient org-context injection from the USER-owned org dir (HOME override).
# Proves K1 — the hook injects org CONTENT, not just a status nudge.
TMPHOME=$(mktemp -d)
mkdir -p "$TMPHOME/.claude/ms-ai-architect/org"
cat > "$TMPHOME/.claude/ms-ai-architect/org/organization-profile.md" <<'ORGEOF'
---
category: organization-profile
completed: true
---
# Virksomhetsprofil
## Sektor
Statlig
## Virksomhet
Testetaten
ORGEOF
OUTPUT=$(CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" HOME="$TMPHOME" node "$SCRIPTS_DIR/session-start-context.mjs" 2>/dev/null)
if echo "$OUTPUT" | grep -q "Virksomhetskontekst (auto-injisert"; then
pass "Injects ambient org-context block when user org/ has content (K1)"
else
fail "Missing ambient org-context block when user org/ has content"
fi
if echo "$OUTPUT" | grep -q "Sektor: Statlig"; then
pass "Ambient block reflects an org fact (Sektor: Statlig)"
else
fail "Ambient block missing org fact"
fi
# Empty home (no user org, no plugin org) => onboarding nudge, NO ambient block.
TMPHOME2=$(mktemp -d)
OUTPUT=$(CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" HOME="$TMPHOME2" node "$SCRIPTS_DIR/session-start-context.mjs" 2>/dev/null)
if echo "$OUTPUT" | grep -q "Ingen virksomhetstilpasning"; then
pass "No org content => onboarding nudge"
else
fail "Expected onboarding nudge when no org content"
fi
if echo "$OUTPUT" | grep -q "Virksomhetskontekst (auto-injisert"; then
fail "Should NOT inject ambient block when org is empty"
else
pass "No ambient block when org is empty"
fi
rm -rf "$TMPHOME" "$TMPHOME2"
echo ""
# -------------------------------------------------------
# stop-assessment-reminder.mjs
# -------------------------------------------------------
echo "--- stop-assessment-reminder.mjs ---"
# Test from a temp dir without .work/
TMPDIR_TEST=$(mktemp -d)
OUTPUT=$(cd "$TMPDIR_TEST" && node "$SCRIPTS_DIR/stop-assessment-reminder.mjs" 2>/dev/null)
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
pass "No .work/: exit 0"
else
fail "No .work/: expected exit 0, got $EXIT_CODE"
fi
if [ "$OUTPUT" = "{}" ]; then
pass "No .work/: returns {}"
else
fail "No .work/: expected {}, got: $OUTPUT"
fi
# Test with a fresh .work/ session
mkdir -p "$TMPDIR_TEST/.work/test-session"
touch "$TMPDIR_TEST/.work/test-session/state.json"
OUTPUT=$(cd "$TMPDIR_TEST" && node "$SCRIPTS_DIR/stop-assessment-reminder.mjs" 2>/dev/null)
if echo "$OUTPUT" | grep -q "systemMessage"; then
pass "Fresh .work/: returns systemMessage"
else
fail "Fresh .work/: expected systemMessage in output"
fi
if echo "$OUTPUT" | grep -q "architect:adr"; then
pass "Fresh .work/: suggests /architect:adr"
else
fail "Fresh .work/: missing /architect:adr suggestion"
fi
rm -rf "$TMPDIR_TEST"
echo ""
# -------------------------------------------------------
# Summary
# -------------------------------------------------------
TOTAL=$((PASS + FAIL))
echo "=== Results: $PASS/$TOTAL passed, $FAIL failed ==="
if [ "$FAIL" -gt 0 ]; then
exit 1
fi