codemie-test-harness 0.1.206__py3-none-any.whl → 0.1.207__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.

@@ -7,11 +7,15 @@ from codemie_test_harness.tests.ui.pageobject.assistants.generate_with_ai_modal
7
7
  AIAssistantGeneratorPage,
8
8
  )
9
9
  from codemie_test_harness.tests.ui.pageobject.base_page import BasePage
10
+ from tests.ui.pageobject.assistants.assistant_mcp_server import (
11
+ AssistantMCPIntegrationModal,
12
+ )
13
+ from tests.ui.pageobject.assistants.assistant_sidebar import AssistantSidebar
10
14
 
11
15
 
12
- class CreateAssistantPage(BasePage):
16
+ class CreateEditAssistantPage(BasePage):
13
17
  """
14
- Create Assistant page object following Page Object Model (POM) best practices.
18
+ Create/Edit Assistant page object following Page Object Model (POM) best practices.
15
19
 
16
20
  This class encapsulates all interactions with the Create Assistant page,
17
21
  providing a clean interface for test automation while hiding implementation details.
@@ -23,6 +27,8 @@ class CreateAssistantPage(BasePage):
23
27
  def __init__(self, page):
24
28
  """Initialize the Create Assistant page object."""
25
29
  super().__init__(page)
30
+ self.sidebar = AssistantSidebar(page)
31
+ self.mcp = AssistantMCPIntegrationModal(page)
26
32
  self.ai_generator_modal = AIAssistantGeneratorPage(
27
33
  page
28
34
  ) # AI Assistant Generator modal
@@ -39,34 +45,37 @@ class CreateAssistantPage(BasePage):
39
45
  @property
40
46
  def page_title(self) -> Locator:
41
47
  """Page title 'Create Assistant' element"""
42
- return (
43
- self.page.locator('.text-h3:has-text("Create Assistant")')
44
- or self.page.locator(
45
- 'div.text-h3.text-white.font-semibold:has-text("Create Assistant")'
46
- )
47
- or self.page.locator('h1:has-text("Create Assistant")')
48
+ return self.page.locator(
49
+ 'h1.text-h3.text-text-main.font-semibold:has-text("Create Assistant")'
48
50
  )
49
51
 
50
52
  @property
51
53
  def generate_with_ai_button(self) -> Locator:
52
54
  """Generate with AI button in header with magical styling"""
53
- return (
54
- self.page.locator(
55
- 'button.button.magical.medium:has-text("Generate with AI")'
56
- )
57
- or self.page.locator('button:has-text("Generate with AI")')
58
- or self.page.locator("button:has(svg + text)").filter(
59
- has_text="Generate with AI"
60
- )
61
- )
55
+ return self.page.locator(
56
+ 'button.bg-magical-button:has-text("Generate with AI")'
57
+ ).first
62
58
 
63
59
  @property
64
60
  def create_button(self) -> Locator:
65
61
  """Create button with plus icon (primary button)"""
66
- return (
67
- self.page.locator("button#submit")
68
- or self.page.locator('button.button.primary.medium:has-text("Create")')
69
- or self.page.locator('button:has-text("Create"):has(svg)')
62
+ return self.page.locator('button.bg-button-primary-bg:has-text("Create")')
63
+
64
+ @property
65
+ def save_button(self) -> Locator:
66
+ """Save button"""
67
+ return self.page.locator('button.bg-button-primary-bg:has-text("Save")')
68
+
69
+ @property
70
+ def cancel_button(self) -> Locator:
71
+ """Cancel button"""
72
+ return self.page.locator('button.bg-button-secondary-bg:has-text("Cancel")')
73
+
74
+ @property
75
+ def back_button(self) -> Locator:
76
+ """Back button"""
77
+ return self.page.locator(
78
+ 'button.bg-button-secondary-bg:has(svg[viewBox="0 0 18 18"])'
70
79
  )
71
80
 
72
81
  # =============================================================================
@@ -79,82 +88,103 @@ class CreateAssistantPage(BasePage):
79
88
  return self.page.locator('h4:has-text("Assistant Setup")')
80
89
 
81
90
  @property
82
- def project_dropdown(self) -> Locator:
83
- """Project selection multiselect dropdown"""
84
- return (
85
- self.page.locator("div.p-multiselect#project")
86
- or self.page.locator('[name="project"].p-multiselect')
87
- or self.page.locator(".p-multiselect-label-container")
88
- )
91
+ def shared_toggle(self) -> Locator:
92
+ """'Shared with project' toggle switch - returns the label which is clickable"""
93
+ return self.page.locator('label:has-text("Shared with project")')
89
94
 
90
95
  @property
91
- def shared_toggle(self) -> Locator:
92
- """'Shared with project' toggle switch"""
93
- return self.page.locator("label.switch-wrapper span.switch")
96
+ def shared_toggle_checkbox(self) -> Locator:
97
+ """'Shared with project' checkbox input (hidden) - use for checking state only"""
98
+ return self.page.locator(
99
+ 'label:has-text("Shared with project") input[type="checkbox"]'
100
+ )
94
101
 
95
102
  @property
96
103
  def name_input(self) -> Locator:
97
104
  """Assistant name input field with data-testid validation"""
98
- return (
99
- self.page.locator('input#name[data-testid="validation"]')
100
- or self.page.locator('input[placeholder="Name*"]')
101
- or self.page.locator('input[name="name"]')
102
- )
105
+ return self.page.locator('input[placeholder="Name*"]')
103
106
 
104
107
  @property
105
108
  def slug_input(self) -> Locator:
106
109
  """Assistant slug input field"""
107
- return (
108
- self.page.locator('input#slug[data-testid="validation"]')
109
- or self.page.locator(
110
- 'input[placeholder="Unique human-readable identifier"]'
111
- )
112
- or self.page.locator('input[name="slug"]')
113
- )
110
+ return self.page.locator('input[name="slug"]')
114
111
 
115
112
  @property
116
113
  def icon_url_input(self) -> Locator:
117
114
  """Assistant icon URL input field"""
118
- return (
119
- self.page.locator('input#icon_url[data-testid="validation"]')
120
- or self.page.locator('input[placeholder="URL to the assistant\'s icon"]')
121
- or self.page.locator('input[name="icon_url"]')
122
- )
115
+ return self.page.locator('input[name="icon_url"]')
123
116
 
124
117
  @property
125
118
  def description_textarea(self) -> Locator:
126
119
  """Assistant description textarea with placeholder"""
127
- return (
128
- self.page.locator('textarea#description[name="description"]')
129
- or self.page.locator('textarea[placeholder="Description*"]')
130
- or self.page.locator(".textarea-wrapper textarea")
120
+ return self.page.locator(
121
+ 'textarea[name="description"][placeholder="Description*"]'
122
+ )
123
+
124
+ @property
125
+ def categories_dropdown(self) -> Locator:
126
+ """Categories selection multiselect dropdown"""
127
+ return self.page.locator(
128
+ 'div.p-multiselect:has(div.p-multiselect-label:has-text("Select categories"))'
131
129
  )
132
130
 
133
131
  @property
134
132
  def conversation_starters_input(self) -> Locator:
135
133
  """Conversation starters input field with InputGroup"""
136
- return (
137
- self.page.locator("input.p-inputtext#conversationStarters-0")
138
- or self.page.locator('input[name="conversationStarters"]')
139
- or self.page.locator(".p-inputgroup input")
140
- )
134
+ return self.page.locator('input[name="conversation_starters"]')
141
135
 
142
136
  @property
143
137
  def add_conversation_starter_button(self) -> Locator:
144
138
  """Add conversation starter button with plus icon"""
145
- return (
146
- self.page.locator('button.button.secondary.medium:has-text("Add")').nth(0)
147
- or self.page.locator('button:has-text("Add"):has(svg)').first
148
- or self.page.locator('.flex.justify-between button:has-text("Add")')
139
+ return self.page.locator(
140
+ 'label:has-text("Conversation starters") + button:has-text("Add")'
149
141
  )
150
142
 
151
143
  @property
152
144
  def delete_conversation_starter_button(self) -> Locator:
153
145
  """Delete conversation starter button (trash icon in InputGroup)"""
154
- return (
155
- self.page.locator(".p-inputgroup-addon button:has(svg)")
156
- or self.page.locator('button:has(path[d*="M9.5 1.25a3.25"])')
157
- or self.page.locator(".p-inputgroup button")
146
+ return self.page.locator(".p-inputgroup button.bg-button-secondary-bg:has(svg)")
147
+
148
+ @property
149
+ def name_error_message(self):
150
+ """Name field error message."""
151
+ return self.page.locator(
152
+ 'label:has(input[name="name"]) div.text-sm.text-error-main.input-error-message'
153
+ )
154
+
155
+ @property
156
+ def icon_error_message(self):
157
+ """Icon field error message."""
158
+ return self.page.locator(
159
+ 'label:has(input[name="icon_url"]) div.text-sm.text-error-main.input-error-message'
160
+ )
161
+
162
+ @property
163
+ def description_error_message(self):
164
+ """Description field error message."""
165
+ return self.page.locator(
166
+ 'div:has(textarea[name="description"][placeholder="Description*"]) div.text-fire-50.text-sm'
167
+ )
168
+
169
+ @property
170
+ def system_prompt_error_message(self):
171
+ """System prompt field error message."""
172
+ return self.page.locator(
173
+ 'div:has(textarea[placeholder="System Instructions*"]) div.text-fire-50.text-sm'
174
+ )
175
+
176
+ @property
177
+ def temperature_error_message(self):
178
+ """Temperature field error message."""
179
+ return self.page.locator(
180
+ 'label:has(input[name="temperature"]) div.text-sm.text-error-main.input-error-message'
181
+ )
182
+
183
+ @property
184
+ def top_p_error_message(self):
185
+ """Top P field error message."""
186
+ return self.page.locator(
187
+ 'label:has(input[name="top_p"]) div.text-sm.text-error-main.input-error-message'
158
188
  )
159
189
 
160
190
  # =============================================================================
@@ -170,56 +200,201 @@ class CreateAssistantPage(BasePage):
170
200
  def system_instructions_label(self) -> Locator:
171
201
  """System Instructions label"""
172
202
  return self.page.locator(
173
- '.text-sm.font-semibold:has-text("System Instructions")'
203
+ 'p.text-sm.font-semibold:has-text("System Instructions")'
174
204
  )
175
205
 
176
206
  @property
177
207
  def system_prompt_textarea(self) -> Locator:
178
208
  """System instructions textarea with full height"""
179
- return (
180
- self.page.locator('textarea#system_prompt[name="system_prompt"]')
181
- or self.page.locator('textarea[placeholder="System Instructions*"]')
182
- or self.page.locator(".textarea-wrapper.h-full textarea")
183
- )
209
+ return self.page.locator('textarea[placeholder="System Instructions*"]')
210
+
211
+ @property
212
+ def generate_with_ai_system_instructions_button(self) -> Locator:
213
+ """Generate with AI button for system instructions"""
214
+ return self.page.locator(
215
+ 'button.bg-magical-button:has-text("Generate with AI")'
216
+ ).nth(1)
184
217
 
185
218
  @property
186
219
  def expand_system_prompt_button(self) -> Locator:
187
220
  """Expand system prompt button"""
188
- return (
189
- self.page.locator('button.button.secondary.medium:has-text("Expand")')
190
- or self.page.locator('button:has-text("Expand"):has(svg)')
191
- or self.page.locator('.flex.gap-4 button:has-text("Expand")')
221
+ return self.page.locator('button.bg-button-secondary-bg:has-text("Expand")')
222
+
223
+ @property
224
+ def current_user_prompt_var_button(self) -> Locator:
225
+ """Current User prompt variable button"""
226
+ return self.page.locator('button:has-text("Current User")')
227
+
228
+ @property
229
+ def date_prompt_var_button(self) -> Locator:
230
+ """Date prompt variable button"""
231
+ return self.page.locator('button:has-text("Date")')
232
+
233
+ @property
234
+ def manage_prompt_vars_button(self) -> Locator:
235
+ """Manage Prompt Vars button"""
236
+ return self.page.locator(
237
+ 'button.bg-button-primary-bg:has-text("Manage Prompt Vars")'
192
238
  )
193
239
 
194
240
  @property
195
- def model_type_dropdown(self) -> Locator:
196
- """LLM model type multiselect dropdown"""
197
- return (
198
- self.page.locator("div.p-multiselect#model_type")
199
- or self.page.locator('[name="model_type"].p-multiselect')
200
- or self.page.locator(
201
- '.p-multiselect:has(.p-multiselect-label:has-text("Default LLM Model"))'
202
- )
241
+ def llm_model_dropdown(self) -> Locator:
242
+ """LLM model selection dropdown"""
243
+ return self.page.locator(
244
+ 'div.p-multiselect:has(div.p-multiselect-label:has-text("Default: GPT-4.1"))'
203
245
  )
204
246
 
205
247
  @property
206
248
  def temperature_input(self) -> Locator:
207
249
  """Temperature input field (0-2 range)"""
208
- return (
209
- self.page.locator('input#temperature[data-testid="validation"]')
210
- or self.page.locator('input[placeholder="0-2"]')
211
- or self.page.locator('input[name="temperature"]')
212
- )
250
+ return self.page.locator('input[name="temperature"][placeholder="0-2"]')
213
251
 
214
252
  @property
215
253
  def top_p_input(self) -> Locator:
216
254
  """Top P input field (0-1 range)"""
255
+ return self.page.locator('input[name="top_p"][placeholder="0-1"]')
256
+
257
+ # ==================== DataSource Context ====================
258
+ @property
259
+ def datasource_context_label(self):
260
+ """Label 'Datasource Context' above the dropdown."""
261
+ return self.page.locator(
262
+ 'div.text-xs.text-text-secondary:has-text("Datasource Context")'
263
+ )
264
+
265
+ @property
266
+ def datasource_context_add_button(self):
267
+ """'Add' button next to the Datasource Context label."""
268
+ return self.page.locator(
269
+ 'div:has-text("Datasource Context") + button:has-text("Add")'
270
+ )
271
+
272
+ @property
273
+ def datasource_context_dropdown(self):
274
+ """Datasource Context dropdown (multiselect input)."""
275
+ return self.page.locator("div.p-multiselect#context-selector")
276
+
277
+ @property
278
+ def datasource_context_dropdown_label(self):
279
+ """The visible label text inside the datasource context dropdown."""
280
+ return self.datasource_context_dropdown.locator("div.p-multiselect-label")
281
+
282
+ # ==================== Sub-Assistant Context ====================
283
+ @property
284
+ def sub_assistants_label(self):
285
+ """Label 'Sub-Assistants' above the sub assistants dropdown."""
286
+ return self.page.get_by_text("Sub-Assistants", exact=True)
287
+
288
+ @property
289
+ def sub_assistants_dropdown(self):
290
+ """Sub Assistants dropdown (multiselect input)."""
291
+ return self.page.locator(
292
+ 'div.p-multiselect:has(div.p-multiselect-label:has-text("Select Sub-Assistants"))'
293
+ )
294
+
295
+ @property
296
+ def sub_assistants_dropdown_label(self):
297
+ """The label inside the sub assistants dropdown."""
298
+ return self.sub_assistants_dropdown.locator("div.p-multiselect-label")
299
+
300
+ # ======= Tools Accordion Locators =======
301
+
302
+ @property
303
+ def available_tools_accordion(self) -> Locator:
304
+ """Available Tools accordion section"""
305
+ return self.page.locator(
306
+ 'div.p-accordion-header:has(h1.font-bold:has-text("Available Tools"))'
307
+ )
308
+
309
+ @property
310
+ def external_tools_accordion(self) -> Locator:
311
+ """External Tools accordion section"""
312
+ return self.page.locator(
313
+ 'div.p-accordion-header:has(h1.font-bold:has-text("External Tools"))'
314
+ )
315
+
316
+ @step
317
+ def section(self, name: str) -> Locator:
318
+ """Get main accordion section (Available Tools or External Tools) by name"""
319
+ return self.page.locator(
320
+ f'div.p-accordion-header:has(h1.font-bold.text-text-quaternary:has-text("{name}"))'
321
+ )
322
+
323
+ @step
324
+ def toolkit(self, section_name: str, toolkit_name: str) -> Locator:
325
+ """Get toolkit accordion header within a section by name
326
+ Handles both spaced and non-spaced toolkit names (e.g., 'Open API' vs 'OpenAPI')"""
327
+ # Try the exact name first, if not found try without spaces
328
+ toolkit_name_no_space = toolkit_name.replace(" ", "")
329
+ # Look for h2 with the toolkit name, which is inside the accordion header
330
+ return self.page.locator(
331
+ f'div.p-accordion-header:has(h2.font-medium:text-is("{toolkit_name}")),'
332
+ f'div.p-accordion-header:has(h2.font-medium:text-is("{toolkit_name_no_space}"))'
333
+ ).first
334
+
335
+ @step
336
+ def tool_rows_under_toolkit(self, toolkit_name: str) -> Locator:
337
+ """Returns all tool rows (each with a label and a checkbox) under an expanded toolkit panel."""
338
+ panel = self.page.locator(
339
+ "div.p-accordion-tab.p-accordion-tab-active div.p-accordion-content"
340
+ ).filter(has_text=toolkit_name)
341
+ return panel.locator(
342
+ "div.grid.grid-cols-[auto,1fr]"
343
+ ) # Adapt selector to match tool row
344
+
345
+ @step
346
+ def tool_label_spans_under_toolkit(self, tool: str) -> Locator:
347
+ tool_stripped = tool.strip()
348
+ if "mcp" in tool_stripped.lower():
349
+ return (
350
+ self.page.locator("div.p-accordion-tab-active div.p-accordion-content")
351
+ .locator('button, [id*="mcp"]')
352
+ .filter(has_text=tool_stripped)
353
+ .first
354
+ )
355
+ return self.page.locator(
356
+ "div.p-accordion-tab-active div.p-accordion-content label"
357
+ ).get_by_text(tool_stripped, exact=True)
358
+
359
+ @step
360
+ def tool_checkbox(self, tool_name: str) -> Locator:
217
361
  return (
218
- self.page.locator('input#top_p[data-testid="validation"]')
219
- or self.page.locator('input[placeholder="0-1"]')
220
- or self.page.locator('input[name="top_p"]')
362
+ self.page.locator("span")
363
+ .filter(has_text=tool_name)
364
+ .locator("xpath=..")
365
+ .locator("input[type=checkbox]")
221
366
  )
222
367
 
368
+ @step
369
+ def tool_row(self, tool_name: str) -> Locator:
370
+ return (
371
+ self.page.locator("span")
372
+ .filter(has_text=tool_name)
373
+ .locator("xpath=ancestor::div[contains(@class,'grid')]")
374
+ )
375
+
376
+ @step
377
+ def select_section(self, section_name: str):
378
+ self.section(section_name).click()
379
+ return self
380
+
381
+ @step
382
+ def select_toolkit(self, section: str, toolkit: str):
383
+ self.toolkit(section, toolkit).click()
384
+ return self
385
+
386
+ @step
387
+ def should_be_visible_tool(self, tool: str):
388
+ expect(self.tool_label_spans_under_toolkit(tool)).to_be_visible()
389
+ return self
390
+
391
+ @step
392
+ def select_tool(self, tool: str):
393
+ self.tool_label_spans_under_toolkit(tool).click()
394
+ if self.mcp.is_pop_visible():
395
+ self.mcp.fill_mcp_server_base_form()
396
+ return self
397
+
223
398
  # ==================== NAVIGATION METHODS ====================
224
399
 
225
400
  @step
@@ -444,8 +619,8 @@ class CreateAssistantPage(BasePage):
444
619
  Returns:
445
620
  self: Returns the page object for method chaining
446
621
  """
