File size: 10,204 Bytes
2fcd9cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
"""
Chat Functionality Tests

Tests for the chat interface and command system.
"""

import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
import time

from config import BASE_URL, EXPLICIT_WAIT


@pytest.mark.chat
class TestChatFunctionality:
    """Test suite for chat and command functionality."""

    def _load_character_for_chat(self, driver):
        """Helper to load a character before testing chat."""
        driver.get(BASE_URL)
        time.sleep(2)

        # Load Thorin quickly
        dropdown_inputs = driver.find_elements(By.CSS_SELECTOR, "input[role='combobox'], input.svelte-1cl284h")
        if not dropdown_inputs:
            dropdown_inputs = driver.find_elements(By.CSS_SELECTOR, "input[type='text']")

        if len(dropdown_inputs) > 0:
            dropdown = dropdown_inputs[0]
            dropdown.click()
            dropdown.clear()
            dropdown.send_keys("Thorin")
            dropdown.send_keys(Keys.ENTER)
            time.sleep(0.5)

            # Click Load button
            buttons = driver.find_elements(By.TAG_NAME, "button")
            for btn in buttons:
                if "Load" in btn.text:
                    btn.click()
                    break
            time.sleep(2)

    def _send_chat_message(self, driver, message):
        """Helper to send a chat message."""
        # Find textarea
        textareas = driver.find_elements(By.TAG_NAME, "textarea")
        chat_input = None

        for textarea in textareas:
            placeholder = textarea.get_attribute("placeholder") or ""
            if "action" in placeholder.lower() or textarea.is_displayed():
                chat_input = textarea
                break

        assert chat_input is not None, "Chat input not found"

        # Clear and type message
        chat_input.clear()
        chat_input.send_keys(message)
        time.sleep(0.5)

        # Find and click Send button
        buttons = driver.find_elements(By.TAG_NAME, "button")
        send_button = None
        for btn in buttons:
            if "Send" in btn.text and btn.is_displayed():
                send_button = btn
                break

        assert send_button is not None, "Send button not found"
        send_button.click()

    def test_chat_input_exists(self, driver):
        """Test that chat input field exists."""
        self._load_character_for_chat(driver)

        textareas = driver.find_elements(By.TAG_NAME, "textarea")
        assert len(textareas) > 0, "No chat input (textarea) found"
        print(f"βœ… Chat input exists ({len(textareas)} textareas found)")

    def test_send_button_exists(self, driver):
        """Test that Send button exists."""
        self._load_character_for_chat(driver)

        buttons = driver.find_elements(By.TAG_NAME, "button")
        send_button_found = any("Send" in btn.text for btn in buttons if btn.text)

        assert send_button_found, "Send button not found"
        print("βœ… Send button exists")

    def test_clear_history_button_exists(self, driver):
        """Test that Clear History button exists."""
        self._load_character_for_chat(driver)

        buttons = driver.find_elements(By.TAG_NAME, "button")
        clear_button_found = any("Clear" in btn.text for btn in buttons if btn.text)

        assert clear_button_found, "Clear History button not found"
        print("βœ… Clear History button exists")

    def test_send_simple_message(self, driver):
        """Test sending a simple chat message."""
        self._load_character_for_chat(driver)

        test_message = "I look around"
        self._send_chat_message(driver, test_message)

        # Wait for response (this may take time depending on LLM)
        time.sleep(5)

        # Check if message appears in chat history
        body_text = driver.find_element(By.TAG_NAME, "body").text

        # The message should appear somewhere in the page
        # (Gradio chatbot displays messages in custom components)
        print(f"βœ… Sent message: '{test_message}'")
        print("⚠️  Response verification requires LLM - check logs")

        assert True  # Pass if no errors occurred

    def test_help_command(self, driver):
        """Test /help command."""
        self._load_character_for_chat(driver)

        self._send_chat_message(driver, "/help")
        time.sleep(3)

        # Look for help text in response
        body_text = driver.find_element(By.TAG_NAME, "body").text

        # Check for common help text keywords
        help_keywords = ["command", "help", "stats", "context", "rag"]
        found_keywords = [kw for kw in help_keywords if kw.lower() in body_text.lower()]

        assert len(found_keywords) > 0, \
            f"Help command may not have responded. Found keywords: {found_keywords}"

        print(f"βœ… /help command executed (found keywords: {found_keywords})")

    def test_stats_command(self, driver):
        """Test /stats command."""
        self._load_character_for_chat(driver)

        self._send_chat_message(driver, "/stats")
        time.sleep(3)

        body_text = driver.find_element(By.TAG_NAME, "body").text

        # Check for stat-related text
        stat_keywords = ["STR", "DEX", "CON", "HP", "AC"]
        found_stats = [stat for stat in stat_keywords if stat in body_text]

        assert len(found_stats) > 0, \
            f"Stats command may not have responded. Found: {found_stats}"

        print(f"βœ… /stats command executed (found: {found_stats})")

    def test_context_command(self, driver):
        """Test /context command."""
        self._load_character_for_chat(driver)

        self._send_chat_message(driver, "/context")
        time.sleep(3)

        body_text = driver.find_element(By.TAG_NAME, "body").text

        # Check for context-related text
        context_keywords = ["context", "player", "character", "Thorin"]
        found_keywords = [kw for kw in context_keywords if kw in body_text]

        assert len(found_keywords) > 0, \
            f"Context command may not have responded. Found: {found_keywords}"

        print(f"βœ… /context command executed (found: {found_keywords})")

    def test_rag_command(self, driver):
        """Test /rag command for searching D&D rules."""
        self._load_character_for_chat(driver)

        self._send_chat_message(driver, "/rag fireball")
        time.sleep(4)

        body_text = driver.find_element(By.TAG_NAME, "body").text

        # Check for RAG-related text or spell info
        rag_keywords = ["RAG", "fireball", "spell", "search", "result"]
        found_keywords = [kw for kw in rag_keywords if kw.lower() in body_text.lower()]

        assert len(found_keywords) > 0, \
            f"RAG command may not have responded. Found: {found_keywords}"

        print(f"βœ… /rag command executed (found: {found_keywords})")

    def test_clear_chat_history(self, driver):
        """Test clearing chat history."""
        self._load_character_for_chat(driver)

        # Send a message first
        self._send_chat_message(driver, "test message")
        time.sleep(2)

        # Click Clear History button
        buttons = driver.find_elements(By.TAG_NAME, "button")
        clear_button = None
        for btn in buttons:
            if "Clear" in btn.text and btn.is_displayed():
                clear_button = btn
                break

        assert clear_button is not None, "Clear History button not found"
        clear_button.click()
        time.sleep(1)

        print("βœ… Clear History button clicked")
        # Actual verification of cleared history depends on Gradio implementation

    def test_multiple_messages(self, driver):
        """Test sending multiple messages in sequence."""
        self._load_character_for_chat(driver)

        messages = [
            "Hello",
            "I draw my sword",
            "/stats"
        ]

        for msg in messages:
            self._send_chat_message(driver, msg)
            time.sleep(2)

        print(f"βœ… Sent {len(messages)} messages successfully")
        assert True

    def test_chat_input_clears_after_send(self, driver):
        """Test that chat input clears after sending message."""
        self._load_character_for_chat(driver)

        # Find textarea
        textareas = driver.find_elements(By.TAG_NAME, "textarea")
        chat_input = textareas[0] if textareas else None
        assert chat_input is not None

        # Send message
        chat_input.clear()
        chat_input.send_keys("test")

        # Click Send
        buttons = driver.find_elements(By.TAG_NAME, "button")
        for btn in buttons:
            if "Send" in btn.text and btn.is_displayed():
                btn.click()
                break

        time.sleep(1)

        # Check if input is cleared (Gradio usually clears it)
        # This may vary based on Gradio version
        current_value = chat_input.get_attribute("value") or ""

        if current_value == "":
            print("βœ… Chat input cleared after sending")
        else:
            print(f"⚠️  Chat input not cleared (current value: '{current_value}')")

        assert True  # Don't fail on this

    @pytest.mark.slow
    def test_wait_for_llm_response(self, driver):
        """Test waiting for actual LLM response (slow test)."""
        self._load_character_for_chat(driver)

        self._send_chat_message(driver, "I look around the room")

        # Wait longer for LLM response
        print("⏳ Waiting for LLM response (this may take 10-30 seconds)...")
        time.sleep(15)

        body_text = driver.find_element(By.TAG_NAME, "body").text

        # Just verify no error occurred
        error_keywords = ["error", "failed", "exception"]
        errors_found = [err for err in error_keywords if err.lower() in body_text.lower()]

        if len(errors_found) > 0:
            print(f"⚠️  Possible errors detected: {errors_found}")
        else:
            print("βœ… No obvious errors after LLM response wait")

        assert True  # Pass if test completes