app
DigiKey Electronics Search
Public Made by Adomby adom
DigiKey component search in your workspace — millions of parts with real-time stock, quantity pricing and datasheets. CLI verbs, a Hydrogen app, and a shared backend service.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
#!/usr/bin/env bash
# adom-digikey smoke test — real-backend search assertions.
#
# Runs a fixed set of real-world keyword queries against the Node + SQLite
# backend and asserts each returns at least one component whose `mfr` field
# contains the expected substring. Catches regressions like the 2026-04 bug
# where handleSearch destructured `query` but every caller sent `keyword`,
# silently routing all searches to "top stocked parts" (capacitors).
#
# Usage:
# tests/smoke.sh # hits deployed backend
# tests/smoke.sh http://127.0.0.1:8777 # local backend
# DIGIKEY_API=http://127.0.0.1:8777 tests/smoke.sh # same via env
#
# Exit code: 0 iff all cases pass. Non-zero + red FAIL line otherwise.
set -u
BACKEND="${1:-${DIGIKEY_API:-https://digikey-gjuu8l5t69uh.adom.cloud}}"
BACKEND="${BACKEND%/}"
# ANSI only on a real terminal (adom-cli-design rule: no color escapes in
# captured stdout).
if [ -t 1 ]; then
C_OK=$'\033[32m'; C_FAIL=$'\033[31m'; C_DIM=$'\033[2m'; C_BOLD=$'\033[1m'; C_RESET=$'\033[0m'
else
C_OK=''; C_FAIL=''; C_DIM=''; C_BOLD=''; C_RESET=''
fi
pass=0; fail=0; failures=()
run_case() {
local label="$1" keyword="$2" expect_substr="$3" expect_min="${4:-1}"
local body resp count match
body=$(jq -n --arg k "$keyword" '{action:"search", keyword:$k, limit:5}')
resp=$(curl -sS --max-time 10 -X POST "$BACKEND/" \
-H 'content-type: application/json' -d "$body" 2>/dev/null)
if [ -z "$resp" ]; then
fail=$((fail+1)); failures+=("$label — backend unreachable or empty response")
printf '%sFAIL%s %-36s %s\n' "$C_FAIL" "$C_RESET" "$label" "(no response)"
return
fi
count=$(printf '%s' "$resp" | jq '.count // 0' 2>/dev/null)
if [ -z "$expect_substr" ]; then
# Just assert >= expect_min results, no substring check.
if [ "$count" -ge "$expect_min" ]; then
pass=$((pass+1))
printf '%sPASS%s %-36s count=%s\n' "$C_OK" "$C_RESET" "$label" "$count"
else
fail=$((fail+1)); failures+=("$label — count=$count expected >=$expect_min")
printf '%sFAIL%s %-36s count=%s (expected >=%s)\n' "$C_FAIL" "$C_RESET" "$label" "$count" "$expect_min"
fi
return
fi
match=$(printf '%s' "$resp" | jq --arg s "$expect_substr" \
'[.components[]? | (.mpn // .mfr // "") + " " + (.description // "") | ascii_downcase | contains($s | ascii_downcase)] | any' 2>/dev/null)
if [ "$match" = "true" ] && [ "$count" -ge "$expect_min" ]; then
pass=$((pass+1))
printf '%sPASS%s %-36s count=%s mfr contains %s\n' "$C_OK" "$C_RESET" "$label" "$count" "$expect_substr"
else
fail=$((fail+1)); failures+=("$label — count=$count, mfr-contains-'$expect_substr'=$match")
printf '%sFAIL%s %-36s count=%s mfr contains %s? %s\n' \
"$C_FAIL" "$C_RESET" "$label" "$count" "$expect_substr" "${match:-null}"
fi
}
run_negative() {
local label="$1" keyword="$2"
local body resp count
body=$(jq -n --arg k "$keyword" '{action:"search", keyword:$k, limit:5}')
resp=$(curl -sS --max-time 10 -X POST "$BACKEND/" \
-H 'content-type: application/json' -d "$body" 2>/dev/null)
count=$(printf '%s' "$resp" | jq '.count // 0' 2>/dev/null)
if [ "$count" = "0" ]; then
pass=$((pass+1))
printf '%sPASS%s %-36s count=0 (expected)\n' "$C_OK" "$C_RESET" "$label"
else
fail=$((fail+1)); failures+=("$label — nonsense keyword returned $count results (should be 0)")
printf '%sFAIL%s %-36s count=%s (expected 0)\n' "$C_FAIL" "$C_RESET" "$label" "$count"
fi
}
echo "${C_BOLD}adom-digikey smoke test${C_RESET} ${C_DIM}backend: $BACKEND${C_RESET}"
echo "${C_DIM}────────────────────────────────────────────────────────${C_RESET}"
# Canonical MPNs that should always match.
run_case "esp32 (generic)" "ESP32" "esp32" 1
run_case "esp32-s3 (variant)" "ESP32-S3" "esp32-s3" 1
run_case "stm32f103 (arm mcu)" "STM32F103" "stm32f103" 1
run_case "lm358 (op-amp)" "LM358" "lm358" 1
run_case "ne555 (timer)" "NE555" "ne555" 1
run_case "tl072 (audio op-amp)" "TL072" "tl072" 1
run_case "atmega328 (arduino mcu)" "ATmega328" "atmega328" 1
run_case "ams1117 (ldo)" "AMS1117" "ams1117" 1
run_case "ch340 (usb-uart)" "CH340" "ch340" 1
run_case "w25q (spi flash)" "W25Q" "w25q" 1
# DigiKey-specific MPN (LM1117-3.3 LDO).
run_case "lm1117-3.3 (ldo)" "LM1117-3.3" "lm1117" 1
# Broad keyword — at least one match.
run_case "100nF 0603 (keyword)" "100nF 0603" "" 1
# Nonsense query should return 0, not default fallback.
run_negative "bogus keyword" "XYZZZZ999NOTAPART"
echo "${C_DIM}────────────────────────────────────────────────────────${C_RESET}"
if [ "$fail" -eq 0 ]; then
echo "${C_OK}${C_BOLD}OK${C_RESET} ${pass} passed, 0 failed"
exit 0
else
echo "${C_FAIL}${C_BOLD}FAIL${C_RESET} ${pass} passed, ${fail} failed"
for f in "${failures[@]}"; do echo " - $f"; done
exit 1
fi