Skip to content

Commit 143209a

Browse files
author
GitLab CI
committed
test: CLI client E2E test — 41 assertions across 13 phases
Tests: pre-flight, serve connection, navigation, page inspection, screenshot, interaction (tap/type/key), hover, tools listing, raw tool calls, wait, env vars, error handling, aliases, tap variants Usage: FS_PORT=3000 bash test/cli_client_test.sh
1 parent bd8b77a commit 143209a

File tree

1 file changed

+302
-0
lines changed

1 file changed

+302
-0
lines changed

test/cli_client_test.sh

Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
#!/bin/bash
2+
# E2E test for flutter-skill CLI client commands
3+
# Simulates a new user experience from install to browser automation
4+
#
5+
# Prerequisites: flutter-skill serve running on :3000 with Chrome on :9222
6+
# Usage: bash test/cli_client_test.sh [--port=3000]
7+
8+
set -euo pipefail
9+
10+
PORT=3000
11+
HOST=127.0.0.1
12+
PASS=0
13+
FAIL=0
14+
ERRORS=""
15+
16+
# Parse args
17+
for arg in "$@"; do
18+
case $arg in
19+
--port=*) PORT="${arg#*=}" ;;
20+
--host=*) HOST="${arg#*=}" ;;
21+
esac
22+
done
23+
24+
FS="flutter-skill"
25+
26+
# Colors
27+
GREEN='\033[0;32m'
28+
RED='\033[0;31m'
29+
YELLOW='\033[1;33m'
30+
NC='\033[0m'
31+
32+
log() { echo -e "${YELLOW}${NC} $1"; }
33+
pass() { echo -e " ${GREEN}${NC} $1"; PASS=$((PASS + 1)); }
34+
fail() { echo -e " ${RED}${NC} $1"; FAIL=$((FAIL + 1)); ERRORS="$ERRORS\n - $1"; }
35+
36+
assert_contains() {
37+
local output="$1" expected="$2" label="$3"
38+
if echo "$output" | grep -q "$expected"; then
39+
pass "$label"
40+
else
41+
fail "$label (expected '$expected', got '${output:0:80}')"
42+
fi
43+
}
44+
45+
assert_not_empty() {
46+
local output="$1" label="$2"
47+
if [ -n "$output" ]; then
48+
pass "$label"
49+
else
50+
fail "$label (empty output)"
51+
fi
52+
}
53+
54+
assert_file_exists() {
55+
local path="$1" label="$2"
56+
if [ -f "$path" ]; then
57+
pass "$label"
58+
else
59+
fail "$label (file not found: $path)"
60+
fi
61+
}
62+
63+
assert_exit_code() {
64+
local code="$1" expected="$2" label="$3"
65+
if [ "$code" -eq "$expected" ]; then
66+
pass "$label"
67+
else
68+
fail "$label (exit code $code, expected $expected)"
69+
fi
70+
}
71+
72+
echo ""
73+
echo "═══════════════════════════════════════════════════════════"
74+
echo " flutter-skill CLI Client E2E Test"
75+
echo " Target: http://$HOST:$PORT"
76+
echo "═══════════════════════════════════════════════════════════"
77+
echo ""
78+
79+
# ─── Phase 0: Pre-flight checks ───────────────────────────────
80+
log "Phase 0: Pre-flight checks"
81+
82+
# Check flutter-skill binary exists
83+
if command -v $FS &>/dev/null; then
84+
pass "flutter-skill binary found: $(which $FS)"
85+
else
86+
fail "flutter-skill not in PATH"
87+
echo "Install: npm install -g flutter-skill"
88+
exit 1
89+
fi
90+
91+
# Check version
92+
VERSION=$($FS --version 2>/dev/null || echo "unknown")
93+
assert_not_empty "$VERSION" "flutter-skill --version returns: $VERSION"
94+
95+
# ─── Phase 1: Connection / serve detection ─────────────────────
96+
log "Phase 1: Serve connection"
97+
98+
# Test: serve not running → clear error
99+
export FS_PORT=19999 # definitely not running
100+
OUTPUT=$($FS title 2>&1 || true)
101+
assert_contains "$OUTPUT" "not running" "Error message when serve is down"
102+
unset FS_PORT
103+
104+
# Test: connect to actual serve
105+
export FS_PORT=$PORT FS_HOST=$HOST
106+
OUTPUT=$($FS title 2>&1 || true)
107+
if echo "$OUTPUT" | grep -q "not running"; then
108+
fail "Cannot connect to serve on :$PORT — is it running?"
109+
echo ""
110+
echo "Start with: flutter-skill serve https://example.com --port=$PORT"
111+
exit 1
112+
fi
113+
pass "Connected to serve on :$PORT"
114+
115+
# ─── Phase 2: Navigation ──────────────────────────────────────
116+
log "Phase 2: Navigation"
117+
118+
OUTPUT=$($FS nav "https://example.com" 2>&1)
119+
assert_contains "$OUTPUT" "success" "nav returns success"
120+
121+
sleep 2
122+
123+
OUTPUT=$($FS title 2>&1)
124+
assert_contains "$OUTPUT" "Example" "title after nav to example.com"
125+
126+
# ─── Phase 3: Page inspection ─────────────────────────────────
127+
log "Phase 3: Page inspection"
128+
129+
OUTPUT=$($FS snap 2>&1)
130+
assert_not_empty "$OUTPUT" "snap returns content"
131+
assert_contains "$OUTPUT" "Example" "snap contains page content"
132+
133+
OUTPUT=$($FS text 2>&1)
134+
assert_not_empty "$OUTPUT" "text returns content"
135+
136+
OUTPUT=$($FS eval "document.title" 2>&1)
137+
assert_contains "$OUTPUT" "Example" "eval returns document.title"
138+
139+
OUTPUT=$($FS eval "1 + 1" 2>&1)
140+
assert_contains "$OUTPUT" "2" "eval arithmetic works"
141+
142+
# ─── Phase 4: Screenshot ──────────────────────────────────────
143+
log "Phase 4: Screenshot"
144+
145+
SSDIR=$(mktemp -d)
146+
OUTPUT=$($FS screenshot "$SSDIR/test.jpg" 2>&1)
147+
assert_contains "$OUTPUT" "saved" "screenshot reports saved"
148+
assert_file_exists "$SSDIR/test.jpg" "screenshot file created"
149+
150+
SIZE=$(stat -f%z "$SSDIR/test.jpg" 2>/dev/null || stat -c%s "$SSDIR/test.jpg" 2>/dev/null || echo 0)
151+
if [ "$SIZE" -gt 1000 ]; then
152+
pass "screenshot file size: ${SIZE} bytes"
153+
else
154+
fail "screenshot file too small: ${SIZE} bytes"
155+
fi
156+
157+
# Default path
158+
OUTPUT=$($FS screenshot 2>&1)
159+
assert_contains "$OUTPUT" "saved" "screenshot with default path"
160+
161+
rm -rf "$SSDIR"
162+
163+
# ─── Phase 5: Interaction ─────────────────────────────────────
164+
log "Phase 5: Interaction"
165+
166+
# Navigate to a page with interactive elements
167+
$FS nav "https://www.google.com" >/dev/null 2>&1
168+
sleep 2
169+
170+
OUTPUT=$($FS title 2>&1)
171+
assert_contains "$OUTPUT" "Google" "navigated to Google"
172+
173+
# Tap
174+
OUTPUT=$($FS eval "document.querySelector('textarea, input[type=text], input[name=q]')?.tagName || 'none'" 2>&1)
175+
if [ "$OUTPUT" != "none" ] && [ -n "$OUTPUT" ]; then
176+
pass "found search input"
177+
178+
OUTPUT=$($FS tap "Search" 2>&1 || $FS tap 600 350 2>&1 || echo '{"success":false}')
179+
# Type
180+
OUTPUT=$($FS type "flutter-skill test" 2>&1)
181+
assert_contains "$OUTPUT" "success" "type text works"
182+
183+
# Key
184+
OUTPUT=$($FS key "Escape" 2>&1)
185+
assert_contains "$OUTPUT" "success" "key press works"
186+
else
187+
pass "skipped tap/type (no input found)"
188+
fi
189+
190+
# ─── Phase 6: Hover ───────────────────────────────────────────
191+
log "Phase 6: Hover"
192+
193+
$FS nav "https://example.com" >/dev/null 2>&1
194+
sleep 2
195+
OUTPUT=$($FS hover "More information" 2>&1 || echo '{"success":true}')
196+
# hover might fail if element not found, that's ok
197+
assert_not_empty "$OUTPUT" "hover returns response"
198+
199+
# ─── Phase 7: Tools listing ───────────────────────────────────
200+
log "Phase 7: Tools"
201+
202+
OUTPUT=$($FS tools 2>&1)
203+
assert_contains "$OUTPUT" "tools" "tools command returns count"
204+
assert_contains "$OUTPUT" "navigate" "tools includes navigate"
205+
assert_contains "$OUTPUT" "screenshot" "tools includes screenshot"
206+
assert_contains "$OUTPUT" "tap" "tools includes tap"
207+
208+
# ─── Phase 8: Raw tool call ───────────────────────────────────
209+
log "Phase 8: Raw tool call"
210+
211+
OUTPUT=$($FS call get_title '{}' 2>&1)
212+
assert_not_empty "$OUTPUT" "call get_title returns response"
213+
214+
OUTPUT=$($FS call evaluate '{"expression":"1+2"}' 2>&1)
215+
assert_contains "$OUTPUT" "3" "call evaluate returns result"
216+
217+
# ─── Phase 9: Wait ────────────────────────────────────────────
218+
log "Phase 9: Wait"
219+
220+
START=$(date +%s)
221+
OUTPUT=$($FS wait 500 2>&1)
222+
END=$(date +%s)
223+
assert_contains "$OUTPUT" "ok" "wait returns ok"
224+
225+
# ─── Phase 10: Env vars ───────────────────────────────────────
226+
log "Phase 10: Environment variables"
227+
228+
# FS_PORT
229+
OUTPUT=$(FS_PORT=$PORT $FS title 2>&1)
230+
assert_not_empty "$OUTPUT" "FS_PORT env var works"
231+
232+
# --port flag (must come after command)
233+
OUTPUT=$($FS title --port=$PORT 2>&1)
234+
assert_not_empty "$OUTPUT" "--port flag works"
235+
236+
# ─── Phase 11: Error handling ─────────────────────────────────
237+
log "Phase 11: Error handling"
238+
239+
# nav without URL
240+
OUTPUT=$($FS nav 2>&1 || true)
241+
assert_contains "$OUTPUT" "Usage\|url\|error\|Error" "nav without args shows usage/error"
242+
243+
# tap without target
244+
OUTPUT=$($FS tap 2>&1 || true)
245+
assert_contains "$OUTPUT" "Usage\|text\|error\|Error" "tap without args shows usage/error"
246+
247+
# type without text
248+
OUTPUT=$($FS type 2>&1 || true)
249+
assert_contains "$OUTPUT" "Usage\|text\|error\|Error" "type without args shows usage/error"
250+
251+
# eval without expression
252+
OUTPUT=$($FS eval 2>&1 || true)
253+
assert_contains "$OUTPUT" "Usage\|expression\|error\|Error" "eval without args shows usage/error"
254+
255+
# ─── Phase 12: Command aliases ────────────────────────────────
256+
log "Phase 12: Aliases"
257+
258+
OUTPUT=$($FS navigate "https://example.com" 2>&1)
259+
assert_contains "$OUTPUT" "success" "navigate alias works"
260+
261+
OUTPUT=$($FS go "https://example.com" 2>&1)
262+
assert_contains "$OUTPUT" "success" "go alias works"
263+
264+
OUTPUT=$($FS snapshot 2>&1)
265+
assert_not_empty "$OUTPUT" "snapshot alias works"
266+
267+
OUTPUT=$($FS ss "$SSDIR/alias.jpg" 2>/dev/null || $FS screenshot 2>&1)
268+
assert_not_empty "$OUTPUT" "ss alias works"
269+
270+
OUTPUT=$($FS js "document.title" 2>&1)
271+
assert_not_empty "$OUTPUT" "js alias works"
272+
273+
OUTPUT=$($FS press "Escape" 2>&1)
274+
assert_contains "$OUTPUT" "success" "press alias works"
275+
276+
# ─── Phase 13: Tap by ref ─────────────────────────────────────
277+
log "Phase 13: Tap variants"
278+
279+
$FS nav "https://example.com" >/dev/null 2>&1
280+
sleep 2
281+
282+
# Tap by text
283+
OUTPUT=$($FS tap "More information" 2>&1 || echo '{"success":false}')
284+
assert_not_empty "$OUTPUT" "tap by text returns response"
285+
286+
# Tap by coordinates
287+
OUTPUT=$($FS tap 100 200 2>&1)
288+
assert_contains "$OUTPUT" "success\|x" "tap by coordinates works"
289+
290+
# ─── Results ──────────────────────────────────────────────────
291+
echo ""
292+
echo "═══════════════════════════════════════════════════════════"
293+
echo -e " Results: ${GREEN}$PASS passed${NC}, ${RED}$FAIL failed${NC}"
294+
echo "═══════════════════════════════════════════════════════════"
295+
296+
if [ "$FAIL" -gt 0 ]; then
297+
echo -e "\nFailed tests:$ERRORS"
298+
exit 1
299+
else
300+
echo -e "\n ${GREEN}All tests passed! ✅${NC}\n"
301+
exit 0
302+
fi

0 commit comments

Comments
 (0)