Skip to content

Commit 9f4b56a

Browse files
grichaclaude
andauthored
Add Maestro chat tests for Claude Code and OpenCode (#21)
* Add Maestro chat tests for Claude Code and OpenCode - Add testIDs to SessionChatScreen (chat-input, send-button, stop-button, user-message, assistant-message, thinking-dots) - Add testIDs to WorkspaceDetailScreen chat picker (new-chat-claude-code, new-chat-opencode, new-chat-codex) - Add Maestro test flows for Claude Code and OpenCode chat - Update workflow to: - Install Docker via Colima on macOS - Build workspace Docker image - Start Perry agent with test workspace - Increase timeout to 60 minutes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Make chat tests local-only, remove Docker from CI - Remove Docker/Colima setup from CI (not supported on GitHub macOS runners) - Use --exclude-tags=chat to skip chat tests in CI - Chat tests (CC + OpenCode) remain for local testing - Reduce timeout back to 45 minutes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 8750e82 commit 9f4b56a

5 files changed

Lines changed: 141 additions & 5 deletions

File tree

.github/workflows/mobile-e2e.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ jobs:
129129
working-directory: mobile
130130
run: |
131131
export PATH="$HOME/.maestro/bin:$PATH"
132-
maestro test .maestro/flows/ --format junit --output maestro-report.xml
132+
# Exclude chat tests (require backend) - run those locally
133+
maestro test .maestro/flows/ --exclude-tags=chat --format junit --output maestro-report.xml
133134
env:
134135
MAESTRO_DRIVER_STARTUP_TIMEOUT: 120000
135136

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
appId: com.gricha.perry
2+
name: Chat - Claude Code
3+
tags:
4+
- chat
5+
- claude-code
6+
---
7+
- launchApp:
8+
clearState: true
9+
10+
# Configure server connection
11+
- tapOn:
12+
id: "hostname-input"
13+
- inputText: "localhost"
14+
- tapOn:
15+
id: "port-input"
16+
- eraseText
17+
- inputText: "7391"
18+
- tapOn:
19+
id: "connect-button"
20+
21+
# Wait for workspace list to load
22+
- extendedWaitUntil:
23+
visible: "test"
24+
timeout: 30000
25+
26+
# Tap on test workspace
27+
- tapOn: "test"
28+
29+
# Wait for workspace detail screen
30+
- extendedWaitUntil:
31+
visible:
32+
id: "new-chat-button"
33+
timeout: 10000
34+
35+
# Start new Claude Code chat
36+
- tapOn:
37+
id: "new-chat-button"
38+
39+
# Select Claude Code from picker
40+
- tapOn:
41+
id: "new-chat-claude-code"
42+
43+
# Wait for chat screen to load and connect
44+
- extendedWaitUntil:
45+
visible:
46+
id: "chat-input"
47+
timeout: 15000
48+
49+
# Type and send a simple message
50+
- tapOn:
51+
id: "chat-input"
52+
- inputText: "Say hello"
53+
- tapOn:
54+
id: "send-button"
55+
56+
# Verify thinking dots appear (streaming started)
57+
- extendedWaitUntil:
58+
visible:
59+
id: "thinking-dots"
60+
timeout: 10000
61+
62+
# Wait for response to complete (thinking dots disappear, assistant message appears)
63+
- extendedWaitUntil:
64+
visible:
65+
id: "assistant-message"
66+
timeout: 120000
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
appId: com.gricha.perry
2+
name: Chat - OpenCode
3+
tags:
4+
- chat
5+
- opencode
6+
---
7+
- launchApp:
8+
clearState: true
9+
10+
# Configure server connection
11+
- tapOn:
12+
id: "hostname-input"
13+
- inputText: "localhost"
14+
- tapOn:
15+
id: "port-input"
16+
- eraseText
17+
- inputText: "7391"
18+
- tapOn:
19+
id: "connect-button"
20+
21+
# Wait for workspace list to load
22+
- extendedWaitUntil:
23+
visible: "test"
24+
timeout: 30000
25+
26+
# Tap on test workspace
27+
- tapOn: "test"
28+
29+
# Wait for workspace detail screen
30+
- extendedWaitUntil:
31+
visible:
32+
id: "new-chat-button"
33+
timeout: 10000
34+
35+
# Start new OpenCode chat
36+
- tapOn:
37+
id: "new-chat-button"
38+
39+
# Select OpenCode from picker
40+
- tapOn:
41+
id: "new-chat-opencode"
42+
43+
# Wait for chat screen to load and connect
44+
- extendedWaitUntil:
45+
visible:
46+
id: "chat-input"
47+
timeout: 15000
48+
49+
# Type and send a simple message
50+
- tapOn:
51+
id: "chat-input"
52+
- inputText: "Say hello"
53+
- tapOn:
54+
id: "send-button"
55+
56+
# Verify thinking dots appear (streaming started)
57+
- extendedWaitUntil:
58+
visible:
59+
id: "thinking-dots"
60+
timeout: 10000
61+
62+
# Wait for response to complete (thinking dots disappear, assistant message appears)
63+
- extendedWaitUntil:
64+
visible:
65+
id: "assistant-message"
66+
timeout: 120000

mobile/src/screens/SessionChatScreen.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ function MessageBubble({ message }: { message: ChatMessage }) {
177177

178178
if (message.role === 'user') {
179179
return (
180-
<View style={styles.userBubble}>
180+
<View style={styles.userBubble} testID="user-message">
181181
<Text style={styles.messageText}>{trimmedContent}</Text>
182182
</View>
183183
)
@@ -192,7 +192,7 @@ function MessageBubble({ message }: { message: ChatMessage }) {
192192
}
193193

194194
return (
195-
<View style={styles.assistantBubble}>
195+
<View style={styles.assistantBubble} testID="assistant-message">
196196
<Text style={styles.messageText}>{trimmedContent}</Text>
197197
</View>
198198
)
@@ -230,7 +230,7 @@ function ThinkingDots() {
230230
}, [dot1, dot2, dot3])
231231

232232
return (
233-
<View style={styles.thinkingDots}>
233+
<View style={styles.thinkingDots} testID="thinking-dots">
234234
<Animated.View style={[styles.dot, { opacity: dot1 }]} />
235235
<Animated.View style={[styles.dot, { opacity: dot2 }]} />
236236
<Animated.View style={[styles.dot, { opacity: dot3 }]} />
@@ -684,16 +684,18 @@ export function SessionChatScreen({ route, navigation }: any) {
684684
multiline
685685
maxLength={4000}
686686
editable={connected && !isStreaming}
687+
testID="chat-input"
687688
/>
688689
{isStreaming ? (
689-
<TouchableOpacity style={styles.stopBtn} onPress={interrupt}>
690+
<TouchableOpacity style={styles.stopBtn} onPress={interrupt} testID="stop-button">
690691
<Text style={styles.stopBtnText}>Stop</Text>
691692
</TouchableOpacity>
692693
) : (
693694
<TouchableOpacity
694695
style={[styles.sendBtn, (!connected || !input.trim()) && styles.sendBtnDisabled]}
695696
onPress={sendMessage}
696697
disabled={!connected || !input.trim()}
698+
testID="send-button"
697699
>
698700
<Text style={styles.sendBtnText}>Send</Text>
699701
</TouchableOpacity>

mobile/src/screens/WorkspaceDetailScreen.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ export function WorkspaceDetailScreen({ route, navigation }: any) {
260260
setShowNewChatPicker(false)
261261
navigation.navigate('SessionChat', { workspaceName: name, isNew: true, agentType: type })
262262
}}
263+
testID={`new-chat-${type}`}
263264
>
264265
<View style={[styles.agentBadgeLarge, { backgroundColor: type === 'claude-code' ? '#8b5cf6' : type === 'opencode' ? '#22c55e' : '#f59e0b' }]}>
265266
<Text style={styles.agentBadgeLargeText}>{type === 'claude-code' ? 'CC' : type === 'opencode' ? 'OC' : 'CX'}</Text>

0 commit comments

Comments
 (0)