#!/usr/bin/env bash # ───────────────────────────────────────────────────────────────────────────── # export-visual-screenshots.sh # # Collects visual regression screenshots and test-results (diffs) into a # structured folder for AI review. # # Usage: # ./scripts/export-visual-screenshots.sh [output-dir] # # Default output: visual-review/ # ───────────────────────────────────────────────────────────────────────────── set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" OUTPUT_DIR="${1:-$PROJECT_ROOT/visual-review}" # Read project name from .env PROJECT_NAME="tibi-project" if [[ -f "$PROJECT_ROOT/.env" ]]; then PROJECT_NAME=$(grep -E '^PROJECT_NAME=' "$PROJECT_ROOT/.env" | cut -d= -f2 || echo "tibi-project") fi SCREENSHOTS_DIR="$PROJECT_ROOT/tests/e2e-visual/__screenshots__" TEST_RESULTS_DIR="$PROJECT_ROOT/test-results" rm -rf "$OUTPUT_DIR" mkdir -p "$OUTPUT_DIR/baselines" "$OUTPUT_DIR/diffs" echo "📸 Exporting visual regression data to $OUTPUT_DIR" echo "" if [[ -d "$SCREENSHOTS_DIR" ]]; then echo " ✓ Copying baseline screenshots..." cp -r "$SCREENSHOTS_DIR"/* "$OUTPUT_DIR/baselines/" 2>/dev/null || true else echo " ⚠ No baseline screenshots found at $SCREENSHOTS_DIR" echo " Run: yarn test:visual:update to generate baseline screenshots first." fi DIFF_COUNT=0 if [[ -d "$TEST_RESULTS_DIR" ]]; then while IFS= read -r -d '' file; do rel="${file#$TEST_RESULTS_DIR/}" dest_dir="$OUTPUT_DIR/diffs/$(dirname "$rel")" mkdir -p "$dest_dir" cp "$file" "$dest_dir/" ((DIFF_COUNT++)) || true done < <(find "$TEST_RESULTS_DIR" \( -name "*-actual.png" -o -name "*-expected.png" -o -name "*-diff.png" \) -print0 2>/dev/null) fi echo " ✓ Generating manifest.json..." MANIFEST="$OUTPUT_DIR/manifest.json" echo "{" > "$MANIFEST" echo ' "generated": "'"$(date -u +"%Y-%m-%dT%H:%M:%SZ")"'",' >> "$MANIFEST" echo ' "project": "'"$PROJECT_NAME"'",' >> "$MANIFEST" echo ' "viewports": {' >> "$MANIFEST" echo ' "visual-desktop": { "width": 1280, "height": 720, "device": "Desktop Chrome" },' >> "$MANIFEST" echo ' "visual-iphonese": { "width": 375, "height": 667, "device": "iPhone SE" },' >> "$MANIFEST" echo ' "visual-ipad": { "width": 768, "height": 1024, "device": "iPad Mini" }' >> "$MANIFEST" echo ' },' >> "$MANIFEST" echo ' "baselines": [' >> "$MANIFEST" FIRST=true if [[ -d "$OUTPUT_DIR/baselines" ]]; then while IFS= read -r -d '' file; do rel="${file#$OUTPUT_DIR/}" project=$(echo "$rel" | cut -d'/' -f2) if [[ "$FIRST" == "true" ]]; then FIRST=false else echo "," >> "$MANIFEST" fi printf ' { "path": "%s", "project": "%s" }' "$rel" "$project" >> "$MANIFEST" done < <(find "$OUTPUT_DIR/baselines" -name "*.png" -print0 2>/dev/null | sort -z) fi echo "" >> "$MANIFEST" echo ' ],' >> "$MANIFEST" echo ' "diffs": [' >> "$MANIFEST" FIRST=true if [[ -d "$OUTPUT_DIR/diffs" ]] && [[ $DIFF_COUNT -gt 0 ]]; then while IFS= read -r -d '' file; do rel="${file#$OUTPUT_DIR/}" if [[ "$FIRST" == "true" ]]; then FIRST=false else echo "," >> "$MANIFEST" fi printf ' { "path": "%s" }' "$rel" >> "$MANIFEST" done < <(find "$OUTPUT_DIR/diffs" -name "*.png" -print0 2>/dev/null | sort -z) fi echo "" >> "$MANIFEST" echo ' ],' >> "$MANIFEST" echo " \"diffCount\": $DIFF_COUNT" >> "$MANIFEST" echo "}" >> "$MANIFEST" BASELINE_COUNT=$(find "$OUTPUT_DIR/baselines" -name "*.png" 2>/dev/null | wc -l) echo "" echo " 📊 Summary:" echo " Baselines: $BASELINE_COUNT screenshots" echo " Diffs: $DIFF_COUNT images (actual/expected/diff)" echo " Manifest: $MANIFEST" echo "" echo " 💡 Review files in $OUTPUT_DIR/" echo " Or attach screenshots to a Copilot Chat for AI review."