build-small-hackathon/CodeFlow
10
1#!/usr/bin/env bash2# Headless-Chrome smoke test for frontend.html.3#4# Two kinds of checks:5# • STATIC — markup that's in the file regardless of rendering (buttons,6# controls). Grepped straight from frontend.html → 100% reliable.7# • DYNAMIC — proof the page actually rendered: CodeMirror mounted (its CDN/ESM8# imports ran), the editor wrap was revealed and the textarea fallback hidden.9# These need a real browser, so we render with headless Chrome.10#11# Only the dynamic half can flake (CDN timing), so the headless dump is retried12# until it's complete. Static checks never touch the browser.13#14# Usage: ./smoke-test.sh (exit 0 = pass, 1 = fail)15set -euo pipefail16cd "$(dirname "$0")"17 18FILE="frontend.html"19src="$(cat "$FILE")"20 21CHROME="${CHROME:-/Applications/Google Chrome.app/Contents/MacOS/Google Chrome}"22[ -x "$CHROME" ] || { echo "✗ Chrome not found at: $CHROME (set \$CHROME)"; exit 1; }23 24# Retry the dump until it's a COMPLETE render (has </html> AND the CodeMirror25# mount), up to 5 attempts — guards against partial/pre-render dumps.26dom=""27for attempt in 1 2 3 4 5; do28 dom="$("$CHROME" --headless --disable-gpu --no-sandbox \29 --virtual-time-budget=25000 \30 --dump-dom "file://$PWD/$FILE" 2>/dev/null)"31 if grep -q '</html>' <<<"$dom" && grep -q 'class="cm-editor' <<<"$dom"; then32 break33 fi34 [ "$attempt" -lt 5 ] && { echo "… incomplete render (attempt $attempt), retrying"; sleep 1; }35done36 37fail=038chk() { # chk "<haystack>" "<label>" "<grep -E pattern>" "<want: yes|no>"39 # here-string (not echo|grep): with `set -o pipefail`, grep -q matching closes40 # the pipe early → echo gets SIGPIPE → the pipeline falsely reports failure.41 if grep -qE "$3" <<<"$1"; then found=yes; else found=no; fi42 if [ "$found" = "$4" ]; then echo "✓ $2"; else echo "✗ $2 (wanted match=$4, got=$found)"; fail=1; fi43}44static() { chk "$src" "$1" "$2" "$3"; } # grep the source file45dynamic(){ chk "$dom" "$1" "$2" "$3"; } # grep the rendered DOM46 47echo "— dynamic (needs a real render) —"48dynamic "editor mounted (.cm-editor present)" 'class="cm-editor' yes49dynamic "line-number gutter rendered" 'class="cm-gutterElement' yes50dynamic "editor-wrap revealed by JS (not hidden)" '<div id="editor-wrap" class="editor-wrap">' yes51dynamic "textarea fallback hidden by JS" '<textarea id="code-fallback"[^>]*hidden' yes52 53echo "— static (markup in the file) —"54static "language selector present" 'id="lang-select"' yes55static "Copy / Clear buttons present" 'id="copy-btn".*|id="clear-btn"' yes56static "Generate is compact (in action bar)" '<button id="submit-btn" class="btn-primary"' yes57static "output toolbar present (Copy Mermaid)" 'id="copy-mmd-btn"' yes58static "SVG / PNG export buttons present" 'id="svg-btn".*|id="png-btn"' yes59static "export buttons disabled until a render" '<button id="svg-btn"[^>]*disabled' yes60static "theme toggle present" 'id="theme-toggle"' yes61static "zoom controls present" 'id="zoom-ctrl"' yes62static "flow-arrow cue present" 'class="flow-arrow"' yes63 64echo65[ "$fail" -eq 0 ] && echo "PASS" || echo "FAIL"66exit "$fail"67 