Skip to content

Commit d474905

Browse files
authored
Merge pull request #5127 from pfarestveit/calendly
BEA: add Calendly to appt tests
2 parents 219ba83 + c69d303 commit d474905

7 files changed

Lines changed: 100 additions & 31 deletions

File tree

bea/config/bea_test_base_configs.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,10 @@ def set_test_students(self, count, opts=None):
295295
app.logger.info('Running tests using students with appointments')
296296
sids = nessie_utils.get_all_student_sids()
297297

298+
calendly_sids = nessie_timeline_utils.get_sids_with_calendly_appts()
299+
calendly_sids = list(set(sids) & set(calendly_sids))
300+
app.logger.info(f'There are {len(calendly_sids)} students with Calendly appointments')
301+
298302
sis_sids = nessie_timeline_utils.get_sids_with_sis_appts()
299303
sis_sids = list(set(sids) & set(sis_sids))
300304
app.logger.info(f'There are {len(sis_sids)} students with SIS appointments')
@@ -303,7 +307,7 @@ def set_test_students(self, count, opts=None):
303307
ycbm_sids = list(set(sids) & set(ycbm_sids))
304308
app.logger.info(f'There are {len(ycbm_sids)} students with YCBM appointments')
305309

306-
for sid_list in [sis_sids, ycbm_sids]:
310+
for sid_list in [calendly_sids, sis_sids, ycbm_sids]:
307311
random.shuffle(sid_list)
308312
test_sids.extend(sid_list[:count])
309313

bea/config/bea_test_config.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ def appts_content(self):
4747
# Generate test cases for parameterized tests
4848
for student in self.test_students:
4949
# Throw out junk SIS appts
50-
appts = [a for a in nessie_timeline_utils.get_sis_appts(student) if '504GatewayTimeout' not in a.detail][0:limit]
50+
appts = [a for a in nessie_timeline_utils.get_sis_appts(student) if '504GatewayTimeout' not in a.detail]
51+
appts = appts[0:limit] if appts else []
52+
calendly_appts = nessie_timeline_utils.get_calendly_appts(student)[0:limit]
53+
appts.extend(calendly_appts)
5154
ycbm_appts = nessie_timeline_utils.get_ycbm_appts(student)[0:limit]
5255
appts.extend(ycbm_appts)
5356
for appt in appts:

