|
13 | 13 | from django.urls import reverse as urlreverse |
14 | 14 | from django.utils.text import slugify |
15 | 15 | from django.db.models import F |
| 16 | +from pytz import timezone |
16 | 17 | #from django.test.utils import override_settings |
17 | 18 |
|
18 | 19 | import debug # pyflakes:ignore |
|
23 | 24 | from ietf.person.models import Person |
24 | 25 | from ietf.group.models import Group |
25 | 26 | from ietf.group.factories import GroupFactory |
26 | | -from ietf.meeting.factories import SessionFactory |
| 27 | +from ietf.meeting.factories import SessionFactory, TimeSlotFactory |
27 | 28 | from ietf.meeting.test_data import make_meeting_test_data, make_interim_meeting |
28 | 29 | from ietf.meeting.models import (Schedule, SchedTimeSessAssignment, Session, |
29 | 30 | Room, TimeSlot, Constraint, ConstraintName, |
@@ -904,6 +905,200 @@ def test_session_materials_modal(self): |
904 | 905 | self.driver.find_element_by_xpath('//a[text()="%s"]' % slide.title) |
905 | 906 |
|
906 | 907 |
|
| 908 | +@skipIf(skip_selenium, skip_message) |
| 909 | +class WeekviewTests(MeetingTestCase): |
| 910 | + def setUp(self): |
| 911 | + super(WeekviewTests, self).setUp() |
| 912 | + self.meeting = make_meeting_test_data() |
| 913 | + |
| 914 | + def get_expected_items(self): |
| 915 | + expected_items = self.meeting.schedule.assignments.exclude(timeslot__type__in=['lead', 'offagenda']) |
| 916 | + self.assertGreater(len(expected_items), 0, 'Test setup generated an empty schedule') |
| 917 | + return expected_items |
| 918 | + |
| 919 | + def test_timezone_default(self): |
| 920 | + """Week view should show local times by default""" |
| 921 | + self.assertNotEqual(self.meeting.time_zone.lower(), 'utc', |
| 922 | + 'Cannot test local time weekview because meeting is using UTC time.') |
| 923 | + self.login() |
| 924 | + self.driver.get(self.absreverse('ietf.meeting.views.week_view')) |
| 925 | + for item in self.get_expected_items(): |
| 926 | + if item.session.name: |
| 927 | + expected_name = item.session.name |
| 928 | + elif item.timeslot.type_id == 'break': |
| 929 | + expected_name = item.timeslot.name |
| 930 | + else: |
| 931 | + expected_name = item.session.group.name |
| 932 | + expected_time = '-'.join([item.timeslot.local_start_time().strftime('%H%M'), |
| 933 | + item.timeslot.local_end_time().strftime('%H%M')]) |
| 934 | + WebDriverWait(self.driver, 2).until( |
| 935 | + expected_conditions.presence_of_element_located( |
| 936 | + (By.XPATH, |
| 937 | + '//div/div[contains(text(), "%s")]/span[contains(text(), "%s")]' % ( |
| 938 | + expected_time, expected_name)) |
| 939 | + ) |
| 940 | + ) |
| 941 | + |
| 942 | + def test_timezone_selection(self): |
| 943 | + """Week view should show time zones when requested""" |
| 944 | + # Must test utc; others are picked arbitrarily |
| 945 | + zones_to_test = ['utc', 'America/Halifax', 'Asia/Bangkok', 'Africa/Dakar', 'Europe/Dublin'] |
| 946 | + self.login() |
| 947 | + for zone_name in zones_to_test: |
| 948 | + zone = timezone(zone_name) |
| 949 | + self.driver.get(self.absreverse('ietf.meeting.views.week_view') + '?tz=' + zone_name) |
| 950 | + for item in self.get_expected_items(): |
| 951 | + if item.session.name: |
| 952 | + expected_name = item.session.name |
| 953 | + elif item.timeslot.type_id == 'break': |
| 954 | + expected_name = item.timeslot.name |
| 955 | + else: |
| 956 | + expected_name = item.session.group.name |
| 957 | + |
| 958 | + start_time = item.timeslot.utc_start_time().astimezone(zone) |
| 959 | + end_time = item.timeslot.utc_end_time().astimezone(zone) |
| 960 | + expected_time = '-'.join([start_time.strftime('%H%M'), |
| 961 | + end_time.strftime('%H%M')]) |
| 962 | + |
| 963 | + WebDriverWait(self.driver, 2).until( |
| 964 | + expected_conditions.presence_of_element_located( |
| 965 | + (By.XPATH, |
| 966 | + '//div/div[contains(text(), "%s")]/span[contains(text(), "%s")]' % ( |
| 967 | + expected_time, expected_name)) |
| 968 | + ), |
| 969 | + 'Could not find event "%s" at %s for time zone %s' % (expected_name, |
| 970 | + expected_time, |
| 971 | + zone_name), |
| 972 | + ) |
| 973 | + |
| 974 | + def test_event_wrapping(self): |
| 975 | + """Events that overlap midnight should be shown on both days |
| 976 | + |
| 977 | + This assumes that the meeting is in America/New_York timezone. |
| 978 | + """ |
| 979 | + def _assert_wrapped(displayed, expected_time_string): |
| 980 | + self.assertEqual(len(displayed), 2) |
| 981 | + first = displayed[0] |
| 982 | + first_parent = first.find_element_by_xpath('..') |
| 983 | + second = displayed[1] |
| 984 | + second_parent = second.find_element_by_xpath('..') |
| 985 | + self.assertNotIn('continued', first.text) |
| 986 | + self.assertIn(expected_time_string, first_parent.text) |
| 987 | + self.assertIn('continued', second.text) |
| 988 | + self.assertIn(expected_time_string, second_parent.text) |
| 989 | + |
| 990 | + def _assert_not_wrapped(displayed, expected_time_string): |
| 991 | + self.assertEqual(len(displayed), 1) |
| 992 | + first = displayed[0] |
| 993 | + first_parent = first.find_element_by_xpath('..') |
| 994 | + self.assertNotIn('continued', first.text) |
| 995 | + self.assertIn(expected_time_string, first_parent.text) |
| 996 | + |
| 997 | + duration = datetime.timedelta(minutes=120) # minutes |
| 998 | + |
| 999 | + # Session during a single day in meeting local time but multi-day UTC |
| 1000 | + # Compute a time that overlaps midnight, UTC, but won't when shifted to a local time zone |
| 1001 | + start_time_utc = timezone('UTC').localize( |
| 1002 | + datetime.datetime.combine(self.meeting.date, datetime.time(23,0)) |
| 1003 | + ) |
| 1004 | + start_time_local = start_time_utc.astimezone(timezone(self.meeting.time_zone)) |
| 1005 | + |
| 1006 | + daytime_session = SessionFactory( |
| 1007 | + meeting=self.meeting, |
| 1008 | + name='Single Day Session for Wrapping Test', |
| 1009 | + add_to_schedule=False, |
| 1010 | + ) |
| 1011 | + daytime_timeslot = TimeSlotFactory( |
| 1012 | + meeting=self.meeting, |
| 1013 | + time=start_time_local.replace(tzinfo=None), # drop timezone for Django |
| 1014 | + duration=duration, |
| 1015 | + ) |
| 1016 | + daytime_session.timeslotassignments.create(timeslot=daytime_timeslot, schedule=self.meeting.schedule) |
| 1017 | + |
| 1018 | + # Session that overlaps midnight in meeting local time |
| 1019 | + overnight_session = SessionFactory( |
| 1020 | + meeting=self.meeting, |
| 1021 | + name='Overnight Session for Wrapping Test', |
| 1022 | + add_to_schedule=False, |
| 1023 | + ) |
| 1024 | + overnight_timeslot = TimeSlotFactory( |
| 1025 | + meeting=self.meeting, |
| 1026 | + time=datetime.datetime.combine(self.meeting.date, datetime.time(23,0)), |
| 1027 | + duration=duration, |
| 1028 | + ) |
| 1029 | + overnight_session.timeslotassignments.create(timeslot=overnight_timeslot, schedule=self.meeting.schedule) |
| 1030 | + |
| 1031 | + # Check assumptions about events overlapping midnight |
| 1032 | + self.assertEqual(daytime_timeslot.local_start_time().day, |
| 1033 | + daytime_timeslot.local_end_time().day, |
| 1034 | + 'Daytime event should not overlap midnight in local time') |
| 1035 | + self.assertNotEqual(daytime_timeslot.utc_start_time().day, |
| 1036 | + daytime_timeslot.utc_end_time().day, |
| 1037 | + 'Daytime event should overlap midnight in UTC') |
| 1038 | + |
| 1039 | + self.assertNotEqual(overnight_timeslot.local_start_time().day, |
| 1040 | + overnight_timeslot.local_end_time().day, |
| 1041 | + 'Overnight event should overlap midnight in local time') |
| 1042 | + self.assertEqual(overnight_timeslot.utc_start_time().day, |
| 1043 | + overnight_timeslot.utc_end_time().day, |
| 1044 | + 'Overnight event should not overlap midnight in UTC') |
| 1045 | + |
| 1046 | + self.login() |
| 1047 | + |
| 1048 | + # Test in meeting local time |
| 1049 | + self.driver.get(self.absreverse('ietf.meeting.views.week_view')) |
| 1050 | + |
| 1051 | + time_string = '-'.join([daytime_timeslot.local_start_time().strftime('%H%M'), |
| 1052 | + daytime_timeslot.local_end_time().strftime('%H%M')]) |
| 1053 | + displayed = WebDriverWait(self.driver, 2).until( |
| 1054 | + expected_conditions.presence_of_all_elements_located( |
| 1055 | + (By.XPATH, |
| 1056 | + '//div/div[contains(text(), "%s")]/span[contains(text(), "%s")]' % ( |
| 1057 | + time_string, |
| 1058 | + daytime_session.name)) |
| 1059 | + ) |
| 1060 | + ) |
| 1061 | + _assert_not_wrapped(displayed, time_string) |
| 1062 | + |
| 1063 | + time_string = '-'.join([overnight_timeslot.local_start_time().strftime('%H%M'), |
| 1064 | + overnight_timeslot.local_end_time().strftime('%H%M')]) |
| 1065 | + displayed = WebDriverWait(self.driver, 2).until( |
| 1066 | + expected_conditions.presence_of_all_elements_located( |
| 1067 | + (By.XPATH, |
| 1068 | + '//div/div[contains(text(), "%s")]/span[contains(text(), "%s")]' % ( |
| 1069 | + time_string, |
| 1070 | + overnight_session.name)) |
| 1071 | + ) |
| 1072 | + ) |
| 1073 | + _assert_wrapped(displayed, time_string) |
| 1074 | + |
| 1075 | + # Test in utc time |
| 1076 | + self.driver.get(self.absreverse('ietf.meeting.views.week_view') + '?tz=utc') |
| 1077 | + |
| 1078 | + time_string = '-'.join([daytime_timeslot.utc_start_time().strftime('%H%M'), |
| 1079 | + daytime_timeslot.utc_end_time().strftime('%H%M')]) |
| 1080 | + displayed = WebDriverWait(self.driver, 2).until( |
| 1081 | + expected_conditions.presence_of_all_elements_located( |
| 1082 | + (By.XPATH, |
| 1083 | + '//div/div[contains(text(), "%s")]/span[contains(text(), "%s")]' % ( |
| 1084 | + time_string, |
| 1085 | + daytime_session.name)) |
| 1086 | + ) |
| 1087 | + ) |
| 1088 | + _assert_wrapped(displayed, time_string) |
| 1089 | + |
| 1090 | + time_string = '-'.join([overnight_timeslot.utc_start_time().strftime('%H%M'), |
| 1091 | + overnight_timeslot.utc_end_time().strftime('%H%M')]) |
| 1092 | + displayed = WebDriverWait(self.driver, 2).until( |
| 1093 | + expected_conditions.presence_of_all_elements_located( |
| 1094 | + (By.XPATH, |
| 1095 | + '//div/div[contains(text(), "%s")]/span[contains(text(), "%s")]' % ( |
| 1096 | + time_string, |
| 1097 | + overnight_session.name)) |
| 1098 | + ) |
| 1099 | + ) |
| 1100 | + _assert_not_wrapped(displayed, time_string) |
| 1101 | + |
907 | 1102 | @skipIf(skip_selenium, skip_message) |
908 | 1103 | class InterimTests(MeetingTestCase): |
909 | 1104 | def setUp(self): |
|
0 commit comments