"""Unit tests for Planner Grid view helpers.""" from __future__ import annotations from unittest.mock import MagicMock, patch from selenium.webdriver.common.by import By from onedrive_planner import ( _clean_grid_task_title, _grid_row_status, _grid_row_task_name, _is_attachments_empty, _is_panel_placeholder_text, _is_status_sorted_descending, _parse_status_blob, _sort_descending_menu_selected, ) def _grid_row(*, status_value: str = "", status_text: str = "", task_name: str = ""): row = MagicMock() row.is_displayed.return_value = True row.text = task_name status_btn = MagicMock() status_btn.is_displayed.return_value = True status_btn.get_attribute.side_effect = lambda name: ( status_value if name == "value" else "" ) status_btn.text = status_text name_cell = MagicMock() name_cell.is_displayed.return_value = True name_cell.get_attribute.return_value = f"Task Name {task_name}" name_span = MagicMock() name_span.is_displayed.return_value = True name_span.text = task_name def find_elements(by, xpath): xp = xpath or "" if "combobox" in xp: return [status_btn] if "gridcell" in xp and "span" not in xp: return [name_cell] if "span" in xp: return [name_span] return [] row.find_elements.side_effect = find_elements name_cell.find_elements.side_effect = lambda by, xpath: [name_span] return row def test_grid_row_status_not_started(): row = _grid_row(status_value="notStarted", status_text="Not started") assert _grid_row_status(row) == "not started" def test_grid_row_status_reads_status_column_not_bucket(): row = MagicMock() row.is_displayed.return_value = True bucket_btn = MagicMock() bucket_btn.is_displayed.return_value = True bucket_btn.get_attribute.side_effect = lambda name: "todo" if name == "value" else "" bucket_btn.text = "To do" status_btn = MagicMock() status_btn.is_displayed.return_value = True status_btn.get_attribute.side_effect = lambda name: "notStarted" if name == "value" else "" status_btn.text = "Not started" status_cell = MagicMock() status_cell.is_displayed.return_value = True status_cell.get_attribute.return_value = "Status Not started" status_cell.text = "Not started" status_cell.find_elements.side_effect = lambda by, xpath: ( [status_btn] if "combobox" in xpath else [] ) bucket_cell = MagicMock() bucket_cell.is_displayed.return_value = True bucket_cell.get_attribute.return_value = "Bucket To do" bucket_cell.text = "To do" bucket_cell.find_elements.side_effect = lambda by, xpath: ( [bucket_btn] if "combobox" in xpath else [] ) def find_elements(by, xpath): xp = xpath or "" if "gridcell" in xp: return [status_cell, bucket_cell] if "combobox" in xp: return [bucket_btn, status_btn] return [] row.find_elements.side_effect = find_elements assert _grid_row_status(row) == "not started" def test_grid_row_status_in_progress(): row = _grid_row(status_value="inProgress", status_text="In progress") assert _grid_row_status(row) == "in progress" def test_grid_row_task_name_from_aria(): row = _grid_row(task_name="Missing Insurance Info") assert _grid_row_task_name(row) == "Missing Insurance Info" def test_clean_grid_task_title_strips_a11y_hint(): raw = "Missing Insurance Info. Press Alt + I to open task details, or pre" assert _clean_grid_task_title(raw) == "Missing Insurance Info" def test_grid_row_task_name_strips_a11y_from_span(): row = MagicMock() row.is_displayed.return_value = True row.text = "" name_cell = MagicMock() name_cell.is_displayed.return_value = True name_cell.get_attribute.return_value = "" name_span = MagicMock() name_span.is_displayed.return_value = True name_span.text = "6.10 priority :). Press Alt + I to open task details" def find_elements(by, xpath): xp = xpath or "" if "combobox" in xp: return [] if "gridcell" in xp and "span" not in xp: return [name_cell] if "span" in xp: return [name_span] return [] row.find_elements.side_effect = find_elements name_cell.find_elements.side_effect = lambda by, xpath: [name_span] assert _grid_row_task_name(row) == "6.10 priority :)" def test_is_panel_placeholder_text(): assert _is_panel_placeholder_text("Type a description or add notes here") assert not _is_panel_placeholder_text("Missing Insurance Info") def test_is_status_sorted_descending(): header = MagicMock() header.get_attribute.side_effect = lambda name: ( "descending" if name == "aria-sort" else "" ) assert _is_status_sorted_descending(header) is True header.get_attribute.side_effect = lambda name: ( "ascending" if name == "aria-sort" else "" ) assert _is_status_sorted_descending(header) is False header.get_attribute.side_effect = lambda name: "" if name == "aria-sort" else "" assert _is_status_sorted_descending(header) is False def test_sort_descending_menu_selected(): driver = MagicMock() checked_btn = MagicMock() checked_btn.is_displayed.return_value = True driver.find_elements.side_effect = lambda by, xpath: ( [checked_btn] if "aria-checked='true'" in xpath else [] ) assert _sort_descending_menu_selected(driver) is True driver.find_elements.side_effect = lambda by, xpath: [] assert _sort_descending_menu_selected(driver) is False def test_parse_status_blob(): assert _parse_status_blob("Not started") == "not started" assert _parse_status_blob("Status Completed") == "completed" assert _parse_status_blob("To do") is None def test_is_attachments_empty_detects_empty_panel(): driver = MagicMock() panel = MagicMock() panel.is_displayed.return_value = True panel.text = "Select, upload, or add a link to a file or website\nAdd attachment" driver.find_elements.return_value = [panel] with patch("onedrive_planner._attachment_tab_count", return_value=0), patch( "onedrive_planner._discover_listed_attachment_names", return_value=[] ), patch("onedrive_planner._list_attachment_rows", return_value=[]): assert _is_attachments_empty(driver) is True def test_is_attachments_empty_false_when_tab_count(): driver = MagicMock() with patch("onedrive_planner._attachment_tab_count", return_value=2): assert _is_attachments_empty(driver) is False