codemie-test-harness 0.1.181__py3-none-any.whl → 0.1.183__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/datasource/test_file_indexing.py +2 -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/tests/workflow/assistant_tools/mcp/test_workflow_with_assistant_with_mcp_server.py +3 -5
- codemie_test_harness/tests/workflow/virtual_assistant_tools/mcp/test_workflow_with_mcp_server.py +3 -4
- {codemie_test_harness-0.1.181.dist-info → codemie_test_harness-0.1.183.dist-info}/METADATA +2 -2
- {codemie_test_harness-0.1.181.dist-info → codemie_test_harness-0.1.183.dist-info}/RECORD +32 -24
- /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.181.dist-info → codemie_test_harness-0.1.183.dist-info}/WHEEL +0 -0
- {codemie_test_harness-0.1.181.dist-info → codemie_test_harness-0.1.183.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Chats Sidebar Page Object for CodeMie UI Testing
|
|
3
|
+
|
|
4
|
+
This module implements the Chats Sidebar page object following the established POM patterns
|
|
5
|
+
in the CodeMie test harness. It provides comprehensive support for chat sidebar functionality
|
|
6
|
+
including assistants management, chat navigation, and folder organization.
|
|
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 codemie_test_harness.tests.ui.pageobject.base_page import BasePage
|
|
17
|
+
from playwright.sync_api import expect, Locator
|
|
18
|
+
from reportportal_client import step
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ChatsSidebar(BasePage):
|
|
22
|
+
"""
|
|
23
|
+
Chats Sidebar page object with comprehensive sidebar functionality support.
|
|
24
|
+
|
|
25
|
+
This class encapsulates all chat sidebar-related UI interactions including:
|
|
26
|
+
- Assistants section management
|
|
27
|
+
- Chat history navigation
|
|
28
|
+
- Folder management
|
|
29
|
+
- Sidebar navigation and actions
|
|
30
|
+
|
|
31
|
+
Follows established POM patterns with property-based locators and method chaining.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self, page):
|
|
35
|
+
super().__init__(page)
|
|
36
|
+
|
|
37
|
+
# ==================== MAIN SIDEBAR CONTAINER ====================
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def sidebar_container(self) -> Locator:
|
|
41
|
+
"""Main sidebar container."""
|
|
42
|
+
return self.page.locator(
|
|
43
|
+
"div.z-10.h-full.overflow-y-auto.min-w-sidebar.max-w-sidebar"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# ==================== ASSISTANTS SECTION ====================
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def assistants_accordion(self) -> Locator:
|
|
50
|
+
"""Assistants accordion section."""
|
|
51
|
+
return self.sidebar_container.locator('[data-pc-name="accordion"]')
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def assistants_header(self) -> Locator:
|
|
55
|
+
"""Assistants accordion header."""
|
|
56
|
+
return self.assistants_accordion.locator(".p-accordion-header")
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def assistants_header_action(self) -> Locator:
|
|
60
|
+
"""Assistants accordion header action button."""
|
|
61
|
+
return self.assistants_header.locator(".p-accordion-header-action")
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def assistants_header_icon(self) -> Locator:
|
|
65
|
+
"""Assistants accordion chevron icon."""
|
|
66
|
+
return self.assistants_header.locator("svg")
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def assistants_header_title(self) -> Locator:
|
|
70
|
+
"""Assistants accordion header title text."""
|
|
71
|
+
return self.assistants_header.locator(".p-accordion-header-text")
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def assistants_content(self) -> Locator:
|
|
75
|
+
"""Assistants accordion content area."""
|
|
76
|
+
return self.assistants_accordion.locator(".p-accordion-content")
|
|
77
|
+
|
|
78
|
+
# ==================== ASSISTANT ITEMS ====================
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def assistant_item_container(self) -> Locator:
|
|
82
|
+
"""Individual assistant item container."""
|
|
83
|
+
return self.assistants_content.locator(
|
|
84
|
+
".flex.justify-between.items-center.h-8.mb-2.ml-6.mr-4"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def assistant_avatar(self) -> Locator:
|
|
89
|
+
"""Assistant avatar image."""
|
|
90
|
+
return self.assistant_item_container.locator('img[alt="assistant icon"]')
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def assistant_name(self) -> Locator:
|
|
94
|
+
"""Assistant name text."""
|
|
95
|
+
return self.assistant_item_container.locator(
|
|
96
|
+
"span.block.w-full.truncate.text-text-main.text-sm.font-normal"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def assistant_menu_button(self) -> Locator:
|
|
101
|
+
"""Assistant menu/options button (three dots)."""
|
|
102
|
+
return self.assistant_item_container.locator("button.button.tertiary.medium")
|
|
103
|
+
|
|
104
|
+
def get_assistant_by_name(self, assistant_name: str) -> Locator:
|
|
105
|
+
"""Get specific assistant item by name."""
|
|
106
|
+
return self.assistant_item_container.locator(
|
|
107
|
+
f'span[title*="{assistant_name}"]'
|
|
108
|
+
).locator("..")
|
|
109
|
+
|
|
110
|
+
# ==================== EXPLORE ASSISTANTS ====================
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def explore_assistants_button(self) -> Locator:
|
|
114
|
+
"""Explore Assistants navigation button."""
|
|
115
|
+
return self.sidebar_container.locator("button#navigate")
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def explore_assistants_icon(self) -> Locator:
|
|
119
|
+
"""Explore Assistants button icon."""
|
|
120
|
+
return self.explore_assistants_button.locator("svg")
|
|
121
|
+
|
|
122
|
+
# ==================== DIVIDER ====================
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def section_divider(self) -> Locator:
|
|
126
|
+
"""Divider between assistants and chats sections."""
|
|
127
|
+
return self.sidebar_container.locator(".p-divider")
|
|
128
|
+
|
|
129
|
+
# ==================== CHATS SECTION ====================
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def chats_section_button(self) -> Locator:
|
|
133
|
+
"""Chats section toggle button."""
|
|
134
|
+
return self.sidebar_container.locator("button").filter(has_text="Chats")
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def chats_section_icon(self) -> Locator:
|
|
138
|
+
"""Chats section chevron icon."""
|
|
139
|
+
return self.chats_section_button.locator("svg")
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def chats_section_title(self) -> Locator:
|
|
143
|
+
"""Chats section title text."""
|
|
144
|
+
return self.chats_section_button.locator("span", has_text="Chats")
|
|
145
|
+
|
|
146
|
+
# ==================== CHAT HISTORY LIST ====================
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def chat_history_container(self) -> Locator:
|
|
150
|
+
"""Chat history list container."""
|
|
151
|
+
return self.sidebar_container.locator("ul")
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def chat_items(self) -> Locator:
|
|
155
|
+
"""All chat items in the history list."""
|
|
156
|
+
return self.chat_history_container.locator("li")
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def active_chat_item(self) -> Locator:
|
|
160
|
+
"""Currently active/selected chat item."""
|
|
161
|
+
return self.page.locator("li.bg-panel-50")
|
|
162
|
+
|
|
163
|
+
def get_chat_item_by_index(self, index: int) -> Locator:
|
|
164
|
+
"""Get specific chat item by index (0-based)."""
|
|
165
|
+
return self.chat_items.nth(index)
|
|
166
|
+
|
|
167
|
+
def get_chat_item_by_text(self, chat_text: str) -> Locator:
|
|
168
|
+
"""Get specific chat item by partial text content."""
|
|
169
|
+
return self.chat_items.filter(has_text=chat_text)
|
|
170
|
+
|
|
171
|
+
# ==================== CHAT ITEM ELEMENTS ====================
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def chat_item_link(self) -> Locator:
|
|
175
|
+
"""Chat item link element."""
|
|
176
|
+
return self.chat_items.locator("a.text-inherit")
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def chat_item_name_input(self) -> Locator:
|
|
180
|
+
"""Chat item name edit input (when editing)."""
|
|
181
|
+
return self.chat_items.locator("input.edit-name")
|
|
182
|
+
|
|
183
|
+
@property
|
|
184
|
+
def chat_item_menu_button(self) -> Locator:
|
|
185
|
+
"""Chat item menu/options button (three dots)."""
|
|
186
|
+
return self.chat_items.locator("button.button.tertiary.medium")
|
|
187
|
+
|
|
188
|
+
# ==================== FOLDERS SECTION ====================
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def folders_section_button(self) -> Locator:
|
|
192
|
+
"""Folders section toggle button."""
|
|
193
|
+
return self.sidebar_container.locator("button").filter(has_text="Folders")
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def folders_section_icon(self) -> Locator:
|
|
197
|
+
"""Folders section chevron icon."""
|
|
198
|
+
return self.folders_section_button.locator("svg").first
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def folders_section_title(self) -> Locator:
|
|
202
|
+
"""Folders section title text."""
|
|
203
|
+
return self.folders_section_button.locator("span", has_text="Folders")
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def create_folder_button(self) -> Locator:
|
|
207
|
+
"""Create new folder button."""
|
|
208
|
+
return self.folders_section_button.locator('button[title="Create Folder"]')
|
|
209
|
+
|
|
210
|
+
@property
|
|
211
|
+
def create_folder_icon(self) -> Locator:
|
|
212
|
+
"""Create folder button icon."""
|
|
213
|
+
return self.create_folder_button.locator("svg")
|
|
214
|
+
|
|
215
|
+
# ==================== INTERACTION METHODS ====================
|
|
216
|
+
|
|
217
|
+
@step
|
|
218
|
+
def toggle_assistants_section(self):
|
|
219
|
+
"""Toggle the assistants accordion section."""
|
|
220
|
+
self.assistants_header_action.click()
|
|
221
|
+
return self
|
|
222
|
+
|
|
223
|
+
@step
|
|
224
|
+
def click_explore_assistants(self):
|
|
225
|
+
"""Click the Explore Assistants button."""
|
|
226
|
+
self.explore_assistants_button.click()
|
|
227
|
+
return self
|
|
228
|
+
|
|
229
|
+
@step
|
|
230
|
+
def click_assistant_by_name(self, assistant_name: str):
|
|
231
|
+
"""Click on a specific assistant by name."""
|
|
232
|
+
assistant = self.get_assistant_by_name(assistant_name)
|
|
233
|
+
assistant.click()
|
|
234
|
+
return self
|
|
235
|
+
|
|
236
|
+
@step
|
|
237
|
+
def click_assistant_menu(self, assistant_name: str = None):
|
|
238
|
+
"""Click the menu button for a specific assistant or the first one."""
|
|
239
|
+
if assistant_name:
|
|
240
|
+
assistant = self.get_assistant_by_name(assistant_name)
|
|
241
|
+
assistant.locator("button.button.tertiary.medium").click()
|
|
242
|
+
else:
|
|
243
|
+
self.assistant_menu_button.first.click()
|
|
244
|
+
return self
|
|
245
|
+
|
|
246
|
+
@step
|
|
247
|
+
def toggle_chats_section(self):
|
|
248
|
+
"""Toggle the chats section."""
|
|
249
|
+
self.chats_section_button.click()
|
|
250
|
+
return self
|
|
251
|
+
|
|
252
|
+
@step
|
|
253
|
+
def click_chat_item(self, index: int = 0):
|
|
254
|
+
"""Click on a specific chat item by index."""
|
|
255
|
+
chat_item = self.get_chat_item_by_index(index)
|
|
256
|
+
chat_item.click()
|
|
257
|
+
return self
|
|
258
|
+
|
|
259
|
+
@step
|
|
260
|
+
def click_chat_by_text(self, chat_text: str):
|
|
261
|
+
"""Click on a specific chat item by text content."""
|
|
262
|
+
chat_item = self.get_chat_item_by_text(chat_text)
|
|
263
|
+
chat_item.click()
|
|
264
|
+
return self
|
|
265
|
+
|
|
266
|
+
@step
|
|
267
|
+
def click_chat_menu(self, index: int = 0):
|
|
268
|
+
"""Click the menu button for a specific chat item."""
|
|
269
|
+
chat_item = self.get_chat_item_by_index(index)
|
|
270
|
+
menu_button = chat_item.locator("button.button.tertiary.medium")
|
|
271
|
+
menu_button.click()
|
|
272
|
+
return self
|
|
273
|
+
|
|
274
|
+
@step
|
|
275
|
+
def toggle_folders_section(self):
|
|
276
|
+
"""Toggle the folders section."""
|
|
277
|
+
self.folders_section_button.click()
|
|
278
|
+
return self
|
|
279
|
+
|
|
280
|
+
@step
|
|
281
|
+
def click_create_folder(self):
|
|
282
|
+
"""Click the create folder button."""
|
|
283
|
+
self.create_folder_button.click()
|
|
284
|
+
return self
|
|
285
|
+
|
|
286
|
+
@step
|
|
287
|
+
def edit_chat_name(self, index: int, new_name: str):
|
|
288
|
+
"""Edit the name of a specific chat item."""
|
|
289
|
+
chat_item = self.get_chat_item_by_index(index)
|
|
290
|
+
# This would trigger edit mode - implementation depends on actual UI behavior
|
|
291
|
+
# For now, assuming double-click or specific action triggers edit
|
|
292
|
+
chat_item.dblclick()
|
|
293
|
+
|
|
294
|
+
name_input = chat_item.locator("input.edit-name")
|
|
295
|
+
if name_input.is_visible():
|
|
296
|
+
name_input.fill(new_name)
|
|
297
|
+
name_input.press("Enter")
|
|
298
|
+
return self
|
|
299
|
+
|
|
300
|
+
# ==================== VERIFICATION METHODS ====================
|
|
301
|
+
|
|
302
|
+
@step
|
|
303
|
+
def should_have_sidebar_visible(self):
|
|
304
|
+
"""Verify that the main sidebar container is visible."""
|
|
305
|
+
expect(self.sidebar_container).to_be_visible()
|
|
306
|
+
return self
|
|
307
|
+
|
|
308
|
+
@step
|
|
309
|
+
def should_have_assistants_section_visible(self):
|
|
310
|
+
"""Verify that the assistants section is visible."""
|
|
311
|
+
expect(self.assistants_accordion).to_be_visible()
|
|
312
|
+
expect(self.assistants_header).to_be_visible()
|
|
313
|
+
expect(self.assistants_header_title).to_contain_class("uppercase")
|
|
314
|
+
expect(self.assistants_header_title).to_have_text("Assistants")
|
|
315
|
+
return self
|
|
316
|
+
|
|
317
|
+
@step
|
|
318
|
+
def should_have_assistants_section_expanded(self):
|
|
319
|
+
"""Verify that the assistants section is expanded."""
|
|
320
|
+
expect(self.assistants_accordion).to_have_attribute("data-p-active", "true")
|
|
321
|
+
expect(self.assistants_content).to_be_visible()
|
|
322
|
+
return self
|
|
323
|
+
|
|
324
|
+
@step
|
|
325
|
+
def should_have_assistants_section_collapsed(self):
|
|
326
|
+
"""Verify that the assistants section is collapsed."""
|
|
327
|
+
expect(self.assistants_accordion).to_have_attribute("data-p-active", "false")
|
|
328
|
+
expect(self.assistants_content).to_be_hidden()
|
|
329
|
+
return self
|
|
330
|
+
|
|
331
|
+
@step
|
|
332
|
+
def should_have_assistant_visible(self, assistant_name: str):
|
|
333
|
+
"""Verify that a specific assistant is visible."""
|
|
334
|
+
assistant = self.get_assistant_by_name(assistant_name)
|
|
335
|
+
expect(assistant).to_be_visible()
|
|
336
|
+
return self
|
|
337
|
+
|
|
338
|
+
@step
|
|
339
|
+
def should_have_assistant_avatar_visible(self):
|
|
340
|
+
"""Verify that assistant avatar is visible."""
|
|
341
|
+
expect(self.assistant_avatar).to_be_visible()
|
|
342
|
+
return self
|
|
343
|
+
|
|
344
|
+
@step
|
|
345
|
+
def should_have_explore_assistants_button_visible(self):
|
|
346
|
+
"""Verify that the Explore Assistants button is visible."""
|
|
347
|
+
expect(self.explore_assistants_button).to_be_visible()
|
|
348
|
+
expect(self.explore_assistants_button).to_contain_text("Explore Assistants")
|
|
349
|
+
return self
|
|
350
|
+
|
|
351
|
+
@step
|
|
352
|
+
def should_have_section_divider_visible(self):
|
|
353
|
+
"""Verify that the section divider is visible."""
|
|
354
|
+
expect(self.section_divider).to_be_visible()
|
|
355
|
+
return self
|
|
356
|
+
|
|
357
|
+
@step
|
|
358
|
+
def should_have_chats_section_visible(self):
|
|
359
|
+
"""Verify that the chats section is visible."""
|
|
360
|
+
expect(self.chats_section_button).to_be_visible()
|
|
361
|
+
expect(self.chats_section_title).to_have_text("Chats")
|
|
362
|
+
return self
|
|
363
|
+
|
|
364
|
+
@step
|
|
365
|
+
def should_have_chat_history_visible(self):
|
|
366
|
+
"""Verify that the chat history container is visible."""
|
|
367
|
+
expect(self.chat_history_container).to_be_visible()
|
|
368
|
+
return self
|
|
369
|
+
|
|
370
|
+
@step
|
|
371
|
+
def should_have_chat_items(self, expected_count: int = None):
|
|
372
|
+
"""Verify that chat items are present, optionally checking count."""
|
|
373
|
+
expect(self.chat_items.first).to_be_visible()
|
|
374
|
+
if expected_count is not None:
|
|
375
|
+
expect(self.chat_items).to_have_count(expected_count)
|
|
376
|
+
return self
|
|
377
|
+
|
|
378
|
+
@step
|
|
379
|
+
def should_have_active_chat_item(self):
|
|
380
|
+
"""Verify that there is an active/selected chat item."""
|
|
381
|
+
expect(self.active_chat_item).to_be_visible()
|
|
382
|
+
return self
|
|
383
|
+
|
|
384
|
+
@step
|
|
385
|
+
def should_have_chat_item_with_text(self, chat_text: str):
|
|
386
|
+
"""Verify that a chat item with specific text exists."""
|
|
387
|
+
chat_item = self.get_chat_item_by_text(chat_text)
|
|
388
|
+
expect(chat_item).to_be_visible()
|
|
389
|
+
return self
|
|
390
|
+
|
|
391
|
+
@step
|
|
392
|
+
def should_have_folders_section_visible(self):
|
|
393
|
+
"""Verify that the folders section is visible."""
|
|
394
|
+
expect(self.folders_section_button).to_be_visible()
|
|
395
|
+
expect(self.folders_section_title).to_have_text("Folders")
|
|
396
|
+
return self
|
|
397
|
+
|
|
398
|
+
@step
|
|
399
|
+
def should_have_create_folder_button_visible(self):
|
|
400
|
+
"""Verify that the create folder button is visible."""
|
|
401
|
+
expect(self.create_folder_button).to_be_visible()
|
|
402
|
+
return self
|
|
403
|
+
|
|
404
|
+
@step
|
|
405
|
+
def should_have_assistant_menu_button_visible(self):
|
|
406
|
+
"""Verify that assistant menu buttons are visible."""
|
|
407
|
+
expect(self.assistant_menu_button.first).to_be_visible()
|
|
408
|
+
return self
|
|
409
|
+
|
|
410
|
+
@step
|
|
411
|
+
def should_have_chat_menu_buttons_visible(self):
|
|
412
|
+
"""Verify that chat item menu buttons are visible."""
|
|
413
|
+
expect(self.chat_item_menu_button.first).to_be_visible()
|
|
414
|
+
return self
|
|
415
|
+
|
|
416
|
+
# ==================== UTILITY METHODS ====================
|
|
417
|
+
|
|
418
|
+
@step
|
|
419
|
+
def get_chat_items_count(self) -> int:
|
|
420
|
+
"""Get the total number of chat items."""
|
|
421
|
+
return self.chat_items.count()
|
|
422
|
+
|
|
423
|
+
@step
|
|
424
|
+
def get_active_chat_title(self) -> str:
|
|
425
|
+
"""Get the text of the currently active chat item."""
|
|
426
|
+
return self.active_chat_item.locator("a").inner_text()
|
|
427
|
+
|
|
428
|
+
@step
|
|
429
|
+
def get_assistant_names(self) -> list:
|
|
430
|
+
"""Get a list of all visible assistant names."""
|
|
431
|
+
names = []
|
|
432
|
+
count = self.assistant_name.count()
|
|
433
|
+
for i in range(count):
|
|
434
|
+
names.append(self.assistant_name.nth(i).inner_text())
|
|
435
|
+
return names
|
|
436
|
+
|
|
437
|
+
@step
|
|
438
|
+
def get_chat_texts(self) -> list:
|
|
439
|
+
"""Get a list of all chat item texts."""
|
|
440
|
+
texts = []
|
|
441
|
+
count = self.chat_items.count()
|
|
442
|
+
for i in range(count):
|
|
443
|
+
chat_link = self.chat_items.nth(i).locator("a")
|
|
444
|
+
if chat_link.is_visible():
|
|
445
|
+
texts.append(chat_link.inner_text())
|
|
446
|
+
return texts
|
|
447
|
+
|
|
448
|
+
@step
|
|
449
|
+
def wait_for_sidebar_load(self, timeout: int = 10000):
|
|
450
|
+
"""Wait for the sidebar to fully load."""
|
|
451
|
+
self.sidebar_container.wait_for(state="visible", timeout=timeout)
|
|
452
|
+
return self
|
|
453
|
+
|
|
454
|
+
@step
|
|
455
|
+
def scroll_chat_history_to_top(self):
|
|
456
|
+
"""Scroll the chat history to the top."""
|
|
457
|
+
self.chat_history_container.evaluate("element => element.scrollTop = 0")
|
|
458
|
+
return self
|
|
459
|
+
|
|
460
|
+
@step
|
|
461
|
+
def scroll_chat_history_to_bottom(self):
|
|
462
|
+
"""Scroll the chat history to the bottom."""
|
|
463
|
+
self.chat_history_container.evaluate(
|
|
464
|
+
"element => element.scrollTop = element.scrollHeight"
|
|
465
|
+
)
|
|
466
|
+
return self
|
|
467
|
+
|
|
468
|
+
# ==================== COMPREHENSIVE VERIFICATION METHODS ====================
|
|
469
|
+
|
|
470
|
+
@step
|
|
471
|
+
def verify_all_sidebar_sections_visibility(self):
|
|
472
|
+
"""Comprehensive verification of all sidebar sections."""
|
|
473
|
+
self.should_have_sidebar_visible()
|
|
474
|
+
self.should_have_assistants_section_visible()
|
|
475
|
+
self.should_have_explore_assistants_button_visible()
|
|
476
|
+
self.should_have_chats_section_visible()
|
|
477
|
+
self.should_have_chat_history_visible()
|
|
478
|
+
self.should_have_active_chat_item()
|
|
479
|
+
self.should_have_folders_section_visible()
|
|
480
|
+
return self
|
|
481
|
+
|
|
482
|
+
@step
|
|
483
|
+
def verify_assistants_section(self):
|
|
484
|
+
"""Verify assistants section functionality."""
|
|
485
|
+
self.should_have_assistants_section_visible()
|
|
486
|
+
self.should_have_assistants_section_expanded()
|
|
487
|
+
self.should_have_assistant_avatar_visible()
|
|
488
|
+
self.should_have_assistant_menu_button_visible()
|
|
489
|
+
return self
|