codemie-test-harness 0.1.182__py3-none-any.whl → 0.1.184__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of codemie-test-harness might be problematic. Click here for more details.
- codemie_test_harness/tests/assistant/tools/codebase/test_codebase_tools.py +1 -1
- codemie_test_harness/tests/ui/__init__.py +1 -0
- codemie_test_harness/tests/ui/assistants/test_create_assistant.py +3 -11
- codemie_test_harness/tests/ui/chats/conftest.py +14 -0
- codemie_test_harness/tests/ui/chats/test_chat_configuration.py +221 -0
- codemie_test_harness/tests/ui/chats/test_chat_functionality.py +222 -0
- codemie_test_harness/tests/ui/conftest.py +25 -4
- codemie_test_harness/tests/ui/datasource/test_create_datasource.py +8 -8
- codemie_test_harness/tests/ui/datasource/test_datasource_page.py +3 -3
- codemie_test_harness/tests/ui/datasource/test_edit_datasource.py +7 -6
- codemie_test_harness/tests/ui/datasource/test_view_datasource.py +6 -7
- codemie_test_harness/tests/ui/integrations/test_create_integration.py +3 -3
- codemie_test_harness/tests/ui/pageobject/base_page.py +12 -1
- codemie_test_harness/tests/ui/pageobject/chats/chat_page.py +622 -0
- codemie_test_harness/tests/ui/pageobject/chats/chats_sidebar.py +489 -0
- codemie_test_harness/tests/ui/pageobject/chats/configuration_panel.py +228 -0
- codemie_test_harness/tests/ui/pageobject/chats/configure_and_test_panel.py +102 -0
- codemie_test_harness/tests/ui/pageobject/datasources/create_edit_datasource_page.py +9 -8
- codemie_test_harness/tests/ui/pageobject/datasources/datasource_page.py +4 -4
- codemie_test_harness/tests/ui/pageobject/datasources/datasource_sidebar.py +4 -3
- codemie_test_harness/tests/ui/pageobject/integrations/create_integration_page.py +2 -2
- codemie_test_harness/tests/ui/{_test_data → test_data}/assistant_test_data.py +2 -0
- codemie_test_harness/tests/ui/test_data/chat_test_data.py +98 -0
- {codemie_test_harness-0.1.182.dist-info → codemie_test_harness-0.1.184.dist-info}/METADATA +2 -2
- {codemie_test_harness-0.1.182.dist-info → codemie_test_harness-0.1.184.dist-info}/RECORD +30 -22
- /codemie_test_harness/tests/ui/{_test_data → test_data}/__init__.py +0 -0
- /codemie_test_harness/tests/ui/{_test_data → test_data}/datasource_test_data.py +0 -0
- /codemie_test_harness/tests/ui/{_test_data → test_data}/integration_test_data.py +0 -0
- {codemie_test_harness-0.1.182.dist-info → codemie_test_harness-0.1.184.dist-info}/WHEEL +0 -0
- {codemie_test_harness-0.1.182.dist-info → codemie_test_harness-0.1.184.dist-info}/entry_points.txt +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
+
from pathlib import Path
|
|
2
3
|
|
|
3
4
|
from playwright.sync_api import expect, Locator
|
|
4
5
|
from reportportal_client import step
|
|
@@ -32,7 +33,7 @@ class BasePage:
|
|
|
32
33
|
|
|
33
34
|
@property
|
|
34
35
|
def create_button(self) -> Locator:
|
|
35
|
-
"""
|
|
36
|
+
"""Create button in header"""
|
|
36
37
|
return self.page.locator("button").filter(has_text="Create")
|
|
37
38
|
|
|
38
39
|
@property
|
|
@@ -197,6 +198,16 @@ class BasePage:
|
|
|
197
198
|
"""Get the current page URL."""
|
|
198
199
|
return self.page.url
|
|
199
200
|
|
|
201
|
+
@step
|
|
202
|
+
def evaluate_current_url(self) -> str:
|
|
203
|
+
"""Evaluate the current page URL."""
|
|
204
|
+
return self.page.evaluate("() => window.location.href")
|
|
205
|
+
|
|
206
|
+
@step
|
|
207
|
+
def get_id_from_url(self, url: str) -> str:
|
|
208
|
+
"""Extract the ID from the URL after the last slash."""
|
|
209
|
+
return Path(url).name
|
|
210
|
+
|
|
200
211
|
# Verification methods for pop-ups
|
|
201
212
|
@step
|
|
202
213
|
def should_see_new_release_popup(self):
|
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Chat Page Object for CodeMie UI Testing
|
|
3
|
+
|
|
4
|
+
This module implements the Chat page object following the established POM patterns
|
|
5
|
+
in the CodeMie test harness. It provides comprehensive support for chat functionality
|
|
6
|
+
including chat creation, message handling, and configuration management.
|
|
7
|
+
|
|
8
|
+
Following the same architecture as other page objects in the framework:
|
|
9
|
+
- Property-based element locators with multiple fallbacks
|
|
10
|
+
- Comprehensive verification methods
|
|
11
|
+
- Integration with ReportPortal via @step decorators
|
|
12
|
+
- Method chaining support for fluent API
|
|
13
|
+
- Robust error handling and graceful degradation
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from playwright.sync_api import expect, Locator
|
|
17
|
+
from reportportal_client import step
|
|
18
|
+
|
|
19
|
+
from codemie_test_harness.tests.ui import conversation_ids
|
|
20
|
+
from codemie_test_harness.tests.ui.pageobject.base_page import BasePage
|
|
21
|
+
from codemie_test_harness.tests.ui.pageobject.chats.configuration_panel import (
|
|
22
|
+
ConfigurationPanel,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# noinspection PyArgumentList
|
|
27
|
+
class ChatPage(BasePage):
|
|
28
|
+
"""
|
|
29
|
+
Chat page object with comprehensive chat functionality support.
|
|
30
|
+
|
|
31
|
+
This class encapsulates all chat-related UI interactions including:
|
|
32
|
+
- Chat creation and management
|
|
33
|
+
- Message composition and sending
|
|
34
|
+
- Configuration handling
|
|
35
|
+
- Navigation and verification methods
|
|
36
|
+
|
|
37
|
+
Follows established POM patterns with property-based locators and method chaining.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
chat_id = None
|
|
41
|
+
|
|
42
|
+
def __init__(self, page):
|
|
43
|
+
super().__init__(page)
|
|
44
|
+
self.page_url = "/#/chats"
|
|
45
|
+
|
|
46
|
+
# ==================== CORE CHAT ELEMENTS ====================
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def new_chat_button(self) -> Locator:
|
|
50
|
+
"""Primary new chat button"""
|
|
51
|
+
return self.page.locator("#new-chat")
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def chat_input(self) -> Locator:
|
|
55
|
+
"""Main chat input field with comprehensive selector strategy."""
|
|
56
|
+
return self.page.locator(".ql-editor")
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def send_button(self) -> Locator:
|
|
60
|
+
"""Send message button."""
|
|
61
|
+
return self.page.locator("button").filter(has_text="Send")
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def chat_history_container(self) -> Locator:
|
|
65
|
+
"""Container holding all chat messages."""
|
|
66
|
+
return self.page.locator(".history")
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def user_message(self) -> Locator:
|
|
70
|
+
"""Individual user message element."""
|
|
71
|
+
return self.chat_history_container.locator(".request")
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def assistant_message(self) -> Locator:
|
|
75
|
+
"""Individual user message element."""
|
|
76
|
+
return self.chat_history_container.locator(".content")
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def processed_in_field(self) -> Locator:
|
|
80
|
+
return self.chat_history_container.locator("span").filter(
|
|
81
|
+
has_text="Processed in"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def search_assistant_list(self) -> Locator:
|
|
86
|
+
return self.page.locator("#quill-mention-list")
|
|
87
|
+
|
|
88
|
+
# ==================== ACTION BUTTONS ====================
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def action_buttons_bar(self) -> Locator:
|
|
92
|
+
"""Execution Info button with tooltip."""
|
|
93
|
+
return self.page.locator("div.ml-auto")
|
|
94
|
+
|
|
95
|
+
# ==================== CHAT HISTORY CONTAINER ACTION BUTTONS ====================
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def user_message_copy_button(self) -> Locator:
|
|
99
|
+
"""Copy button for user messages - first button in user message actions."""
|
|
100
|
+
return self.chat_history_container.locator("a.chat-message-action").nth(0)
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def user_message_edit_button(self) -> Locator:
|
|
104
|
+
"""Edit button for user messages - second button in user message actions."""
|
|
105
|
+
return self.chat_history_container.locator("a.chat-message-action").nth(1)
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def user_message_regenerate_button(self) -> Locator:
|
|
109
|
+
"""Regenerate/refresh button for user messages - third button in user message actions."""
|
|
110
|
+
return self.chat_history_container.locator("a.chat-message-action").nth(2)
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def user_message_delete_button(self) -> Locator:
|
|
114
|
+
"""Delete button for user messages - fourth button in user message actions."""
|
|
115
|
+
return self.chat_history_container.locator("a.chat-message-action").nth(3)
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def assistant_message_copy_button(self) -> Locator:
|
|
119
|
+
"""Copy button for assistant messages - first button in assistant message actions."""
|
|
120
|
+
return self.chat_history_container.locator(
|
|
121
|
+
".action-buttons a.chat-message-action"
|
|
122
|
+
).nth(0)
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def assistant_message_edit_button(self) -> Locator:
|
|
126
|
+
"""Edit button for assistant messages - second button in assistant message actions."""
|
|
127
|
+
return self.chat_history_container.locator(
|
|
128
|
+
".action-buttons a.chat-message-action"
|
|
129
|
+
).nth(1)
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def assistant_message_share_button(self) -> Locator:
|
|
133
|
+
"""Share/export button for assistant messages - button with up arrow icon."""
|
|
134
|
+
return self.chat_history_container.locator(
|
|
135
|
+
".action-buttons button.button.tertiary.medium"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def execution_info_button(self) -> Locator:
|
|
140
|
+
"""Execution Info button with tooltip."""
|
|
141
|
+
return self.action_buttons_bar.locator("button.button.secondary.medium").nth(0)
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def share_chat_button(self) -> Locator:
|
|
145
|
+
"""Share chat button with share icon."""
|
|
146
|
+
return self.action_buttons_bar.locator("button.button.secondary.medium").nth(1)
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def export_chat_button(self) -> Locator:
|
|
150
|
+
"""Export chat button with export icon."""
|
|
151
|
+
return self.action_buttons_bar.locator("button.button.secondary.medium").nth(2)
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def clear_chat_button(self) -> Locator:
|
|
155
|
+
"""Clear chat button with clear/delete icon."""
|
|
156
|
+
return self.action_buttons_bar.locator("button.button.secondary.medium").nth(3)
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def add_attachment_button(self) -> Locator:
|
|
160
|
+
"""Add attachment button with paperclip icon."""
|
|
161
|
+
return self.page.locator('button[aria-label*="attach"]')
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def start_conversation_invitation(self) -> Locator:
|
|
165
|
+
"""Start conversation invitation text and elements."""
|
|
166
|
+
return self.page.locator("h1").filter(
|
|
167
|
+
has_text="Start a conversation with an assistant"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
@property
|
|
171
|
+
def conversation_invitation_subtitle(self) -> Locator:
|
|
172
|
+
"""Conversation subtitle text."""
|
|
173
|
+
return self.page.get_by_text(
|
|
174
|
+
"Ask anything or type @ and choose assistant from the list"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# ==================== CONFIGURATION ELEMENTS ====================
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def configuration_button(self) -> Locator:
|
|
181
|
+
"""Configuration button with text and icon."""
|
|
182
|
+
return self.page.locator("button").filter(has_text="Configuration")
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
def chat_configuration_panel(self):
|
|
186
|
+
"""Chat configuration component."""
|
|
187
|
+
return ConfigurationPanel(self.page)
|
|
188
|
+
|
|
189
|
+
# ==================== CHAT HISTORY AND SIDEBAR ====================
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def chat_sidebar(self) -> Locator:
|
|
193
|
+
"""Chat history sidebar."""
|
|
194
|
+
return self.page.locator("")
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def chat_history_items(self) -> Locator:
|
|
198
|
+
"""Individual chat history items in sidebar."""
|
|
199
|
+
return self.chat_sidebar.locator("")
|
|
200
|
+
|
|
201
|
+
# ==================== NAVIGATION METHODS ====================
|
|
202
|
+
|
|
203
|
+
@step
|
|
204
|
+
def navigate_to(self, chat_id: str):
|
|
205
|
+
"""Navigate to the main chat page."""
|
|
206
|
+
self.page.goto(f"{self.page_url}/{chat_id}")
|
|
207
|
+
self.wait_for_page_load()
|
|
208
|
+
self.chat_id = chat_id
|
|
209
|
+
return self
|
|
210
|
+
|
|
211
|
+
@step
|
|
212
|
+
def start_new_chat(self):
|
|
213
|
+
"""Start a new chat conversation."""
|
|
214
|
+
if self.new_chat_button.is_visible():
|
|
215
|
+
self.new_chat_button.click()
|
|
216
|
+
self.wait_for_page_load()
|
|
217
|
+
_id = self.get_id_from_url(self.evaluate_current_url())
|
|
218
|
+
conversation_ids.append(_id)
|
|
219
|
+
self.chat_id = _id
|
|
220
|
+
return _id
|
|
221
|
+
return None
|
|
222
|
+
|
|
223
|
+
# ==================== ACTION BUTTON METHODS ====================
|
|
224
|
+
|
|
225
|
+
@step
|
|
226
|
+
def click_execution_info(self):
|
|
227
|
+
"""Click the execution info button."""
|
|
228
|
+
self.execution_info_button.click()
|
|
229
|
+
return self
|
|
230
|
+
|
|
231
|
+
@step
|
|
232
|
+
def click_share_chat(self):
|
|
233
|
+
"""Click the share chat button."""
|
|
234
|
+
self.share_chat_button.click()
|
|
235
|
+
return self
|
|
236
|
+
|
|
237
|
+
@step
|
|
238
|
+
def click_export_chat(self):
|
|
239
|
+
"""Click the export chat button."""
|
|
240
|
+
self.export_chat_button.click()
|
|
241
|
+
return self
|
|
242
|
+
|
|
243
|
+
@step
|
|
244
|
+
def click_clear_chat(self):
|
|
245
|
+
"""Click the clear chat button."""
|
|
246
|
+
self.clear_chat_button.click()
|
|
247
|
+
return self
|
|
248
|
+
|
|
249
|
+
@step
|
|
250
|
+
def click_add_attachment(self):
|
|
251
|
+
"""Click the add attachment button."""
|
|
252
|
+
self.add_attachment_button.click()
|
|
253
|
+
return self
|
|
254
|
+
|
|
255
|
+
@step
|
|
256
|
+
def click_configuration(self):
|
|
257
|
+
"""Click the configuration button."""
|
|
258
|
+
self.configuration_button.click()
|
|
259
|
+
return self
|
|
260
|
+
|
|
261
|
+
@step
|
|
262
|
+
def open_configuration(self):
|
|
263
|
+
if not self.chat_configuration_panel.panel.is_visible():
|
|
264
|
+
"""Open the configuration panel."""
|
|
265
|
+
self.click_configuration()
|
|
266
|
+
return self
|
|
267
|
+
|
|
268
|
+
@step
|
|
269
|
+
def close_configuration(self):
|
|
270
|
+
if self.chat_configuration_panel.panel.is_visible():
|
|
271
|
+
"""Close the configuration panel."""
|
|
272
|
+
self.click_configuration()
|
|
273
|
+
return self
|
|
274
|
+
|
|
275
|
+
# ==================== CHAT INTERACTION METHODS ====================
|
|
276
|
+
|
|
277
|
+
@step
|
|
278
|
+
def send_message(self, message: str, assistant_name=""):
|
|
279
|
+
"""
|
|
280
|
+
Send a message in the chat.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
message: The message text to send
|
|
284
|
+
assistant_name: assistant_name
|
|
285
|
+
"""
|
|
286
|
+
if not assistant_name == "":
|
|
287
|
+
self.chat_input.fill(f"@{assistant_name}")
|
|
288
|
+
self.get_assistant_item_in_list(assistant_name).click()
|
|
289
|
+
self.chat_input.type(message)
|
|
290
|
+
self.send_button.click()
|
|
291
|
+
return self
|
|
292
|
+
else:
|
|
293
|
+
self.chat_input.fill(message)
|
|
294
|
+
self.send_button.click()
|
|
295
|
+
return self
|
|
296
|
+
|
|
297
|
+
@step
|
|
298
|
+
def clear_chat_input(self):
|
|
299
|
+
"""Clear the chat input field."""
|
|
300
|
+
self.chat_input.fill("")
|
|
301
|
+
return self
|
|
302
|
+
|
|
303
|
+
@step
|
|
304
|
+
def type_message_without_sending(self, message: str):
|
|
305
|
+
"""Type a message without sending it."""
|
|
306
|
+
self.chat_input.fill(message)
|
|
307
|
+
return self
|
|
308
|
+
|
|
309
|
+
@step
|
|
310
|
+
def send_test_message(self, message: str = "Test message"):
|
|
311
|
+
"""Send a test message for verification purposes."""
|
|
312
|
+
self.send_message(message)
|
|
313
|
+
return self
|
|
314
|
+
|
|
315
|
+
@step
|
|
316
|
+
def get_assistant_item_in_list(self, name: str) -> Locator:
|
|
317
|
+
return self.search_assistant_list.locator("p").filter(has_text=name)
|
|
318
|
+
|
|
319
|
+
# ==================== ACTION BUTTON VERIFICATION METHODS ====================
|
|
320
|
+
|
|
321
|
+
@step
|
|
322
|
+
def should_have_execution_info_button_visible(self):
|
|
323
|
+
"""Verify that the execution info button is visible."""
|
|
324
|
+
expect(self.execution_info_button).to_be_visible()
|
|
325
|
+
return self
|
|
326
|
+
|
|
327
|
+
@step
|
|
328
|
+
def should_have_share_chat_button_visible(self):
|
|
329
|
+
"""Verify that the share chat button is visible."""
|
|
330
|
+
expect(self.share_chat_button).to_be_visible()
|
|
331
|
+
return self
|
|
332
|
+
|
|
333
|
+
@step
|
|
334
|
+
def should_have_export_chat_button_visible(self):
|
|
335
|
+
"""Verify that the export chat button is visible."""
|
|
336
|
+
expect(self.export_chat_button).to_be_visible()
|
|
337
|
+
return self
|
|
338
|
+
|
|
339
|
+
@step
|
|
340
|
+
def should_have_clear_chat_button_visible(self):
|
|
341
|
+
"""Verify that the clear chat button is visible."""
|
|
342
|
+
expect(self.clear_chat_button).to_be_visible()
|
|
343
|
+
return self
|
|
344
|
+
|
|
345
|
+
@step
|
|
346
|
+
def should_have_configuration_button_visible(self):
|
|
347
|
+
"""Verify that the configuration button is visible."""
|
|
348
|
+
expect(self.configuration_button).to_be_visible()
|
|
349
|
+
return self
|
|
350
|
+
|
|
351
|
+
@step
|
|
352
|
+
def should_have_add_attachment_button_visible(self):
|
|
353
|
+
"""Verify that the add attachment button is visible."""
|
|
354
|
+
expect(self.add_attachment_button).to_be_visible()
|
|
355
|
+
return self
|
|
356
|
+
|
|
357
|
+
@step
|
|
358
|
+
def should_have_start_conversation_invitation_visible(self):
|
|
359
|
+
"""Verify that the start conversation invitation is visible."""
|
|
360
|
+
expect(self.start_conversation_invitation).to_be_visible()
|
|
361
|
+
return self
|
|
362
|
+
|
|
363
|
+
@step
|
|
364
|
+
def should_have_conversation_subtitle_visible(self):
|
|
365
|
+
"""Verify that the conversation subtitle is visible."""
|
|
366
|
+
expect(self.conversation_invitation_subtitle).to_be_visible()
|
|
367
|
+
return self
|
|
368
|
+
|
|
369
|
+
# ==================== CHAT HISTORY CONTAINER BUTTON VERIFICATION METHODS ====================
|
|
370
|
+
|
|
371
|
+
@step
|
|
372
|
+
def should_have_user_message_copy_button_visible(self):
|
|
373
|
+
"""Verify that the user message copy button is visible."""
|
|
374
|
+
expect(self.user_message_copy_button).to_be_visible()
|
|
375
|
+
return self
|
|
376
|
+
|
|
377
|
+
@step
|
|
378
|
+
def should_have_user_message_edit_button_visible(self):
|
|
379
|
+
"""Verify that the user message edit button is visible."""
|
|
380
|
+
expect(self.user_message_edit_button).to_be_visible()
|
|
381
|
+
return self
|
|
382
|
+
|
|
383
|
+
@step
|
|
384
|
+
def should_have_user_message_regenerate_button_visible(self):
|
|
385
|
+
"""Verify that the user message regenerate button is visible."""
|
|
386
|
+
expect(self.user_message_regenerate_button).to_be_visible()
|
|
387
|
+
return self
|
|
388
|
+
|
|
389
|
+
@step
|
|
390
|
+
def should_have_user_message_delete_button_visible(self):
|
|
391
|
+
"""Verify that the user message delete button is visible."""
|
|
392
|
+
expect(self.user_message_delete_button).to_be_visible()
|
|
393
|
+
return self
|
|
394
|
+
|
|
395
|
+
@step
|
|
396
|
+
def should_have_assistant_message_copy_button_visible(self):
|
|
397
|
+
"""Verify that the assistant message copy button is visible."""
|
|
398
|
+
expect(self.assistant_message_copy_button).to_be_visible()
|
|
399
|
+
return self
|
|
400
|
+
|
|
401
|
+
@step
|
|
402
|
+
def should_have_assistant_message_edit_button_visible(self):
|
|
403
|
+
"""Verify that the assistant message edit button is visible."""
|
|
404
|
+
expect(self.assistant_message_edit_button).to_be_visible()
|
|
405
|
+
return self
|
|
406
|
+
|
|
407
|
+
@step
|
|
408
|
+
def should_have_assistant_message_share_button_visible(self):
|
|
409
|
+
"""Verify that the assistant message share button is visible."""
|
|
410
|
+
expect(self.assistant_message_share_button).to_be_visible()
|
|
411
|
+
return self
|
|
412
|
+
|
|
413
|
+
# ==================== VERIFICATION METHODS ====================
|
|
414
|
+
|
|
415
|
+
@step
|
|
416
|
+
def should_be_on_chat_page(self):
|
|
417
|
+
"""Verify that we are on the chat page."""
|
|
418
|
+
expect(self.page).to_have_url(f"{self.page_url}/{self.chat_id}")
|
|
419
|
+
return self
|
|
420
|
+
|
|
421
|
+
@step
|
|
422
|
+
def should_have_new_chat_button_visible(self):
|
|
423
|
+
"""Verify that the new chat button is visible."""
|
|
424
|
+
expect(self.new_chat_button).to_be_visible()
|
|
425
|
+
return self
|
|
426
|
+
|
|
427
|
+
@step
|
|
428
|
+
def should_have_chat_input_visible(self):
|
|
429
|
+
"""Verify that the chat input field is visible."""
|
|
430
|
+
expect(self.chat_input).to_be_visible()
|
|
431
|
+
return self
|
|
432
|
+
|
|
433
|
+
@step
|
|
434
|
+
def should_have_send_button_visible(self):
|
|
435
|
+
"""Verify that the send button is visible."""
|
|
436
|
+
expect(self.send_button).to_be_visible()
|
|
437
|
+
return self
|
|
438
|
+
|
|
439
|
+
@step
|
|
440
|
+
def should_have_send_button_enabled(self):
|
|
441
|
+
"""Verify that the send button is enabled."""
|
|
442
|
+
expect(self.send_button).to_be_enabled()
|
|
443
|
+
return self
|
|
444
|
+
|
|
445
|
+
@step
|
|
446
|
+
def should_have_send_button_disabled(self):
|
|
447
|
+
"""Verify that the send button is disabled."""
|
|
448
|
+
expect(self.send_button).to_be_disabled()
|
|
449
|
+
return self
|
|
450
|
+
|
|
451
|
+
@step
|
|
452
|
+
def should_have_message_sent(self, message_text: str):
|
|
453
|
+
"""
|
|
454
|
+
Verify that a specific message was sent and appears in chat.
|
|
455
|
+
|
|
456
|
+
Args:
|
|
457
|
+
message_text: The message text to verify
|
|
458
|
+
"""
|
|
459
|
+
message_locator = self.user_message.filter(has_text=message_text)
|
|
460
|
+
expect(message_locator.first).to_be_visible()
|
|
461
|
+
return self
|
|
462
|
+
|
|
463
|
+
@step
|
|
464
|
+
def should_have_assistant_response(self):
|
|
465
|
+
"""Verify that assistant has provided a response."""
|
|
466
|
+
expect(self.assistant_message.first).to_be_visible()
|
|
467
|
+
return self
|
|
468
|
+
|
|
469
|
+
@step
|
|
470
|
+
def should_have_new_chat_created(self):
|
|
471
|
+
"""Verify that a new chat has been successfully created."""
|
|
472
|
+
# Check that we can interact with chat elements
|
|
473
|
+
self.should_have_chat_input_visible()
|
|
474
|
+
self.should_have_send_button_visible()
|
|
475
|
+
|
|
476
|
+
# Verify that messages are visible (at least user message)
|
|
477
|
+
expect(self.user_message.first).to_be_visible()
|
|
478
|
+
return self
|
|
479
|
+
|
|
480
|
+
@step
|
|
481
|
+
def should_have_configuration_panel_opened(self):
|
|
482
|
+
# Verify that configuration panel is opened
|
|
483
|
+
expect(self.chat_configuration_panel.panel).to_be_visible()
|
|
484
|
+
return self
|
|
485
|
+
|
|
486
|
+
@step
|
|
487
|
+
def should_have_configuration_panel_closed(self):
|
|
488
|
+
# Verify that configuration panel is closed
|
|
489
|
+
expect(self.chat_configuration_panel.panel).to_be_hidden()
|
|
490
|
+
return self
|
|
491
|
+
|
|
492
|
+
@step
|
|
493
|
+
def should_have_history_visible(self):
|
|
494
|
+
"""Verify that the chat messages container is visible."""
|
|
495
|
+
expect(self.chat_history_container).to_be_visible()
|
|
496
|
+
return self
|
|
497
|
+
|
|
498
|
+
@step
|
|
499
|
+
def should_have_empty_chat_input(self):
|
|
500
|
+
"""Verify that the chat input field is empty."""
|
|
501
|
+
expect(self.chat_input).to_have_text("")
|
|
502
|
+
return self
|
|
503
|
+
|
|
504
|
+
@step
|
|
505
|
+
def should_have_chat_input_value(self, expected_value: str):
|
|
506
|
+
"""
|
|
507
|
+
Verify that the chat input has a specific value.
|
|
508
|
+
|
|
509
|
+
Args:
|
|
510
|
+
expected_value: The expected input value
|
|
511
|
+
"""
|
|
512
|
+
expect(self.chat_input).to_have_text(expected_value)
|
|
513
|
+
return self
|
|
514
|
+
|
|
515
|
+
@step
|
|
516
|
+
def should_have_sidebar_visible(self):
|
|
517
|
+
"""Verify that the chat sidebar is visible."""
|
|
518
|
+
expect(self.chat_sidebar).to_be_visible()
|
|
519
|
+
return self
|
|
520
|
+
|
|
521
|
+
@step
|
|
522
|
+
def should_have_chat_history_items(self):
|
|
523
|
+
"""Verify that chat history items are present."""
|
|
524
|
+
expect(self.chat_history_items.first).to_be_visible()
|
|
525
|
+
return self
|
|
526
|
+
|
|
527
|
+
# ==================== UTILITY METHODS ====================
|
|
528
|
+
|
|
529
|
+
@step
|
|
530
|
+
def get_user_message_count(self) -> int:
|
|
531
|
+
"""Get the number of user messages."""
|
|
532
|
+
return self.user_message.count()
|
|
533
|
+
|
|
534
|
+
@step
|
|
535
|
+
def get_assistant_message_count(self) -> int:
|
|
536
|
+
"""Get the number of assistant messages."""
|
|
537
|
+
return self.assistant_message.count()
|
|
538
|
+
|
|
539
|
+
@step
|
|
540
|
+
def get_last_user_message_text(self) -> str:
|
|
541
|
+
"""Get the text of the last user message."""
|
|
542
|
+
return self.user_message.last.inner_text()
|
|
543
|
+
|
|
544
|
+
@step
|
|
545
|
+
def get_last_assistant_message_text(self) -> str:
|
|
546
|
+
"""Get the text of the last assistant message."""
|
|
547
|
+
return self.assistant_message.last.inner_text()
|
|
548
|
+
|
|
549
|
+
@step
|
|
550
|
+
def get_chat_input_value(self) -> str:
|
|
551
|
+
"""Get the current value of the chat input field."""
|
|
552
|
+
return self.chat_input.input_value()
|
|
553
|
+
|
|
554
|
+
@step
|
|
555
|
+
def wait_for_assistant_response(self, timeout: int = 30000):
|
|
556
|
+
"""
|
|
557
|
+
Wait for assistant response to complete.
|
|
558
|
+
|
|
559
|
+
Args:
|
|
560
|
+
timeout: Timeout in milliseconds
|
|
561
|
+
"""
|
|
562
|
+
self.processed_in_field.last.wait_for(state="visible", timeout=timeout)
|
|
563
|
+
return self
|
|
564
|
+
|
|
565
|
+
@step
|
|
566
|
+
def scroll_to_bottom_of_chat(self):
|
|
567
|
+
"""Scroll to the bottom of the chat messages."""
|
|
568
|
+
self.chat_history_container.evaluate(
|
|
569
|
+
"element => element.scrollTop = element.scrollHeight"
|
|
570
|
+
)
|
|
571
|
+
return self
|
|
572
|
+
|
|
573
|
+
@step
|
|
574
|
+
def scroll_to_top_of_chat(self):
|
|
575
|
+
"""Scroll to the top of the chat messages."""
|
|
576
|
+
self.chat_history_container.evaluate("element => element.scrollTop = 0")
|
|
577
|
+
return self
|
|
578
|
+
|
|
579
|
+
# ==================== INTEGRATION VERIFICATION ====================
|
|
580
|
+
|
|
581
|
+
@step
|
|
582
|
+
def verify_all_essential_elements_visible(self):
|
|
583
|
+
"""Comprehensive verification of all essential chat page elements."""
|
|
584
|
+
self.should_have_new_chat_button_visible()
|
|
585
|
+
self.should_have_chat_input_visible()
|
|
586
|
+
self.should_have_send_button_visible()
|
|
587
|
+
self.should_have_add_attachment_button_visible()
|
|
588
|
+
self.should_have_configuration_button_visible()
|
|
589
|
+
return self
|
|
590
|
+
|
|
591
|
+
@step
|
|
592
|
+
def verify_all_action_buttons_visible(self):
|
|
593
|
+
"""Verify all action buttons in the toolbar are visible."""
|
|
594
|
+
self.should_have_execution_info_button_visible()
|
|
595
|
+
self.should_have_share_chat_button_visible()
|
|
596
|
+
self.should_have_export_chat_button_visible()
|
|
597
|
+
self.should_have_clear_chat_button_visible()
|
|
598
|
+
self.should_have_configuration_button_visible()
|
|
599
|
+
return self
|
|
600
|
+
|
|
601
|
+
@step
|
|
602
|
+
def verify_empty_chat_state(self):
|
|
603
|
+
"""Verify the empty chat state with invitation message."""
|
|
604
|
+
self.should_have_start_conversation_invitation_visible()
|
|
605
|
+
self.should_have_conversation_subtitle_visible()
|
|
606
|
+
self.should_have_chat_input_visible()
|
|
607
|
+
self.should_have_send_button_visible()
|
|
608
|
+
return self
|
|
609
|
+
|
|
610
|
+
@step
|
|
611
|
+
def verify_all_chat_history_action_buttons_visible(self):
|
|
612
|
+
"""Verify all 7 action buttons in chat history container are visible."""
|
|
613
|
+
(
|
|
614
|
+
self.should_have_user_message_copy_button_visible()
|
|
615
|
+
.should_have_user_message_edit_button_visible()
|
|
616
|
+
.should_have_user_message_regenerate_button_visible()
|
|
617
|
+
.should_have_user_message_delete_button_visible()
|
|
618
|
+
.should_have_assistant_message_copy_button_visible()
|
|
619
|
+
.should_have_assistant_message_edit_button_visible()
|
|
620
|
+
.should_have_assistant_message_share_button_visible()
|
|
621
|
+
)
|
|
622
|
+
return self
|