Skip to content

Commit d55fb30

Browse files
maxkostyKosty Maleyev
andauthored
[tda,react,agent] TDA automation for AI Agent (#1164)
* [react] AI Agent Frontend v0 - r2 * [tda,react,agent] TDA automation for AI Agent * run _tda/test_ai_agent with only 1 browser * remove _tda/test_about_employees --------- Co-authored-by: Kosty Maleyev <kosty@mac.lan>
1 parent 8afa03f commit d55fb30

File tree

4 files changed

+115
-38
lines changed

4 files changed

+115
-38
lines changed

_tda/conftest.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,24 @@ def desktop_web_driver(request, se_prefix):
512512
with _local_browser(request, se) as b:
513513
yield b
514514

515+
516+
@pytest.fixture
517+
def desktop_web_1browser_driver(request, se_prefix):
518+
"""Like desktop_web_driver but only uses the first browser from CONFIG.browsers (no parameterization)"""
519+
browser_config = CONFIG.browsers[0]
520+
521+
import builtins
522+
builtins._current_browser_config = browser_config
523+
524+
# Create a wrapper that mimics request.param for _sauce_browser
525+
request.param = browser_config
526+
527+
se = f'{se_prefix}-sauce-{browser_config.param_display}'
528+
sentry_sdk.set_tag("se", se)
529+
with _sauce_browser(request, se) as b:
530+
yield b
531+
532+
515533
@pytest.fixture
516534
def android_react_native_emu_driver(request, se_prefix):
517535

_tda/desktop_web/test_about_employees.py

Lines changed: 0 additions & 35 deletions
This file was deleted.

_tda/desktop_web/test_ai_agent.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import time
2+
import sentry_sdk
3+
from selenium.webdriver.common.by import By
4+
5+
6+
# Time to wait after conversation completes before closing the chat
7+
# This allows for proper Sentry trace capture
8+
WAIT_BEFORE_CLOSE_SECONDS = 80
9+
10+
11+
def test_ai_agent(desktop_web_1browser_driver, endpoints):
12+
"""
13+
Test the AI Agent Chat widget on the React homepage.
14+
15+
This test:
16+
1. Opens the chat widget
17+
2. Waits for the welcome messages
18+
3. Answers "full sun" to the light question
19+
4. Answers "yes" to the maintenance question
20+
5. Waits for the API response
21+
6. Waits 80 seconds for trace data capture
22+
7. Closes the chat by clicking X
23+
"""
24+
25+
endpoint = endpoints.react_endpoint
26+
27+
url = endpoint # use default backend as it doesn't matter for this test
28+
29+
try:
30+
# Navigate to the homepage
31+
desktop_web_1browser_driver.get(url)
32+
33+
# Wait for page to load
34+
time.sleep(3)
35+
36+
# Click the AI Agent button to open chat
37+
chat_button = desktop_web_1browser_driver.find_element(By.ID, 'chat-widget-button')
38+
chat_button.click()
39+
40+
# Wait for the chat to open and show initial messages
41+
# The bot will show typing indicator, then welcome message, then typing, then first question
42+
time.sleep(5)
43+
44+
# Find the input field (indicates first question is ready)
45+
chat_input = desktop_web_1browser_driver.find_element(By.ID, 'chat-message-input')
46+
47+
# Answer the first question: "How much light does your room get?"
48+
chat_input.send_keys("full sun")
49+
50+
# Click Send
51+
send_button = desktop_web_1browser_driver.find_element(By.ID, 'chat-send-button')
52+
send_button.click()
53+
54+
# Wait for the second question to appear
55+
time.sleep(3)
56+
57+
# Find the input field again
58+
chat_input = desktop_web_1browser_driver.find_element(By.ID, 'chat-message-input')
59+
60+
# Answer the second question: "Are you only looking for low-maintenance plants?"
61+
chat_input.send_keys("yes")
62+
63+
# Click Send
64+
send_button = desktop_web_1browser_driver.find_element(By.ID, 'chat-send-button')
65+
send_button.click()
66+
67+
# Wait for the API response to appear
68+
# The bot will show typing indicator while waiting for the API, then show the response
69+
time.sleep(10)
70+
71+
# Wait the specified time before closing to allow trace data to be captured
72+
print(f"Waiting {WAIT_BEFORE_CLOSE_SECONDS} seconds before closing chat...")
73+
time.sleep(WAIT_BEFORE_CLOSE_SECONDS)
74+
75+
# Close the chat by clicking the chat button again (chat close button may not be visible)
76+
chat_button.click()
77+
78+
# Small delay to ensure the close action completes
79+
time.sleep(2)
80+
81+
except Exception as err:
82+
sentry_sdk.capture_exception(err)
83+
raise

react/src/components/ChatWidget.jsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const ChatWidget = () => {
2222
const typingSpanRef = useRef(null);
2323
const typingTimeoutRef = useRef(null);
2424
const inactivityTimeoutRef = useRef(null);
25+
const initTimeoutsRef = useRef([]);
2526

2627
const scrollToBottom = () => {
2728
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
@@ -40,6 +41,9 @@ const ChatWidget = () => {
4041
clearTimeout(inactivityTimeoutRef.current);
4142
inactivityTimeoutRef.current = null;
4243
}
44+
// Clear any pending initialization timeouts
45+
initTimeoutsRef.current.forEach(timeoutId => clearTimeout(timeoutId));
46+
initTimeoutsRef.current = [];
4347

4448
// Record how the session ended
4549
if (chatSpanRef.current) {
@@ -116,10 +120,14 @@ const ChatWidget = () => {
116120

117121
useEffect(() => {
118122
if (isOpen && conversationState === 'initial') {
123+
// Clear any existing init timeouts
124+
initTimeoutsRef.current.forEach(timeoutId => clearTimeout(timeoutId));
125+
initTimeoutsRef.current = [];
126+
119127
// Show typing indicator
120128
setMessages([{ type: 'typing', id: generateMessageId() }]);
121129

122-
setTimeout(() => {
130+
const timeout1 = setTimeout(() => {
123131
// Remove typing indicator and show welcome message
124132
addBotMessage("Hi, I can help you pick the right plants for your home", () => {
125133
setMessages([
@@ -132,16 +140,19 @@ const ChatWidget = () => {
132140
});
133141

134142
// Show second message after a brief pause
135-
setTimeout(() => {
143+
const timeout2 = setTimeout(() => {
136144
// Show typing indicator
137145
setMessages(prev => [...prev, { type: 'typing', id: generateMessageId() }]);
138146

139-
setTimeout(() => {
147+
const timeout3 = setTimeout(() => {
140148
addBotMessage('How much light does your room get?');
141149
setConversationState('awaiting_light');
142150
}, 1000);
151+
initTimeoutsRef.current.push(timeout3);
143152
}, 500);
153+
initTimeoutsRef.current.push(timeout2);
144154
}, 1000);
155+
initTimeoutsRef.current.push(timeout1);
145156
}
146157
}, [isOpen, conversationState, addBotMessage]);
147158

0 commit comments

Comments
 (0)