447
- # Check current state and toggle if needed
448
- is_currently_checked = self.shared_toggle.is_checked()
622
+ # Check current state using the hidden checkbox and toggle if needed by clicking the label
623
+ is_currently_checked = self.shared_toggle_checkbox.is_checked()
449
624
  if (shared and not is_currently_checked) or (
450
625
  not shared and is_currently_checked
451
626
  ):
@@ -495,6 +670,17 @@ class CreateAssistantPage(BasePage):
495
670
  self.create_button.click()
496
671
  return self
497
672
 
673
+ @step
674
+ def click_save(self):
675
+ """
676
+ Click the Create button to create the assistant.
677
+
678
+ Returns:
679
+ self: Returns the page object for method chaining
680
+ """
681
+ self.save_button.click()
682
+ return self
683
+
498
684
  @step
499
685
  def click_cancel(self):
500
686
  """
@@ -528,6 +714,27 @@ class CreateAssistantPage(BasePage):
528
714
  self.generate_with_ai_button.click()
529
715
  return self
530
716
 
717
+ def select_tool_option(self, toolkit_name: str, label: str, checked: bool = True):
718
+ self.expand_toolkit(toolkit_name)
719
+ checkbox = self.toolkit_checkbox_by_label(toolkit_name, label)
720
+ if checked != checkbox.is_checked():
721
+ checkbox.click()
722
+ return self
723
+
724
+ def get_all_tools_in_toolkit(self, toolkit_name: str):
725
+ """
726
+ Returns a list of tuples (label, checked) for all tool features inside a toolkit accordion.
727
+ """
728
+ panel = self.toolkit_accordion_panel(toolkit_name)
729
+ labels = panel.locator(".checkbox-label span.text-sm").all_text_contents()
730
+ checkboxes = panel.locator('input[type="checkbox"]')
731
+ return [
732
+ (lbl, checkboxes.nth(idx).is_checked()) for idx, lbl in enumerate(labels)
733
+ ]
734
+
735
+ def toolkit_select_all_checkbox(self, toolkit_name: str):
736
+ return self.toolkit_checkbox_by_label(toolkit_name, "Select all")
737
+
531
738
  # ==================== COMPREHENSIVE ASSISTANT CREATION METHOD ====================
532
739
 
533
740
  @step
@@ -594,6 +801,7 @@ class CreateAssistantPage(BasePage):
594
801
  def should_have_all_form_fields_visible(self):
595
802
  """Verify that all essential form fields are visible."""
596
803
  expect(self.name_input).to_be_visible()
804
+ expect(self.slug_input).to_be_visible()
597
805
  expect(self.description_textarea).to_be_visible()
598
806
  expect(self.system_prompt_textarea).to_be_visible()
599
807
  return self
@@ -623,6 +831,12 @@ class CreateAssistantPage(BasePage):
623
831
  expect(self.system_prompt_textarea).to_have_value(expected_prompt)
624
832
  return self
625
833
 
834
+ @step
835
+ def should_have_categories_visible(self):
836
+ """Verify categories dropdown is visible.."""
837
+ expect(self.categories_dropdown).to_be_visible()
838
+ return self
839
+
626
840
  @step
627
841
  def should_have_icon_url_value(self, expected_url: str):
628
842
  """Verify icon URL field has expected value."""
@@ -632,13 +846,13 @@ class CreateAssistantPage(BasePage):
632
846
  @step
633
847
  def should_have_shared_checked(self):
634
848
  """Verify shared toggle is checked."""
635
- expect(self.shared_toggle).to_be_checked()
849
+ expect(self.shared_toggle_checkbox).to_be_checked()
636
850
  return self
637
851
 
638
852
  @step
639
853
  def should_have_shared_unchecked(self):
640
854
  """Verify shared toggle is unchecked."""
641
- expect(self.shared_toggle).not_to_be_checked()
855
+ expect(self.shared_toggle_checkbox).not_to_be_checked()
642
856
  return self
643
857
 
644
858
  @step
@@ -667,3 +881,73 @@ class CreateAssistantPage(BasePage):
667
881
  expect(self.system_prompt_textarea).to_have_value("")
668
882
  expect(self.icon_url_input).to_have_value("")
669
883
  return self
884
+
885
+ @step
886
+ def should_have_top_p_and_temperature(self):
887
+ """Verify top p and temperature fields are visible."""
888
+ expect(self.temperature_input).to_be_visible()
889
+ expect(self.top_p_input).to_be_visible()
890
+ return self
891
+
892
+ @step
893
+ def should_have_top_p_and_temperature_value(self, temperature: str, top_p: str):
894
+ """Verify top p and temperature field values is visible."""
895
+ expect(self.temperature_input).to_have_value(temperature)
896
+ expect(self.top_p_input).to_have_value(top_p)
897
+
898
+ @step
899
+ def should_have_datasource_context(self):
900
+ """Verify datasource context fields are visible."""
901
+ expect(self.datasource_context_label).to_be_visible()
902
+ expect(self.datasource_context_add_button).to_be_visible()
903
+ expect(self.datasource_context_dropdown).to_be_visible()
904
+ return self
905
+
906
+ @step
907
+ def should_have_sub_assistants_context(self):
908
+ """Verify sub assistants context fields are visible."""
909
+ expect(self.sub_assistants_label).to_be_visible()
910
+ expect(self.sub_assistants_dropdown).to_be_visible()
911
+ return self
912
+
913
+ @step
914
+ def should_have_name_error_textarea(self, error_message: str):
915
+ """Verify name error text field is visible."""
916
+ expect(self.name_error_message).to_be_visible()
917
+ expect(self.name_error_message).to_have_text(error_message)
918
+ return self
919
+
920
+ @step
921
+ def should_have_description_error_textarea(self, error_message: str):
922
+ """Verify description error text field is visible."""
923
+ expect(self.description_error_message).to_be_visible()
924
+ expect(self.description_error_message).to_have_text(error_message)
925
+ return self
926
+
927
+ @step
928
+ def should_have_system_prompt_error_textarea(self, error_message: str):
929
+ """Verify system prompt error text field is visible."""
930
+ expect(self.system_prompt_error_message).to_be_visible()
931
+ expect(self.system_prompt_error_message).to_have_text(error_message)
932
+ return self
933
+
934
+ @step
935
+ def should_have_icon_error_textarea(self, error_message: str):
936
+ """Verify icon error text field is visible."""
937
+ expect(self.icon_error_message).to_be_visible()
938
+ expect(self.icon_error_message).to_have_text(error_message)
939
+ return self
940
+
941
+ @step
942
+ def should_have_temperature_error_textarea(self, error_message: str):
943
+ """Verify temperature error text field is visible."""
944
+ expect(self.temperature_error_message).to_be_visible()
945
+ expect(self.temperature_error_message).to_have_text(error_message)
946
+ return self
947
+
948
+ @step
949
+ def should_have_top_p_error_textarea(self, error_message: str):
950
+ """Verify top p error text field is visible."""
951
+ expect(self.top_p_error_message).to_be_visible()
952
+ expect(self.top_p_error_message).to_have_text(error_message)
953
+ return self