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.

Files changed (32) hide show
  1. codemie_test_harness/tests/assistant/datasource/test_file_indexing.py +2 -1
  2. codemie_test_harness/tests/ui/__init__.py +1 -0
  3. codemie_test_harness/tests/ui/assistants/test_create_assistant.py +3 -11
  4. codemie_test_harness/tests/ui/chats/conftest.py +14 -0
  5. codemie_test_harness/tests/ui/chats/test_chat_configuration.py +221 -0
  6. codemie_test_harness/tests/ui/chats/test_chat_functionality.py +222 -0
  7. codemie_test_harness/tests/ui/conftest.py +25 -4
  8. codemie_test_harness/tests/ui/datasource/test_create_datasource.py +8 -8
  9. codemie_test_harness/tests/ui/datasource/test_datasource_page.py +3 -3
  10. codemie_test_harness/tests/ui/datasource/test_edit_datasource.py +7 -6
  11. codemie_test_harness/tests/ui/datasource/test_view_datasource.py +6 -7
  12. codemie_test_harness/tests/ui/integrations/test_create_integration.py +3 -3
  13. codemie_test_harness/tests/ui/pageobject/base_page.py +12 -1
  14. codemie_test_harness/tests/ui/pageobject/chats/chat_page.py +622 -0
  15. codemie_test_harness/tests/ui/pageobject/chats/chats_sidebar.py +489 -0
  16. codemie_test_harness/tests/ui/pageobject/chats/configuration_panel.py +228 -0
  17. codemie_test_harness/tests/ui/pageobject/chats/configure_and_test_panel.py +102 -0
  18. codemie_test_harness/tests/ui/pageobject/datasources/create_edit_datasource_page.py +9 -8
  19. codemie_test_harness/tests/ui/pageobject/datasources/datasource_page.py +4 -4
  20. codemie_test_harness/tests/ui/pageobject/datasources/datasource_sidebar.py +4 -3
  21. codemie_test_harness/tests/ui/pageobject/integrations/create_integration_page.py +2 -2
  22. codemie_test_harness/tests/ui/{_test_data → test_data}/assistant_test_data.py +2 -0
  23. codemie_test_harness/tests/ui/test_data/chat_test_data.py +98 -0
  24. codemie_test_harness/tests/workflow/assistant_tools/mcp/test_workflow_with_assistant_with_mcp_server.py +3 -5
  25. codemie_test_harness/tests/workflow/virtual_assistant_tools/mcp/test_workflow_with_mcp_server.py +3 -4
  26. {codemie_test_harness-0.1.181.dist-info → codemie_test_harness-0.1.183.dist-info}/METADATA +2 -2
  27. {codemie_test_harness-0.1.181.dist-info → codemie_test_harness-0.1.183.dist-info}/RECORD +32 -24
  28. /codemie_test_harness/tests/ui/{_test_data → test_data}/__init__.py +0 -0
  29. /codemie_test_harness/tests/ui/{_test_data → test_data}/datasource_test_data.py +0 -0
  30. /codemie_test_harness/tests/ui/{_test_data → test_data}/integration_test_data.py +0 -0
  31. {codemie_test_harness-0.1.181.dist-info → codemie_test_harness-0.1.183.dist-info}/WHEEL +0 -0
  32. {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