Skip to content

Commit 38beb5c

Browse files
authored
SY-3545: Automate Statuses QA (#2002)
* SY-3545: Automate Statuses QA
1 parent 5624eef commit 38beb5c

9 files changed

Lines changed: 509 additions & 69 deletions

File tree

.github/PULL_REQUEST_TEMPLATE/rc.md

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -294,33 +294,6 @@ I can successfully:
294294
- **Arc Editor**
295295
- [ ] Create an alarm automation that changes statuses and includes the following blocks: channel source, constant, comparison, stable for, select, and status change.
296296

297-
### Statuses
298-
299-
I can successfully:
300-
301-
- **Search and Command Palette**
302-
- [ ] Open the status explorer.
303-
- [ ] Open the status create modal.
304-
305-
- **Status Create Modal**
306-
- [ ] Create a new status.
307-
- [ ] Create a new status with labels.
308-
309-
- **Status Explorer**
310-
- [ ] Filter statuses by labels.
311-
- [ ] Delete a single status.
312-
- [ ] Delete multiple statuses.
313-
- [ ] Favorite a status.
314-
- [ ] Unfavorite a status.
315-
316-
- **Status Notifications**
317-
- [ ] See status notifications in the bottom right corner when creating a new status.
318-
319-
- **Status Toolbar**
320-
- [ ] Unfavorite a status
321-
- [ ] Delete a status
322-
- [ ] Rename a status
323-
324297
### Version
325298

326299
I can successfully:

integration/console/console.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from console.notifications import NotificationsClient
2121
from console.rack import RackClient
2222
from console.ranges import RangesClient
23+
from console.statuses import StatusesClient
2324
from console.workspace import WorkspaceClient
2425
from framework.utils import get_results_path
2526

@@ -43,6 +44,7 @@ class Console:
4344
notifications: NotificationsClient
4445
rack: RackClient
4546
ranges: RangesClient
47+
statuses: StatusesClient
4648
workspace: WorkspaceClient
4749
page: Page
4850

@@ -58,6 +60,7 @@ def __init__(self, page: Page, client: sy.Synnax):
5860
self.access = AccessClient(self.layout)
5961
self.channels = ChannelClient(self.layout, self.client)
6062
self.ranges = RangesClient(self.layout)
63+
self.statuses = StatusesClient(self.layout)
6164
self.workspace = WorkspaceClient(self.layout, self.client)
6265

6366
def check_for_error_screen(self) -> None:

integration/console/labels.py

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def create(self, name: str, *, color: str | None = None) -> None:
5858
save_button.click()
5959
create_form.wait_for(state="hidden", timeout=5000)
6060

61-
label_item = self._find_label_item(name)
61+
label_item = self._wait_for_label_item(name)
6262
if label_item is None:
6363
items = self._find_label_items()
6464
all_names = self._enumerate_label_names(items)
@@ -71,15 +71,31 @@ def create(self, name: str, *, color: str | None = None) -> None:
7171
def exists(self, name: str) -> bool:
7272
"""Check if a label exists by name."""
7373
self._open_edit_modal()
74-
label_item = self._find_label_item(name)
75-
exists = label_item is not None
74+
items_locator = self.layout.page.locator(
75+
f"{_LABEL_ITEM_SELECTOR}:not(.console--create)"
76+
)
77+
try:
78+
items_locator.first.wait_for(state="visible", timeout=5000)
79+
except PlaywrightTimeoutError:
80+
self._close_edit_modal()
81+
return False
82+
found = False
83+
for item in items_locator.all():
84+
if not item.is_visible():
85+
continue
86+
name_input = item.locator("input[placeholder='Label Name']").first
87+
if name_input.count() == 0:
88+
continue
89+
if name_input.input_value().strip() == name.strip():
90+
found = True
91+
break
7692
self._close_edit_modal()
77-
return exists
93+
return found
7894

7995
def get_color(self, name: str) -> str:
8096
"""Get the color of a label by name."""
8197
self._open_edit_modal()
82-
label_item = self._find_label_item(name)
98+
label_item = self._wait_for_label_item(name)
8399
if label_item is None:
84100
raise ValueError(f"Label '{name}' not found")
85101
color_swatch = label_item.locator(".pluto-color-swatch").first
@@ -104,7 +120,7 @@ def rename(self, *, old_name: str, new_name: str) -> None:
104120
"""
105121
self._open_edit_modal()
106122

107-
label_item = self._find_label_item(old_name)
123+
label_item = self._wait_for_label_item(old_name)
108124
if label_item is None:
109125
raise ValueError(f"Label '{old_name}' not found")
110126

@@ -115,7 +131,7 @@ def rename(self, *, old_name: str, new_name: str) -> None:
115131
name_input.press("Enter")
116132
expect(name_input).to_have_value(new_name, timeout=5000)
117133

118-
renamed_item = self._find_label_item(new_name)
134+
renamed_item = self._wait_for_label_item(new_name)
119135

120136
if renamed_item is None:
121137
all_items = self._find_label_items()
@@ -137,7 +153,7 @@ def delete(self, name: str) -> None:
137153
"""
138154
self._open_edit_modal()
139155

140-
label_item = self._find_label_item(name)
156+
label_item = self._wait_for_label_item(name)
141157
if label_item is None:
142158
items = self._find_label_items()
143159
all_names = self._enumerate_label_names(items)
@@ -156,12 +172,6 @@ def delete(self, name: str) -> None:
156172
state="hidden", timeout=10000
157173
)
158174

