Files
AOS/aos-verify6.sh
T
Z User e45b68bb8b feat: IMAP mail sync with thread-to-contact matching (PRD §6.1)
Real IMAP connection via imapflow library:
- Connects to IMAP server (IMAPFlow, TLS on port 993)
- Fetches recent messages (configurable limit, default 20)
- Extracts: from, fromEmail, subject, date, snippet (200 chars)
- Thread-to-contact matching (PRD §6.1):
  1. Match sender email against persons table
  2. If no person match, extract domain and match against company.website
  3. Returns matchedCompany + matchedPerson for each email
- Audit-logged (action: crm.mailsync:imap)
- Zod validated (host, port, user, password, folder, limit)
- 502 on IMAP connection failure with detail
- 400 on validation failure

Tested: invalid creds → 502 'IMAP connection failed', missing host → 400
2026-10-27 22:50:50 +00:00

142 lines
7.4 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Single-process verification: server + browser tests, all in one bash call.
set -u
cd /home/z/my-project
BASE=http://127.0.0.1:3000
SHOTS=/home/z/my-project/aos-shots
mkdir -p "$SHOTS"
echo "=== Start server + reseed ==="
pkill -f "next dev" 2>/dev/null; pkill -f "tee dev.log" 2>/dev/null; sleep 2
bun run dev > dev.log 2>&1 &
SRV=$!
for i in $(seq 1 90); do curl -s -o /dev/null "$BASE/" 2>/dev/null && break; sleep 1; done
echo " ready after ${i}s"
sleep 3
# reseed cleanly
curl -s -X POST "$BASE/api/aos/seed" >/dev/null
echo " reseeded"
sleep 2
agent-browser open "$BASE/" >/dev/null 2>&1
agent-browser wait --load networkidle >/dev/null 2>&1 || true
agent-browser wait 3500 >/dev/null 2>&1
agent-browser set viewport 1440 900 >/dev/null 2>&1
# helper: read active H1
h1() { agent-browser get text h1 2>/dev/null | head -1; }
echo ""
echo "=== T1: Audit view ==="
agent-browser find text "Audit-Protokoll" click >/dev/null 2>&1
agent-browser wait 3000 >/dev/null 2>&1
echo " H1=$(h1)"
agent-browser screenshot --full "$SHOTS/v6-audit.png" >/dev/null 2>&1 && echo " shot OK"
# click first audit entry to show detail
agent-browser eval "document.querySelectorAll('button[class*=border]')[0]?.click()" >/dev/null 2>&1
agent-browser wait 1500 >/dev/null 2>&1
agent-browser screenshot --full "$SHOTS/v6-audit-detail.png" >/dev/null 2>&1 && echo " detail shot OK"
echo ""
echo "=== T2: CRM company drawer ==="
agent-browser find text "CRM" click >/dev/null 2>&1
agent-browser wait 3000 >/dev/null 2>&1
agent-browser find role tab click --name "Firmen" >/dev/null 2>&1
agent-browser wait 2000 >/dev/null 2>&1
agent-browser eval "document.querySelector('tbody tr')?.click()" >/dev/null 2>&1
agent-browser wait 2500 >/dev/null 2>&1
STATE=$(agent-browser eval "!!document.querySelector('[role=dialog]') ? 'OPEN' : 'CLOSED'" 2>/dev/null | tail -1 | tr -d '"')
echo " drawer: $STATE"
agent-browser screenshot --full "$SHOTS/v6-company-drawer.png" >/dev/null 2>&1 && echo " shot OK"
agent-browser press Escape >/dev/null 2>&1; agent-browser wait 800 >/dev/null 2>&1
echo ""
echo "=== T3: Create Deal modal ==="
agent-browser find text "CRM" click >/dev/null 2>&1; agent-browser wait 1500 >/dev/null 2>&1
# the header "+ Deal" button — use semantic find
agent-browser find role button click --name "Deal" >/dev/null 2>&1 || agent-browser eval "Array.from(document.querySelectorAll('button')).find(b=>b.textContent?.trim()==='Deal')?.click()" >/dev/null 2>&1
agent-browser wait 2000 >/dev/null 2>&1
STATE=$(agent-browser eval "!!document.querySelector('[role=dialog]') ? 'OPEN' : 'CLOSED'" 2>/dev/null | tail -1 | tr -d '"')
echo " modal: $STATE"
agent-browser screenshot --full "$SHOTS/v6-create-deal.png" >/dev/null 2>&1 && echo " shot OK"
# fill title
agent-browser eval "const i=document.querySelector('input[placeholder*=z.B]'); if(i){i.focus(); i.value='E2E Test-Deal'; i.dispatchEvent(new Event('input',{bubbles:true}))}" >/dev/null 2>&1
agent-browser wait 500 >/dev/null 2>&1
agent-browser screenshot --full "$SHOTS/v6-create-deal-filled.png" >/dev/null 2>&1 && echo " filled shot OK"
# click Anlegen
agent-browser find text "Anlegen" click >/dev/null 2>&1
agent-browser wait 3000 >/dev/null 2>&1
agent-browser screenshot --full "$SHOTS/v6-create-deal-done.png" >/dev/null 2>&1 && echo " done shot OK"
echo ""
echo "=== T4: Finance invoice dialog + finalize ==="
agent-browser find text "Finanzen" click >/dev/null 2>&1
agent-browser wait 3000 >/dev/null 2>&1
agent-browser eval "document.querySelector('tbody tr')?.click()" >/dev/null 2>&1
agent-browser wait 2000 >/dev/null 2>&1
STATE=$(agent-browser eval "!!document.querySelector('[role=dialog]') ? 'OPEN' : 'CLOSED'" 2>/dev/null | tail -1 | tr -d '"')
echo " dialog: $STATE"
agent-browser screenshot --full "$SHOTS/v6-invoice-dialog.png" >/dev/null 2>&1 && echo " shot OK"
# if draft, click Finalisieren
agent-browser find text "Finalisieren & versenden" click >/dev/null 2>&1 || echo " (no finalize button — invoice not draft)"
agent-browser wait 3000 >/dev/null 2>&1
agent-browser press Escape >/dev/null 2>&1; agent-browser wait 500 >/dev/null 2>&1
echo ""
echo "=== T5: Projects add task + log time ==="
agent-browser find text "Projekte" click >/dev/null 2>&1
agent-browser wait 3000 >/dev/null 2>&1
# fill task input via eval (more reliable than snapshot ref)
agent-browser eval "const i=document.querySelector('input[placeholder*=Neue]'); if(i){i.focus(); i.value='E2E-Aufgabe'; i.dispatchEvent(new Event('input',{bubbles:true}))}" >/dev/null 2>&1
agent-browser wait 500 >/dev/null 2>&1
agent-browser find text "Hinzufügen" click >/dev/null 2>&1 || agent-browser eval "Array.from(document.querySelectorAll('button')).find(b=>b.textContent?.includes('Hinzufügen'))?.click()" >/dev/null 2>&1
agent-browser wait 3000 >/dev/null 2>&1
echo " task add attempted"
agent-browser screenshot --full "$SHOTS/v6-projects-task.png" >/dev/null 2>&1 && echo " task shot OK"
# switch to Zeit tab
agent-browser find role tab click --name "Zeit" >/dev/null 2>&1 || agent-browser find text "Zeit" click >/dev/null 2>&1
agent-browser wait 2000 >/dev/null 2>&1
agent-browser eval "const ds=document.querySelectorAll('input[placeholder*=SSO]')[0]||document.querySelector('input[placeholder*=z.B]'); if(ds){ds.focus(); ds.value='E2E-Zeitbuchung'; ds.dispatchEvent(new Event('input',{bubbles:true}))}" >/dev/null 2>&1
agent-browser eval "const m=document.querySelector('input[placeholder*=90]'); if(m){m.focus(); m.value='60'; m.dispatchEvent(new Event('input',{bubbles:true}))}" >/dev/null 2>&1
agent-browser wait 500 >/dev/null 2>&1
agent-browser find text "Buchen" click >/dev/null 2>&1 || agent-browser eval "Array.from(document.querySelectorAll('button')).find(b=>b.textContent?.includes('Buchen'))?.click()" >/dev/null 2>&1
agent-browser wait 3000 >/dev/null 2>&1
agent-browser screenshot --full "$SHOTS/v6-projects-time.png" >/dev/null 2>&1 && echo " time shot OK"
echo ""
echo "=== T6: Command palette search ==="
agent-browser eval "window.dispatchEvent(new KeyboardEvent('keydown',{key:'k',metaKey:true}))" >/dev/null 2>&1
agent-browser wait 1500 >/dev/null 2>&1
agent-browser eval "const i=document.querySelector('input[placeholder*=Suche]'); if(i){i.focus(); i.value='Hamburg'; i.dispatchEvent(new Event('input',{bubbles:true}))}" >/dev/null 2>&1
agent-browser wait 2000 >/dev/null 2>&1
agent-browser screenshot --full "$SHOTS/v6-command-search.png" >/dev/null 2>&1 && echo " search shot OK"
agent-browser press Escape >/dev/null 2>&1; agent-browser wait 500 >/dev/null 2>&1
echo ""
echo "=== T7: Leads approve + convert ==="
agent-browser find text "Leads Finder" click >/dev/null 2>&1
agent-browser wait 3000 >/dev/null 2>&1
agent-browser find text "Genehmigen" click >/dev/null 2>&1
agent-browser wait 2500 >/dev/null 2>&1
agent-browser screenshot --full "$SHOTS/v6-lead-approved.png" >/dev/null 2>&1 && echo " approved shot OK"
agent-browser find text "In CRM konvertieren" click >/dev/null 2>&1
agent-browser wait 3500 >/dev/null 2>&1
agent-browser screenshot --full "$SHOTS/v6-lead-converted.png" >/dev/null 2>&1 && echo " converted shot OK"
echo ""
echo "=== Errors ==="
agent-browser errors 2>&1 | head -10
echo "--- console (last 5) ---"
agent-browser console 2>&1 | tail -5
echo ""
echo "=== Cleanup ==="
agent-browser close >/dev/null 2>&1
kill $SRV 2>/dev/null
echo "=== dev.log (errors) ==="
grep -iE "error|⨯|500" dev.log | grep -v "SIGTERM" | tail -10
echo ""
echo "=== Screenshots ==="
ls -la "$SHOTS"/v6-* 2>/dev/null | tail -15
echo "=== DONE ==="