From 5dd8f648ace53fc6389bc33edab38bcee624e6fb Mon Sep 17 00:00:00 2001 From: Ivymaster Date: Tue, 20 Oct 2026 17:03:38 +0200 Subject: [PATCH] Updated tests --- system/seeders/BS001_helper_functions.sql | 19 +- system/seeders/TST83711_003_add_kalender.sql | 88 +- tests/cypress/cypress.config.js | 36 +- .../specs/api/tempus/tempus.collisions.cy.js | 1890 +++++++++-------- .../ui/tempus/tempus.course-picker.cy.js | 364 ++-- .../e2e/specs/ui/tempus/tempus.events.cy.js | 928 ++++---- .../e2e/specs/ui/tempus/tempus.filters.cy.js | 604 +++--- .../e2e/specs/ui/tempus/tempus.roles.cy.js | 586 ++--- .../cypress/support/pages/tempus.po.js | 1149 +++++----- 9 files changed, 2920 insertions(+), 2744 deletions(-) diff --git a/system/seeders/BS001_helper_functions.sql b/system/seeders/BS001_helper_functions.sql index ca5d20783..3264210e2 100644 --- a/system/seeders/BS001_helper_functions.sql +++ b/system/seeders/BS001_helper_functions.sql @@ -33,4 +33,21 @@ DECLARE res varchar(32); SELECT studiensemester_kurzbz into res FROM public.tbl_studiensemester WHERE start<=now() ORDER BY start DESC LIMIT 1; return res; END; -$$ LANGUAGE plpgsql; \ No newline at end of file +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION get_current_week_timestamp( + p_day_offset INTEGER, + p_time TIME, + p_utc_offset INTERVAL DEFAULT INTERVAL '+00:00' +) +RETURNS TIMESTAMPTZ +LANGUAGE plpgsql +AS $$ +BEGIN + RETURN ( + date_trunc('week', CURRENT_DATE) + + (p_day_offset * INTERVAL '1 day') + + p_time + ) AT TIME ZONE p_utc_offset; +END; +$$; \ No newline at end of file diff --git a/system/seeders/TST83711_003_add_kalender.sql b/system/seeders/TST83711_003_add_kalender.sql index 94149dece..f196ae5b8 100644 --- a/system/seeders/TST83711_003_add_kalender.sql +++ b/system/seeders/TST83711_003_add_kalender.sql @@ -30,14 +30,14 @@ VALUES -- Calendar setup for event drag and drop tests INSERT INTO lehre.tbl_kalender (von, bis, typ, status_kurzbz, vorgaenger_kalender_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '08:00:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '08:45:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '08:45:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '09:30:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '09:40:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '10:25:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '10:25:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '11:10:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '09:40:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '10:25:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '09:40:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '10:25:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '10:25:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '11:10:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '10:25:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '11:10:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') +(get_current_week_timestamp(2, '08:00:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '08:45:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(2, '08:45:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '09:30:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(2, '09:40:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '10:25:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(2, '10:25:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '11:10:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(2, '09:40:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '10:25:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(2, '09:40:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '10:25:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(2, '10:25:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '11:10:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(2, '10:25:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '11:10:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') ; INSERT INTO lehre.tbl_kalender_ort @@ -61,11 +61,15 @@ VALUES -- Calendar setup for resize tests INSERT INTO lehre.tbl_kalender (von, bis, typ, status_kurzbz, vorgaenger_kalender_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '08:00:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '08:45:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '10:25:00', date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '11:10:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '10:25:00', date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '11:10:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') +(get_current_week_timestamp(3, '08:00:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '08:45:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(3, '10:25:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '11:10:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(3, '10:25:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '11:10:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') ; +INSERT INTO lehre.tbl_kalender_ort +(location, ort_kurzbz, kalender_id) +VALUES(NULL, 'Bro_F7.39', 9); + INSERT INTO lehre.tbl_kalender_lehreinheit (lehreinheit_id, kalender_id) VALUES @@ -78,12 +82,12 @@ VALUES -- Calendar setup for role preview tests INSERT INTO lehre.tbl_kalender (von, bis, typ, status_kurzbz, vorgaenger_kalender_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '13:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '14:20:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '13:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '14:20:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '13:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '14:20:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '13:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '14:20:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '13:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '14:20:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '13:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '14:20:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') +(get_current_week_timestamp(3, '13:35:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '14:20:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(3, '13:35:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '14:20:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(3, '13:35:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '14:20:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(3, '13:35:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '14:20:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(3, '13:35:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '14:20:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(3, '13:35:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '14:20:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') ; INSERT INTO lehre.tbl_kalender_lehreinheit @@ -100,8 +104,8 @@ VALUES -- Calendar setup for API event creation tests INSERT INTO lehre.tbl_kalender (von, bis, typ, status_kurzbz, vorgaenger_kalender_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '18:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '19:20:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '18:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '19:20:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') +(get_current_week_timestamp(2, '18:35:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '19:20:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(3, '18:35:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '19:20:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') ; INSERT INTO lehre.tbl_kalender_lehreinheit @@ -116,17 +120,17 @@ VALUES INSERT INTO lehre.tbl_kalender (von, bis, typ, status_kurzbz, vorgaenger_kalender_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '1 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '1 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '20:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '21:00:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '20:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '21:00:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '20:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '4 day' + TIME '21:00:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '5 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '5 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '5 day' + TIME '20:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '5 day' + TIME '21:00:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '5 day' + TIME '20:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '5 day' + TIME '21:00:00', 'reservierung', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') +(get_current_week_timestamp(1, '19:30:00', INTERVAL '+02:00'), get_current_week_timestamp(1, '20:15:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(2, '19:30:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '20:15:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(2, '20:15:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '21:00:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(3, '19:30:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '20:15:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(3, '20:15:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '21:00:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(4, '19:30:00', INTERVAL '+02:00'), get_current_week_timestamp(4, '20:15:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(4, '19:30:00', INTERVAL '+02:00'), get_current_week_timestamp(4, '20:15:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(4, '20:15:00', INTERVAL '+02:00'), get_current_week_timestamp(4, '21:00:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(5, '19:30:00', INTERVAL '+02:00'), get_current_week_timestamp(5, '20:15:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(5, '20:15:00', INTERVAL '+02:00'), get_current_week_timestamp(5, '21:00:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(5, '20:15:00', INTERVAL '+02:00'), get_current_week_timestamp(5, '21:00:00', INTERVAL '+02:00'), 'reservierung', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') ; INSERT INTO lehre.tbl_kalender_ort @@ -155,8 +159,8 @@ VALUES -- Calendar setup for Stundenraster disabled tests INSERT INTO lehre.tbl_kalender (von, bis, typ, status_kurzbz, vorgaenger_kalender_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '11:20:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '12:05:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '11:20:00', date_trunc('week', CURRENT_DATE) + INTERVAL '2 day' + TIME '12:05:00', 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') +(get_current_week_timestamp(2, '11:20:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '12:05:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(2, '11:20:00', INTERVAL '+02:00'), get_current_week_timestamp(2, '12:05:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, now(), 'demoadmin', NULL, 'demoadmin') ; INSERT INTO lehre.tbl_kalender_lehreinheit @@ -171,10 +175,10 @@ VALUES INSERT INTO lehre.tbl_kalender (von, bis, typ, status_kurzbz, vorgaenger_kalender_id, eindeutige_kalender_gruppen_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '19:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '20:15:00', 'lehreinheit', 'live', NULL, 'ec1bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '20:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '21:00:00', 'lehreinheit', 'live', NULL, 'ec2bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '17:50:00', date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '18:35:00', 'lehreinheit', 'live', NULL, 'ec3bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '18:35:00', date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '19:20:00', 'lehreinheit', 'live', NULL, 'ec4bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin') +(get_current_week_timestamp(6, '19:30:00', INTERVAL '+02:00'), get_current_week_timestamp(6, '20:15:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, 'ec1bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(6, '20:15:00', INTERVAL '+02:00'), get_current_week_timestamp(6, '21:00:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, 'ec2bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(6, '17:50:00', INTERVAL '+02:00'), get_current_week_timestamp(6, '18:35:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, 'ec3bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(6, '18:35:00', INTERVAL '+02:00'), get_current_week_timestamp(6, '19:20:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, 'ec4bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin') ; INSERT INTO lehre.tbl_kalender_lehreinheit @@ -189,7 +193,7 @@ VALUES INSERT INTO lehre.tbl_kalender (von, bis, typ, status_kurzbz, vorgaenger_kalender_id, eindeutige_kalender_gruppen_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '16:55:00', date_trunc('week', CURRENT_DATE) + INTERVAL '6 day' + TIME '17:40:00', 'lehreinheit', 'live', NULL, 'ec1bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin'); +(get_current_week_timestamp(6, '16:55:00', INTERVAL '+02:00'), get_current_week_timestamp(6, '17:40:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, 'ec1bd001-facf-4b21-a671-bcb2d4f037fd', now(), 'demoadmin', NULL, 'demoadmin'); INSERT INTO lehre.tbl_kalender_lehreinheit (lehreinheit_id, kalender_id) @@ -200,8 +204,8 @@ VALUES INSERT INTO lehre.tbl_kalender (von, bis, typ, status_kurzbz, vorgaenger_kalender_id, eindeutige_kalender_gruppen_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '14:30:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '15:15:00', 'lehreinheit', 'live', NULL, null, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '15:15:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '16:00:00', 'lehreinheit', 'live', NULL, null, now(), 'demoadmin', NULL, 'demoadmin'); +(get_current_week_timestamp(3, '14:30:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '15:15:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, null, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(3, '15:15:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '16:00:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, null, now(), 'demoadmin', NULL, 'demoadmin'); INSERT INTO lehre.tbl_kalender_lehreinheit (lehreinheit_id, kalender_id) @@ -218,8 +222,8 @@ VALUES INSERT INTO lehre.tbl_kalender (von, bis, typ, status_kurzbz, vorgaenger_kalender_id, eindeutige_kalender_gruppen_id, insertamum, insertvon, updateamum, updatevon) VALUES -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '16:10:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '16:55:00', 'lehreinheit', 'live', NULL, null, now(), 'demoadmin', NULL, 'demoadmin'), -(date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '16:55:00', date_trunc('week', CURRENT_DATE) + INTERVAL '3 day' + TIME '17:40:00', 'lehreinheit', 'live', NULL, null, now(), 'demoadmin', NULL, 'demoadmin'); +(get_current_week_timestamp(3, '16:10:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '16:55:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, null, now(), 'demoadmin', NULL, 'demoadmin'), +(get_current_week_timestamp(3, '16:55:00', INTERVAL '+02:00'), get_current_week_timestamp(3, '17:40:00', INTERVAL '+02:00'), 'lehreinheit', 'live', NULL, null, now(), 'demoadmin', NULL, 'demoadmin'); INSERT INTO lehre.tbl_kalender_lehreinheit (lehreinheit_id, kalender_id) @@ -290,5 +294,5 @@ VALUES(30, 'teilnehmer', 'demolektor4', NULL, NULL, NULL, NULL, NULL, NULL, NULL INSERT INTO campus.tbl_zeitsperre (zeitsperre_id, zeitsperretyp_kurzbz, mitarbeiter_uid, bezeichnung, vondatum, vonstunde, bisdatum, bisstunde, vertretung_uid, updateamum, updatevon, insertamum, insertvon, erreichbarkeit_kurzbz, freigabeamum, freigabevon) -VALUES(1, 'DienstV', 'demolektor1', 'Test', date_trunc('week', CURRENT_DATE) + INTERVAL '5 day', NULL, date_trunc('week', CURRENT_DATE) + INTERVAL '5 day', NULL, 'demoadmin', '2007-04-02 11:04:31.000', 'demoadmin', '2007-04-02 11:04:31.000', 'demoadmin', 't', NULL, NULL); +VALUES(1, 'DienstV', 'demolektor1', 'Test', get_current_week_timestamp(5, '00:00:00', INTERVAL '+02:00'), NULL, get_current_week_timestamp(5, '00:00:00', INTERVAL '+02:00'), NULL, 'demoadmin', '2007-04-02 11:04:31.000', 'demoadmin', '2007-04-02 11:04:31.000', 'demoadmin', 't', NULL, NULL); diff --git a/tests/cypress/cypress.config.js b/tests/cypress/cypress.config.js index 4baed1ccb..6131ef764 100644 --- a/tests/cypress/cypress.config.js +++ b/tests/cypress/cypress.config.js @@ -1,22 +1,22 @@ -const { defineConfig } = require("cypress"); -require("dotenv").config(); +const { defineConfig } = require('cypress'); +require('dotenv').config(); module.exports = defineConfig({ - allowCypressEnv: true, - - e2e: { - baseUrl: process.env.BASE_URL || "http://localhost:8080", - defaultCommandTimeout: 20000, - pageLoadTimeout: 20000, - retries: { - runMode: 2, - openMode: 2 - } - }, - env: { - adminusername: process.env.USER_NAME || "2", - adminpassword: process.env.USER_PASSWORD || "2", - loginAsUser: process.env.LOGIN_AS_USER || process.env.USER_NAME || "demoadmin" - } + allowCypressEnv: true, + e2e: { + baseUrl: process.env.BASE_URL || 'http://localhost:8080', + defaultCommandTimeout: 10000, + pageLoadTimeout: 10000, + retries: { + runMode: 1, + openMode: 1, + }, + }, + env: { + adminusername: process.env.USER_NAME || '2', + adminpassword: process.env.USER_PASSWORD || '2', + loginAsUser: + process.env.LOGIN_AS_USER || process.env.USER_NAME || 'demoadmin', + }, }); diff --git a/tests/cypress/cypress/e2e/specs/api/tempus/tempus.collisions.cy.js b/tests/cypress/cypress/e2e/specs/api/tempus/tempus.collisions.cy.js index 02bcb54ad..08ee52c18 100644 --- a/tests/cypress/cypress/e2e/specs/api/tempus/tempus.collisions.cy.js +++ b/tests/cypress/cypress/e2e/specs/api/tempus/tempus.collisions.cy.js @@ -1,961 +1,979 @@ -import { tempusApi } from "../../../../support/api/tempusApi"; -import { getDateForDay } from "../../../../support/helpers/date"; +import { tempusApi } from '../../../../support/api/tempusApi'; +import { getDateForDay } from '../../../../support/helpers/date'; import { - getTempusTestSemester, - TEMPUS_TEST_STUDY_PLAN_SHORT_CODE, -} from "../../../../support/helpers/tempusTestData"; + getTempusTestSemester, + TEMPUS_TEST_STUDY_PLAN_SHORT_CODE, +} from '../../../../support/helpers/tempusTestData'; let TEMPUS_TEST_SEMESTER; -describe("Tempus Kalender API", () => { - before(() => { - cy.login(); - getTempusTestSemester().then((semester) => { - TEMPUS_TEST_SEMESTER = semester; - }); - }); - - beforeEach(() => { - cy.login(); - tempusApi.resetTempusScenario(); - }); - - it("event creation works for non collision case", () => { - tempusApi.getDegreeProgramTree().then((stgTree) => { - let studyPlan = stgTree.find((plan) => - plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), - ); - expect(studyPlan, "study plan for test event creation").to.exist; - - tempusApi - .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) - .then((courses) => { - let course = courses.find((course) => course.lehrfach === "MAT"); - expect(course, "course for test event creation").to.exist; - - tempusApi - .updateSettingsData(tempusApi.getSettingsData()) - .then((response) => { - const lehreinheitId = course.lehreinheit_id; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; - - const startDateTime = `${getDateForDay("monday")} 17:50`; - const endDateTime = `${getDateForDay("monday")} 18:35`; - - tempusApi - .createKalenderEvent(lehreinheitId, startDateTime, endDateTime) - .then((response) => { - expect(response.status).to.eq(200); - expect(response.body).to.have.nested.property( - "meta.status", - "success", - ); - }); - }); - }); - }); - }); - - it("prohibited event creation due to zeitsperre collision", () => { - tempusApi.getDegreeProgramTree().then((stgTree) => { - let studyPlan = stgTree.find((plan) => - plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), - ); - expect(studyPlan, "study plan for test event creation").to.exist; - - tempusApi - .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) - .then((courses) => { - let course = courses.find((course) => - course.lektoren.some((lector) => lector.kurzbz === "DemoLKT1"), - ); - expect(course, "course for test event creation").to.exist; - - tempusApi - .updateSettingsData(tempusApi.getSettingsData()) - .then((response) => { - const lehreinheitId = course.lehreinheit_id; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; - - const startDateTime = `${getDateForDay("saturday")} 18:35`; - const endDateTime = `${getDateForDay("saturday")} 19:20`; - - tempusApi - .createKalenderEvent(lehreinheitId, startDateTime, endDateTime) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); - - let hasTimeLockCollisionError = response.body.errors.some( - (error) => error.errorCode === "absences_collision", - ); - expect( - hasTimeLockCollisionError, - "response contains time lock collision error", - ).to.be.true; - }); - }); - }); - }); - }); - - it("prohibited event creation due to student group collision", () => { - tempusApi.getDegreeProgramTree().then((stgTree) => { - let studyPlan = stgTree.find((plan) => - plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), - ); - expect(studyPlan, "study plan for test event creation").to.exist; - - tempusApi - .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) - .then((courses) => { - let course = courses.find( - (course) => - course.lehrfach === "ENG" && - course.lektoren.some((lector) => lector.kurzbz === "DemoLKT3"), - ); - expect(course, "course for test event creation").to.exist; - - tempusApi - .updateSettingsData(tempusApi.getSettingsData()) - .then((response) => { - const lehreinheitId = course.lehreinheit_id; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; - - const startDateTime = `${getDateForDay("wednesday")} 18:35`; - const endDateTime = `${getDateForDay("wednesday")} 19:20`; - - tempusApi - .createKalenderEvent(lehreinheitId, startDateTime, endDateTime) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); - let hasStudentGroupCollisionError = response.body.errors.some( - (error) => error.errorCode === "verband_collision", - ); - expect( - hasStudentGroupCollisionError, - "response contains student collision error", - ).to.be.true; - }); - }); - }); - }); - }); - - it("prohibited event creation due to direct student collision", () => { - let settingsData = tempusApi.getSettingsData(); - settingsData.kollision_student = true; - - tempusApi.getDegreeProgramTree().then((stgTree) => { - let studyPlan = stgTree.find((plan) => - plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), - ); - expect(studyPlan, "study plan for test event creation").to.exist; - - tempusApi - .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) - .then((courses) => { - let course = courses.find( - (course) => - course.lehrfach === "ENG" && - course.lektoren.some((lector) => lector.kurzbz === "DemoLKT3"), - ); - expect(course, "course for test event creation").to.exist; - - tempusApi.updateSettingsData(settingsData).then((response) => { - tempusApi - .getPlannerEvents( - getDateForDay("monday"), - getDateForDay("monday"), - ) - .then((events) => { - const lehreinheitId = course.lehreinheit_id; - expect(lehreinheitId, "lehreinheit id for test event creation") - .to.exist; - - const startDateTime = `${getDateForDay("friday")} 20:15`; - const endDateTime = `${getDateForDay("friday")} 21:00`; - - tempusApi - .createKalenderEvent( - lehreinheitId, - startDateTime, - endDateTime, - ) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); - let hasStudentCollisionError = response.body.errors.some( - (error) => error.errorCode === "student_collision", - ); - expect( - hasStudentCollisionError, - "response contains student collision error", - ).to.be.true; - }); - }); - }); - }); - }); - }); - - it("prohibited event creation due to lector collision", () => { - tempusApi.getDegreeProgramTree().then((stgTree) => { - let studyPlan = stgTree.find((plan) => - plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), - ); - expect(studyPlan, "study plan for test event creation").to.exist; - - tempusApi - .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) - .then((courses) => { - let course = courses.find((course) => - course.lektoren.some((lector) => lector.kurzbz === "DemoLKT4"), - ); - expect(course, "course for test event creation").to.exist; - - tempusApi - .updateSettingsData(tempusApi.getSettingsData()) - .then((response) => { - tempusApi - .getPlannerEvents( - getDateForDay("monday"), - getDateForDay("monday"), - ) - .then((events) => { - const lehreinheitId = course.lehreinheit_id; - expect( - lehreinheitId, - "lehreinheit id for test event creation", - ).to.exist; - - const startDateTime = `${getDateForDay("thursday")} 18:35`; - const endDateTime = `${getDateForDay("thursday")} 19:20`; - - tempusApi - .createKalenderEvent( - lehreinheitId, - startDateTime, - endDateTime, - ) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); - let hasLectorCollisionError = response.body.errors.some( - (error) => error.errorCode === "lector_collision", - ); - expect( - hasLectorCollisionError, - "response contains lector collision error", - ).to.be.true; - }); - }); - }); - }); - }); - }); - - it("event update works for non collision case", () => { - tempusApi - .updateSettingsData(tempusApi.getSettingsData()) - .then((response) => { - tempusApi - .getPlannerEvents(getDateForDay("tuesday"), getDateForDay("tuesday")) - .then((events) => { - const sourceEvent = events.find( - (event) => - event.type === "lehreinheit" && - event.beginn === "19:30:00" && - event.ende === "20:15:00", - ); - expect( - sourceEvent, - "source event without collision for update test", - ).to.exist; - - const startDateTime = `${sourceEvent.datum} 20:15`; - const endDateTime = `${sourceEvent.datum} 21:00`; - - tempusApi - .updateKalenderEvent( - sourceEvent.kalender_id, - startDateTime, - endDateTime, - ) - .then((response) => { - expect(response.status).to.eq(200); - expect(response.body).to.have.nested.property( - "meta.status", - "success", - ); - }); - }); - }); - }); - - it("prohibited event update due to room collision", () => { - tempusApi - .updateSettingsData(tempusApi.getSettingsData()) - .then((response) => { - tempusApi - .getPlannerEvents( - getDateForDay("wednesday"), - getDateForDay("wednesday"), - ) - .then((events) => { - const sourceEvent = events.find( - (event) => - event.type === "lehreinheit" && - event.beginn === "19:30:00" && - event.ende === "20:15:00", - ); - expect( - sourceEvent, - "source event with fixed time and room for collision test", - ).to.exist; - - const startDateTime = `${sourceEvent.datum} 20:15`; - const endDateTime = `${sourceEvent.datum} 21:00`; - - tempusApi - .updateKalenderEvent( - sourceEvent.kalender_id, - startDateTime, - endDateTime, - ) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); - - let hasRoomCollisionError = response.body.errors.some( - (error) => error.errorCode === "room_collision", - ); - expect( - hasRoomCollisionError, - "response contains room collision error", - ).to.be.true; - }); - }); - }); - }); - - it("prohibited event update due to student group collision", () => { - tempusApi - .updateSettingsData(tempusApi.getSettingsData()) - .then((response) => { - tempusApi - .getPlannerEvents( - getDateForDay("thursday"), - getDateForDay("thursday"), - ) - .then((events) => { - const sourceEvent = events.find( - (event) => - event.type === "lehreinheit" && - event.beginn === "19:30:00" && - event.ende === "20:15:00", - ); - expect( - sourceEvent, - "source event with fixed time and room for collision test", - ).to.exist; - - const startDateTime = `${sourceEvent.datum} 20:15`; - const endDateTime = `${sourceEvent.datum} 21:00`; - - tempusApi - .updateKalenderEvent( - sourceEvent.kalender_id, - startDateTime, - endDateTime, - ) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); - let hasStudentGroupCollisionError = response.body.errors.some( - (error) => error.errorCode === "verband_collision", - ); - expect( - hasStudentGroupCollisionError, - "response contains student group collision error", - ).to.be.true; - }); - }); - }); - }); - - it("prohibited event update due to direct student collision", () => { - let settingsData = tempusApi.getSettingsData(); - settingsData.kollision_student = true; - - tempusApi.updateSettingsData(settingsData).then((response) => { - tempusApi - .getPlannerEvents(getDateForDay("friday"), getDateForDay("friday")) - .then((events) => { - const sourceEvent = events.find( - (event) => - event.type === "lehreinheit" && - event.beginn === "19:30:00" && - event.ende === "20:15:00" && - event.lektor.some((lector) => lector.kurzbz === "DemoLKT3"), - ); - expect( - sourceEvent, - "source event with fixed time and room for collision test", - ).to.exist; - - const startDateTime = `${sourceEvent.datum} 20:15`; - const endDateTime = `${sourceEvent.datum} 21:00`; - - tempusApi - .updateKalenderEvent( - sourceEvent.kalender_id, - startDateTime, - endDateTime, - ) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); - let hasDirectStudentCollisionError = response.body.errors.some( - (error) => error.errorCode === "student_collision", - ); - expect( - hasDirectStudentCollisionError, - "response contains student collision error", - ).to.be.true; - }); - }); - }); - }); - - it("prohibited event update due to lector collision", () => { - let settingsData = tempusApi.getSettingsData(); - settingsData.kollision_student = false; - - tempusApi.updateSettingsData(settingsData).then((response) => { - tempusApi - .getPlannerEvents(getDateForDay("saturday"), getDateForDay("saturday")) - .then((events) => { - const sourceEvent = events.find( - (event) => - event.type === "lehreinheit" && - event.beginn === "19:30:00" && - event.ende === "20:15:00", - ); - expect( - sourceEvent, - "source event with fixed time and room for collision test", - ).to.exist; - - const startDateTime = `${sourceEvent.datum} 20:15`; - const endDateTime = `${sourceEvent.datum} 21:00`; - - tempusApi - .updateKalenderEvent( - sourceEvent.kalender_id, - startDateTime, - endDateTime, - ) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); - let hasLectorCollisionError = response.body.errors.some( - (error) => error.errorCode === "lector_collision", - ); - expect( - hasLectorCollisionError, - "response contains lector collision error", - ).to.be.true; - }); - }); - }); - }); - - it("prohibited event update due to lector - zeitsperre collision", () => { - let settingsData = tempusApi.getSettingsData(); - settingsData.kollision_student = false; - - tempusApi.updateSettingsData(settingsData).then((response) => { - tempusApi - .getPlannerEvents(getDateForDay("friday"), getDateForDay("friday")) - .then((events) => { - const sourceEvent = events.find( - (event) => - event.type === "lehreinheit" && - event.beginn === "19:30:00" && - event.ende === "20:15:00" && - event.lektor.some((lector) => lector.kurzbz === "DemoLKT1"), - ); - expect( - sourceEvent, - "source event with fixed time and room for collision test", - ).to.exist; - - const startDateTime = `${getDateForDay("saturday")} 20:15`; - const endDateTime = `${getDateForDay("saturday")} 21:00`; - - tempusApi - .updateKalenderEvent( - sourceEvent.kalender_id, - startDateTime, - endDateTime, - ) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); - - let hasTimeLockCollisionError = response.body.errors.some( - (error) => error.errorCode === "absences_collision", - ); - expect( - hasTimeLockCollisionError, - "response contains time lock collision error", - ).to.be.true; - }); - }); - }); - }); - - it("event update works for entries without collision", () => { - let settingsData = tempusApi.getSettingsData(); - tempusApi.updateSettingsData(settingsData).then((response) => { - tempusApi - .getPlannerEvents(getDateForDay("sunday"), getDateForDay("sunday")) - .then((events) => { - const sourceEvent = events.find( - (event) => - event.beginn === "17:50:00" && - event.ende === "18:35:00" && - event.lektor.some((lector) => lector.kurzbz === "DemoLKT1"), - ); - expect( - sourceEvent, - "source event with fixed time and resources for collision test", - ).to.exist; - - const startDateTime = `${sourceEvent.datum} 18:35`; - const endDateTime = `${sourceEvent.datum} 19:20`; - - tempusApi - .updateKalenderEvent( - sourceEvent.kalender_id, - startDateTime, - endDateTime, - ) - .then((response) => { - expect(response.status).to.eq(200); - expect(response.body).to.have.nested.property( - "meta.status", - "success", - ); - }); - }); - }); - }); - - it("prohibited event update due to resources collision", () => { - let settingsData = tempusApi.getSettingsData(); - tempusApi.updateSettingsData(settingsData).then((response) => { - tempusApi - .getPlannerEvents(getDateForDay("sunday"), getDateForDay("sunday")) - .then((events) => { - const sourceEvent = events.find( - (event) => - event.beginn === "19:30:00" && - event.ende === "20:15:00" && - event.lektor.some((lector) => lector.kurzbz === "DemoLKT4"), - ); - expect( - sourceEvent, - "source event with fixed time and resources for collision test", - ).to.exist; - - const startDateTime = `${sourceEvent.datum} 20:15`; - const endDateTime = `${sourceEvent.datum} 21:00`; - - tempusApi - .updateKalenderEvent( - sourceEvent.kalender_id, - startDateTime, - endDateTime, - ) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); - let hasResourcesCollisionError = response.body.errors.some( - (error) => error.errorCode === "resource_collision", - ); - expect( - hasResourcesCollisionError, - "response contains resources collision error", - ).to.be.true; - }); - }); - }); - }); - - it("prohibited event update due to lector - reservation collision", () => { - let settingsData = tempusApi.getSettingsData(); - settingsData.kollision_student = false; - - tempusApi.updateSettingsData(settingsData).then((response) => { - tempusApi - .getPlannerEvents(getDateForDay("saturday"), getDateForDay("saturday")) - .then((events) => { - const sourceEvent = events.find( - (event) => - event.type === "lehreinheit" && - event.beginn === "19:30:00" && - event.ende === "20:15:00" && - event.lektor.some((lector) => lector.kurzbz === "DemoLKT4"), - ); - expect( - sourceEvent, - "source event with fixed time and room for collision test", - ).to.exist; - - const startDateTime = `${sourceEvent.datum} 20:15`; - const endDateTime = `${sourceEvent.datum} 21:00`; - - tempusApi - .updateKalenderEvent( - sourceEvent.kalender_id, - startDateTime, - endDateTime, - ) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); - let hasReservationCollisionError = response.body.errors.some( - (error) => error.errorCode === "reservation_collision", - ); - expect( - hasReservationCollisionError, - "response contains reservation collision error", - ).to.be.true; - }); - }); - }); - }); - - it("prohibited reservation update due to reservation - lector collision", () => { - let settingsData = tempusApi.getSettingsData(); - settingsData.kollision_student = false; - - tempusApi.updateSettingsData(settingsData).then((response) => { - tempusApi - .getPlannerEvents(getDateForDay("saturday"), getDateForDay("saturday")) - .then((events) => { - const sourceEvent = events.find( - (event) => - event.type === "reservierung" && - event.beginn === "20:15:00" && - event.ende === "21:00:00" && - event.lektor.some((lector) => lector.kurzbz === "DemoLKT1"), - ); - expect( - sourceEvent, - "source event with fixed time and room for collision test", - ).to.exist; - - const startDateTime = `${sourceEvent.datum} 19:30`; - const endDateTime = `${sourceEvent.datum} 20:15`; - - tempusApi - .updateKalenderEvent( - sourceEvent.kalender_id, - startDateTime, - endDateTime, - ) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); - let hasReservationCollisionError = response.body.errors.some( - (error) => error.errorCode === "lector_collision", - ); - expect( - hasReservationCollisionError, - "response contains lector collision error", - ).to.be.true; - }); - }); - }); - }); - - it("event creation fails for inactive roomless and active room selection dialog config option, if no room is selected, for the first attempt", () => { - tempusApi.getDegreeProgramTree().then((stgTree) => { - let studyPlan = stgTree.find((plan) => - plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), - ); - expect(studyPlan, "study plan for test event creation").to.exist; - - let settingsData = tempusApi.getSettingsData(); - settingsData.roomless_planning = false; - settingsData.room_planning = "dialog_room_planning"; - - tempusApi - .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) - .then((courses) => { - let course = courses.find((course) => course.lehrfach === "MAT"); - expect(course, "course for test event creation").to.exist; - - tempusApi - .updateSettingsData(settingsData) - .then((response) => { - const lehreinheitId = course.lehreinheit_id; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; - - const startDateTime = `${getDateForDay("monday")} 17:50`; - const endDateTime = `${getDateForDay("monday")} 18:35`; - - tempusApi - .createKalenderEvent(lehreinheitId, startDateTime, endDateTime, []) - .then((response) => { - expect(response.status).to.eq(200); - expect(response.body).to.have.nested.property( - "data.needs_room_selection", - true, - ); - expect(response.body).to.have.nested.property( - "meta.status", - "success", - ); - }); - }); - }); - }); - }); - - it("event creation fails for inactive roomless and active room selection dialog config option, if no room is selected, for the second attempt", () => { - tempusApi.getDegreeProgramTree().then((stgTree) => { - let studyPlan = stgTree.find((plan) => - plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), - ); - expect(studyPlan, "study plan for test event creation").to.exist; - - let settingsData = tempusApi.getSettingsData(); - settingsData.roomless_planning = false; - settingsData.room_planning = "dialog_room_planning"; - - tempusApi - .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) - .then((courses) => { - let course = courses.find((course) => course.lehrfach === "MAT"); - expect(course, "course for test event creation").to.exist; - - tempusApi - .updateSettingsData(settingsData) - .then((response) => { - const lehreinheitId = course.lehreinheit_id; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; - - const startDateTime = `${getDateForDay("monday")} 17:50`; - const endDateTime = `${getDateForDay("monday")} 18:35`; - - tempusApi - .createKalenderEvent(lehreinheitId, startDateTime, endDateTime, [], false) - .then((response) => { - expect(response.status).to.eq(500); - expect(response.body.errors).to.be.an("array"); - let hasRoomlessPlanningError = response.body.errors.some( - (error) => error.errorCode === "roomless_planning_error", +describe('Tempus Kalender API', () => { + before(() => { + cy.login(); + getTempusTestSemester().then((semester) => { + TEMPUS_TEST_SEMESTER = semester; + }); + }); + + beforeEach(() => { + cy.login(); + tempusApi.resetTempusScenario(); + }); + + it('event creation works for non collision case', () => { + tempusApi.getDegreeProgramTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), + ); + expect(studyPlan, 'study plan for test event creation').to.exist; + + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) + .then((courses) => { + let course = courses.find((course) => course.lehrfach === 'MAT'); + expect(course, 'course for test event creation').to.exist; + + tempusApi + .updateSettingsData(tempusApi.getSettingsData()) + .then((response) => { + const lehreinheitId = course.lehreinheit_id; + expect(lehreinheitId, 'lehreinheit id for test event creation').to + .exist; + + const startDateTime = `${getDateForDay('monday')} 17:50`; + const endDateTime = `${getDateForDay('monday')} 18:35`; + + tempusApi + .createKalenderEvent(lehreinheitId, startDateTime, endDateTime) + .then((response) => { + expect(response.status).to.eq(200); + expect(response.body).to.have.nested.property( + 'meta.status', + 'success', + ); + }); + }); + }); + }); + }); + + it('prohibited event creation due to zeitsperre collision', () => { + tempusApi.getDegreeProgramTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), + ); + expect(studyPlan, 'study plan for test event creation').to.exist; + + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) + .then((courses) => { + let course = courses.find((course) => + course.lektoren.some((lector) => lector.kurzbz === 'DemoLKT1'), + ); + expect(course, 'course for test event creation').to.exist; + + tempusApi + .updateSettingsData(tempusApi.getSettingsData()) + .then((response) => { + const lehreinheitId = course.lehreinheit_id; + expect(lehreinheitId, 'lehreinheit id for test event creation').to + .exist; + + const startDateTime = `${getDateForDay('saturday')} 18:35`; + const endDateTime = `${getDateForDay('saturday')} 19:20`; + + tempusApi + .createKalenderEvent(lehreinheitId, startDateTime, endDateTime) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body).to.have.nested.property( + 'meta.status', + 'error', + ); + expect(response.body.errors).to.be.an('array'); + + let hasTimeLockCollisionError = response.body.errors.some( + (error) => error.errorCode === 'absences_collision', + ); + expect( + hasTimeLockCollisionError, + 'response contains time lock collision error', + ).to.be.true; + }); + }); + }); + }); + }); + + it('prohibited event creation due to student group collision', () => { + tempusApi.getDegreeProgramTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), + ); + expect(studyPlan, 'study plan for test event creation').to.exist; + + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) + .then((courses) => { + let course = courses.find( + (course) => + course.lehrfach === 'ENG' && + course.lektoren.some((lector) => lector.kurzbz === 'DemoLKT3'), + ); + expect(course, 'course for test event creation').to.exist; + + tempusApi + .updateSettingsData(tempusApi.getSettingsData()) + .then((response) => { + const lehreinheitId = course.lehreinheit_id; + expect(lehreinheitId, 'lehreinheit id for test event creation').to + .exist; + + const startDateTime = `${getDateForDay('wednesday')} 18:35`; + const endDateTime = `${getDateForDay('wednesday')} 19:20`; + + tempusApi + .createKalenderEvent(lehreinheitId, startDateTime, endDateTime) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body).to.have.nested.property( + 'meta.status', + 'error', + ); + expect(response.body.errors).to.be.an('array'); + let hasStudentGroupCollisionError = response.body.errors.some( + (error) => error.errorCode === 'verband_collision', + ); + expect( + hasStudentGroupCollisionError, + 'response contains student collision error', + ).to.be.true; + }); + }); + }); + }); + }); + + it('prohibited event creation due to direct student collision', () => { + let settingsData = tempusApi.getSettingsData(); + settingsData.kollision_student = true; + + tempusApi.getDegreeProgramTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), + ); + expect(studyPlan, 'study plan for test event creation').to.exist; + + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) + .then((courses) => { + let course = courses.find( + (course) => + course.lehrfach === 'ENG' && + course.lektoren.some((lector) => lector.kurzbz === 'DemoLKT3'), + ); + expect(course, 'course for test event creation').to.exist; + + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi + .getPlannerEvents( + getDateForDay('monday'), + getDateForDay('monday'), + ) + .then((events) => { + const lehreinheitId = course.lehreinheit_id; + expect(lehreinheitId, 'lehreinheit id for test event creation') + .to.exist; + + const startDateTime = `${getDateForDay('friday')} 20:15`; + const endDateTime = `${getDateForDay('friday')} 21:00`; + + tempusApi + .createKalenderEvent( + lehreinheitId, + startDateTime, + endDateTime, + ) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body).to.have.nested.property( + 'meta.status', + 'error', + ); + expect(response.body.errors).to.be.an('array'); + let hasStudentCollisionError = response.body.errors.some( + (error) => error.errorCode === 'student_collision', + ); + expect( + hasStudentCollisionError, + 'response contains student collision error', + ).to.be.true; + }); + }); + }); + }); + }); + }); + + it('prohibited event creation due to lector collision', () => { + tempusApi.getDegreeProgramTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), + ); + expect(studyPlan, 'study plan for test event creation').to.exist; + + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) + .then((courses) => { + let course = courses.find((course) => + course.lektoren.some((lector) => lector.kurzbz === 'DemoLKT4'), + ); + expect(course, 'course for test event creation').to.exist; + + tempusApi + .updateSettingsData(tempusApi.getSettingsData()) + .then((response) => { + tempusApi + .getPlannerEvents( + getDateForDay('monday'), + getDateForDay('monday'), + ) + .then((events) => { + const lehreinheitId = course.lehreinheit_id; + expect( + lehreinheitId, + 'lehreinheit id for test event creation', + ).to.exist; + + const startDateTime = `${getDateForDay('thursday')} 18:35`; + const endDateTime = `${getDateForDay('thursday')} 19:20`; + + tempusApi + .createKalenderEvent( + lehreinheitId, + startDateTime, + endDateTime, + ) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body).to.have.nested.property( + 'meta.status', + 'error', + ); + expect(response.body.errors).to.be.an('array'); + let hasLectorCollisionError = response.body.errors.some( + (error) => error.errorCode === 'lector_collision', + ); + expect( + hasLectorCollisionError, + 'response contains lector collision error', + ).to.be.true; + }); + }); + }); + }); + }); + }); + + it('event update works for non collision case', () => { + tempusApi + .updateSettingsData(tempusApi.getSettingsData()) + .then((response) => { + tempusApi + .getPlannerEvents(getDateForDay('tuesday'), getDateForDay('tuesday')) + .then((events) => { + const sourceEvent = events.find( + (event) => + event.type === 'lehreinheit' && + event.beginn === '19:30:00' && + event.ende === '20:15:00', + ); + expect( + sourceEvent, + 'source event without collision for update test', + ).to.exist; + + const startDateTime = `${sourceEvent.datum} 20:15`; + const endDateTime = `${sourceEvent.datum} 21:00`; + + tempusApi + .updateKalenderEvent( + sourceEvent.kalender_id, + startDateTime, + endDateTime, + ) + .then((response) => { + expect(response.status).to.eq(200); + expect(response.body).to.have.nested.property( + 'meta.status', + 'success', + ); + }); + }); + }); + }); + + it('prohibited event update due to room collision', () => { + tempusApi + .updateSettingsData(tempusApi.getSettingsData()) + .then((response) => { + tempusApi + .getPlannerEvents( + getDateForDay('wednesday'), + getDateForDay('wednesday'), + ) + .then((events) => { + const sourceEvent = events.find( + (event) => + event.type === 'lehreinheit' && + event.beginn === '19:30:00' && + event.ende === '20:15:00', + ); + expect( + sourceEvent, + 'source event with fixed time and room for collision test', + ).to.exist; + + const startDateTime = `${sourceEvent.datum} 20:15`; + const endDateTime = `${sourceEvent.datum} 21:00`; + + tempusApi + .updateKalenderEvent( + sourceEvent.kalender_id, + startDateTime, + endDateTime, + ) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body).to.have.nested.property( + 'meta.status', + 'error', + ); + expect(response.body.errors).to.be.an('array'); + + let hasRoomCollisionError = response.body.errors.some( + (error) => error.errorCode === 'room_collision', + ); + expect( + hasRoomCollisionError, + 'response contains room collision error', + ).to.be.true; + }); + }); + }); + }); + + it('prohibited event update due to student group collision', () => { + tempusApi + .updateSettingsData(tempusApi.getSettingsData()) + .then((response) => { + tempusApi + .getPlannerEvents( + getDateForDay('thursday'), + getDateForDay('thursday'), + ) + .then((events) => { + const sourceEvent = events.find( + (event) => + event.type === 'lehreinheit' && + event.beginn === '19:30:00' && + event.ende === '20:15:00', + ); + expect( + sourceEvent, + 'source event with fixed time and room for collision test', + ).to.exist; + + const startDateTime = `${sourceEvent.datum} 20:15`; + const endDateTime = `${sourceEvent.datum} 21:00`; + + tempusApi + .updateKalenderEvent( + sourceEvent.kalender_id, + startDateTime, + endDateTime, + ) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body).to.have.nested.property( + 'meta.status', + 'error', + ); + expect(response.body.errors).to.be.an('array'); + let hasStudentGroupCollisionError = response.body.errors.some( + (error) => error.errorCode === 'verband_collision', + ); + expect( + hasStudentGroupCollisionError, + 'response contains student group collision error', + ).to.be.true; + }); + }); + }); + }); + + it('prohibited event update due to direct student collision', () => { + let settingsData = tempusApi.getSettingsData(); + settingsData.kollision_student = true; + + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi + .getPlannerEvents(getDateForDay('friday'), getDateForDay('friday')) + .then((events) => { + const sourceEvent = events.find( + (event) => + event.type === 'lehreinheit' && + event.beginn === '19:30:00' && + event.ende === '20:15:00' && + event.lektor.some((lector) => lector.kurzbz === 'DemoLKT3'), ); expect( - hasRoomlessPlanningError, - "response contains roomless planning error", - ).to.be.true; - }); - }); - }); - }); - }); + sourceEvent, + 'source event with fixed time and room for collision test', + ).to.exist; - it("event creation works for inactive roomless and active priority room config option, if no room is selected", () => { - tempusApi.getDegreeProgramTree().then((stgTree) => { - let studyPlan = stgTree.find((plan) => - plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), - ); - expect(studyPlan, "study plan for test event creation").to.exist; + const startDateTime = `${sourceEvent.datum} 20:15`; + const endDateTime = `${sourceEvent.datum} 21:00`; - let settingsData = tempusApi.getSettingsData(); - settingsData.roomless_planning = false; - settingsData.room_planning = "priority_room_planning"; + tempusApi + .updateKalenderEvent( + sourceEvent.kalender_id, + startDateTime, + endDateTime, + ) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body).to.have.nested.property( + 'meta.status', + 'error', + ); + expect(response.body.errors).to.be.an('array'); + let hasDirectStudentCollisionError = response.body.errors.some( + (error) => error.errorCode === 'student_collision', + ); + expect( + hasDirectStudentCollisionError, + 'response contains student collision error', + ).to.be.true; + }); + }); + }); + }); - tempusApi - .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) - .then((courses) => { - let course = courses.find((course) => course.lehrfach === "MAT"); - expect(course, "course for test event creation").to.exist; + it('prohibited event update due to lector collision', () => { + let settingsData = tempusApi.getSettingsData(); + settingsData.kollision_student = false; - tempusApi - .updateSettingsData(settingsData) - .then((response) => { - const lehreinheitId = course.lehreinheit_id; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi + .getPlannerEvents(getDateForDay('saturday'), getDateForDay('saturday')) + .then((events) => { + const sourceEvent = events.find( + (event) => + event.type === 'lehreinheit' && + event.beginn === '19:30:00' && + event.ende === '20:15:00', + ); + expect( + sourceEvent, + 'source event with fixed time and room for collision test', + ).to.exist; - const startDateTime = `${getDateForDay("monday")} 17:50`; - const endDateTime = `${getDateForDay("monday")} 18:35`; + const startDateTime = `${sourceEvent.datum} 20:15`; + const endDateTime = `${sourceEvent.datum} 21:00`; - tempusApi - .createKalenderEvent(lehreinheitId, startDateTime, endDateTime, []) - .then((response) => { - expect(response.status).to.eq(200); - expect(response.body).to.not.have.nested.property( - "data.needs_room_selection", - true, - ); - expect(response.body).to.have.nested.property( - "meta.status", - "success", - ); - }); - }); - }); - }); - }); + tempusApi + .updateKalenderEvent( + sourceEvent.kalender_id, + startDateTime, + endDateTime, + ) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body).to.have.nested.property( + 'meta.status', + 'error', + ); + expect(response.body.errors).to.be.an('array'); + let hasLectorCollisionError = response.body.errors.some( + (error) => error.errorCode === 'lector_collision', + ); + expect( + hasLectorCollisionError, + 'response contains lector collision error', + ).to.be.true; + }); + }); + }); + }); - it("event creation fails for active roomless and active room selection dialog config option, if no room is selected, for the first attempt", () => { - tempusApi.getDegreeProgramTree().then((stgTree) => { - let studyPlan = stgTree.find((plan) => - plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), - ); - expect(studyPlan, "study plan for test event creation").to.exist; + it('prohibited event update due to lector - zeitsperre collision', () => { + let settingsData = tempusApi.getSettingsData(); + settingsData.kollision_student = false; - let settingsData = tempusApi.getSettingsData(); - settingsData.roomless_planning = true; - settingsData.room_planning = "dialog_room_planning"; + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi + .getPlannerEvents(getDateForDay('friday'), getDateForDay('friday')) + .then((events) => { + const sourceEvent = events.find( + (event) => + event.type === 'lehreinheit' && + event.beginn === '19:30:00' && + event.ende === '20:15:00' && + event.lektor.some((lector) => lector.kurzbz === 'DemoLKT1'), + ); + expect( + sourceEvent, + 'source event with fixed time and room for collision test', + ).to.exist; - tempusApi - .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) - .then((courses) => { - let course = courses.find((course) => course.lehrfach === "MAT"); - expect(course, "course for test event creation").to.exist; + const startDateTime = `${getDateForDay('saturday')} 20:15`; + const endDateTime = `${getDateForDay('saturday')} 21:00`; - tempusApi - .updateSettingsData(settingsData) - .then((response) => { - const lehreinheitId = course.lehreinheit_id; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; + tempusApi + .updateKalenderEvent( + sourceEvent.kalender_id, + startDateTime, + endDateTime, + ) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body).to.have.nested.property( + 'meta.status', + 'error', + ); + expect(response.body.errors).to.be.an('array'); - const startDateTime = `${getDateForDay("monday")} 17:50`; - const endDateTime = `${getDateForDay("monday")} 18:35`; + let hasTimeLockCollisionError = response.body.errors.some( + (error) => error.errorCode === 'absences_collision', + ); + expect( + hasTimeLockCollisionError, + 'response contains time lock collision error', + ).to.be.true; + }); + }); + }); + }); - tempusApi - .createKalenderEvent(lehreinheitId, startDateTime, endDateTime, [], true) - .then((response) => { - expect(response.status).to.eq(200); - expect(response.body).to.have.nested.property( - "data.needs_room_selection", - true, - ); - expect(response.body).to.have.nested.property( - "meta.status", - "success", - ); - }); - }); - }); - }); - }); + it('event update works for entries without collision', () => { + let settingsData = tempusApi.getSettingsData(); + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi + .getPlannerEvents(getDateForDay('sunday'), getDateForDay('sunday')) + .then((events) => { + const sourceEvent = events.find( + (event) => + event.beginn === '17:50:00' && + event.ende === '18:35:00' && + event.lektor.some((lector) => lector.kurzbz === 'DemoLKT1'), + ); + expect( + sourceEvent, + 'source event with fixed time and resources for collision test', + ).to.exist; - it("event creation works for active roomless and active room selection dialog config option, if no room is selected, for the second attempt", () => { - tempusApi.getDegreeProgramTree().then((stgTree) => { - let studyPlan = stgTree.find((plan) => - plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), - ); - expect(studyPlan, "study plan for test event creation").to.exist; + const startDateTime = `${sourceEvent.datum} 18:35`; + const endDateTime = `${sourceEvent.datum} 19:20`; - let settingsData = tempusApi.getSettingsData(); - settingsData.roomless_planning = true; - settingsData.room_planning = "dialog_room_planning"; + tempusApi + .updateKalenderEvent( + sourceEvent.kalender_id, + startDateTime, + endDateTime, + ) + .then((response) => { + expect(response.status).to.eq(200); + expect(response.body).to.have.nested.property( + 'meta.status', + 'success', + ); + }); + }); + }); + }); - tempusApi - .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) - .then((courses) => { - let course = courses.find((course) => course.lehrfach === "MAT"); - expect(course, "course for test event creation").to.exist; + it('prohibited event update due to resources collision', () => { + let settingsData = tempusApi.getSettingsData(); + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi + .getPlannerEvents(getDateForDay('sunday'), getDateForDay('sunday')) + .then((events) => { + const sourceEvent = events.find( + (event) => + event.beginn === '19:30:00' && + event.ende === '20:15:00' && + event.lektor.some((lector) => lector.kurzbz === 'DemoLKT4'), + ); + expect( + sourceEvent, + 'source event with fixed time and resources for collision test', + ).to.exist; - tempusApi - .updateSettingsData(settingsData) - .then((response) => { - const lehreinheitId = course.lehreinheit_id; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; + const startDateTime = `${sourceEvent.datum} 20:15`; + const endDateTime = `${sourceEvent.datum} 21:00`; - const startDateTime = `${getDateForDay("monday")} 17:50`; - const endDateTime = `${getDateForDay("monday")} 18:35`; + tempusApi + .updateKalenderEvent( + sourceEvent.kalender_id, + startDateTime, + endDateTime, + ) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body).to.have.nested.property( + 'meta.status', + 'error', + ); + expect(response.body.errors).to.be.an('array'); + let hasResourcesCollisionError = response.body.errors.some( + (error) => error.errorCode === 'resource_collision', + ); + expect( + hasResourcesCollisionError, + 'response contains resources collision error', + ).to.be.true; + }); + }); + }); + }); - tempusApi - .createKalenderEvent(lehreinheitId, startDateTime, endDateTime, [], false) - .then((response) => { - expect(response.status).to.eq(200); - expect(response.body).to.not.have.nested.property( - "data.needs_room_selection", - true, - ); - expect(response.body).to.have.nested.property( - "meta.status", - "success", - ); - }); - }); - }); - }); - }); + it('prohibited event update due to lector - reservation collision', () => { + let settingsData = tempusApi.getSettingsData(); + settingsData.kollision_student = false; + + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi + .getPlannerEvents(getDateForDay('saturday'), getDateForDay('saturday')) + .then((events) => { + const sourceEvent = events.find( + (event) => + event.type === 'lehreinheit' && + event.beginn === '19:30:00' && + event.ende === '20:15:00' && + event.lektor.some((lector) => lector.kurzbz === 'DemoLKT4'), + ); + expect( + sourceEvent, + 'source event with fixed time and room for collision test', + ).to.exist; + + const startDateTime = `${sourceEvent.datum} 20:15`; + const endDateTime = `${sourceEvent.datum} 21:00`; + + tempusApi + .updateKalenderEvent( + sourceEvent.kalender_id, + startDateTime, + endDateTime, + ) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body).to.have.nested.property( + 'meta.status', + 'error', + ); + expect(response.body.errors).to.be.an('array'); + let hasReservationCollisionError = response.body.errors.some( + (error) => error.errorCode === 'reservation_collision', + ); + expect( + hasReservationCollisionError, + 'response contains reservation collision error', + ).to.be.true; + }); + }); + }); + }); + + it('prohibited reservation update due to reservation - lector collision', () => { + let settingsData = tempusApi.getSettingsData(); + settingsData.kollision_student = false; + + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi + .getPlannerEvents(getDateForDay('saturday'), getDateForDay('saturday')) + .then((events) => { + const sourceEvent = events.find( + (event) => + event.type === 'reservierung' && + event.beginn === '20:15:00' && + event.ende === '21:00:00' && + event.lektor.some((lector) => lector.kurzbz === 'DemoLKT1'), + ); + expect( + sourceEvent, + 'source event with fixed time and room for collision test', + ).to.exist; + + const startDateTime = `${sourceEvent.datum} 19:30`; + const endDateTime = `${sourceEvent.datum} 20:15`; + + tempusApi + .updateKalenderEvent( + sourceEvent.kalender_id, + startDateTime, + endDateTime, + ) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body).to.have.nested.property( + 'meta.status', + 'error', + ); + expect(response.body.errors).to.be.an('array'); + let hasReservationCollisionError = response.body.errors.some( + (error) => error.errorCode === 'lector_collision', + ); + expect( + hasReservationCollisionError, + 'response contains lector collision error', + ).to.be.true; + }); + }); + }); + }); + + it('event creation fails for inactive roomless and active room selection dialog config option, if no room is selected, for the first attempt', () => { + tempusApi.getDegreeProgramTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), + ); + expect(studyPlan, 'study plan for test event creation').to.exist; + + let settingsData = tempusApi.getSettingsData(); + settingsData.roomless_planning = false; + settingsData.room_planning = 'dialog_room_planning'; + + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) + .then((courses) => { + let course = courses.find((course) => course.lehrfach === 'MAT'); + expect(course, 'course for test event creation').to.exist; + + tempusApi.updateSettingsData(settingsData).then((response) => { + const lehreinheitId = course.lehreinheit_id; + expect(lehreinheitId, 'lehreinheit id for test event creation').to + .exist; + + const startDateTime = `${getDateForDay('monday')} 17:50`; + const endDateTime = `${getDateForDay('monday')} 18:35`; + + tempusApi + .createKalenderEvent( + lehreinheitId, + startDateTime, + endDateTime, + [], + ) + .then((response) => { + expect(response.status).to.eq(200); + expect(response.body).to.have.nested.property( + 'data.needs_room_selection', + true, + ); + expect(response.body).to.have.nested.property( + 'meta.status', + 'success', + ); + }); + }); + }); + }); + }); + + it('event creation fails for inactive roomless and active room selection dialog config option, if no room is selected, for the second attempt', () => { + tempusApi.getDegreeProgramTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), + ); + expect(studyPlan, 'study plan for test event creation').to.exist; + + let settingsData = tempusApi.getSettingsData(); + settingsData.roomless_planning = false; + settingsData.room_planning = 'dialog_room_planning'; + + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) + .then((courses) => { + let course = courses.find((course) => course.lehrfach === 'MAT'); + expect(course, 'course for test event creation').to.exist; + + tempusApi.updateSettingsData(settingsData).then((response) => { + const lehreinheitId = course.lehreinheit_id; + expect(lehreinheitId, 'lehreinheit id for test event creation').to + .exist; + + const startDateTime = `${getDateForDay('monday')} 17:50`; + const endDateTime = `${getDateForDay('monday')} 18:35`; + + tempusApi + .createKalenderEvent( + lehreinheitId, + startDateTime, + endDateTime, + [], + false, + ) + .then((response) => { + expect(response.status).to.eq(500); + expect(response.body.errors).to.be.an('array'); + let hasRoomlessPlanningError = response.body.errors.some( + (error) => error.errorCode === 'roomless_planning_error', + ); + expect( + hasRoomlessPlanningError, + 'response contains roomless planning error', + ).to.be.true; + }); + }); + }); + }); + }); + + it('event creation works for inactive roomless and active priority room config option, if no room is selected', () => { + tempusApi.getDegreeProgramTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), + ); + expect(studyPlan, 'study plan for test event creation').to.exist; + + let settingsData = tempusApi.getSettingsData(); + settingsData.roomless_planning = false; + settingsData.room_planning = 'priority_room_planning'; + + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) + .then((courses) => { + let course = courses.find((course) => course.lehrfach === 'MAT'); + expect(course, 'course for test event creation').to.exist; + + tempusApi.updateSettingsData(settingsData).then((response) => { + const lehreinheitId = course.lehreinheit_id; + expect(lehreinheitId, 'lehreinheit id for test event creation').to + .exist; + + const startDateTime = `${getDateForDay('monday')} 17:50`; + const endDateTime = `${getDateForDay('monday')} 18:35`; + + tempusApi + .createKalenderEvent( + lehreinheitId, + startDateTime, + endDateTime, + [], + ) + .then((response) => { + expect(response.status).to.eq(200); + expect(response.body).to.not.have.nested.property( + 'data.needs_room_selection', + true, + ); + expect(response.body).to.have.nested.property( + 'meta.status', + 'success', + ); + }); + }); + }); + }); + }); + + it('event creation fails for active roomless and active room selection dialog config option, if no room is selected, for the first attempt', () => { + tempusApi.getDegreeProgramTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), + ); + expect(studyPlan, 'study plan for test event creation').to.exist; + + let settingsData = tempusApi.getSettingsData(); + settingsData.roomless_planning = true; + settingsData.room_planning = 'dialog_room_planning'; + + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) + .then((courses) => { + let course = courses.find((course) => course.lehrfach === 'MAT'); + expect(course, 'course for test event creation').to.exist; + + tempusApi.updateSettingsData(settingsData).then((response) => { + const lehreinheitId = course.lehreinheit_id; + expect(lehreinheitId, 'lehreinheit id for test event creation').to + .exist; + + const startDateTime = `${getDateForDay('monday')} 17:50`; + const endDateTime = `${getDateForDay('monday')} 18:35`; + + tempusApi + .createKalenderEvent( + lehreinheitId, + startDateTime, + endDateTime, + [], + true, + ) + .then((response) => { + expect(response.status).to.eq(200); + expect(response.body).to.have.nested.property( + 'data.needs_room_selection', + true, + ); + expect(response.body).to.have.nested.property( + 'meta.status', + 'success', + ); + }); + }); + }); + }); + }); + + it('event creation works for active roomless and active room selection dialog config option, if no room is selected, for the second attempt', () => { + tempusApi.getDegreeProgramTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE), + ); + expect(studyPlan, 'study plan for test event creation').to.exist; + + let settingsData = tempusApi.getSettingsData(); + settingsData.roomless_planning = true; + settingsData.room_planning = 'dialog_room_planning'; + + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER) + .then((courses) => { + let course = courses.find((course) => course.lehrfach === 'MAT'); + expect(course, 'course for test event creation').to.exist; + + tempusApi.updateSettingsData(settingsData).then((response) => { + const lehreinheitId = course.lehreinheit_id; + expect(lehreinheitId, 'lehreinheit id for test event creation').to + .exist; + + const startDateTime = `${getDateForDay('monday')} 17:50`; + const endDateTime = `${getDateForDay('monday')} 18:35`; + + tempusApi + .createKalenderEvent( + lehreinheitId, + startDateTime, + endDateTime, + [], + false, + ) + .then((response) => { + expect(response.status).to.eq(200); + expect(response.body).to.not.have.nested.property( + 'data.needs_room_selection', + true, + ); + expect(response.body).to.have.nested.property( + 'meta.status', + 'success', + ); + }); + }); + }); + }); + }); }); diff --git a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.course-picker.cy.js b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.course-picker.cy.js index 81f2a714e..cb87b1bd8 100644 --- a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.course-picker.cy.js +++ b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.course-picker.cy.js @@ -1,194 +1,200 @@ -import { waitForOk } from "../../../../support/helpers/network"; -import { tempusPage } from "../../../../support/pages/tempus.po"; -import { tempusApi } from "../../../../support/api/tempusApi"; +import { waitForOk } from '../../../../support/helpers/network'; +import { tempusPage } from '../../../../support/pages/tempus.po'; +import { tempusApi } from '../../../../support/api/tempusApi'; -const TARGETED_STUDY_PLAN_SHORT_CODE = "STG5"; - -context("Tempus course picker tests", () => { - before(() => { - tempusPage.visitAndWaitForPlanner(); - tempusPage.setCurrentSemester(); - }); - - beforeEach(() => { - tempusPage.visitAndWaitForPlanner(); - }); - - it("shows a course's events after selecting it", () => { - tempusPage.getSlideInCoursesMenu().should("exist"); - tempusPage.getCourseTreeRows().should("have.length.greaterThan", 0); - tempusPage.getCoursePicker().should("exist"); - tempusPage.getCoursePickerRows().should("have.length", 0); - - tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); - waitForOk("@fetchCoursePickerCourses"); - - tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0); - }); - - it("filters course teaching units using the course-picker search", () => { - tempusPage.getSlideInCoursesMenu().should("exist"); - tempusPage.getCourseTreeRows().should("have.length.greaterThan", 0); - tempusPage.getCoursePicker().should("exist"); - tempusPage.getCoursePickerRows().should("have.length", 0); - - tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); - waitForOk("@fetchCoursePickerCourses"); - - cy.wait(1000); - - tempusPage.getCoursePickerRows() - .should("be.visible") - .should("have.length.greaterThan", 0); - - tempusPage - .getCoursePickerRows() - .last() - .find("div:first span:first") - .invoke("text") - .as("randomCourseText"); - - cy.get("@randomCourseText").then((randomCourseText) => { - tempusPage.getCoursePickerSearchInput().type(randomCourseText); - - tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0); - tempusPage - .getCoursePickerRows() - .first() - .should("contain.text", randomCourseText); - }); - }); - -it("for active room selection dialog config option, shows room selection dialog when adding a course from the course-picker", () => { - let settingsData = tempusApi.getSettingsData(); - settingsData.roomless_planning = false; - settingsData.room_planning = "dialog_room_planning"; - - tempusApi.updateSettingsData(settingsData).then((response) => { - tempusApi.deletePlannerEventsForDay("monday"); +const TARGETED_STUDY_PLAN_SHORT_CODE = 'STG5'; +context('Tempus course picker tests', () => { + before(() => { tempusPage.visitAndWaitForPlanner(); - tempusPage.waitForCalendarToFinishLoading(); + tempusPage.setCurrentSemester(); + }); + + beforeEach(() => { + tempusPage.visitAndWaitForPlanner(); + }); + + it("shows a course's events after selecting it", () => { + tempusPage.getSlideInCoursesMenu().should('exist'); + tempusPage.getCourseTreeRows().should('have.length.greaterThan', 0); + tempusPage.getCoursePicker().should('exist'); + tempusPage.getCoursePickerRows().should('have.length', 0); tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); - waitForOk("@fetchCoursePickerCourses"); + waitForOk('@fetchCoursePickerCourses'); - tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0); + tempusPage.getCoursePickerRows().should('have.length.greaterThan', 0); + }); - tempusPage.getCalendarEvents().then(($events) => { - const initialEventCount = $events.length; + it('filters course teaching units using the course-picker search', () => { + tempusPage.getSlideInCoursesMenu().should('exist'); + tempusPage.getCourseTreeRows().should('have.length.greaterThan', 0); + tempusPage.getCoursePicker().should('exist'); + tempusPage.getCoursePickerRows().should('have.length', 0); - tempusPage.dropCourseOnCalendarPart(0, 10); - waitForOk("@addCalendarEvent"); - - tempusPage.getRoomSelectionModal().should("be.visible"); - tempusPage.selectFirstRoomAndSave(); + tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); + waitForOk('@fetchCoursePickerCourses'); - waitForOk("@addCalendarEvent"); - waitForOk("@fetchPlanData"); + cy.wait(1000); + tempusPage + .getCoursePickerRows() + .should('be.visible') + .should('have.length.greaterThan', 0); + + tempusPage + .getCoursePickerRows() + .last() + .find('div:first span:first') + .invoke('text') + .as('randomCourseText'); + + cy.get('@randomCourseText').then((randomCourseText) => { + tempusPage.getCoursePickerSearchInput().type(randomCourseText); + + tempusPage.getCoursePickerRows().should('have.length.greaterThan', 0); + tempusPage + .getCoursePickerRows() + .first() + .should('contain.text', randomCourseText); + }); + }); + + it('for active room selection dialog config option, shows room selection dialog when adding a course from the course-picker', () => { + let settingsData = tempusApi.getSettingsData(); + settingsData.roomless_planning = false; + settingsData.room_planning = 'dialog_room_planning'; + + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi.deletePlannerEventsForDay('monday'); + + tempusPage.visitAndWaitForPlanner(); tempusPage.waitForCalendarToFinishLoading(); - tempusPage - .getCalendarEvents() - .should("have.length", initialEventCount + 1); + tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); + waitForOk('@fetchCoursePickerCourses'); + + tempusPage.getCoursePickerRows().should('have.length.greaterThan', 0); + + tempusPage.getCalendarEvents().then(($events) => { + const initialEventCount = $events.length; + + tempusPage.dropCourseOnCalendarPart(0, 10); + waitForOk('@addCalendarEvent'); + + tempusPage.getRoomSelectionModal().should('be.visible'); + tempusPage.selectFirstRoomAndSave(); + + waitForOk('@addCalendarEvent'); + waitForOk('@fetchPlanData'); + + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage + .getCalendarEvents() + .should('have.length', initialEventCount + 1); + }); + }); + }); + + it('for active room selection dialog config option, does not add an event to the calendar when the room selection dialog is closed', () => { + let settingsData = tempusApi.getSettingsData(); + settingsData.roomless_planning = false; + settingsData.room_planning = 'dialog_room_planning'; + + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi.deletePlannerEventsForDay('monday'); + + tempusPage.visitAndWaitForPlanner(); + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); + waitForOk('@fetchCoursePickerCourses'); + + tempusPage.getCoursePickerRows().should('have.length.greaterThan', 0); + + tempusPage.getCalendarEvents().then(($events) => { + const initialEventCount = $events.length; + + tempusPage.dropCourseOnCalendarPart(0, 10); + + tempusPage.getRoomSelectionModal().should('be.visible'); + tempusPage + .getRoomSelectionModal() + .find("button[data-cy='closeRoomSelection']") + .click(); + tempusPage.getRoomSelectionModal().should('not.exist'); + + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage.getCalendarEvents().should('have.length', initialEventCount); + }); + }); + }); + + it('for active room selection dialog config option, does not add an event to the calendar when no room is selected', () => { + let settingsData = tempusApi.getSettingsData(); + settingsData.roomless_planning = false; + settingsData.room_planning = 'dialog_room_planning'; + + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi.deletePlannerEventsForDay('monday'); + + tempusPage.visitAndWaitForPlanner(); + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); + waitForOk('@fetchCoursePickerCourses'); + + tempusPage.getCoursePickerRows().should('have.length.greaterThan', 0); + + tempusPage.getCalendarEvents().then(($events) => { + const initialEventCount = $events.length; + + tempusPage.dropCourseOnCalendarPart(0, 10); + + tempusPage.getRoomSelectionModal().should('be.visible'); + tempusPage + .getRoomSelectionModal() + .find("button[data-cy='saveRoomSelection']") + .click(); + tempusPage.getRoomSelectionModal().should('exist'); + + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage.getCalendarEvents().should('have.length', initialEventCount); + }); + }); + }); + + it('for active priority room config option, adds an event to the calendar without room selection dialog', () => { + let settingsData = tempusApi.getSettingsData(); + settingsData.roomless_planning = false; + settingsData.room_planning = 'priority_room_planning'; + + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi.deletePlannerEventsForDay('monday'); + + tempusPage.visitAndWaitForPlanner(); + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); + waitForOk('@fetchCoursePickerCourses'); + + tempusPage.getCoursePickerRows().should('have.length.greaterThan', 0); + + tempusPage.getCalendarEvents().then(($events) => { + const initialEventCount = $events.length; + + tempusPage.dropCourseOnCalendarPart(0, 10); + + tempusPage.getRoomSelectionModal().should('not.exist'); + tempusPage.getCalendarEvents().should('have.length', initialEventCount); + + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage.getCalendarEvents().should('have.length', initialEventCount); + }); }); }); }); - -it("for active room selection dialog config option, does not add an event to the calendar when the room selection dialog is closed", () => { - let settingsData = tempusApi.getSettingsData(); - settingsData.roomless_planning = false; - settingsData.room_planning = "dialog_room_planning"; - - tempusApi.updateSettingsData(settingsData).then((response) => { - tempusApi.deletePlannerEventsForDay("monday"); - - tempusPage.visitAndWaitForPlanner(); - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); - waitForOk("@fetchCoursePickerCourses"); - - tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0); - - tempusPage.getCalendarEvents().then(($events) => { - const initialEventCount = $events.length; - - tempusPage.dropCourseOnCalendarPart(0, 10); - - tempusPage.getRoomSelectionModal().should("be.visible"); - tempusPage.getRoomSelectionModal().find("button[data-cy='closeRoomSelection']").click(); - tempusPage.getRoomSelectionModal().should("not.exist"); - - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage.getCalendarEvents().should("have.length", initialEventCount); - }); - }); -}); - -it("for active room selection dialog config option, does not add an event to the calendar when no room is selected", () => { - let settingsData = tempusApi.getSettingsData(); - settingsData.roomless_planning = false; - settingsData.room_planning = "dialog_room_planning"; - - tempusApi.updateSettingsData(settingsData).then((response) => { - tempusApi.deletePlannerEventsForDay("monday"); - - tempusPage.visitAndWaitForPlanner(); - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); - waitForOk("@fetchCoursePickerCourses"); - - tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0); - - tempusPage.getCalendarEvents().then(($events) => { - const initialEventCount = $events.length; - - tempusPage.dropCourseOnCalendarPart(0, 10); - - tempusPage.getRoomSelectionModal().should("be.visible"); - tempusPage.getRoomSelectionModal().find("button[data-cy='saveRoomSelection']").click(); - tempusPage.getRoomSelectionModal().should("exist"); - - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage.getCalendarEvents().should("have.length", initialEventCount); - }); - }); -}); - -it("for active priority room config option, adds an event to the calendar without room selection dialog", () => { - let settingsData = tempusApi.getSettingsData(); - settingsData.roomless_planning = false; - settingsData.room_planning = "priority_room_planning"; - - tempusApi.updateSettingsData(settingsData).then((response) => { - tempusApi.deletePlannerEventsForDay("monday"); - - tempusPage.visitAndWaitForPlanner(); - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); - waitForOk("@fetchCoursePickerCourses"); - - tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0); - - tempusPage.getCalendarEvents().then(($events) => { - const initialEventCount = $events.length; - - tempusPage.dropCourseOnCalendarPart(0, 10); - - tempusPage.getRoomSelectionModal().should("not.exist"); - tempusPage.getCalendarEvents().should("have.length", initialEventCount); - - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage.getCalendarEvents().should("have.length", initialEventCount); - }); - }); -}); - -}); diff --git a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.events.cy.js b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.events.cy.js index 4ef9bf313..54408a59f 100644 --- a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.events.cy.js +++ b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.events.cy.js @@ -1,473 +1,483 @@ -import { waitForOk } from "../../../../support/helpers/network"; -import { tempusApi } from "../../../../support/api/tempusApi"; +import { waitForOk } from '../../../../support/helpers/network'; +import { tempusApi } from '../../../../support/api/tempusApi'; import { - LEKTOR, - STUDENT, - tempusPage, -} from "../../../../support/pages/tempus.po"; + LEKTOR, + STUDENT, + tempusPage, +} from '../../../../support/pages/tempus.po'; -const TARGETED_STUDY_PLAN_SHORT_CODE = "STG5"; +const TARGETED_STUDY_PLAN_SHORT_CODE = 'STG5'; -context("Tempus event mutation tests", () => { - beforeEach(() => { - tempusPage.visitAndWaitForPlanner(); +context('Tempus event mutation tests', () => { + before(() => { + cy.login(); - tempusApi.deletePlannerEventsForDay("monday"); - }); + let settingsData = tempusApi.getSettingsData(); + settingsData.ignore_kollision = true; + settingsData.roomless_planning = false; + settingsData.room_planning = 'dialog_room_planning'; + tempusApi.updateSettingsData(settingsData); + }); + beforeEach(() => { + tempusPage.visitAndWaitForPlanner(); - it("updates an event room in the planner preview while other previews retain the original room", () => { - tempusPage.syncAndReloadPlanner(); + tempusApi.deletePlannerEventsForDay('monday'); + }); - tempusPage - .getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime( - "Wednesday", - "08:00:00", - ) - .should("have.length.greaterThan", 0); - - tempusPage - .getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime( - "Wednesday", - "08:00:00", - ) - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; - - const eventData = JSON.parse(eventJSON); - const eventId = eventData?.id; - let originalRoom = eventData?.orig?.ort_kurzbz; - if (Array.isArray(originalRoom)) originalRoom = originalRoom.length ? originalRoom[0] : ""; - - expect(eventId, "planner event id").to.exist; - expect(originalRoom, "original event room").to.be.a("string").and.not.be - .empty; - - tempusPage.expectCalendarEventRoom(eventId, originalRoom); - - tempusPage.changeEventRoom(eventId, originalRoom).then((result) => { - const { newRoom, updatedEventId } = result; - tempusPage.expectCalendarEventRoom(updatedEventId, newRoom); - - tempusPage.selectRoleAndWait(LEKTOR); - tempusPage.expectCalendarEventRoom(eventId, originalRoom); - - tempusPage.selectRoleAndWait(STUDENT); - tempusPage.expectCalendarEventRoom(eventId, originalRoom); - }); - }); - }); - - it("selects and displays a room for an event", () => { - tempusPage - .getCalendarEventsByWeekdayAndTimeRange( - "Thursday", - "14:30:00", - "15:15:00", - ) - .should("have.length.greaterThan", 0) - .first() - .rightclick(); - - tempusPage.getEventContextMenuOption("Raumauswahl").click({ force: true }); - waitForOk("@fetchRoomSuggestions"); - - tempusPage.selectFirstRoomAndSave().then((selectedRoom) => { - tempusPage.waitForUpdatedEventId().then((updatedEventId) => { - waitForOk("@fetchPlanData"); - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage.expectCalendarEventRoom(updatedEventId, selectedRoom); - }); - }); - }); - - it("changes an event room", () => { - tempusPage - .getCalendarEventsByWeekdayAndTimeRange( - "Thursday", - "15:15:00", - "16:00:00", - ) - .should("have.length.greaterThan", 0) - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; - - const eventData = JSON.parse(eventJSON); - const eventId = eventData?.id; - let originalRoom = eventData?.orig?.ort_kurzbz; - if (Array.isArray(originalRoom)) - originalRoom = originalRoom.length ? originalRoom[0] : ""; - - expect(eventId, "planner event id").to.exist; - expect(originalRoom, "original event room").to.be.a("string").and.not - .be.empty; - - tempusPage.changeEventRoom(eventId, originalRoom).then((result) => { - expect(result.newRoom, "updated room").to.not.eq(originalRoom); - tempusPage.expectCalendarEventRoom( - result.updatedEventId, - result.newRoom, - ); - }); - }); - }); - - it("adds multiple rooms to an event", () => { - tempusPage - .getCalendarEventsByWeekdayAndTimeRange( - "Thursday", - "15:15:00", - "16:00:00", - ) - .should("have.length.greaterThan", 0) - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; - - const eventData = JSON.parse(eventJSON); - const eventId = eventData?.id; - const currentRooms = eventData?.orig?.ort_kurzbz ?? []; - - expect(eventId, "planner event id").to.exist; - - tempusPage.getCalendarEventById(eventId).rightclick(); - tempusPage.getEventContextMenuOption("Raumauswahl").click({ force: true }); - waitForOk("@fetchRoomSuggestions"); - - tempusPage - .selectAdditionalRoomsAndSave(currentRooms) - .then((additionalRooms) => { - tempusPage.waitForUpdatedEventId().then((updatedEventId) => { - waitForOk("@fetchPlanData"); - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage.expectCalendarEventRooms(updatedEventId, additionalRooms); - }); - }); - }); - }); - - - it("moves an event from the calendar to the parking slot", () => { - tempusPage.getEventParkingSlot().should("exist"); - tempusPage.getParkedEvents().should("have.length", 0); - - tempusPage - .getCalendarEventsByWeekdayAndStartTime("Wednesday", "08:45:00") - .first() - .drag(tempusPage.selectors.parkingSlot); - - tempusPage.getParkedEvents().should("have.length", 1); - }); - - it("keeps a deleted planner event visible in lecturer and student previews, before syncing", () => { - tempusPage.syncAndReloadPlanner(); - - tempusPage - .getCalendarEventsBySoftTimeRange("16:10:00", "16:55:00") - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; - - const eventGroupId = - JSON.parse(eventJSON)?.orig?.eindeutige_kalender_gruppen_id; - expect(eventGroupId).to.exist; + it('updates an event room in the planner preview while other previews retain the original room', () => { + tempusPage + .getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime( + 'Wednesday', + '08:00:00', + ) + .should('have.length.greaterThan', 0); tempusPage - .getCalendarEventByUniqueCalenderGroupId(eventGroupId) + .getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime( + 'Wednesday', + '08:00:00', + ) + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; + + const eventData = JSON.parse(eventJSON); + const eventId = eventData?.id; + let originalRoom = eventData?.orig?.ort_kurzbz; + if (Array.isArray(originalRoom)) + originalRoom = originalRoom.length ? originalRoom[0] : ''; + + expect(eventId, 'planner event id').to.exist; + expect(originalRoom, 'original event room').to.be.a('string').and.not.be + .empty; + + tempusPage.expectCalendarEventRoom(eventId, originalRoom); + + tempusPage.changeEventRoom(eventId, originalRoom).then((result) => { + const { newRoom, updatedEventId } = result; + tempusPage.expectCalendarEventRoom(updatedEventId, newRoom); + + tempusPage.selectRoleAndWait(LEKTOR); + tempusPage.expectCalendarEventRoom(eventId, originalRoom); + + tempusPage.selectRoleAndWait(STUDENT); + tempusPage.expectCalendarEventRoom(eventId, originalRoom); + }); + }); + }); + + it('selects and displays a room for an event', () => { + tempusPage + .getCalendarEventsByWeekdayAndTimeRange( + 'Thursday', + '14:30:00', + '15:15:00', + ) + .should('have.length.greaterThan', 0) + .first() .rightclick(); - tempusPage - .getEventContextMenuOption("Delete") - .click({ force: true }); + tempusPage.getEventContextMenuOption('Raumauswahl').click({ force: true }); + waitForOk('@fetchRoomSuggestions'); - waitForOk("@deleteCalendarEvent"); - waitForOk("@fetchPlanData"); + tempusPage.selectFirstRoomAndSave().then((selectedRoom) => { + tempusPage.waitForUpdatedEventId().then((updatedEventId) => { + waitForOk('@fetchPlanData'); + tempusPage.waitForCalendarToFinishLoading(); - tempusPage - .getCalendarEventByUniqueCalenderGroupId(eventGroupId) - .should("exist"); - - tempusPage.selectRoleAndWait(LEKTOR); - tempusPage - .getCalendarEventByUniqueCalenderGroupId(eventGroupId) - .should("exist"); - - tempusPage.selectRoleAndWait(STUDENT); - tempusPage - .getCalendarEventByUniqueCalenderGroupId(eventGroupId) - .should("exist"); + tempusPage.expectCalendarEventRoom(updatedEventId, selectedRoom); + }); }); -}); - -it("keeps a deleted planner event invisible after syncing", () => { - tempusPage.syncAndReloadPlanner(); - - tempusPage - .getCalendarEventsBySoftTimeRange("16:55:00", "17:40:00") - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; - - const eventGroupId = - JSON.parse(eventJSON)?.orig?.eindeutige_kalender_gruppen_id; - expect(eventGroupId).to.exist; - - tempusPage - .getCalendarEventByUniqueCalenderGroupId(eventGroupId) - .rightclick(); - - tempusPage - .getEventContextMenuOption("Delete") - .click({ force: true }); - - waitForOk("@deleteCalendarEvent"); - waitForOk("@fetchPlanData"); - - tempusPage - .getCalendarEventByUniqueCalenderGroupId(eventGroupId) - .should("exist"); - - tempusPage.syncAndReloadPlanner(); - - tempusPage - .getCalendarEventByUniqueCalenderGroupId(eventGroupId) - .should("not.exist"); - - tempusPage.selectRoleAndWait(LEKTOR); - tempusPage - .getCalendarEventByUniqueCalenderGroupId(eventGroupId) - .should("not.exist"); - - tempusPage.selectRoleAndWait(STUDENT); - tempusPage - .getCalendarEventByUniqueCalenderGroupId(eventGroupId) - .should("not.exist"); - }); -}); - - it("resizes an event from the bottom in the planner preview", () => { - tempusPage.getCalendarSection().should("exist"); - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage - .getCalendarEventsByWeekdayAndStartTime("Thursday", "08:00:00") - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - cy.wrap(JSON.parse(eventJSON)).its("id").as("eventId"); - cy.wrap(JSON.parse(eventJSON).orig) - .its("beginn") - .as("originalEventStart"); - cy.wrap(JSON.parse(eventJSON).orig).its("ende").as("originalEventEnd"); - }); - - cy.get("@eventId").then((eventId) => { - tempusPage - .getCalendarEventById(eventId) - .find(".fhc-resize-bar--bottom") - .first() - .realHover() - .realMouseDown("center", { - button: "left", - }) - .realMouseMove(0, 5) - .realMouseMove(0, 5) - .realMouseMove(0, 10) - .realMouseMove(0, 100) - .realMouseUp(); - - cy.wait("@updateCalendarEvent").then((interception) => { - expect(interception.response.statusCode).to.eq(200); - expect(interception.response.body.data).to.exist; - const updatedGroupEventId = - interception.response.body.data?.eindeutige_kalender_gruppen_id ?? - interception.response.body.data; - cy.wrap(updatedGroupEventId).as("updatedGroupEventId"); - }); - waitForOk("@fetchPlanData"); - - cy.get("@updatedGroupEventId").then((updatedGroupEventId) => { - tempusPage - .getCalendarEventByUniqueCalenderGroupId(updatedGroupEventId) - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - let newEventStart = JSON.parse(eventJSON)?.orig?.beginn; - let newEventEnd = JSON.parse(eventJSON)?.orig?.ende; - - cy.get("@originalEventStart").then((originalEventStart) => { - expect(newEventStart).to.eq(originalEventStart); - }); - cy.get("@originalEventEnd").then((originalEventEnd) => { - expect(newEventEnd).to.not.eq(originalEventEnd); - }); - }); - }); - }); - }); - - it.skip("resizes an event from the top in the planner preview", () => { - tempusPage.getCalendarSection().should("exist"); - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage - .getCalendarEventsByWeekdayAndStartTime("Friday", "10:25:00") - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - cy.wrap(JSON.parse(eventJSON)).its("id").as("eventId"); - cy.wrap(JSON.parse(eventJSON).orig) - .its("beginn") - .as("originalEventStart"); - cy.wrap(JSON.parse(eventJSON).orig).its("ende").as("originalEventEnd"); - }); - - cy.get("@eventId").then((eventId) => { - tempusPage - .getCalendarEventById(eventId) - .find(".fhc-resize-bar--top") - .first() - .realHover() - .realMouseDown("center", { - button: "left", - }) - .realMouseMove(0, -5) - .realMouseMove(0, -5) - .realMouseMove(0, -10) - .realMouseMove(0, -20) - .realMouseUp(); - - cy.wait("@updateCalendarEvent").then((interception) => { - expect(interception.response.statusCode).to.eq(200); - expect(interception.response.body.data).to.exist; - - const updatedGroupEventId = - interception.response.body.data?.eindeutige_kalender_gruppen_id ?? - interception.response.body.data; - - cy.wrap(updatedGroupEventId).as("updatedGroupEventId"); - }); - waitForOk("@fetchPlanData"); - - cy.get("@updatedGroupEventId").then((updatedGroupEventId) => { - tempusPage - .getCalendarEventByUniqueCalenderGroupId(updatedGroupEventId) - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - let newEventStart = JSON.parse(eventJSON)?.orig?.beginn; - let newEventEnd = JSON.parse(eventJSON)?.orig?.ende; - - cy.get("@originalEventStart").then((originalEventStart) => { - expect(newEventStart).to.not.eq(originalEventStart); - }); - cy.get("@originalEventEnd").then((originalEventEnd) => { - expect(newEventEnd).to.eq(originalEventEnd); - }); - }); - }); - }); - }); - - it.skip("adds a course event to the calendar when Stundenraster is disabled", () => { - tempusPage.setCurrentSemester(); - - tempusPage.getCalendarSection().should("exist"); - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage.disableStundenraster(); - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); - waitForOk("@fetchCoursePickerCourses"); - - cy.wait(1000); - - tempusPage.getCalendarEvents().then(($events) => { - cy.wrap($events.length).as("initialEventCount"); - }); - - tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0); - - tempusPage - .getCoursePickerRows() - .first() - .scrollIntoView() - .should("be.visible") - .drag(".fhc-calendar-base-grid-line:first", { - waitForAnimations: true, - animationDistanceThreshold: 0, - target: { position: "top" }, - }); - - waitForOk("@addCalendarEvent"); - waitForOk("@fetchPlanData"); - - tempusPage.waitForCalendarToFinishLoading(); - - cy.get("@initialEventCount").then((initialEventCount) => { - tempusPage - .getCalendarEvents() - .should("have.length", initialEventCount + 1); - }); - }); - - it.skip("moves an existing event when Stundenraster is disabled", () => { - tempusPage.syncAndReloadPlanner(); - tempusPage.waitForCalendarToFinishLoading(); - - tempusPage.disableStundenraster(); - - cy.wait(1000); - - tempusPage - .getCalendarEventsByWeekdayAndStartTime("Wednesday", "11:20:00") - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; - - const eventId = JSON.parse(eventJSON)?.id; - expect(eventId).to.exist; - - tempusPage - .getCalendarEventById(eventId) - .should("be.visible") - .drag(".fhc-calendar-base-grid-line:first", { - waitForAnimations: true, - animationDistanceThreshold: 0, - target: { position: "top" }, - }); - - cy.wait("@updateCalendarEvent").then((interception) => { - expect(interception.response.statusCode).to.eq(200); - - const updatedEventId = tempusPage.getUpdatedKalenderId(interception); - expect(updatedEventId, "updated planner event id").to.exist; - - cy.wrap(updatedEventId).as("updatedEventId"); - }); - waitForOk("@fetchPlanData"); - tempusPage.waitForCalendarToFinishLoading(); - - cy.get("@updatedEventId").then((updatedEventId) => { - tempusPage.getCalendarEventById(updatedEventId).should("be.visible"); - - tempusPage - .getCalendarEventsByWeekday("Monday") - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((movedEventJSON) => { - const movedEventId = JSON.parse(movedEventJSON)?.id; - expect(movedEventId).to.eq(updatedEventId); - }); - }); - }); - }); + }); + + it('changes an event room', () => { + tempusPage + .getCalendarEventsByWeekdayAndTimeRange( + 'Thursday', + '15:15:00', + '16:00:00', + ) + .should('have.length.greaterThan', 0) + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; + + const eventData = JSON.parse(eventJSON); + const eventId = eventData?.id; + let originalRoom = eventData?.orig?.ort_kurzbz; + if (Array.isArray(originalRoom)) + originalRoom = originalRoom.length ? originalRoom[0] : ''; + + expect(eventId, 'planner event id').to.exist; + expect(originalRoom, 'original event room').to.be.a('string').and.not.be + .empty; + + tempusPage.changeEventRoom(eventId, originalRoom).then((result) => { + expect(result.newRoom, 'updated room').to.not.eq(originalRoom); + tempusPage.expectCalendarEventRoom( + result.updatedEventId, + result.newRoom, + ); + }); + }); + }); + + it('adds multiple rooms to an event', () => { + tempusPage + .getCalendarEventsByWeekdayAndTimeRange( + 'Thursday', + '15:15:00', + '16:00:00', + ) + .should('have.length.greaterThan', 0) + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; + + const eventData = JSON.parse(eventJSON); + const eventId = eventData?.id; + const currentRooms = eventData?.orig?.ort_kurzbz ?? []; + + expect(eventId, 'planner event id').to.exist; + + tempusPage.getCalendarEventById(eventId).rightclick(); + tempusPage + .getEventContextMenuOption('Raumauswahl') + .click({ force: true }); + waitForOk('@fetchRoomSuggestions'); + + tempusPage + .selectAdditionalRoomsAndSave(currentRooms) + .then((additionalRooms) => { + tempusPage.waitForUpdatedEventId().then((updatedEventId) => { + waitForOk('@fetchPlanData'); + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage.expectCalendarEventRooms( + updatedEventId, + additionalRooms, + ); + }); + }); + }); + }); + + it('moves an event from the calendar to the parking slot', () => { + tempusPage.getEventParkingSlot().should('exist'); + tempusPage.getParkedEvents().should('have.length', 0); + + tempusPage + .getCalendarEventsByWeekdayAndStartTime('Wednesday', '08:45:00') + .first() + .drag(tempusPage.selectors.parkingSlot); + + tempusPage.getParkedEvents().should('have.length', 1); + }); + + it('keeps a deleted planner event visible in lecturer and student previews, before syncing', () => { + tempusPage.syncAndReloadPlanner(); + + tempusPage + .getCalendarEventsBySoftTimeRange('16:10:00', '16:55:00') + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; + + const eventGroupId = + JSON.parse(eventJSON)?.orig?.eindeutige_kalender_gruppen_id; + expect(eventGroupId).to.exist; + + tempusPage + .getCalendarEventByUniqueCalenderGroupId(eventGroupId) + .rightclick(); + + tempusPage.getEventContextMenuOption('Delete').click({ force: true }); + + waitForOk('@deleteCalendarEvent'); + waitForOk('@fetchPlanData'); + + tempusPage + .getCalendarEventByUniqueCalenderGroupId(eventGroupId) + .should('exist'); + + tempusPage.selectRoleAndWait(LEKTOR); + tempusPage + .getCalendarEventByUniqueCalenderGroupId(eventGroupId) + .should('exist'); + + tempusPage.selectRoleAndWait(STUDENT); + tempusPage + .getCalendarEventByUniqueCalenderGroupId(eventGroupId) + .should('exist'); + }); + }); + + it('keeps a deleted planner event invisible after syncing', () => { + tempusPage.syncAndReloadPlanner(); + + tempusPage + .getCalendarEventsBySoftTimeRange('16:55:00', '17:40:00') + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; + + const eventGroupId = + JSON.parse(eventJSON)?.orig?.eindeutige_kalender_gruppen_id; + expect(eventGroupId).to.exist; + + tempusPage + .getCalendarEventByUniqueCalenderGroupId(eventGroupId) + .rightclick(); + + tempusPage.getEventContextMenuOption('Delete').click({ force: true }); + + waitForOk('@deleteCalendarEvent'); + waitForOk('@fetchPlanData'); + + tempusPage + .getCalendarEventByUniqueCalenderGroupId(eventGroupId) + .should('exist'); + + tempusPage.syncAndReloadPlanner(); + + tempusPage + .getCalendarEventByUniqueCalenderGroupId(eventGroupId) + .should('not.exist'); + + tempusPage.selectRoleAndWait(LEKTOR); + tempusPage + .getCalendarEventByUniqueCalenderGroupId(eventGroupId) + .should('not.exist'); + + tempusPage.selectRoleAndWait(STUDENT); + tempusPage + .getCalendarEventByUniqueCalenderGroupId(eventGroupId) + .should('not.exist'); + }); + }); + + it('resizes an event from the bottom in the planner preview', () => { + tempusPage.getCalendarSection().should('exist'); + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage + .getCalendarEventsByWeekdayAndStartTime('Thursday', '08:00:00') + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + cy.wrap(JSON.parse(eventJSON)).its('id').as('eventId'); + cy.wrap(JSON.parse(eventJSON).orig) + .its('beginn') + .as('originalEventStart'); + cy.wrap(JSON.parse(eventJSON).orig).its('ende').as('originalEventEnd'); + }); + + cy.get('@eventId').then((eventId) => { + tempusPage.scrollCalendarEventIntoView(eventId).then(() => { + tempusPage + .getCalendarEventById(eventId) + .find('.fhc-resize-bar--bottom') + .first() + .realHover() + .realMouseDown('center', { + button: 'left', + }) + .realMouseMove(0, 5) + .realMouseMove(0, 5) + .realMouseMove(0, 10) + .realMouseMove(0, 100) + .realMouseUp(); + }); + + cy.wait('@updateCalendarEvent').then((interception) => { + expect(interception.response.statusCode).to.eq(200); + expect(interception.response.body.data).to.exist; + const updatedGroupEventId = + interception.response.body.data?.eindeutige_kalender_gruppen_id ?? + interception.response.body.data; + cy.wrap(updatedGroupEventId).as('updatedGroupEventId'); + }); + waitForOk('@fetchPlanData'); + + cy.get('@updatedGroupEventId').then((updatedGroupEventId) => { + tempusPage + .getCalendarEventByUniqueCalenderGroupId(updatedGroupEventId) + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + let newEventStart = JSON.parse(eventJSON)?.orig?.beginn; + let newEventEnd = JSON.parse(eventJSON)?.orig?.ende; + + cy.get('@originalEventStart').then((originalEventStart) => { + expect(newEventStart).to.eq(originalEventStart); + }); + cy.get('@originalEventEnd').then((originalEventEnd) => { + expect(newEventEnd).to.not.eq(originalEventEnd); + }); + }); + }); + }); + }); + + it.skip('resizes an event from the top in the planner preview', () => { + tempusPage.getCalendarSection().should('exist'); + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage + .getCalendarEventsByWeekdayAndStartTime('Friday', '10:25:00') + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + cy.wrap(JSON.parse(eventJSON)).its('id').as('eventId'); + cy.wrap(JSON.parse(eventJSON).orig) + .its('beginn') + .as('originalEventStart'); + cy.wrap(JSON.parse(eventJSON).orig).its('ende').as('originalEventEnd'); + }); + + cy.get('@eventId').then((eventId) => { + tempusPage + .getCalendarEventById(eventId) + .find('.fhc-resize-bar--top') + .first() + .realHover() + .realMouseDown('center', { + button: 'left', + }) + .realMouseMove(0, -5) + .realMouseMove(0, -5) + .realMouseMove(0, -10) + .realMouseMove(0, -20) + .realMouseUp(); + + cy.wait('@updateCalendarEvent').then((interception) => { + expect(interception.response.statusCode).to.eq(200); + expect(interception.response.body.data).to.exist; + + const updatedGroupEventId = + interception.response.body.data?.eindeutige_kalender_gruppen_id ?? + interception.response.body.data; + + cy.wrap(updatedGroupEventId).as('updatedGroupEventId'); + }); + waitForOk('@fetchPlanData'); + + cy.get('@updatedGroupEventId').then((updatedGroupEventId) => { + tempusPage + .getCalendarEventByUniqueCalenderGroupId(updatedGroupEventId) + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + let newEventStart = JSON.parse(eventJSON)?.orig?.beginn; + let newEventEnd = JSON.parse(eventJSON)?.orig?.ende; + + cy.get('@originalEventStart').then((originalEventStart) => { + expect(newEventStart).to.not.eq(originalEventStart); + }); + cy.get('@originalEventEnd').then((originalEventEnd) => { + expect(newEventEnd).to.eq(originalEventEnd); + }); + }); + }); + }); + }); + + it.skip('adds a course event to the calendar when Stundenraster is disabled', () => { + tempusPage.setCurrentSemester(); + + tempusPage.getCalendarSection().should('exist'); + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage.disableStundenraster(); + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); + waitForOk('@fetchCoursePickerCourses'); + + cy.wait(1000); + + tempusPage.getCalendarEvents().then(($events) => { + cy.wrap($events.length).as('initialEventCount'); + }); + + tempusPage.getCoursePickerRows().should('have.length.greaterThan', 0); + + tempusPage + .getCoursePickerRows() + .first() + .scrollIntoView() + .should('be.visible') + .drag('.fhc-calendar-base-grid-line:first', { + waitForAnimations: true, + animationDistanceThreshold: 0, + target: { position: 'top' }, + }); + + waitForOk('@addCalendarEvent'); + waitForOk('@fetchPlanData'); + + tempusPage.waitForCalendarToFinishLoading(); + + cy.get('@initialEventCount').then((initialEventCount) => { + tempusPage + .getCalendarEvents() + .should('have.length', initialEventCount + 1); + }); + }); + + it.skip('moves an existing event when Stundenraster is disabled', () => { + tempusPage.syncAndReloadPlanner(); + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage.disableStundenraster(); + + cy.wait(1000); + + tempusPage + .getCalendarEventsByWeekdayAndStartTime('Wednesday', '11:20:00') + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; + + const eventId = JSON.parse(eventJSON)?.id; + expect(eventId).to.exist; + + tempusPage + .getCalendarEventById(eventId) + .should('be.visible') + .drag('.fhc-calendar-base-grid-line:first', { + waitForAnimations: true, + animationDistanceThreshold: 0, + target: { position: 'top' }, + }); + + cy.wait('@updateCalendarEvent').then((interception) => { + expect(interception.response.statusCode).to.eq(200); + + const updatedEventId = tempusPage.getUpdatedKalenderId(interception); + expect(updatedEventId, 'updated planner event id').to.exist; + + cy.wrap(updatedEventId).as('updatedEventId'); + }); + waitForOk('@fetchPlanData'); + tempusPage.waitForCalendarToFinishLoading(); + + cy.get('@updatedEventId').then((updatedEventId) => { + tempusPage.getCalendarEventById(updatedEventId).should('be.visible'); + + tempusPage + .getCalendarEventsByWeekday('Monday') + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((movedEventJSON) => { + const movedEventId = JSON.parse(movedEventJSON)?.id; + expect(movedEventId).to.eq(updatedEventId); + }); + }); + }); + }); }); diff --git a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.filters.cy.js b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.filters.cy.js index 7fef61ab6..68bad749f 100644 --- a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.filters.cy.js +++ b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.filters.cy.js @@ -1,356 +1,370 @@ -import { waitForOk } from "../../../../support/helpers/network"; -import { tempusPage } from "../../../../support/pages/tempus.po"; +import { waitForOk } from '../../../../support/helpers/network'; +import { tempusPage } from '../../../../support/pages/tempus.po'; +import { tempusApi } from '../../../../support/api/tempusApi'; -context("Tempus filter tests", () => { - beforeEach(() => { - tempusPage.visitAndWaitForPlanner(); - }); +context('Tempus filter tests', () => { + before(() => { + cy.login(); - it("filters calendar events by a selected room", () => { - tempusPage.waitForCalendarToFinishLoading(); + let settingsData = tempusApi.getSettingsData(); + settingsData.ignore_kollision = true; + settingsData.roomless_planning = false; + settingsData.room_planning = 'dialog_room_planning'; + tempusApi.updateSettingsData(settingsData); + }); - tempusPage - .getCalendarEventsWithRoom() - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; + beforeEach(() => { + tempusPage.visitAndWaitForPlanner(); + }); - let selectedRoom = JSON.parse(eventJSON)?.orig?.ort_kurzbz; - if (Array.isArray(selectedRoom)) selectedRoom = selectedRoom.length ? selectedRoom[0] : ""; + it('filters calendar events by a selected room', () => { + tempusPage.waitForCalendarToFinishLoading(); - expect(selectedRoom, "first event room").to.be.a("string").and.not.be - .empty; - expect( - selectedRoom.length, - "room search query length", - ).to.be.greaterThan(1); + tempusPage + .getCalendarEventsWithRoom() + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; - tempusPage.getNavbarSearchInput().clear().type(selectedRoom, { - parseSpecialCharSequences: false, - }); - waitForOk("@searchbarSearch"); + let selectedRoom = JSON.parse(eventJSON)?.orig?.ort_kurzbz; + if (Array.isArray(selectedRoom)) + selectedRoom = selectedRoom.length ? selectedRoom[0] : ''; - tempusPage - .getNavbarRoomSearchResult(selectedRoom) - .should("be.visible") - .click(); - waitForOk("@fetchPlanData"); - tempusPage.waitForCalendarToFinishLoading(); + expect(selectedRoom, 'first event room').to.be.a('string').and.not.be + .empty; + expect( + selectedRoom.length, + 'room search query length', + ).to.be.greaterThan(1); - tempusPage.getSelectedRoomIndicator(selectedRoom).should("be.visible"); - tempusPage.getCalendarEvents().should("have.length.greaterThan", 0); - tempusPage.getCalendarEvents().each(($event) => { - const eventData = tempusPage.getCalendarEventData($event); + tempusPage.getNavbarSearchInput().clear().type(selectedRoom, { + parseSpecialCharSequences: false, + }); + waitForOk('@searchbarSearch'); - let eventRoom = eventData?.orig?.ort_kurzbz; - if (Array.isArray(eventRoom)) eventRoom = eventRoom.length ? eventRoom.join(",") : ""; + tempusPage + .getNavbarRoomSearchResult(selectedRoom) + .should('be.visible') + .click(); + waitForOk('@fetchPlanData'); + tempusPage.waitForCalendarToFinishLoading(); - expect(eventRoom, "event data room").to.contain( - selectedRoom, - ); - cy.wrap($event) - .find("[data-cy='calendar-event-room']") - .invoke("text") - .then((eventPlace) => { - expect(eventPlace.trim(), "event body room").to.contain(selectedRoom); - }); - }); - }); - }); + tempusPage.getSelectedRoomIndicator(selectedRoom).should('be.visible'); + tempusPage.getCalendarEvents().should('have.length.greaterThan', 0); + tempusPage.getCalendarEvents().each(($event) => { + const eventData = tempusPage.getCalendarEventData($event); - it("restores all calendar events after removing a room filter", () => { - tempusPage.waitForCalendarToFinishLoading(); + let eventRoom = eventData?.orig?.ort_kurzbz; + if (Array.isArray(eventRoom)) + eventRoom = eventRoom.length ? eventRoom.join(',') : ''; - tempusPage - .getCalendarEventsWithRoom() - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; + expect(eventRoom, 'event data room').to.contain(selectedRoom); + cy.wrap($event) + .find("[data-cy='calendar-event-room']") + .invoke('text') + .then((eventPlace) => { + expect(eventPlace.trim(), 'event body room').to.contain( + selectedRoom, + ); + }); + }); + }); + }); - let selectedRoom = JSON.parse(eventJSON)?.orig?.ort_kurzbz; - if (Array.isArray(selectedRoom)) selectedRoom = selectedRoom.length ? selectedRoom[0] : ""; + it('restores all calendar events after removing a room filter', () => { + tempusPage.waitForCalendarToFinishLoading(); - expect(selectedRoom, "first event room").to.be.a("string").and.not.be - .empty; - expect( - selectedRoom.length, - "room search query length", - ).to.be.greaterThan(1); + tempusPage + .getCalendarEventsWithRoom() + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; - tempusPage.getCalendarEvents().then(($events) => { - const originalEventCount = $events.length; - cy.wrap(originalEventCount).as("originalEventCount"); - }); + let selectedRoom = JSON.parse(eventJSON)?.orig?.ort_kurzbz; + if (Array.isArray(selectedRoom)) + selectedRoom = selectedRoom.length ? selectedRoom[0] : ''; - tempusPage.getNavbarSearchInput().clear().type(selectedRoom, { - parseSpecialCharSequences: false, - }); - waitForOk("@searchbarSearch"); + expect(selectedRoom, 'first event room').to.be.a('string').and.not.be + .empty; + expect( + selectedRoom.length, + 'room search query length', + ).to.be.greaterThan(1); - tempusPage - .getNavbarRoomSearchResult(selectedRoom) - .should("be.visible") - .click(); - waitForOk("@fetchPlanData"); - tempusPage.waitForCalendarToFinishLoading(); + tempusPage.getCalendarEvents().then(($events) => { + const originalEventCount = $events.length; + cy.wrap(originalEventCount).as('originalEventCount'); + }); - tempusPage.getSelectedRoomIndicator(selectedRoom).should("be.visible"); - tempusPage.getCalendarEvents().should("have.length.greaterThan", 0); + tempusPage.getNavbarSearchInput().clear().type(selectedRoom, { + parseSpecialCharSequences: false, + }); + waitForOk('@searchbarSearch'); - tempusPage.getSelectedRoomRemoveButton(selectedRoom).first().click(); - waitForOk("@fetchPlanData"); - tempusPage.waitForCalendarToFinishLoading(); + tempusPage + .getNavbarRoomSearchResult(selectedRoom) + .should('be.visible') + .click(); + waitForOk('@fetchPlanData'); + tempusPage.waitForCalendarToFinishLoading(); - tempusPage.getSelectedRoomIndicator(selectedRoom).should("not.exist"); - cy.get("@originalEventCount").then((originalEventCount) => { - tempusPage - .getCalendarEvents() - .should("have.length", originalEventCount); - }); - }); - }); + tempusPage.getSelectedRoomIndicator(selectedRoom).should('be.visible'); + tempusPage.getCalendarEvents().should('have.length.greaterThan', 0); - it("filters calendar events by a selected lecturer", () => { - tempusPage.waitForCalendarToFinishLoading(); + tempusPage.getSelectedRoomRemoveButton(selectedRoom).first().click(); + waitForOk('@fetchPlanData'); + tempusPage.waitForCalendarToFinishLoading(); - tempusPage - .getCalendarEventsWithLecturer() - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; + tempusPage.getSelectedRoomIndicator(selectedRoom).should('not.exist'); + cy.get('@originalEventCount').then((originalEventCount) => { + tempusPage + .getCalendarEvents() + .should('have.length', originalEventCount); + }); + }); + }); - const selectedLecturer = tempusPage.getFirstLecturer( - JSON.parse(eventJSON), - ); - expect(selectedLecturer?.kurzbz, "first event lecturer").to.exist; + it('filters calendar events by a selected lecturer', () => { + tempusPage.waitForCalendarToFinishLoading(); - const lecturerSearch = - selectedLecturer.mitarbeiter_uid ?? - selectedLecturer.uid ?? - selectedLecturer.kurzbz; - expect(lecturerSearch, "lecturer search query").to.be.a("string").and - .not.be.empty; + tempusPage + .getCalendarEventsWithLecturer() + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; - tempusPage.getNavbarSearchInput().clear().type(lecturerSearch, { - parseSpecialCharSequences: false, - }); - waitForOk("@searchbarSearch"); + const selectedLecturer = tempusPage.getFirstLecturer( + JSON.parse(eventJSON), + ); + expect(selectedLecturer?.kurzbz, 'first event lecturer').to.exist; - tempusPage - .getFirstNavbarEmployeeSearchResult() - .should("be.visible") - .invoke("text") - .then((lecturerName) => { - const selectedLecturerName = lecturerName.trim(); + const lecturerSearch = + selectedLecturer.mitarbeiter_uid ?? + selectedLecturer.uid ?? + selectedLecturer.kurzbz; + expect(lecturerSearch, 'lecturer search query').to.be.a('string').and + .not.be.empty; - tempusPage.getFirstNavbarEmployeeSearchResult().click(); - waitForOk("@fetchPlanData"); - tempusPage.waitForCalendarToFinishLoading(); + tempusPage.getNavbarSearchInput().clear().type(lecturerSearch, { + parseSpecialCharSequences: false, + }); + waitForOk('@searchbarSearch'); - tempusPage - .getSelectedLecturerIndicator(selectedLecturerName) - .should("be.visible"); - tempusPage.getCalendarEvents().should("have.length.greaterThan", 0); - tempusPage.getCalendarEvents().each(($event) => { - const eventData = tempusPage.getCalendarEventData($event); - const eventLecturers = eventData?.orig?.lektor ?? []; + tempusPage + .getFirstNavbarEmployeeSearchResult() + .should('be.visible') + .invoke('text') + .then((lecturerName) => { + const selectedLecturerName = lecturerName.trim(); - expect( - eventLecturers.map((lecturer) => lecturer.kurzbz), - "event data lecturers", - ).to.include(selectedLecturer.kurzbz); - cy.wrap($event) - .find(".event-lectors") - .then(($lecturers) => { - const bodyLecturers = [...$lecturers].map((lecturer) => - lecturer.innerText.trim(), - ); + tempusPage.getFirstNavbarEmployeeSearchResult().click(); + waitForOk('@fetchPlanData'); + tempusPage.waitForCalendarToFinishLoading(); - expect(bodyLecturers, "event body lecturers").to.include( - selectedLecturer.kurzbz, - ); - }); - }); - }); - }); - }); + tempusPage + .getSelectedLecturerIndicator(selectedLecturerName) + .should('be.visible'); + tempusPage.getCalendarEvents().should('have.length.greaterThan', 0); + tempusPage.getCalendarEvents().each(($event) => { + const eventData = tempusPage.getCalendarEventData($event); + const eventLecturers = eventData?.orig?.lektor ?? []; - it("restores all calendar events after removing a lecturer filter", () => { - tempusPage.waitForCalendarToFinishLoading(); + expect( + eventLecturers.map((lecturer) => lecturer.kurzbz), + 'event data lecturers', + ).to.include(selectedLecturer.kurzbz); + cy.wrap($event) + .find('.event-lectors') + .then(($lecturers) => { + const bodyLecturers = [...$lecturers].map((lecturer) => + lecturer.innerText.trim(), + ); - tempusPage - .getCalendarEventsWithLecturer() - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; + expect(bodyLecturers, 'event body lecturers').to.include( + selectedLecturer.kurzbz, + ); + }); + }); + }); + }); + }); - const selectedLecturer = tempusPage.getFirstLecturer( - JSON.parse(eventJSON), - ); - expect(selectedLecturer?.kurzbz, "first event lecturer").to.exist; + it('restores all calendar events after removing a lecturer filter', () => { + tempusPage.waitForCalendarToFinishLoading(); - const lecturerSearch = - selectedLecturer.mitarbeiter_uid ?? - selectedLecturer.uid ?? - selectedLecturer.kurzbz; - expect(lecturerSearch, "lecturer search query").to.be.a("string").and - .not.be.empty; + tempusPage + .getCalendarEventsWithLecturer() + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; - tempusPage.getCalendarEvents().then(($events) => { - const originalEventCount = $events.length; - cy.wrap(originalEventCount).as("originalEventCount"); - }); + const selectedLecturer = tempusPage.getFirstLecturer( + JSON.parse(eventJSON), + ); + expect(selectedLecturer?.kurzbz, 'first event lecturer').to.exist; - tempusPage.getNavbarSearchInput().clear().type(lecturerSearch, { - parseSpecialCharSequences: false, - }); - waitForOk("@searchbarSearch"); + const lecturerSearch = + selectedLecturer.mitarbeiter_uid ?? + selectedLecturer.uid ?? + selectedLecturer.kurzbz; + expect(lecturerSearch, 'lecturer search query').to.be.a('string').and + .not.be.empty; - tempusPage - .getFirstNavbarEmployeeSearchResult() - .should("be.visible") - .invoke("text") - .then((lecturerName) => { - const selectedLecturerName = lecturerName.trim(); + tempusPage.getCalendarEvents().then(($events) => { + const originalEventCount = $events.length; + cy.wrap(originalEventCount).as('originalEventCount'); + }); - tempusPage.getFirstNavbarEmployeeSearchResult().click(); - waitForOk("@fetchPlanData"); - tempusPage.waitForCalendarToFinishLoading(); + tempusPage.getNavbarSearchInput().clear().type(lecturerSearch, { + parseSpecialCharSequences: false, + }); + waitForOk('@searchbarSearch'); - tempusPage - .getSelectedLecturerIndicator(selectedLecturerName) - .should("be.visible"); - tempusPage.getCalendarEvents().should("have.length.greaterThan", 0); + tempusPage + .getFirstNavbarEmployeeSearchResult() + .should('be.visible') + .invoke('text') + .then((lecturerName) => { + const selectedLecturerName = lecturerName.trim(); - tempusPage - .getSelectedLecturerRemoveButton(selectedLecturerName) - .click(); - waitForOk("@fetchPlanData"); - tempusPage.waitForCalendarToFinishLoading(); + tempusPage.getFirstNavbarEmployeeSearchResult().click(); + waitForOk('@fetchPlanData'); + tempusPage.waitForCalendarToFinishLoading(); - tempusPage - .getSelectedLecturerIndicator(selectedLecturerName) - .should("not.exist"); - cy.get("@originalEventCount").then((originalEventCount) => { - tempusPage - .getCalendarEvents() - .should("have.length", originalEventCount); - }); - }); - }); - }); + tempusPage + .getSelectedLecturerIndicator(selectedLecturerName) + .should('be.visible'); + tempusPage.getCalendarEvents().should('have.length.greaterThan', 0); - it("hides calendar events when the selected lecturer's plan is disabled", () => { - tempusPage.waitForCalendarToFinishLoading(); + tempusPage + .getSelectedLecturerRemoveButton(selectedLecturerName) + .click(); + waitForOk('@fetchPlanData'); + tempusPage.waitForCalendarToFinishLoading(); - tempusPage - .getCalendarEventsWithLecturer() - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; + tempusPage + .getSelectedLecturerIndicator(selectedLecturerName) + .should('not.exist'); + cy.get('@originalEventCount').then((originalEventCount) => { + tempusPage + .getCalendarEvents() + .should('have.length', originalEventCount); + }); + }); + }); + }); - const selectedLecturer = tempusPage.getFirstLecturer( - JSON.parse(eventJSON), - ); - expect(selectedLecturer?.kurzbz, "first event lecturer").to.exist; + it("hides calendar events when the selected lecturer's plan is disabled", () => { + tempusPage.waitForCalendarToFinishLoading(); - const lecturerSearch = - selectedLecturer.mitarbeiter_uid ?? - selectedLecturer.uid ?? - selectedLecturer.kurzbz; - expect(lecturerSearch, "lecturer search query").to.be.a("string").and - .not.be.empty; + tempusPage + .getCalendarEventsWithLecturer() + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; - tempusPage.getNavbarSearchInput().clear().type(lecturerSearch, { - parseSpecialCharSequences: false, - }); - waitForOk("@searchbarSearch"); + const selectedLecturer = tempusPage.getFirstLecturer( + JSON.parse(eventJSON), + ); + expect(selectedLecturer?.kurzbz, 'first event lecturer').to.exist; - tempusPage - .getFirstNavbarEmployeeSearchResult() - .should("be.visible") - .invoke("text") - .then((lecturerName) => { - const selectedLecturerName = lecturerName.trim(); + const lecturerSearch = + selectedLecturer.mitarbeiter_uid ?? + selectedLecturer.uid ?? + selectedLecturer.kurzbz; + expect(lecturerSearch, 'lecturer search query').to.be.a('string').and + .not.be.empty; - tempusPage.getFirstNavbarEmployeeSearchResult().click(); - waitForOk("@fetchPlanData"); - tempusPage.waitForCalendarToFinishLoading(); + tempusPage.getNavbarSearchInput().clear().type(lecturerSearch, { + parseSpecialCharSequences: false, + }); + waitForOk('@searchbarSearch'); - tempusPage - .getSelectedLecturerIndicator(selectedLecturerName) - .should("be.visible"); - tempusPage.getCalendarEvents().should("have.length.greaterThan", 0); + tempusPage + .getFirstNavbarEmployeeSearchResult() + .should('be.visible') + .invoke('text') + .then((lecturerName) => { + const selectedLecturerName = lecturerName.trim(); - tempusPage - .getSelectedLecturerPlanToggle(selectedLecturerName) - .click(); - tempusPage.getCalendarEvents().should("not.exist"); - }); - }); - }); + tempusPage.getFirstNavbarEmployeeSearchResult().click(); + waitForOk('@fetchPlanData'); + tempusPage.waitForCalendarToFinishLoading(); - it("toggles wish overlays for the selected lecturer", () => { - tempusPage.waitForCalendarToFinishLoading(); + tempusPage + .getSelectedLecturerIndicator(selectedLecturerName) + .should('be.visible'); + tempusPage.getCalendarEvents().should('have.length.greaterThan', 0); - tempusPage - .getCalendarEventsWithLecturer() - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; + tempusPage + .getSelectedLecturerPlanToggle(selectedLecturerName) + .click(); + tempusPage.getCalendarEvents().should('not.exist'); + }); + }); + }); - const selectedLecturer = tempusPage.getFirstLecturer( - JSON.parse(eventJSON), - ); - expect(selectedLecturer?.kurzbz, "first event lecturer").to.exist; + it('toggles wish overlays for the selected lecturer', () => { + tempusPage.waitForCalendarToFinishLoading(); - const lecturerSearch = - selectedLecturer.mitarbeiter_uid ?? - selectedLecturer.uid ?? - selectedLecturer.kurzbz; - expect(lecturerSearch, "lecturer search query").to.be.a("string").and - .not.be.empty; + tempusPage + .getCalendarEventsWithLecturer() + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; - tempusPage.getNavbarSearchInput().clear().type(lecturerSearch, { - parseSpecialCharSequences: false, - }); - waitForOk("@searchbarSearch"); + const selectedLecturer = tempusPage.getFirstLecturer( + JSON.parse(eventJSON), + ); + expect(selectedLecturer?.kurzbz, 'first event lecturer').to.exist; - tempusPage - .getFirstNavbarEmployeeSearchResult() - .should("be.visible") - .invoke("text") - .then((lecturerName) => { - const selectedLecturerName = lecturerName.trim(); + const lecturerSearch = + selectedLecturer.mitarbeiter_uid ?? + selectedLecturer.uid ?? + selectedLecturer.kurzbz; + expect(lecturerSearch, 'lecturer search query').to.be.a('string').and + .not.be.empty; - tempusPage.getFirstNavbarEmployeeSearchResult().click(); - waitForOk("@fetchPlanData"); + tempusPage.getNavbarSearchInput().clear().type(lecturerSearch, { + parseSpecialCharSequences: false, + }); + waitForOk('@searchbarSearch'); - tempusPage.waitForCalendarToFinishLoading(); + tempusPage + .getFirstNavbarEmployeeSearchResult() + .should('be.visible') + .invoke('text') + .then((lecturerName) => { + const selectedLecturerName = lecturerName.trim(); - tempusPage - .getSelectedLecturerIndicator(selectedLecturerName) - .should("be.visible"); - tempusPage - .getSelectedLecturerWishToggle(selectedLecturerName) - .should("be.visible") - .click(); - tempusPage.getLecturerWishOverlays().should("have.length", 0); + tempusPage.getFirstNavbarEmployeeSearchResult().click(); + waitForOk('@fetchPlanData'); - tempusPage - .getSelectedLecturerWishToggle(selectedLecturerName) - .should("be.visible") - .click(); - tempusPage - .getLecturerWishOverlays() - .should("have.length.greaterThan", 0); - }); - }); - }); + tempusPage.waitForCalendarToFinishLoading(); + + tempusPage + .getSelectedLecturerIndicator(selectedLecturerName) + .should('be.visible'); + tempusPage + .getSelectedLecturerWishToggle(selectedLecturerName) + .should('be.visible') + .click(); + tempusPage.getLecturerWishOverlays().should('have.length', 0); + + tempusPage + .getSelectedLecturerWishToggle(selectedLecturerName) + .should('be.visible') + .click(); + tempusPage + .getLecturerWishOverlays() + .should('have.length.greaterThan', 0); + }); + }); + }); }); diff --git a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.roles.cy.js b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.roles.cy.js index ab4052886..2f2803d27 100644 --- a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.roles.cy.js +++ b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.roles.cy.js @@ -1,335 +1,383 @@ -import { waitForOk } from "../../../../support/helpers/network"; -import { tempusApi } from "../../../../support/api/tempusApi"; +import { waitForOk } from '../../../../support/helpers/network'; +import { tempusApi } from '../../../../support/api/tempusApi'; import { - LEKTOR, - PLANER, - STUDENT, - tempusPage, -} from "../../../../support/pages/tempus.po"; + LEKTOR, + PLANER, + STUDENT, + tempusPage, +} from '../../../../support/pages/tempus.po'; -context("Tempus role preview tests", () => { - beforeEach(() => { - tempusPage.visitAndWaitForPlanner(); +context('Tempus role preview tests', () => { + before(() => { + cy.login(); - tempusApi.deletePlannerEventsForDay("monday"); - }); + let settingsData = tempusApi.getSettingsData(); + settingsData.ignore_kollision = true; + settingsData.roomless_planning = false; + settingsData.room_planning = 'dialog_room_planning'; + tempusApi.updateSettingsData(settingsData); + }); + beforeEach(() => { + tempusPage.visitAndWaitForPlanner(); - it("shows the same number of calendar events for all role previews", () => { - const rolePreviews = [PLANER, LEKTOR, STUDENT]; - const eventCounts = {}; + tempusApi.deletePlannerEventsForDay('monday'); + }); - tempusPage.syncAndReloadPlanner(); + it('shows the same number of calendar events for all role previews', () => { + const rolePreviews = [PLANER, LEKTOR, STUDENT]; + const eventCounts = {}; - cy.wrap(rolePreviews) - .each((role) => { - tempusPage.selectRoleAndWait(role); + tempusPage.syncAndReloadPlanner(); - tempusPage.getCalendarEvents().then(($events) => { - eventCounts[role] = $events.length; - }); - }) - .then(() => { - const expectedCount = eventCounts[rolePreviews[0]]; + cy.wrap(rolePreviews) + .each((role) => { + tempusPage.selectRoleAndWait(role); - Object.entries(eventCounts).forEach(([role, count]) => { - expect(count, `${role} calendar event count`).to.eq(expectedCount); - }); - }); - }); + tempusPage.getCalendarEvents().then(($events) => { + eventCounts[role] = $events.length; + }); + }) + .then(() => { + const expectedCount = eventCounts[rolePreviews[0]]; - it("keeps events unchanged in lecturer and student previews after a planner edit", () => { - tempusPage.syncAndReloadPlanner(); + Object.entries(eventCounts).forEach(([role, count]) => { + expect(count, `${role} calendar event count`).to.eq(expectedCount); + }); + }); + }); - tempusPage - .getCalendarEventsByTimeRange("13:35:00", "14:20:00") - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; + it('keeps events unchanged in lecturer and student previews after a planner edit', () => { + tempusPage.syncAndReloadPlanner(); - let eventId = JSON.parse(eventJSON)?.id; - expect(eventId).to.exist; + tempusPage + .getCalendarEventsByTimeRange('13:35:00', '14:20:00') + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; - tempusPage.dropEventOnCalendarPart(eventId, 3, { - scrollIntoView: true, - }); + let eventId = JSON.parse(eventJSON)?.id; + expect(eventId).to.exist; - cy.wait("@updateCalendarEvent").then((interception) => { - expect(interception.response.statusCode).to.eq(200); - expect(interception.response.body.data).to.exist; + tempusPage.dropEventOnCalendarPart(eventId, 3, { + scrollIntoView: true, + }); - const updatedEventGroupId = - interception.response.body.data?.eindeutige_kalender_gruppen_id ?? - interception.response.body.data; + cy.wait('@updateCalendarEvent').then((interception) => { + expect(interception.response.statusCode).to.eq(200); + expect(interception.response.body.data).to.exist; - cy.wrap(updatedEventGroupId).as("updatedEventGroupId"); - }); - waitForOk("@fetchPlanData"); + const updatedEventGroupId = + interception.response.body.data?.eindeutige_kalender_gruppen_id ?? + interception.response.body.data; - cy.get("@updatedEventGroupId").then((updatedEventGroupId) => { - tempusPage.getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId).then((gridRowStyle) => { - tempusPage.selectRoleAndWait(LEKTOR); - tempusPage.getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId).then((lecturerGridRow) => { - expect(lecturerGridRow).to.not.eq(gridRowStyle); - }); + cy.wrap(updatedEventGroupId).as('updatedEventGroupId'); + }); + waitForOk('@fetchPlanData'); - tempusPage.selectRoleAndWait(STUDENT); - tempusPage.getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId).then((studentGridRow) => { - expect(studentGridRow).to.not.eq(gridRowStyle); - }); - }); - }); - }); + cy.get('@updatedEventGroupId').then((updatedEventGroupId) => { + tempusPage + .getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId) + .then((gridRowStyle) => { + tempusPage.selectRoleAndWait(LEKTOR); + tempusPage + .getGridRowByContainingUniqueCalendarGroupId( + updatedEventGroupId, + ) + .then((lecturerGridRow) => { + expect(lecturerGridRow).to.not.eq(gridRowStyle); + }); - cy.get(".fhc-calendar-base-grid > div:last-child()").invoke( - "css", - "overflow", - "auto", - ); - }); + tempusPage.selectRoleAndWait(STUDENT); + tempusPage + .getGridRowByContainingUniqueCalendarGroupId( + updatedEventGroupId, + ) + .then((studentGridRow) => { + expect(studentGridRow).to.not.eq(gridRowStyle); + }); + }); + }); + }); - it("keeps events unchanged in lecturer and student previews after a planner edit and syncing", () => { - tempusPage.syncAndReloadPlanner(); + cy.get('.fhc-calendar-base-grid > div:last-child()').invoke( + 'css', + 'overflow', + 'auto', + ); + }); - tempusPage - .getCalendarEventsBySoftTimeRange("13:35:00", "14:20:00") - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; + it('keeps events unchanged in lecturer and student previews after a planner edit and syncing', () => { + tempusPage.syncAndReloadPlanner(); - let eventId = JSON.parse(eventJSON)?.id; - expect(eventId).to.exist; + tempusPage + .getCalendarEventsBySoftTimeRange('13:35:00', '14:20:00') + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; - tempusPage.dropEventOnCalendarPart(eventId, 4, { - scrollIntoView: true, - }); + let eventId = JSON.parse(eventJSON)?.id; + expect(eventId).to.exist; - cy.wait("@updateCalendarEvent").then((interception) => { - expect(interception.response.statusCode).to.eq(200); - expect(interception.response.body.data).to.exist; - - const updatedEventGroupId = - interception.response.body.data?.eindeutige_kalender_gruppen_id ?? - interception.response.body.data; + tempusPage.dropEventOnCalendarPart(eventId, 4, { + scrollIntoView: true, + }); - cy.wrap(updatedEventGroupId).as("updatedEventGroupId"); - }); - waitForOk("@fetchPlanData"); + cy.wait('@updateCalendarEvent').then((interception) => { + expect(interception.response.statusCode).to.eq(200); + expect(interception.response.body.data).to.exist; - tempusPage.syncAndReloadPlanner(); + const updatedEventGroupId = + interception.response.body.data?.eindeutige_kalender_gruppen_id ?? + interception.response.body.data; - cy.get("@updatedEventGroupId").then((updatedEventGroupId) => { - tempusPage.getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId).then((gridRowStyle) => { - tempusPage.selectRoleAndWait(LEKTOR); - tempusPage - .getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId) - .then((lecturerGridRow) => { - expect(lecturerGridRow).not.to.eq(gridRowStyle); - }); + cy.wrap(updatedEventGroupId).as('updatedEventGroupId'); + }); + waitForOk('@fetchPlanData'); - tempusPage.selectRoleAndWait(STUDENT); - tempusPage - .getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId) - .then((studentGridRow) => { - expect(studentGridRow).not.to.eq(gridRowStyle); - }); - }); - }); - }); - }); + tempusPage.syncAndReloadPlanner(); - it("updates events in the lecturer preview but not the student preview after releasing and syncing", () => { - tempusPage.syncAndReloadPlanner(); + cy.get('@updatedEventGroupId').then((updatedEventGroupId) => { + tempusPage + .getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId) + .then((gridRowStyle) => { + tempusPage.selectRoleAndWait(LEKTOR); + tempusPage + .getGridRowByContainingUniqueCalendarGroupId( + updatedEventGroupId, + ) + .then((lecturerGridRow) => { + expect(lecturerGridRow).not.to.eq(gridRowStyle); + }); - tempusPage - .getCalendarEventsBySoftTimeRange("13:35:00", "14:20:00") - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; + tempusPage.selectRoleAndWait(STUDENT); + tempusPage + .getGridRowByContainingUniqueCalendarGroupId( + updatedEventGroupId, + ) + .then((studentGridRow) => { + expect(studentGridRow).not.to.eq(gridRowStyle); + }); + }); + }); + }); + }); - const eventId = JSON.parse(eventJSON)?.id; - expect(eventId).to.exist; + it('updates events in the lecturer preview but not the student preview after releasing and syncing', () => { + tempusPage.syncAndReloadPlanner(); - const updatedEventGroupId = JSON.parse(eventJSON)?.orig?.eindeutige_kalender_gruppen_id; - expect(updatedEventGroupId).to.exist; + tempusPage + .getCalendarEventsBySoftTimeRange('13:35:00', '14:20:00') + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; - tempusPage.dropEventOnCalendarPart(eventId, 4, { - scrollIntoView: true, - }); + const eventId = JSON.parse(eventJSON)?.id; + expect(eventId).to.exist; - cy.wait("@updateCalendarEvent").then((interception) => { - expect(interception.response.statusCode).to.eq(200); - expect(interception.response.body.data).to.exist; + const updatedEventGroupId = + JSON.parse(eventJSON)?.orig?.eindeutige_kalender_gruppen_id; + expect(updatedEventGroupId).to.exist; - const updatedEventGroupId = - interception.response.body.data?.eindeutige_kalender_gruppen_id ?? - interception.response.body.data; + tempusPage.dropEventOnCalendarPart(eventId, 4, { + scrollIntoView: true, + }); - cy.wrap(updatedEventGroupId).as("updatedEventGroupId"); - }); - waitForOk("@fetchPlanData"); + cy.wait('@updateCalendarEvent').then((interception) => { + expect(interception.response.statusCode).to.eq(200); + expect(interception.response.body.data).to.exist; - tempusPage.getCalendarEventByUniqueCalenderGroupId(updatedEventGroupId).rightclick(); - tempusPage - .getEventContextMenuOption("Freischalten für Voransicht") - .click({ force: true }); - waitForOk("@syncCalendarToLecturer"); - waitForOk("@fetchPlanData"); + const updatedEventGroupId = + interception.response.body.data?.eindeutige_kalender_gruppen_id ?? + interception.response.body.data; - tempusPage.syncAndReloadPlanner(); + cy.wrap(updatedEventGroupId).as('updatedEventGroupId'); + }); + waitForOk('@fetchPlanData'); - cy.get("@updatedEventGroupId").then((updatedEventGroupId) => { - tempusPage - .getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId) - .then((plannerGridRow) => { - tempusPage.selectRoleAndWait(LEKTOR); - tempusPage - .getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId) - .then((lecturerGridRow) => { - expect(lecturerGridRow).to.eq(plannerGridRow); - }); + tempusPage + .getCalendarEventByUniqueCalenderGroupId(updatedEventGroupId) + .rightclick(); + tempusPage + .getEventContextMenuOption('Freischalten für Voransicht') + .click({ force: true }); + waitForOk('@syncCalendarToLecturer'); + waitForOk('@fetchPlanData'); - tempusPage.selectRoleAndWait(STUDENT); - tempusPage - .getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId) - .then((studentGridRow) => { - expect(studentGridRow).not.to.eq(plannerGridRow); - }); - }); - }); - }); - }); + tempusPage.syncAndReloadPlanner(); - it("updates events in the lecturer and student previews after releasing for live and syncing", () => { - tempusPage.syncAndReloadPlanner(); + cy.get('@updatedEventGroupId').then((updatedEventGroupId) => { + tempusPage + .getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId) + .then((plannerGridRow) => { + tempusPage.selectRoleAndWait(LEKTOR); + tempusPage + .getGridRowByContainingUniqueCalendarGroupId( + updatedEventGroupId, + ) + .then((lecturerGridRow) => { + expect(lecturerGridRow).to.eq(plannerGridRow); + }); - tempusPage - .getCalendarEventsBySoftTimeRange("13:35:00", "14:20:00") - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; + tempusPage.selectRoleAndWait(STUDENT); + tempusPage + .getGridRowByContainingUniqueCalendarGroupId( + updatedEventGroupId, + ) + .then((studentGridRow) => { + expect(studentGridRow).not.to.eq(plannerGridRow); + }); + }); + }); + }); + }); - const eventId = JSON.parse(eventJSON)?.id; - expect(eventId).to.exist; - const updatedEventGroupId = - JSON.parse(eventJSON)?.orig?.eindeutige_kalender_gruppen_id; - expect(updatedEventGroupId).to.exist; + it('updates events in the lecturer and student previews after releasing for live and syncing', () => { + tempusPage.syncAndReloadPlanner(); - tempusPage.dropEventOnCalendarPart(eventId, 4, { - scrollIntoView: true, - }); + tempusPage + .getCalendarEventsBySoftTimeRange('13:35:00', '14:20:00') + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; - cy.wait("@updateCalendarEvent").then((interception) => { - expect(interception.response.statusCode).to.eq(200); - expect(interception.response.body.data).to.exist; + const eventId = JSON.parse(eventJSON)?.id; + expect(eventId).to.exist; + const updatedEventGroupId = + JSON.parse(eventJSON)?.orig?.eindeutige_kalender_gruppen_id; + expect(updatedEventGroupId).to.exist; - const updatedEventGroupId = - interception.response.body.data?.eindeutige_kalender_gruppen_id ?? - interception.response.body.data; + tempusPage.dropEventOnCalendarPart(eventId, 4, { + scrollIntoView: true, + }); - cy.wrap(updatedEventGroupId).as("updatedEventGroupId"); - }); - waitForOk("@fetchPlanData"); + cy.wait('@updateCalendarEvent').then((interception) => { + expect(interception.response.statusCode).to.eq(200); + expect(interception.response.body.data).to.exist; - tempusPage - .getCalendarEventByUniqueCalenderGroupId(updatedEventGroupId) - .rightclick(); - tempusPage - .getEventContextMenuOption("Freischalten für Live") - .click({ force: true }); - waitForOk("@syncCalendarToStudent"); - waitForOk("@fetchPlanData"); + const updatedEventGroupId = + interception.response.body.data?.eindeutige_kalender_gruppen_id ?? + interception.response.body.data; - tempusPage.syncAndReloadPlanner(); + cy.wrap(updatedEventGroupId).as('updatedEventGroupId'); + }); + waitForOk('@fetchPlanData'); - cy.get("@updatedEventGroupId").then((updatedEventGroupId) => { - tempusPage - .getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId) - .then((plannerGridRow) => { - tempusPage.selectRoleAndWait(LEKTOR); - tempusPage - .getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId) - .then((lecturerGridRow) => { - expect(lecturerGridRow).to.eq(plannerGridRow); - }); + tempusPage + .getCalendarEventByUniqueCalenderGroupId(updatedEventGroupId) + .rightclick(); + tempusPage + .getEventContextMenuOption('Freischalten für Live') + .click({ force: true }); + waitForOk('@syncCalendarToStudent'); + waitForOk('@fetchPlanData'); - tempusPage.selectRoleAndWait(STUDENT); - tempusPage - .getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId) - .then((studentGridRow) => { - expect(studentGridRow).to.eq(plannerGridRow); - }); - }); - }); - }); - }); - - it("prevents event changes in the lecturer preview", () => { - tempusPage.syncAndReloadPlanner(); + tempusPage.syncAndReloadPlanner(); - tempusPage.selectRoleAndWait(LEKTOR); + cy.get('@updatedEventGroupId').then((updatedEventGroupId) => { + tempusPage + .getGridRowByContainingUniqueCalendarGroupId(updatedEventGroupId) + .then((plannerGridRow) => { + tempusPage.selectRoleAndWait(LEKTOR); + tempusPage + .getGridRowByContainingUniqueCalendarGroupId( + updatedEventGroupId, + ) + .then((lecturerGridRow) => { + expect(lecturerGridRow).to.eq(plannerGridRow); + }); - tempusPage - .getCalendarEventsBySoftTimeRange("08:00:00", "14:20:00") - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; + tempusPage.selectRoleAndWait(STUDENT); + tempusPage + .getGridRowByContainingUniqueCalendarGroupId( + updatedEventGroupId, + ) + .then((studentGridRow) => { + expect(studentGridRow).to.eq(plannerGridRow); + }); + }); + }); + }); + }); - let eventId = JSON.parse(eventJSON)?.id; - expect(eventId).to.exist; + it('prevents event changes in the lecturer preview', () => { + tempusPage.syncAndReloadPlanner(); - tempusPage.dropEventOnCalendarPart(eventId, 15); + tempusPage.selectRoleAndWait(LEKTOR); - cy.get("@updateCalendarEvent").should("not.exist"); + tempusPage + .getCalendarEventsBySoftTimeRange('08:00:00', '14:20:00') + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; - tempusPage.getGridRowByContainingEventId(eventId).then((gridRowStyle) => { - tempusPage.selectRoleAndWait(LEKTOR); - tempusPage.getGridRowByContainingEventId(eventId).then((lecturerGridRow) => { - expect(lecturerGridRow).to.eq(gridRowStyle); - }); + let eventId = JSON.parse(eventJSON)?.id; + expect(eventId).to.exist; - tempusPage.selectRoleAndWait(STUDENT); - tempusPage.getGridRowByContainingEventId(eventId).then((studentGridRow) => { - expect(studentGridRow).to.eq(gridRowStyle); - }); - }); - }); - }); + tempusPage.dropEventOnCalendarPart(eventId, 15); - it("prevents event changes in the student preview", () => { - tempusPage.syncAndReloadPlanner(); + cy.get('@updateCalendarEvent').should('not.exist'); - tempusPage.selectRoleAndWait(STUDENT); + tempusPage + .getGridRowByContainingEventId(eventId) + .then((gridRowStyle) => { + tempusPage.selectRoleAndWait(LEKTOR); + tempusPage + .getGridRowByContainingEventId(eventId) + .then((lecturerGridRow) => { + expect(lecturerGridRow).to.eq(gridRowStyle); + }); - tempusPage - .getCalendarEventsBySoftTimeRange("08:00:00", "14:20:00") - .first() - .invoke("attr", "data-fhc-draggable-value") - .then((eventJSON) => { - expect(eventJSON).to.exist; + tempusPage.selectRoleAndWait(STUDENT); + tempusPage + .getGridRowByContainingEventId(eventId) + .then((studentGridRow) => { + expect(studentGridRow).to.eq(gridRowStyle); + }); + }); + }); + }); - let eventId = JSON.parse(eventJSON)?.id; - expect(eventId).to.exist; + it('prevents event changes in the student preview', () => { + tempusPage.syncAndReloadPlanner(); - tempusPage.dropEventOnCalendarPart(eventId, 15); + tempusPage.selectRoleAndWait(STUDENT); - cy.get("@updateCalendarEvent").should("not.exist"); + tempusPage + .getCalendarEventsBySoftTimeRange('08:00:00', '14:20:00') + .first() + .invoke('attr', 'data-fhc-draggable-value') + .then((eventJSON) => { + expect(eventJSON).to.exist; - tempusPage.getGridRowByContainingEventId(eventId).then((gridRowStyle) => { - tempusPage.selectRoleAndWait(LEKTOR); - tempusPage.getGridRowByContainingEventId(eventId).then((lecturerGridRow) => { - expect(lecturerGridRow).to.eq(gridRowStyle); - }); + let eventId = JSON.parse(eventJSON)?.id; + expect(eventId).to.exist; - tempusPage.selectRoleAndWait(STUDENT); - tempusPage.getGridRowByContainingEventId(eventId).then((studentGridRow) => { - expect(studentGridRow).to.eq(gridRowStyle); - }); - }); - }); - }); + tempusPage.dropEventOnCalendarPart(eventId, 15); + + cy.get('@updateCalendarEvent').should('not.exist'); + + tempusPage + .getGridRowByContainingEventId(eventId) + .then((gridRowStyle) => { + tempusPage.selectRoleAndWait(LEKTOR); + tempusPage + .getGridRowByContainingEventId(eventId) + .then((lecturerGridRow) => { + expect(lecturerGridRow).to.eq(gridRowStyle); + }); + + tempusPage.selectRoleAndWait(STUDENT); + tempusPage + .getGridRowByContainingEventId(eventId) + .then((studentGridRow) => { + expect(studentGridRow).to.eq(gridRowStyle); + }); + }); + }); + }); }); diff --git a/tests/cypress/cypress/support/pages/tempus.po.js b/tests/cypress/cypress/support/pages/tempus.po.js index a7e8067f1..583573055 100644 --- a/tests/cypress/cypress/support/pages/tempus.po.js +++ b/tests/cypress/cypress/support/pages/tempus.po.js @@ -1,609 +1,668 @@ -import { waitForOk } from "../helpers/network"; +import { waitForOk } from '../helpers/network'; -export const PLANER = "Planer"; -export const LEKTOR = "Lektor"; -export const STUDENT = "Student"; -export const SYNC = "Sync"; +export const PLANER = 'Planer'; +export const LEKTOR = 'Lektor'; +export const STUDENT = 'Student'; +export const SYNC = 'Sync'; const weekdayToGridRowMap = { - Monday: "1", - Tuesday: "2", - Wednesday: "3", - Thursday: "4", - Friday: "5", - Saturday: "6", - Sunday: "7", + Monday: '1', + Tuesday: '2', + Wednesday: '3', + Thursday: '4', + Friday: '5', + Saturday: '6', + Sunday: '7', }; const roleFetchAliases = { - [PLANER]: "@fetchPlanData", - [LEKTOR]: "@fetchLecturerPlanData", - [STUDENT]: "@fetchStudentPlanData", + [PLANER]: '@fetchPlanData', + [LEKTOR]: '@fetchLecturerPlanData', + [STUDENT]: '@fetchStudentPlanData', }; class TempusPage { - selectors = { - calendarBaseGrid: "div[data-cy='tempus'] [data-cy='calendar-base-grid']", - parkingSlot: "div[data-cy='tempus'] #parkingslot", - }; + selectors = { + calendarBaseGrid: "div[data-cy='tempus'] [data-cy='calendar-base-grid']", + parkingSlot: "div[data-cy='tempus'] #parkingslot", + }; - // Test setup - visit = () => { - const { adminusername, adminpassword } = Cypress.env(); + // Test setup + visit = () => { + const { adminusername, adminpassword } = Cypress.env(); - return cy.visit("/index.ci.php/tempus", { - auth: { - username: adminusername, - password: adminpassword, - }, - onBeforeLoad(win) { - win.localStorage.removeItem("tempus_parking"); - win.localStorage.removeItem("tempus_searchtypes"); - win.sessionStorage.removeItem("tempus_searchstr"); - }, - }); - }; + return cy.visit('/index.ci.php/tempus', { + auth: { + username: adminusername, + password: adminpassword, + }, + onBeforeLoad(win) { + win.localStorage.removeItem('tempus_parking'); + win.localStorage.removeItem('tempus_searchtypes'); + win.sessionStorage.removeItem('tempus_searchstr'); + }, + }); + }; - setupIntercepts = () => { - cy.intercept({ - method: "GET", - url: "**/tempus/Info/getStudiengaenge", - }).as("fetchCourseTree"); - cy.intercept({ - method: "POST", - url: /\/tempus\/Kalender\/getPlan(?:\?|$)/, - }).as("fetchPlanData"); - cy.intercept({ - method: "GET", - url: /\/tempus\/Kalender\/getPlanLecturer(?:\?|$)/, - }).as("fetchLecturerPlanData"); - cy.intercept({ - method: "GET", - url: /\/tempus\/Kalender\/getPlanStudent(?:\?|$)/, - }).as("fetchStudentPlanData"); - cy.intercept({ method: "GET", url: "**/tempus/Kalender/getHistory**" }).as( - "fetchEventHistory", - ); - cy.intercept({ - method: "GET", - url: "**/organisation/studiensemester/current**", - }).as("getCurrentSemester"); - cy.intercept({ - method: "POST", - url: "**/organisation/studiensemester/set**", - }).as("setSemester"); - cy.intercept({ - method: "POST", - url: "**/tempus/Kalender/getRaumvorschlag**", - }).as("fetchRoomSuggestions"); - cy.intercept({ - method: "GET", - url: "**/tempus/OperationalResourceToCalenderAPI/getSchedulableResourcesByCalendar/**", - }).as("fetchResourcesSuggestions"); - cy.intercept({ - method: "GET", - url: "**/tempus/OperationalResourceToCalenderAPI/getAssignedResourcesByCalender/**", - }).as("fetchAssignedResources"); - cy.intercept({ - method: "GET", - url: "**/tempus/Tags/getTags**", - }).as("fetchTags"); - cy.intercept({ - method: "GET", - url: "**/tempus/Tags/getTagsByCalendar/**", - }).as("fetchTagsByCalendar"); - cy.intercept({ - method: "POST", - url: "**/tempus/coursepicker/getCourses**", - }).as("fetchCoursePickerCourses"); - cy.intercept({ - method: "POST", - url: "**/searchbar/search**", - }).as("searchbarSearch"); - cy.intercept({ - method: "POST", - url: "**/tempus/Kalender/addKalenderEvent**", - }).as("addCalendarEvent"); - cy.intercept({ - method: "POST", - url: "**/tempus/Kalender/updateKalenderEvent**", - }).as("updateCalendarEvent"); - cy.intercept({ - method: "POST", - url: "**/tempus/Kalender/deleteEntry**", - }).as("deleteCalendarEvent"); - cy.intercept({ - method: "POST", - url: "**/tempus/Kalender/sync**", - }).as("syncCalendar"); - cy.intercept({ - method: "POST", - url: "**/tempus/Kalender/syncToLecturer**", - }).as("syncCalendarToLecturer"); - cy.intercept({ - method: "POST", - url: "**/tempus/Kalender/syncToStudent**", - }).as("syncCalendarToStudent"); - cy.intercept({ - method: "POST", - url: "**/tempus/Kalender/deleteEntry**", - }).as("deleteCalendarEvent"); - }; + setupIntercepts = () => { + cy.intercept({ + method: 'GET', + url: '**/tempus/Info/getStudiengaenge', + }).as('fetchCourseTree'); + cy.intercept({ + method: 'POST', + url: /\/tempus\/Kalender\/getPlan(?:\?|$)/, + }).as('fetchPlanData'); + cy.intercept({ + method: 'GET', + url: /\/tempus\/Kalender\/getPlanLecturer(?:\?|$)/, + }).as('fetchLecturerPlanData'); + cy.intercept({ + method: 'GET', + url: /\/tempus\/Kalender\/getPlanStudent(?:\?|$)/, + }).as('fetchStudentPlanData'); + cy.intercept({ method: 'GET', url: '**/tempus/Kalender/getHistory**' }).as( + 'fetchEventHistory', + ); + cy.intercept({ + method: 'GET', + url: '**/organisation/studiensemester/current**', + }).as('getCurrentSemester'); + cy.intercept({ + method: 'POST', + url: '**/organisation/studiensemester/set**', + }).as('setSemester'); + cy.intercept({ + method: 'POST', + url: '**/tempus/Kalender/getRaumvorschlag**', + }).as('fetchRoomSuggestions'); + cy.intercept({ + method: 'GET', + url: '**/tempus/OperationalResourceToCalenderAPI/getSchedulableResourcesByCalendar/**', + }).as('fetchResourcesSuggestions'); + cy.intercept({ + method: 'GET', + url: '**/tempus/OperationalResourceToCalenderAPI/getAssignedResourcesByCalender/**', + }).as('fetchAssignedResources'); + cy.intercept({ + method: 'GET', + url: '**/tempus/Tags/getTags**', + }).as('fetchTags'); + cy.intercept({ + method: 'GET', + url: '**/tempus/Tags/getTagsByCalendar/**', + }).as('fetchTagsByCalendar'); + cy.intercept({ + method: 'POST', + url: '**/tempus/coursepicker/getCourses**', + }).as('fetchCoursePickerCourses'); + cy.intercept({ + method: 'POST', + url: '**/searchbar/search**', + }).as('searchbarSearch'); + cy.intercept({ + method: 'POST', + url: '**/tempus/Kalender/addKalenderEvent**', + }).as('addCalendarEvent'); + cy.intercept({ + method: 'POST', + url: '**/tempus/Kalender/updateKalenderEvent**', + }).as('updateCalendarEvent'); + cy.intercept({ + method: 'POST', + url: '**/tempus/Kalender/deleteEntry**', + }).as('deleteCalendarEvent'); + cy.intercept({ + method: 'POST', + url: '**/tempus/Kalender/sync**', + }).as('syncCalendar'); + cy.intercept({ + method: 'POST', + url: '**/tempus/Kalender/syncToLecturer**', + }).as('syncCalendarToLecturer'); + cy.intercept({ + method: 'POST', + url: '**/tempus/Kalender/syncToStudent**', + }).as('syncCalendarToStudent'); + cy.intercept({ + method: 'POST', + url: '**/tempus/Kalender/deleteEntry**', + }).as('deleteCalendarEvent'); + }; - // Main page selectors - getTempusOverview = () => cy.get("div[data-cy='tempus']"); - getSlideInCoursesMenu = () => cy.get("div[data-cy='verbandMenu']"); - getSidebarMenu = () => this.getTempusOverview().find("#sidebarMenu"); - getCalendarSection = () => - this.getTempusOverview().find(".fhc-calendar-base"); - getCalendarBaseGrid = () => - this.getCalendarSection().find("[data-cy='calendar-base-grid']"); - getCalendarModeButtons = () => - this.getCalendarSection().find("[data-cy='calender-header-modes'] button"); - getCalendarTableRows = () => - this.getCalendarSection().find( - "[data-cy='calender-table-view'] .tabulator-row", - ); - getCoursePicker = () => this.getTempusOverview().find("[data-cy='coursepicker']"); - getPreviewRoleOptionsHolder = () => - this.getTempusOverview().find("[data-cy='previewRoleOptionsHolder']"); - getAllCoursesSliderBtn = () => - this.getSidebarMenu().find("button[title='Verband']").first(); - getCourseTreeRows = () => - this.getSlideInCoursesMenu() - .find("tbody tr td.text-break") - .closest("[role='cell']"); - getCourseTreeRowByName = (courseShortName) => - this.getSlideInCoursesMenu() - .contains("tbody tr td.text-break .treemenu-entry", courseShortName) - .closest("[role='cell']"); - getCoursePickerRows = () => this.getCoursePicker().find("[data-cy='coursepicker-row']"); - getCoursePickerSearchInput = () => this.getCoursePicker().find("input"); + // Main page selectors + getTempusOverview = () => cy.get("div[data-cy='tempus']"); + getSlideInCoursesMenu = () => cy.get("div[data-cy='verbandMenu']"); + getSidebarMenu = () => this.getTempusOverview().find('#sidebarMenu'); + getCalendarSection = () => + this.getTempusOverview().find('.fhc-calendar-base'); + getCalendarBaseGrid = () => + this.getCalendarSection().find("[data-cy='calendar-base-grid']"); + getCalendarModeButtons = () => + this.getCalendarSection().find("[data-cy='calender-header-modes'] button"); + getCalendarTableRows = () => + this.getCalendarSection().find( + "[data-cy='calender-table-view'] .tabulator-row", + ); + getCoursePicker = () => + this.getTempusOverview().find("[data-cy='coursepicker']"); + getPreviewRoleOptionsHolder = () => + this.getTempusOverview().find("[data-cy='previewRoleOptionsHolder']"); + getAllCoursesSliderBtn = () => + this.getSidebarMenu().find("button[title='Verband']").first(); + getCourseTreeRows = () => + this.getSlideInCoursesMenu() + .find('tbody tr td.text-break') + .closest("[role='cell']"); + getCourseTreeRowByName = (courseShortName) => + this.getSlideInCoursesMenu() + .contains('tbody tr td.text-break .treemenu-entry', courseShortName) + .closest("[role='cell']"); + getCoursePickerRows = () => + this.getCoursePicker().find("[data-cy='coursepicker-row']"); + getCoursePickerSearchInput = () => this.getCoursePicker().find('input'); - // Calendar selectors and filters - getCalendarEventsPerWeekHolders = () => - this.getCalendarBaseGrid().find(".fhc-calendar-base-grid-line"); - getCalendarEvents = () => - this.getCalendarSection().find("[data-cy='calendar-event']"); - getLecturerWishOverlays = () => - this.getCalendarSection().find(".bg-lecturer-wish"); - getCalendarEventsWithRoom = () => - this.getCalendarEvents().filter((index, event) => { - const eventData = JSON.parse( - event.getAttribute("data-fhc-draggable-value"), - ); + // Calendar selectors and filters + getCalendarEventsPerWeekHolders = () => + this.getCalendarBaseGrid().find('.fhc-calendar-base-grid-line'); + getCalendarEvents = () => + this.getCalendarSection().find("[data-cy='calendar-event']"); + getLecturerWishOverlays = () => + this.getCalendarSection().find('.bg-lecturer-wish'); + getCalendarEventsWithRoom = () => + this.getCalendarEvents().filter((index, event) => { + const eventData = JSON.parse( + event.getAttribute('data-fhc-draggable-value'), + ); - let isArray = Array.isArray(eventData?.orig?.ort_kurzbz); + let isArray = Array.isArray(eventData?.orig?.ort_kurzbz); - return isArray ? eventData?.orig?.ort_kurzbz.length > 0 : !!eventData?.orig?.ort_kurzbz; - }); - getCalendarEventsWithLecturer = () => - this.getCalendarEvents().filter((index, event) => { - const eventData = JSON.parse( - event.getAttribute("data-fhc-draggable-value"), - ); - return eventData?.orig?.lektor?.some((lecturer) => lecturer?.kurzbz); - }); - getCalendarEventsWithLehreinheit = () => - this.getCalendarEvents().filter((index, event) => { - const eventData = JSON.parse( - event.getAttribute("data-fhc-draggable-value"), - ); - const lehreinheitIds = eventData?.orig?.lehreinheit_id; + return isArray + ? eventData?.orig?.ort_kurzbz.length > 0 + : !!eventData?.orig?.ort_kurzbz; + }); + getCalendarEventsWithLecturer = () => + this.getCalendarEvents().filter((index, event) => { + const eventData = JSON.parse( + event.getAttribute('data-fhc-draggable-value'), + ); + return eventData?.orig?.lektor?.some((lecturer) => lecturer?.kurzbz); + }); + getCalendarEventsWithLehreinheit = () => + this.getCalendarEvents().filter((index, event) => { + const eventData = JSON.parse( + event.getAttribute('data-fhc-draggable-value'), + ); + const lehreinheitIds = eventData?.orig?.lehreinheit_id; - return Array.isArray(lehreinheitIds) - ? lehreinheitIds.length > 0 - : !!lehreinheitIds; - }); - getCalendarEventsWithLehreinheitAndRoom = () => - this.getCalendarEventsWithLehreinheit().filter((index, event) => { - const eventData = JSON.parse( - event.getAttribute("data-fhc-draggable-value"), - ); + return Array.isArray(lehreinheitIds) + ? lehreinheitIds.length > 0 + : !!lehreinheitIds; + }); + getCalendarEventsWithLehreinheitAndRoom = () => + this.getCalendarEventsWithLehreinheit().filter((index, event) => { + const eventData = JSON.parse( + event.getAttribute('data-fhc-draggable-value'), + ); - return !!eventData?.orig?.ort_kurzbz; - }); + return !!eventData?.orig?.ort_kurzbz; + }); - // Navbar filters - getNavbarSearchInput = () => - this.getTempusOverview().find("header .searchbar_input"); - getNavbarRoomSearchResult = (room) => { - const escapedRoom = room.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + // Navbar filters + getNavbarSearchInput = () => + this.getTempusOverview().find('header .searchbar_input'); + getNavbarRoomSearchResult = (room) => { + const escapedRoom = room.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - return cy.contains( - ".searchbar-result-room .searchbar-result-template-action", - new RegExp(`^\\s*${escapedRoom}\\s*$`), - ); - }; - getFirstNavbarEmployeeSearchResult = () => - cy - .get( - ".searchbar-result-student .searchbar_data .searchbar-result-template-action", - ) - .first(); - getSelectedRoomIndicator = (room) => - this.getSidebarMenu().contains(".room-selection", room); - getSelectedRoomRemoveButton = (room) => - this.getSelectedRoomIndicator(room).find("i.fa-xmark"); - getSelectedLecturerIndicator = (lecturer) => - this.getSidebarMenu().contains(".lecture-selection .fw-semibold", lecturer); - getSelectedLecturerRemoveButton = (lecturer) => - this.getSelectedLecturerIndicator(lecturer).find("i.fa-xmark"); - getSelectedLecturerPlanToggle = (lecturer) => - this.getSelectedLecturerIndicator(lecturer) - .parent() - .contains(".d-flex.align-items-center", "Plan"); - getSelectedLecturerWishToggle = (lecturer) => - this.getSelectedLecturerIndicator(lecturer) - .parent() - .contains(".d-flex.align-items-center", "Zeitwünsche"); + return cy.contains( + '.searchbar-result-room .searchbar-result-template-action', + new RegExp(`^\\s*${escapedRoom}\\s*$`), + ); + }; + getFirstNavbarEmployeeSearchResult = () => + cy + .get( + '.searchbar-result-student .searchbar_data .searchbar-result-template-action', + ) + .first(); + getSelectedRoomIndicator = (room) => + this.getSidebarMenu().contains('.room-selection', room); + getSelectedRoomRemoveButton = (room) => + this.getSelectedRoomIndicator(room).find('i.fa-xmark'); + getSelectedLecturerIndicator = (lecturer) => + this.getSidebarMenu().contains('.lecture-selection .fw-semibold', lecturer); + getSelectedLecturerRemoveButton = (lecturer) => + this.getSelectedLecturerIndicator(lecturer).find('i.fa-xmark'); + getSelectedLecturerPlanToggle = (lecturer) => + this.getSelectedLecturerIndicator(lecturer) + .parent() + .contains('.d-flex.align-items-center', 'Plan'); + getSelectedLecturerWishToggle = (lecturer) => + this.getSelectedLecturerIndicator(lecturer) + .parent() + .contains('.d-flex.align-items-center', 'Zeitwünsche'); - // Calendar event selectors and data helpers - getCalendarEventById = (id) => - this.getCalendarEvents().filter(`div[data-id="event-${id}"]`); - getCalendarEventByUniqueCalenderGroupId = (groupId) => - this.getCalendarEvents().filter(`div[data-group-id="event-group-${groupId}"]`); - getCalendarPartDropTarget = (partIndex) => - `${this.selectors.calendarBaseGrid} [data-cy='calendar-grid-part'][data-drop-index='${partIndex}']`; - getEventGridRowFromStyle = (style) => - /grid-row:\s*([^;]+)/.exec(style)?.[1]?.trim(); - getGridRowByContainingEventId = (id) => - this.getCalendarEventById(id) - .invoke("attr", "style") - .then((style) => this.getEventGridRowFromStyle(style)); - getGridRowByContainingUniqueCalendarGroupId = (groupId) => - this.getCalendarEventByUniqueCalenderGroupId(groupId) - .invoke("attr", "style") - .then((style) => this.getEventGridRowFromStyle(style)); - getCalendarEventsByWeekday = (weekday) => - this.getCalendarEventsPerWeekHolders() - .eq(weekdayToGridRowMap[weekday] - 1) - .find("[data-cy='calendar-event']"); - getCalendarEventsByStartTime = (startTime) => - this.getCalendarEvents().filter((index, event) => { - const eventData = JSON.parse( - event.getAttribute("data-fhc-draggable-value"), - ); - return eventData?.orig?.beginn === startTime; - }); - getCalendarEventsByTimeRange = (startTime, endTime) => - this.getCalendarEvents().filter((index, event) => { - const eventData = JSON.parse( - event.getAttribute("data-fhc-draggable-value"), - ); - return ( - eventData?.orig?.beginn === startTime && - eventData?.orig?.ende === endTime - ); - }); - getCalendarEventsBySoftTimeRange = (startTime, endTime) => - this.getCalendarEvents().filter((index, event) => { - const eventData = JSON.parse( - event.getAttribute("data-fhc-draggable-value"), - ); - return ( - eventData?.orig?.beginn >= startTime && eventData?.orig?.ende <= endTime - ); - }); - getCalendarEventsByWeekdayAndStartTime = (weekday, startTime) => - this.getCalendarEventsByWeekday(weekday).filter((index, event) => { - const eventData = JSON.parse( - event.getAttribute("data-fhc-draggable-value"), - ); - return eventData?.orig?.beginn === startTime; - }); - getCalendarEventsByWeekdayAndTimeRange = (weekday, startTime, endTime) => - this.getCalendarEventsByWeekday(weekday).filter((index, event) => { - const eventData = JSON.parse( - event.getAttribute("data-fhc-draggable-value"), - ); + // Calendar event selectors and data helpers + getCalendarEventById = (id) => + this.getCalendarEvents().filter(`div[data-id="event-${id}"]`); + getCalendarEventByUniqueCalenderGroupId = (groupId) => + this.getCalendarEvents().filter( + `div[data-group-id="event-group-${groupId}"]`, + ); + getCalendarPartDropTarget = (partIndex) => + `${this.selectors.calendarBaseGrid} [data-cy='calendar-grid-part'][data-drop-index='${partIndex}']`; + getEventGridRowFromStyle = (style) => + /grid-row:\s*([^;]+)/.exec(style)?.[1]?.trim(); + getGridRowByContainingEventId = (id) => + this.getCalendarEventById(id) + .invoke('attr', 'style') + .then((style) => this.getEventGridRowFromStyle(style)); + getGridRowByContainingUniqueCalendarGroupId = (groupId) => + this.getCalendarEventByUniqueCalenderGroupId(groupId) + .invoke('attr', 'style') + .then((style) => this.getEventGridRowFromStyle(style)); + getCalendarEventsByWeekday = (weekday) => + this.getCalendarEventsPerWeekHolders().then(($holders) => { + const index = weekdayToGridRowMap[weekday] - 1; - return ( - eventData?.orig?.beginn === startTime && - eventData?.orig?.ende === endTime - ); - }); - getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime = ( - weekday, - startTime, - ) => - this.getCalendarEventsByWeekdayAndStartTime(weekday, startTime).filter( - (index, event) => { - const eventData = JSON.parse( - event.getAttribute("data-fhc-draggable-value"), - ); + return cy + .wrap($holders) + .eq(index) + .then(($holder) => { + return cy + .wrap($holder) + .find("[data-cy='calendar-event']") + .then(($events) => { + return $events; + }); + }); + }); + getCalendarEventsByStartTime = (startTime) => + this.getCalendarEvents().filter((index, event) => { + const eventData = JSON.parse( + event.getAttribute('data-fhc-draggable-value'), + ); + return eventData?.orig?.beginn === startTime; + }); + getCalendarEventsByTimeRange = (startTime, endTime) => + this.getCalendarEvents().filter((index, event) => { + const eventData = JSON.parse( + event.getAttribute('data-fhc-draggable-value'), + ); + return ( + eventData?.orig?.beginn === startTime && + eventData?.orig?.ende === endTime + ); + }); + getCalendarEventsBySoftTimeRange = (startTime, endTime) => + this.getCalendarEvents().filter((index, event) => { + const eventData = JSON.parse( + event.getAttribute('data-fhc-draggable-value'), + ); + return ( + eventData?.orig?.beginn >= startTime && eventData?.orig?.ende <= endTime + ); + }); + getCalendarEventsByWeekdayAndStartTime = (weekday, startTime) => + this.getCalendarEventsByWeekday(weekday).then(($events) => + $events.filter((index, event) => { + const eventData = JSON.parse( + event.getAttribute('data-fhc-draggable-value'), + ); - return !!eventData?.orig?.ort_kurzbz && eventData?.orig?.lehreinheit_id; - }, - ); - getKalenderId = (eventData) => eventData?.orig?.kalender_id ?? eventData?.id; - getCalendarEventData = ($event) => - JSON.parse($event.attr("data-fhc-draggable-value")); - getFirstLecturer = (eventData) => - eventData?.orig?.lektor?.find((lecturer) => lecturer?.kurzbz); - getUpdatedKalenderId = (interception) => { - const retval = interception.response.body?.data?.kalender_id; + return eventData?.orig?.beginn === startTime; + }), + ); + getCalendarEventsByWeekdayAndTimeRange = (weekday, startTime, endTime) => + this.getCalendarEventsByWeekday(weekday).filter((index, event) => { + const eventData = JSON.parse( + event.getAttribute('data-fhc-draggable-value'), + ); - return retval?.kalender_id ?? retval; - }; + return ( + eventData?.orig?.beginn === startTime && + eventData?.orig?.ende === endTime + ); + }); + getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime = ( + weekday, + startTime, + ) => + this.getCalendarEventsByWeekdayAndStartTime(weekday, startTime).filter( + (index, event) => { + const eventData = JSON.parse( + event.getAttribute('data-fhc-draggable-value'), + ); - // Room-selection actions - chooseDifferentRoomForEvent = (eventId, originalRoom) => { - this.getCalendarEventById(eventId) - .scrollIntoView() - .should("be.visible") - .rightclick(); - this.getEventContextMenuOption("Raumauswahl").click({ force: true }); - waitForOk("@fetchRoomSuggestions"); + return !!eventData?.orig?.ort_kurzbz && eventData?.orig?.lehreinheit_id; + }, + ); + getKalenderId = (eventData) => eventData?.orig?.kalender_id ?? eventData?.id; + getCalendarEventData = ($event) => + JSON.parse($event.attr('data-fhc-draggable-value')); + getFirstLecturer = (eventData) => + eventData?.orig?.lektor?.find((lecturer) => lecturer?.kurzbz); + getUpdatedKalenderId = (interception) => { + const retval = interception.response.body?.data?.kalender_id; - return this.getRoomSelectionOptions() - .should("have.length.greaterThan", 0) - .then(($roomOptions) => { - const getRoomCode = (option) => option.textContent.trim(); - const currentRoomOption = [...$roomOptions].find( - (option) => getRoomCode(option) === originalRoom, - ); - const roomOption = [...$roomOptions].find((option) => { - const room = getRoomCode(option); + return retval?.kalender_id ?? retval; + }; - return room && room !== originalRoom; - }); + scrollCalendarEventIntoView = (eventId) => { + return this.getCalendarEventById(eventId).then(($event) => { + const eventEl = $event[0]; - expect(currentRoomOption, "current room suggestion").to.exist; - expect(roomOption, "different room suggestion").to.exist; + const verticalScroller = eventEl.closest('#grid-main-scrollable'); + const horizontalScroller = eventEl.closest('.fhc-calendar-base-grid'); - const newRoom = getRoomCode(roomOption); + if (!verticalScroller || !horizontalScroller) { + throw new Error('Calendar scroll containers not found'); + } - return cy - .wrap(currentRoomOption) - .click() - .then(() => cy.wrap(roomOption).click()) - .then(() => - cy - .get("[data-cy='saveRoomSelection']") - .should("be.visible") - .click({ force: true }), - ) - .then(() => newRoom); - }); - }; + const eventRect = eventEl.getBoundingClientRect(); + const verticalRect = verticalScroller.getBoundingClientRect(); + const horizontalRect = horizontalScroller.getBoundingClientRect(); - selectFirstRoomAndSave = () => - this.getRoomSelectionOptions() - .should("have.length.greaterThan", 0) - .first() - .then(($roomOption) => { - const room = $roomOption.text().trim(); + verticalScroller.scrollTop += + eventRect.top - + verticalRect.top - + verticalScroller.clientHeight / 2 + + eventRect.height / 2; - return cy - .wrap($roomOption) - .click() - .then(() => - cy - .get("[data-cy='saveRoomSelection']") - .should("be.visible") - .click({ force: true }), - ) - .then(() => room); - }); + horizontalScroller.scrollLeft += + eventRect.left - + horizontalRect.left - + horizontalScroller.clientWidth / 2 + + eventRect.width / 2; + }); + }; - selectAdditionalRoomsAndSave = (currentRooms, roomCount = 2) => - this.getRoomSelectionOptions() - .should("have.length.greaterThan", roomCount) - .then(($roomOptions) => { - const selectedRooms = new Set( - (Array.isArray(currentRooms) ? currentRooms : [currentRooms]).filter( - Boolean, - ), - ); - const additionalRoomOptions = [...$roomOptions] - .filter((roomOption) => !selectedRooms.has(roomOption.textContent.trim())) - .slice(0, roomCount); + // Room-selection actions + chooseDifferentRoomForEvent = (eventId, originalRoom) => { + return this.scrollCalendarEventIntoView(eventId) + .then(() => { + return this.getCalendarEventById(eventId) + .should('be.visible') + .rightclick(); + }) + .then(() => { + this.getEventContextMenuOption('Raumauswahl').click({ force: true }); + waitForOk('@fetchRoomSuggestions'); - expect(additionalRoomOptions, "additional room suggestions").to.have.length( - roomCount, - ); + return this.getRoomSelectionOptions() + .should('have.length.greaterThan', 0) + .then(($roomOptions) => { + const getRoomCode = (option) => option.textContent.trim(); + const currentRoomOption = [...$roomOptions].find( + (option) => getRoomCode(option) === originalRoom, + ); + const roomOption = [...$roomOptions].find((option) => { + const room = getRoomCode(option); - const additionalRooms = additionalRoomOptions.map((roomOption) => - roomOption.textContent.trim(), - ); + return room && room !== originalRoom; + }); - additionalRoomOptions.forEach((roomOption) => cy.wrap(roomOption).click()); + expect(currentRoomOption, 'current room suggestion').to.exist; + expect(roomOption, 'different room suggestion').to.exist; - return cy - .get("[data-cy='saveRoomSelection']") - .should("be.visible") - .click({ force: true }) - .then(() => additionalRooms); - }); + const newRoom = getRoomCode(roomOption); - waitForUpdatedEventId = () => - cy.wait("@updateCalendarEvent").then((interception) => { - expect(interception.response.statusCode).to.eq(200); + return cy + .wrap(currentRoomOption) + .click() + .then(() => cy.wrap(roomOption).click()) + .then(() => + cy + .get("[data-cy='saveRoomSelection']") + .should('be.visible') + .click({ force: true }), + ) + .then(() => newRoom); + }); + }); + }; - const updatedEventId = this.getUpdatedKalenderId(interception); - expect(updatedEventId, "updated planner event id").to.exist; + selectFirstRoomAndSave = () => + this.getRoomSelectionOptions() + .should('have.length.greaterThan', 0) + .first() + .then(($roomOption) => { + const room = $roomOption.text().trim(); - return updatedEventId; - }); - changeEventRoom = (eventId, originalRoom) => - this.chooseDifferentRoomForEvent(eventId, originalRoom).then((newRoom) => - this.waitForUpdatedEventId().then((updatedEventId) => { - waitForOk("@fetchPlanData"); - this.waitForCalendarToFinishLoading(); + return cy + .wrap($roomOption) + .click() + .then(() => + cy + .get("[data-cy='saveRoomSelection']") + .should('be.visible') + .click({ force: true }), + ) + .then(() => room); + }); - return cy.wrap({ newRoom, updatedEventId }); - }), - ); + selectAdditionalRoomsAndSave = (currentRooms, roomCount = 2) => + this.getRoomSelectionOptions() + .should('have.length.greaterThan', roomCount) + .then(($roomOptions) => { + const selectedRooms = new Set( + (Array.isArray(currentRooms) ? currentRooms : [currentRooms]).filter( + Boolean, + ), + ); + const additionalRoomOptions = [...$roomOptions] + .filter( + (roomOption) => !selectedRooms.has(roomOption.textContent.trim()), + ) + .slice(0, roomCount); - // Calendar state and modal selectors - getMondayFirstColumnEventData = ($body) => - [ - ...$body - .find(`${this.selectors.calendarBaseGrid} .fhc-calendar-base-grid-line`) - .first() - .find("[data-cy='calendar-event']"), - ] - .map((event) => { - const eventJSON = event.getAttribute("data-fhc-draggable-value"); + expect( + additionalRoomOptions, + 'additional room suggestions', + ).to.have.length(roomCount); - try { - return eventJSON ? JSON.parse(eventJSON) : null; - } catch { - return null; - } - }) - .filter(Boolean); - getCalendarLoadingEvents = () => - this.getCalendarSection().find(".placeholder-glow"); - getCalendarEventModal = () => - this.getCalendarSection().find(".bootstrap-modal.show"); - getEventContextMenu = () => cy.get("[data-cy='eventContextMenu']"); - getEventContextMenuOption = (option) => - this.getEventContextMenu().contains("button", option); - getRoomSelectionModal = () => - cy - .get("[data-cy='raumauswahlModal']") - .closest(".bootstrap-modal.show"); - getRoomSelectionOptions = () => - this.getRoomSelectionModal().find("[data-cy='room-ort-kurzbz']"); - getResourcesModal = () => - cy - .get("[data-cy='resourcesAssignmentModal']") - .closest(".bootstrap-modal.show"); - getTagsModal = () => - cy.get("[data-cy='tagsAssignmentModal']").closest(".bootstrap-modal.show"); - getCalendarEventRoom = (id) => - this.getCalendarEventById(id).find("[data-cy='calendar-event-room']"); - getStundenrasterToggle = () => - cy.contains(".form-check-label", "Stundenraster").parent(); - getHistoryModal = () => cy.get("[data-cy='historyModal']"); - getReservationDragHandle = () => cy.get("[data-cy='reservationDragHandle']"); - getReservationModal = () => cy.get("[data-cy='reservationModal']"); - getEventParkingSlot = () => this.getSidebarMenu().find("#parkingslot"); - getParkedEvents = () => - this.getEventParkingSlot().find("[data-cy='parked-calendar-event']"); - getPreviewRoleButton = (role) => - this.getPreviewRoleOptionsHolder().contains("button", role); + const additionalRooms = additionalRoomOptions.map((roomOption) => + roomOption.textContent.trim(), + ); - // Navigation and preview actions - getSemesterSetterButton = () => - this.getSidebarMenu().find(".stv-studiensemester button").last(); + additionalRoomOptions.forEach((roomOption) => + cy.wrap(roomOption).click(), + ); - openCoursesMenu = () => { - this.getAllCoursesSliderBtn().click(); - this.getSlideInCoursesMenu().should("be.visible"); - }; + return cy + .get("[data-cy='saveRoomSelection']") + .should('be.visible') + .click({ force: true }) + .then(() => additionalRooms); + }); - selectFirstCourse = () => { - this.openCoursesMenu(); - this.getCourseTreeRows().first().click(); - }; + waitForUpdatedEventId = () => + cy.wait('@updateCalendarEvent').then((interception) => { + expect(interception.response.statusCode).to.eq(200); - selectCourseByName = (courseShortName) => { - this.openCoursesMenu(); - this.getCourseTreeRowByName(courseShortName).click(); - }; + const updatedEventId = this.getUpdatedKalenderId(interception); + expect(updatedEventId, 'updated planner event id').to.exist; - selectPreviewRole = (role) => { - this.getPreviewRoleButton(role).click(); - }; + return updatedEventId; + }); + changeEventRoom = (eventId, originalRoom) => + this.chooseDifferentRoomForEvent(eventId, originalRoom).then((newRoom) => + this.waitForUpdatedEventId().then((updatedEventId) => { + waitForOk('@fetchPlanData'); + this.waitForCalendarToFinishLoading(); - syncAndReloadPlanner = () => { - this.selectPreviewRole(SYNC); - waitForOk("@syncCalendar"); - waitForOk("@fetchPlanData"); - this.waitForCalendarToFinishLoading(); - }; + return cy.wrap({ newRoom, updatedEventId }); + }), + ); - selectRoleAndWait = (role) => { - this.selectPreviewRole(role); - waitForOk(roleFetchAliases[role]); - this.waitForCalendarToFinishLoading(); - }; + // Calendar state and modal selectors + getMondayFirstColumnEventData = ($body) => + [ + ...$body + .find(`${this.selectors.calendarBaseGrid} .fhc-calendar-base-grid-line`) + .first() + .find("[data-cy='calendar-event']"), + ] + .map((event) => { + const eventJSON = event.getAttribute('data-fhc-draggable-value'); - // Assertions and loading state - expectCalendarEventRoom = (eventId, expectedRoom) => { - this.getCalendarEventRoom(eventId) - .scrollIntoView() - .should("be.visible") - .invoke("text") - .then((roomText) => { - expect(roomText.trim(), "event room").to.eq(expectedRoom); - }); - }; + try { + return eventJSON ? JSON.parse(eventJSON) : null; + } catch { + return null; + } + }) + .filter(Boolean); + getCalendarLoadingEvents = () => + this.getCalendarSection().find('.placeholder-glow'); + getCalendarEventModal = () => + this.getCalendarSection().find('.bootstrap-modal.show'); + getEventContextMenu = () => cy.get("[data-cy='eventContextMenu']"); + getEventContextMenuOption = (option) => + this.getEventContextMenu().contains('button', option); + getRoomSelectionModal = () => + cy.get("[data-cy='raumauswahlModal']").closest('.bootstrap-modal.show'); + getRoomSelectionOptions = () => + this.getRoomSelectionModal().find("[data-cy='room-ort-kurzbz']"); + getResourcesModal = () => + cy + .get("[data-cy='resourcesAssignmentModal']") + .closest('.bootstrap-modal.show'); + getTagsModal = () => + cy.get("[data-cy='tagsAssignmentModal']").closest('.bootstrap-modal.show'); + getCalendarEventRoom = (id) => + this.getCalendarEventById(id).find("[data-cy='calendar-event-room']"); + getStundenrasterToggle = () => + cy.contains('.form-check-label', 'Stundenraster').parent(); + getHistoryModal = () => cy.get("[data-cy='historyModal']"); + getReservationDragHandle = () => cy.get("[data-cy='reservationDragHandle']"); + getReservationModal = () => cy.get("[data-cy='reservationModal']"); + getEventParkingSlot = () => this.getSidebarMenu().find('#parkingslot'); + getParkedEvents = () => + this.getEventParkingSlot().find("[data-cy='parked-calendar-event']"); + getPreviewRoleButton = (role) => + this.getPreviewRoleOptionsHolder().contains('button', role); - expectCalendarEventRooms = (eventId, expectedRooms) => { - this.getCalendarEventRoom(eventId) - .scrollIntoView() - .should("be.visible") - .invoke("text") - .then((roomText) => { - expectedRooms.forEach((room) => { - expect(roomText.trim(), "event rooms").to.include(room); - }); - }); - }; + // Navigation and preview actions + getSemesterSetterButton = () => + this.getSidebarMenu().find('.stv-studiensemester button').last(); - visitAndWaitForPlanner = () => { - cy.login(); - this.setupIntercepts(); - this.visit(); + openCoursesMenu = () => { + this.getAllCoursesSliderBtn().click(); + this.getSlideInCoursesMenu().should('be.visible'); + }; - waitForOk("@fetchCourseTree"); - waitForOk("@fetchPlanData"); - this.waitForCalendarToFinishLoading(); - }; + selectFirstCourse = () => { + this.openCoursesMenu(); + this.getCourseTreeRows().first().click(); + }; - disableStundenraster = () => { - this.getStundenrasterToggle().then(($toggle) => { - if ($toggle.find(".fa-toggle-on").length) { - cy.wrap($toggle).click(); - } - }); + selectCourseByName = (courseShortName) => { + this.openCoursesMenu(); + this.getCourseTreeRowByName(courseShortName).click(); + }; - this.getStundenrasterToggle() - .find("i") - .should("have.class", "fa-toggle-off"); - }; + selectPreviewRole = (role) => { + this.getPreviewRoleButton(role).click(); + }; - waitForCalendarToFinishLoading = () => { - this.getCalendarLoadingEvents().should("not.exist"); - }; + syncAndReloadPlanner = () => { + this.selectPreviewRole(SYNC); + waitForOk('@syncCalendar'); + waitForOk('@fetchPlanData'); + this.waitForCalendarToFinishLoading(); + }; - setCurrentSemester = () => { - this.getSemesterSetterButton().click(); - waitForOk("@getCurrentSemester"); - }; + selectRoleAndWait = (role) => { + this.selectPreviewRole(role); + waitForOk(roleFetchAliases[role]); + this.waitForCalendarToFinishLoading(); + }; - // Drag-and-drop actions - dropEventOnCalendarPart = (eventId, partIndex, options = {}) => { - const event = this.getCalendarEventById(eventId); + // Assertions and loading state + expectCalendarEventRoom = (eventId, expectedRoom) => { + return this.scrollCalendarEventIntoView(eventId).then(() => { + this.getCalendarEventRoom(eventId) + .scrollIntoView() + .should('be.visible') + .invoke('text') + .then((roomText) => { + expect(roomText.trim(), 'event room').to.eq(expectedRoom); + }); + }); + }; - return event - .scrollIntoView() - .should("be.visible") - .drag(this.getCalendarPartDropTarget(partIndex), { - waitForAnimations: false, - animationDistanceThreshold: 0, - ...options, - }); - }; + expectCalendarEventRooms = (eventId, expectedRooms) => { + return this.scrollCalendarEventIntoView(eventId).then(() => { + this.getCalendarEventRoom(eventId) + .should('be.visible') + .invoke('text') + .then((roomText) => { + expectedRooms.forEach((room) => { + expect(roomText.trim(), 'event rooms').to.include(room); + }); + }); + }); + }; - dropCourseOnCalendarPart = (courseIndex, partIndex, options = {}) => { - const course = this.getCoursePickerRows() - .eq(courseIndex) - .find("span") - .first(); + visitAndWaitForPlanner = () => { + cy.login(); + this.setupIntercepts(); + this.visit(); - return course - .should("be.visible") - .drag(this.getCalendarPartDropTarget(partIndex), { - waitForAnimations: false, - animationDistanceThreshold: 0, - scrollBehavior: "top", - ...options, - }); - }; + waitForOk('@fetchCourseTree'); + waitForOk('@fetchPlanData'); + this.waitForCalendarToFinishLoading(); + }; + + disableStundenraster = () => { + this.getStundenrasterToggle().then(($toggle) => { + if ($toggle.find('.fa-toggle-on').length) { + cy.wrap($toggle).click(); + } + }); + + this.getStundenrasterToggle() + .find('i') + .should('have.class', 'fa-toggle-off'); + }; + + waitForCalendarToFinishLoading = () => { + this.getCalendarLoadingEvents().should('not.exist'); + }; + + setCurrentSemester = () => { + this.getSemesterSetterButton().click(); + waitForOk('@getCurrentSemester'); + }; + + // Drag-and-drop actions + dropEventOnCalendarPart = (eventId, partIndex, options = {}) => { + return this.scrollCalendarEventIntoView(eventId).then(() => { + return this.getCalendarEventById(eventId) + .should('be.visible') + .drag(this.getCalendarPartDropTarget(partIndex), { + waitForAnimations: false, + animationDistanceThreshold: 0, + ...options, + }); + }); + }; + + dropCourseOnCalendarPart = (courseIndex, partIndex, options = {}) => { + const course = this.getCoursePickerRows() + .eq(courseIndex) + .find('span') + .first(); + + return course + .should('be.visible') + .drag(this.getCalendarPartDropTarget(partIndex), { + waitForAnimations: false, + animationDistanceThreshold: 0, + scrollBehavior: 'top', + ...options, + }); + }; } export const tempusPage = new TempusPage();