#!/usr/bin/env bats # # Tests for scripts/install-ai.sh — bootstrap .ai/ in a fresh project. # # Strategy: redirect HOME to a temp dir, scaffold fresh project trees # under HOME/code/, run install-ai.sh against them. Canonical source # stays the real one (install-ai.sh resolves it relative to its own # location). For the fzf-pick form, stub fzf to take the first line. REAL_REPO="$(cd "$(dirname "$BATS_TEST_FILENAME")/../.." && pwd)" INSTALL_AI="$REAL_REPO/scripts/install-ai.sh" setup() { TEST_HOME="$(mktemp -d -t install-ai-bats.XXXXXX)" HOME_BAK="$HOME" export HOME="$TEST_HOME" mkdir -p "$TEST_HOME/code" "$TEST_HOME/projects" } teardown() { export HOME="$HOME_BAK" rm -rf "$TEST_HOME" } @test "install-ai: happy path with explicit PROJECT + --gitignore" { mkdir -p "$TEST_HOME/code/fresh" (cd "$TEST_HOME/code/fresh" && git init -q) run bash "$INSTALL_AI" --gitignore "$TEST_HOME/code/fresh" [ "$status" -eq 0 ] [ -d "$TEST_HOME/code/fresh/.ai/workflows" ] [ -d "$TEST_HOME/code/fresh/.ai/scripts" ] [ -d "$TEST_HOME/code/fresh/.ai/sessions" ] [ -d "$TEST_HOME/code/fresh/.ai/references" ] [ -d "$TEST_HOME/code/fresh/.ai/retrospectives" ] [ -f "$TEST_HOME/code/fresh/.ai/protocols.org" ] [ -f "$TEST_HOME/code/fresh/.ai/notes.org" ] grep -qFx ".ai/" "$TEST_HOME/code/fresh/.gitignore" } @test "install-ai --track: lands .gitkeep stubs in empty dirs" { mkdir -p "$TEST_HOME/code/tracked" (cd "$TEST_HOME/code/tracked" && git init -q) run bash "$INSTALL_AI" --track "$TEST_HOME/code/tracked" [ "$status" -eq 0 ] [ -f "$TEST_HOME/code/tracked/.ai/sessions/.gitkeep" ] [ -f "$TEST_HOME/code/tracked/.ai/references/.gitkeep" ] [ -f "$TEST_HOME/code/tracked/.ai/retrospectives/.gitkeep" ] } @test "install-ai: refuses on existing .ai/" { mkdir -p "$TEST_HOME/code/already/.ai" echo "marker" > "$TEST_HOME/code/already/.ai/marker.txt" run bash "$INSTALL_AI" --gitignore "$TEST_HOME/code/already" [ "$status" -eq 2 ] [[ "$output" == *"already exists"* ]] # Existing content untouched. [ -f "$TEST_HOME/code/already/.ai/marker.txt" ] } @test "install-ai: notes.org placeholders get substituted" { mkdir -p "$TEST_HOME/code/named-proj" (cd "$TEST_HOME/code/named-proj" && git init -q) run bash "$INSTALL_AI" --gitignore "$TEST_HOME/code/named-proj" [ "$status" -eq 0 ] # Project name landed. grep -q "named-proj" "$TEST_HOME/code/named-proj/.ai/notes.org" # No raw placeholders left. ! grep -q "\[Project Name\]" "$TEST_HOME/code/named-proj/.ai/notes.org" ! grep -q "\[Date\]" "$TEST_HOME/code/named-proj/.ai/notes.org" } @test "install-ai: fzf-pick form selects via stubbed fzf" { # Edge case 3 from todo.org:1766. The fzf-pick form is interactive; # stubbing fzf to take the first stdin line lets us exercise the # discovery+selection path without an interactive terminal. mkdir -p "$TEST_HOME/code/pickme" "$TEST_HOME/code/skipme" (cd "$TEST_HOME/code/pickme" && git init -q) (cd "$TEST_HOME/code/skipme" && git init -q) stub_bin="$(mktemp -d)" cat > "$stub_bin/fzf" <<'EOF' #!/bin/bash # Pass through stdin's first line as the "selection". head -n 1 EOF chmod +x "$stub_bin/fzf" PATH="$stub_bin:$PATH" run bash "$INSTALL_AI" --gitignore rm -rf "$stub_bin" [ "$status" -eq 0 ] # Sort order puts pickme first; fzf-stub returns the first line. [ -d "$TEST_HOME/code/pickme/.ai" ] [ ! -d "$TEST_HOME/code/skipme/.ai" ] }