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
140 lines
6.0 KiB
Bash
Executable File
140 lines
6.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Verify the new AOS features: audit view, company drawer, lead convert, invoice dialog, create deal, search, task/time logging.
|
|
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 ==="
|
|
pkill -f "next dev" 2>/dev/null; sleep 1
|
|
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 2
|
|
|
|
echo ""
|
|
echo "=== New API endpoints ==="
|
|
for ep in "search?q=hamburg" "audit?limit=20"; do
|
|
code=$(curl -s -o /dev/null -w "%{http_code}" "$BASE/api/aos/$ep")
|
|
echo " /api/aos/$ep -> $code"
|
|
done
|
|
|
|
echo ""
|
|
echo "=== Test lead convert API (pick first pending lead) ==="
|
|
LEADS=$(curl -s "$BASE/api/aos/leads")
|
|
# find a pending lead id via python
|
|
LEAD_ID=$(echo "$LEADS" | python3 -c "import sys,json; d=json.load(sys.stdin); print(next((l['id'] for l in d['leads'] if l['status']=='pending'), d['leads'][0]['id']))" 2>/dev/null)
|
|
echo " lead id: $LEAD_ID"
|
|
# first approve it
|
|
curl -s -X PATCH "$BASE/api/aos/leads/$LEAD_ID" -H 'content-type: application/json' -d '{"status":"approved","reviewReason":"Test approval"}' >/dev/null
|
|
echo " approved."
|
|
# then convert
|
|
CONV=$(curl -s -X POST "$BASE/api/aos/leads/convert" -H 'content-type: application/json' -d "{\"leadId\":\"$LEAD_ID\"}")
|
|
echo " convert response (first 200 chars): $(echo "$CONV" | head -c 200)"
|
|
echo ""
|
|
|
|
echo "=== Test create deal API ==="
|
|
DEAL=$(curl -s -X POST "$BASE/api/aos/crm/deals" -H 'content-type: application/json' -d '{"companyId":"","title":"Test Deal","valueCents":500000,"stage":"lead"}')
|
|
echo " (expected 400 for missing companyId) -> $(echo "$DEAL" | head -c 100)"
|
|
|
|
echo ""
|
|
echo "=== Browser: open dashboard ==="
|
|
agent-browser open "$BASE/" >/dev/null 2>&1
|
|
agent-browser wait --load networkidle >/dev/null 2>&1 || true
|
|
agent-browser wait 2000 >/dev/null 2>&1
|
|
|
|
echo "=== Navigate to Audit view ==="
|
|
agent-browser snapshot -i >/tmp/snap.txt 2>&1
|
|
AUDREF=$(grep -i 'button "Audit' /tmp/snap.txt | head -1 | grep -oE 'ref=e[0-9]+' | head -1)
|
|
echo " Audit nav ref: $AUDREF"
|
|
[ -n "$AUDREF" ] && agent-browser click "$AUDREF" >/dev/null 2>&1
|
|
agent-browser wait 2000 >/dev/null 2>&1
|
|
H1=$(agent-browser get text h1 2>/dev/null | head -1)
|
|
echo " Audit H1: $H1"
|
|
agent-browser screenshot --full "$SHOTS/v3-audit.png" >/dev/null 2>&1 && echo " shot audit OK"
|
|
|
|
echo ""
|
|
echo "=== Navigate to CRM, open company drawer ==="
|
|
agent-browser find text "CRM" click >/dev/null 2>&1
|
|
agent-browser wait 2000 >/dev/null 2>&1
|
|
# click on companies tab
|
|
agent-browser snapshot -i >/tmp/snap2.txt 2>&1
|
|
TABREF=$(grep -i 'tab "Firmen"' /tmp/snap2.txt | head -1 | grep -oE 'ref=e[0-9]+' | head -1)
|
|
echo " Firmen tab ref: $TABREF"
|
|
[ -n "$TABREF" ] && agent-browser click "$TABREF" >/dev/null 2>&1
|
|
agent-browser wait 1500 >/dev/null 2>&1
|
|
# click first company row
|
|
agent-browser eval "document.querySelector('tbody tr')?.click()" >/dev/null 2>&1
|
|
agent-browser wait 1500 >/dev/null 2>&1
|
|
agent-browser screenshot --full "$SHOTS/v3-company-drawer.png" >/dev/null 2>&1 && echo " shot company-drawer OK"
|
|
# check drawer content
|
|
DRAWER=$(agent-browser eval "document.querySelector('[role=dialog]')?.textContent?.slice(0,200) || 'no dialog'" 2>/dev/null | tail -1)
|
|
echo " drawer text: $(echo "$DRAWER" | head -c 150)"
|
|
|
|
echo ""
|
|
echo "=== Navigate to Finance, open invoice dialog ==="
|
|
agent-browser find text "Finanzen" click >/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 1500 >/dev/null 2>&1
|
|
agent-browser screenshot --full "$SHOTS/v3-invoice-dialog.png" >/dev/null 2>&1 && echo " shot invoice-dialog OK"
|
|
DIALOG=$(agent-browser eval "document.querySelector('[role=dialog]')?.textContent?.slice(0,200) || 'no dialog'" 2>/dev/null | tail -1)
|
|
echo " dialog text: $(echo "$DIALOG" | head -c 150)"
|
|
|
|
echo ""
|
|
echo "=== Navigate to Projects, add a task ==="
|
|
agent-browser find text "Projekte" click >/dev/null 2>&1
|
|
agent-browser wait 2000 >/dev/null 2>&1
|
|
# the tasks tab is default; find the task input
|
|
agent-browser eval "document.querySelector('input[placeholder*=Neue]')?.focus()" >/dev/null 2>&1
|
|
agent-browser snapshot -i >/tmp/snap3.txt 2>&1
|
|
INPUTREF=$(grep -i 'textbox.*Neue' /tmp/snap3.txt | head -1 | grep -oE 'ref=e[0-9]+' | head -1)
|
|
echo " task input ref: $INPUTREF"
|
|
if [ -n "$INPUTREF" ]; then
|
|
agent-browser fill "$INPUTREF" "E2E Test Aufgabe" >/dev/null 2>&1
|
|
agent-browser wait 500 >/dev/null 2>&1
|
|
# find the Hinzufügen button
|
|
agent-browser find text "Hinzufügen" click >/dev/null 2>&1
|
|
agent-browser wait 2500 >/dev/null 2>&1
|
|
echo " task add attempted"
|
|
fi
|
|
agent-browser screenshot --full "$SHOTS/v3-projects-task.png" >/dev/null 2>&1 && echo " shot projects-task OK"
|
|
|
|
echo ""
|
|
echo "=== Command palette global search ==="
|
|
agent-browser set viewport 1440 900 >/dev/null 2>&1
|
|
# open with ctrl+k
|
|
agent-browser eval "window.dispatchEvent(new KeyboardEvent('keydown',{key:'k',metaKey:true}))" >/dev/null 2>&1
|
|
agent-browser wait 1000 >/dev/null 2>&1
|
|
# type into the palette
|
|
agent-browser snapshot -i >/tmp/snap4.txt 2>&1
|
|
PALREF=$(grep -i 'textbox.*Suche' /tmp/snap4.txt | head -1 | grep -oE 'ref=e[0-9]+' | head -1)
|
|
echo " palette input ref: $PALREF"
|
|
if [ -n "$PALREF" ]; then
|
|
agent-browser fill "$PALREF" "Hamburg" >/dev/null 2>&1
|
|
agent-browser wait 1500 >/dev/null 2>&1
|
|
agent-browser screenshot --full "$SHOTS/v3-command-search.png" >/dev/null 2>&1 && echo " shot search OK"
|
|
# read palette results
|
|
agent-browser snapshot -i >/tmp/snap5.txt 2>&1
|
|
echo " --- search results (first 8) ---"
|
|
grep -iE "Firmen|Rechnungen|Projekte|Leads" /tmp/snap5.txt | head -8
|
|
fi
|
|
agent-browser press Escape >/dev/null 2>&1
|
|
|
|
echo ""
|
|
echo "=== Errors check ==="
|
|
agent-browser errors 2>&1 | head -10
|
|
echo "--- console last 6 ---"
|
|
agent-browser console 2>&1 | tail -6
|
|
|
|
echo ""
|
|
echo "=== Cleanup ==="
|
|
agent-browser close >/dev/null 2>&1
|
|
kill $SRV 2>/dev/null
|
|
echo "=== dev.log tail ==="
|
|
tail -12 dev.log
|
|
echo ""
|
|
echo "=== VERIFICATION COMPLETE ==="
|
|
ls -la "$SHOTS"/v3-* 2>/dev/null | tail -8
|