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.

Files changed (30) hide show
  1. codemie_test_harness/tests/assistant/tools/codebase/test_codebase_tools.py +1 -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-0.1.182.dist-info → codemie_test_harness-0.1.184.dist-info}/METADATA +2 -2
  25. {codemie_test_harness-0.1.182.dist-info → codemie_test_harness-0.1.184.dist-info}/RECORD +30 -22
  26. /codemie_test_harness/tests/ui/{_test_data → test_data}/__init__.py +0 -0
  27. /codemie_test_harness/tests/ui/{_test_data → test_data}/datasource_test_data.py +0 -0
  28. /codemie_test_harness/tests/ui/{_test_data → test_data}/integration_test_data.py +0 -0
  29. {codemie_test_harness-0.1.182.dist-info → codemie_test_harness-0.1.184.dist-info}/WHEEL +0 -0
  30. {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
- """Cancel button in header"""
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