Skip to content

Commit

Permalink
Merge pull request #31 from jjaquish/jjaquish/calendarmonth
Browse files Browse the repository at this point in the history
Added CalendarMonth component
  • Loading branch information
LightOfHeaven1994 authored Aug 24, 2023
2 parents f95fdaa + 06ce2d0 commit 1ebeacc
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ itteration of [widgetastic.patternfly4](https://github.com/RedHatQE/widgetastic.
- [button](https://www.patternfly.org/components/button)
- [card](https://www.patternfly.org/components/card)
- [chip](https://www.patternfly.org/components/chip)
- date and time
- [calendar-month](https://www.patternfly.org/components/date-and-time/calendar-month)
- [description-list](https://www.patternfly.org/components/description-list)
- [dual-list-selector](https://www.patternfly.org/components/dual-list-selector)
- [form-select](https://www.patternfly.org/components/forms/form-select)
Expand Down
2 changes: 2 additions & 0 deletions src/widgetastic_patternfly5/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from .components.chipgroup import ChipReadOnlyError
from .components.chipgroup import StandAloneChipGroup
from .components.clipboardcopy import ClipboardCopy
from .components.date_and_time.calendarmonth import CalendarMonth
from .components.descriptionlist import DescriptionList
from .components.drawer import Drawer
from .components.duallistselector import DualListSelector
Expand Down Expand Up @@ -68,6 +69,7 @@
"BreadCrumb",
"BulletChart",
"Button",
"CalendarMonth",
"Card",
"CardWithActions",
"CategoryChipGroup",
Expand Down
101 changes: 101 additions & 0 deletions src/widgetastic_patternfly5/components/date_and_time/calendarmonth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.keys import Keys
from widgetastic.utils import ParametrizedLocator
from widgetastic.widget import Widget
from widgetastic.xpath import quote

from ..menus.select import Select


class DisabledDate(Exception):
pass


class BaseCalendarMonth:
"""Represents calendar month component.
https://www.patternfly.org/components/date-and-time/calendar-month
"""

CALENDAR_HEADER = ".//div[contains(@class, '-c-calendar-month__header')]"
MONTH_SELECT_LOCATOR = (
f"{CALENDAR_HEADER}//div[contains(@class, 'header-month')]"
)
_month_select_widget = Select(locator=MONTH_SELECT_LOCATOR)
YEAR_INPUT_LOCATOR = f"{CALENDAR_HEADER}//div[contains(@class, '-c-calendar-month__header-year')]//input"
DATE_LOCATOR = ".//button[text()={date}]"

PREV_BUTTON_LOCATOR = f"{CALENDAR_HEADER}//div[contains(@class, 'prev-month')]"
NEXT_BUTTON_LOCATOR = f"{CALENDAR_HEADER}//div[contains(@class, 'next-month')]"

TABLE = ".//table"
SELECTED_DATE_LOCATOR = f"{TABLE}/tbody//td[contains(@class, 'pf-m-selected')]"

def prev(self):
return self.browser.click(self.PREV_BUTTON_LOCATOR)

def next(self):
return self.browser.click(self.NEXT_BUTTON_LOCATOR)

@property
def year(self):
el = self.browser.element(self.YEAR_INPUT_LOCATOR)
return el.get_attribute("value")

@year.setter
def year(self, value):
el = self.browser.element(self.YEAR_INPUT_LOCATOR)
el.send_keys(Keys.CONTROL + "a")
el.send_keys(str(value) + Keys.ENTER)

@property
def month(self):
el = self.browser.element(self.MONTH_SELECT_LOCATOR)
return self.browser.text(el)

@month.setter
def month(self, value):
self._month_select_widget.item_select(value)

@property
def day(self):
try:
el = self.browser.element(self.SELECTED_DATE_LOCATOR)
except NoSuchElementException:
return ""
return self.browser.text(el)

@day.setter
def day(self, value):
el = self.browser.element(self.DATE_LOCATOR.format(date=quote(value)))
if "pf-m-disabled" in el.get_attribute("class") or el.get_attribute("disabled"):
raise DisabledDate(f"Date {value} is disabled for selection")
el.click()

def read(self):
"""Returns the currently selected date in format DD MONTH YYYY."""
return f"{self.day} {self.month} {self.year}"

def fill(self, items):
"""Fills a Calendar with all items.
Example dictionary: {'day': '22', 'month': 'November', 'year': '2023'}"
Args:
items: A dictionary containing what items to select
"""
if type(items) is not dict:
raise TypeError("'items' value has to be dictionary type. ")
if "day" in items:
self.day = items["day"]
if "month" in items:
self.month = items["month"]
if "year" in items:
self.year = items["year"]


class CalendarMonth(BaseCalendarMonth, Widget):
ROOT = ParametrizedLocator("{@locator}")

def __init__(self, parent, locator, logger=None):
super().__init__(parent, logger=logger)
self.locator = locator
74 changes: 74 additions & 0 deletions testing/components/date_and_time/test_calendarmonth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import calendar

import pytest
from widgetastic.widget import View

from widgetastic_patternfly5 import CalendarMonth

TESTING_PAGE_URL = "https://patternfly-react-main.surge.sh/components/date-and-time/calendar-month"

MONTHS_LIST = list(calendar.month_name[1:])


@pytest.fixture
def calendar_month_view(browser):
class TestView(View):
ROOT = ".//div[@id='ws-react-c-calendar-month-selectable-date']"
calendar = CalendarMonth(locator=".//div[@class='pf-v5-c-calendar-month']")

return TestView(browser)


def test_year_selection(calendar_month_view):
assert calendar_month_view.calendar.year
calendar_month_view.calendar.year = "2023"
assert calendar_month_view.calendar.year == "2023"


def test_month_selection(calendar_month_view):
assert calendar_month_view.calendar.month
calendar_month_view.calendar.month = "December"
assert calendar_month_view.calendar.month == "December"


def test_day_selection(calendar_month_view):
calendar_month_view.calendar.day = "20"
assert calendar_month_view.calendar.day == "20"
calendar_month_view.calendar.next()
assert not calendar_month_view.calendar.day


def _get_proper_month_index(index):
max_index = len(MONTHS_LIST) - 1
if index < 0:
index = max_index
elif index > max_index:
index = 0

return index


def test_month_navigation(calendar_month_view):
current_month = calendar_month_view.calendar.month
prev_month_index = _get_proper_month_index(MONTHS_LIST.index(current_month) - 1)
next_month_index = _get_proper_month_index(MONTHS_LIST.index(current_month) + 1)

calendar_month_view.calendar.prev()
prev_month = calendar_month_view.calendar.month
assert prev_month == MONTHS_LIST[prev_month_index]

# reset to current default month
calendar_month_view.calendar.month = current_month

calendar_month_view.calendar.next()
next_month = calendar_month_view.calendar.month
assert next_month == MONTHS_LIST[next_month_index]


def test_fill_and_read(calendar_month_view):
calendar_month_view.calendar.fill({"month": "February", "year": "2023"})
result = calendar_month_view.calendar.read()
assert result == " February 2023"

with pytest.raises(TypeError):
calendar_month_view.calendar.fill("foo")

0 comments on commit 1ebeacc

Please sign in to comment.