159-
still_exists = self._find_label_item(name)
160-
if still_exists is not None:
161-
raise RuntimeError(
162-
f"Failed to delete label '{name}' - still exists after clicking delete"
163-
)
164-
165175
self._close_edit_modal()
166176

167177
def list_all(self) -> list[str]:
@@ -192,7 +202,7 @@ def change_color(self, *, name: str, new_color: str) -> None:
192202
"""
193203
self._open_edit_modal()
194204

195-
label_item = self._find_label_item(name)
205+
label_item = self._wait_for_label_item(name)
196206
if label_item is None:
197207
raise ValueError(f"Label '{name}' not found")
198208

@@ -223,24 +233,27 @@ def _open_edit_modal(self) -> None:
223233
def _close_edit_modal(self) -> None:
224234
self.layout.close_modal(_MODAL_SELECTOR)
225235

226-
def _find_label_item(self, name: str) -> Locator | None:
227-
items_locator = self.layout.page.locator(
228-
f"{_LABEL_ITEM_SELECTOR}:not(.console--create)"
229-
)
236+
def _wait_for_label_item(self, name: str) -> Locator | None:
237+
"""Wait for a label item to appear, polling for async state propagation."""
238+
selector = f"{_LABEL_ITEM_SELECTOR}:not(.console--create)"
239+
items_locator = self.layout.page.locator(selector)
230240
try:
231241
items_locator.first.wait_for(state="visible", timeout=5000)
232242
except PlaywrightTimeoutError:
233243
return None
234-
for item in items_locator.all():
235-
if not item.is_visible():
236-
continue
237-
name_input = item.locator("input[placeholder='Label Name']").first
238-
if name_input.count() == 0:
239-
continue
240-
if name_input.input_value().strip() == name.strip():
241-
element_id = item.get_attribute("id")
242-
return self.layout.page.locator(f"[id='{element_id}']")
243-
return None
244+
item = items_locator.filter(
245+
has=self.layout.page.locator(
246+
f"input[placeholder='Label Name'][value='{name}']"
247+
)
248+
).first
249+
try:
250+
item.wait_for(state="visible", timeout=5000)
251+
except PlaywrightTimeoutError:
252+
return None
253+
element_id = item.get_attribute("id")
254+
if not element_id:
255+
return None
256+
return self.layout.page.locator(f"[id='{element_id}']")
244257

245258
def _find_label_items(self) -> list[Locator]:
246259
return self.layout.page.locator(

0 commit comments

Comments
 (0)