bea/models/notes_and_appts/timeline_record_source.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ class TimelineRecordSource(Enum):
3636
'name': 'BOA',
3737
'schema': None,
3838
}
39+
CALENDLY = {
40+
'name': 'Calendly',
41+
'schema': 'calendly_advising_appointments',
42+
}
3943
DATA = {
4044
'name': 'Data Science',
4145
'schema': 'boac_advising_data_science',

bea/pages/student_page_timeline.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,11 @@ def item_attachment_els(self, item):
147147

148148
def item_attachment_el(self, item, attachment_name):
149149
for el in self.item_attachment_els(item):
150-
if el.text.split('\n')[1].strip().lower() == attachment_name.lower():
150+
if '\n' in el.text:
151+
text = el.text.split('\n')[1]
152+
else:
153+
text = el.text
154+
if text.strip().lower() == attachment_name.lower():
151155
return el
152156

153157
def download_attachment(self, item, attachment, student=None):

bea/test_utils/nessie_timeline_utils.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,51 @@ def get_sis_notes(student):
402402
# APPOINTMENTS
403403

404404

405+
def get_calendly_appts(student):
406+
sql = f"""SELECT boac_advising_appointments.calendly_advising_appointments.id,
407+
boac_advising_appointments.calendly_advising_appointments.title,
408+
boac_advising_appointments.calendly_advising_appointments.questions_and_answers,
409+
boac_advising_appointments.calendly_advising_appointments.host_name,
410+
boac_advising_appointments.calendly_advising_appointments.start_time,
411+
boac_advising_appointments.calendly_advising_appointments.end_time,
412+
boac_advising_appointments.calendly_advising_appointments.canceled_at,
413+
boac_advising_appointments.calendly_advising_appointments.canceled_by,
414+
boac_advising_appointments.calendly_advising_appointments.cancellation_reason,
415+
boac_advising_appointments.calendly_advising_appointments.is_rescheduled,
416+
boac_advising_appointments.calendly_advising_appointments.is_student_no_show
417+
FROM boac_advising_appointments.calendly_advising_appointments
418+
WHERE boac_advising_appointments.calendly_advising_appointments.student_sid = '{student.sid}'"""
419+
app.logger.info(sql)
420+
results = data_loch.safe_execute_rds(sql)
421+
appts = []
422+
for row in results:
423+
advisor = User({'full_name': row['host_name']})
424+
canceled = True if row['canceled_at'] else False
425+
no_show = row['is_student_no_show']
426+
rescheduled = row['is_rescheduled']
427+
if no_show:
428+
status = 'No Show'
429+
elif rescheduled:
430+
status = 'Rescheduled'
431+
elif canceled:
432+
status = 'Cancelled'
433+
else:
434+
status = None
435+
appts.append(Appointment(data={
436+
'record_id': row['id'],
437+
'advisor': advisor,
438+
'cancel_reason': row['cancellation_reason'],
439+
'detail': row['questions_and_answers'],
440+
'end_time': (row['end_time'] and utils.date_to_local_tz(row['end_time'])),
441+
'source': TimelineRecordSource.CALENDLY,
442+
'start_time': (row['start_time'] and utils.date_to_local_tz(row['start_time'])),
443+
'status': status,
444+
'student': student,
445+
'title': re.sub(r'\s+', ' ', str(row['title'])).strip(),
446+
}))
447+
return appts
448+
449+
405450
def get_sis_appts(student):
406451
sql = f"""SELECT sis_advising_notes.advising_appointments.id AS id,
407452
sis_advising_notes.advising_appointments.note_body AS body,
@@ -472,6 +517,7 @@ def get_sis_appts(student):
472517
if t['topic']:
473518
topics.append(t['topic'].upper())
474519
topics.sort()
520+
topics = list(set(topics))
475521

476522
appts.append(Appointment(attachments=attachments,
477523
data=appt_data,
@@ -504,7 +550,6 @@ def get_ycbm_appts(student):
504550
'record_id': str(k),
505551
'advisor': advisor,
506552
'cancel_reason': cancel_reason,
507-
'created_date': (v[0]['starts_at'] and utils.date_to_local_tz(v[0]['starts_at'])),
508553
'detail': v[0]['details'],
509554
'end_time': (v[0]['ends_at'] and utils.date_to_local_tz(v[0]['ends_at'])),
510555
'source': TimelineRecordSource.YCBM,
@@ -517,6 +562,15 @@ def get_ycbm_appts(student):
517562
return appts
518563

519564

565+
def get_sids_with_calendly_appts():
566+
sql = """SELECT DISTINCT student_sid AS sid
567+
FROM boac_advising_appointments.calendly_advising_appointments
568+
WHERE student_uid IS NOT NULL"""
569+
app.logger.info(sql)
570+
results = data_loch.safe_execute_rds(sql)
571+
return list(map(lambda r: str(r['sid']), results))
572+
573+
520574
def get_sids_with_sis_appts():
521575
sql = """SELECT DISTINCT sis_advising_notes.advising_appointments.sid
522576
FROM sis_advising_notes.advising_appointments

bea/tests/test_appt_content.py

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ def test_load_student_page(self, student):
6060
def test_appt_sort_order(self, student):
6161
appts = nessie_timeline_utils.get_sis_appts(student)
6262
appts.extend(nessie_timeline_utils.get_ycbm_appts(student))
63-
appts.sort(key=lambda ap: [ap.created_date, ap.record_id], reverse=True)
63+
appts.extend(nessie_timeline_utils.get_calendly_appts(student))
64+
appts.sort(key=lambda ap: [(ap.created_date or ap.start_time), ap.record_id], reverse=True)
6465
expected_ids = [a.record_id for a in appts]
6566
visible_ids = self.student_page.visible_appt_ids()
6667
utils.assert_equivalence(visible_ids, expected_ids)
@@ -79,7 +80,7 @@ def test_load_student_page(self, tc):
7980

8081
def test_collapsed_detail(self, tc):
8182
visible = self.student_page.collapsed_appt_detail(tc.appt)
82-
if tc.appt.source == TimelineRecordSource.YCBM:
83+
if tc.appt.source in [TimelineRecordSource.CALENDLY, TimelineRecordSource.YCBM]:
8384
assert tc.appt.title
8485
utils.assert_equivalence(visible, tc.appt.title)
8586
elif tc.appt.source == TimelineRecordSource.SIS:
@@ -90,15 +91,14 @@ def test_collapsed_detail(self, tc):
9091
utils.assert_actual_includes_expected(visible, placeholder)
9192

9293
def test_collapsed_status(self, tc):
93-
if tc.appt.status == 'Canceled':
94-
utils.assert_equivalence(self.student_page.collapsed_appt_status(tc.appt), 'CANCELED')
94+
if tc.appt.status:
95+
utils.assert_equivalence(self.student_page.collapsed_appt_status(tc.appt), tc.appt.status.upper())
9596

9697
def test_collapsed_date(self, tc):
9798
if tc.appt.source == TimelineRecordSource.SIS:
98-
assert tc.appt.updated_date
9999
expected = self.student_page.expected_item_short_date_format(tc.appt.updated_date)
100100
else:
101-
expected = self.student_page.expected_item_short_date_format(tc.appt.created_date)
101+
expected = self.student_page.expected_item_short_date_format(tc.appt.start_time)
102102
utils.assert_actual_includes_expected(self.student_page.collapsed_appt_date(tc.appt), expected)
103103

104104
def test_expanded_details(self, tc):
@@ -107,21 +107,18 @@ def test_expanded_details(self, tc):
107107
assert self.student_page.expanded_appt_details(tc.appt)
108108

109109
def test_expanded_date(self, tc):
110-
assert tc.appt.created_date
111-
expected = self.student_page.expected_item_short_date_format(tc.appt.created_date)
110+
if tc.appt.source == TimelineRecordSource.SIS:
111+
expected = self.student_page.expected_item_short_date_format(tc.appt.created_date)
112+
else:
113+
expected = self.student_page.expected_item_short_date_format(tc.appt.start_time)
112114
utils.assert_equivalence(self.student_page.expanded_appt_date(tc.appt), expected)
113115

114116
def test_expanded_times(self, tc):
115-
if tc.appt.source == TimelineRecordSource.YCBM:
116-
assert tc.appt.start_time
117-
assert tc.appt.end_time
117+
if tc.appt.source in [TimelineRecordSource.CALENDLY, TimelineRecordSource.YCBM]:
118118
start = datetime.datetime.strftime(tc.appt.start_time, '%-l:%M %p')
119119
end = datetime.datetime.strftime(tc.appt.end_time, '%-l:%M %p')
120120
utils.assert_actual_includes_expected(self.student_page.expanded_appt_time_range(tc.appt),
121121
f'{start} - {end}')
122-
else:
123-
assert not tc.appt.start_time
124-
assert not tc.appt.end_time
125122

126123
def test_expanded_advisor(self, tc):
127124
# Appts have varying amounts of advisor info, just verify something's there
@@ -131,7 +128,7 @@ def test_expanded_advisor(self, tc):
131128
elif tc.appt.advisor.last_name:
132129
assert visible
133130

134-
def test_expanded_cancellation(self, tc):
131+
def test_expanded_status(self, tc):
135132
visible = self.student_page.expanded_appt_cancel_reason(tc.appt)
136133
if tc.appt.status == 'Canceled' and tc.appt.cancel_reason:
137134
actual = re.sub(r'\W', '', visible)
@@ -143,7 +140,9 @@ def test_expanded_cancellation(self, tc):
143140
def test_expanded_contact_type(self, tc):
144141
visible = self.student_page.expanded_appt_type(tc.appt)
145142
if tc.appt.contact_type and tc.appt.contact_type != 'None':
146-
utils.assert_equivalence(visible, tc.appt.contact_type)
143+
utils.assert_actual_includes_expected(visible, tc.appt.contact_type)
144+
elif tc.appt.source == TimelineRecordSource.CALENDLY:
145+
utils.assert_actual_includes_expected(visible, TimelineRecordSource.CALENDLY.value['name'])
147146
else:
148147
assert not visible
149148

@@ -170,13 +169,14 @@ def test_expanded_attachments(self, tc):
170169
self.student_page.download_attachment(tc.appt, attach, tc.student)
171170

172171
def test_appt_search(self, tc):
173-
search_string = boa_utils.generate_appt_search_query(tc.appt)
174-
if search_string:
175-
self.student_page.show_appts()
176-
self.student_page.clear_timeline_appt_search()
177-
appt_count = len(self.student_page.visible_appt_ids())
178-
self.student_page.search_within_timeline_appts(search_string)
179-
results = self.student_page.visible_appt_ids()
180-
utils.assert_actual_includes_expected(results, tc.appt.record_id)
181-
if appt_count > 1:
182-
assert len(results) < appt_count
172+
if tc.appt.source != TimelineRecordSource.CALENDLY:
173+
search_string = boa_utils.generate_appt_search_query(tc.appt)
174+
if search_string:
175+
self.student_page.show_appts()
176+
self.student_page.clear_timeline_appt_search()
177+
appt_count = len(self.student_page.visible_appt_ids())
178+
self.student_page.search_within_timeline_appts(search_string)
179+
results = self.student_page.visible_appt_ids()
180+
utils.assert_actual_includes_expected(results, tc.appt.record_id)
181+
if appt_count > 1:
182+
assert len(results) < appt_count

bea/tests/test_search_appt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
test.search_appts()
3737

3838

39-
# NB: YCBM appointments are *not* searchable
39+
# NB: Calendly and YCBM appointments are *not* searchable
4040

4141

4242
@pytest.mark.usefixtures('page_objects')

0 commit comments

Comments
 (0)