From 245b7243146ea1bf4dc9a5ba37aaf5d4e2d04d25 Mon Sep 17 00:00:00 2001 From: Ivymaster Date: Mon, 15 Jun 2026 01:01:33 +0200 Subject: [PATCH] Minor rfactor --- system/seeders/014_kalender.sql | 76 +- .../specs/api/tempus/tempus.collisions.cy.js | 1223 ++++++++--------- .../ui/tempus/tempus.course-picker.cy.js | 18 +- .../e2e/specs/ui/tempus/tempus.events.cy.js | 114 +- .../e2e/specs/ui/tempus/tempus.filters.cy.js | 32 +- .../e2e/specs/ui/tempus/tempus.roles.cy.js | 17 +- .../e2e/specs/ui/tempus/tempus.smoke.cy.js | 13 +- .../cypress/cypress/support/api/tempusApi.js | 105 ++ tests/cypress/cypress/support/helpers/date.js | 21 + .../cypress/support/pages/tempus.po.js | 593 ++++---- 10 files changed, 1200 insertions(+), 1012 deletions(-) create mode 100644 tests/cypress/cypress/support/api/tempusApi.js create mode 100644 tests/cypress/cypress/support/helpers/date.js diff --git a/system/seeders/014_kalender.sql b/system/seeders/014_kalender.sql index eb7382a63..e4a3cb0b7 100644 --- a/system/seeders/014_kalender.sql +++ b/system/seeders/014_kalender.sql @@ -43,6 +43,18 @@ INSERT INTO lehre.tbl_kalender INSERT INTO lehre.tbl_kalender_ort (location, ort_kurzbz, kalender_id) VALUES(NULL, 'Bro_F7.37', 1); + +INSERT INTO lehre.tbl_kalender_lehreinheit +(lehreinheit_id, kalender_id) +VALUES +(51001, 1), +(51002, 2), +(51003, 3), +(51003, 4), +(51002, 5), +(51006, 6), +(51002, 7), +(51006, 8); -- //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -53,6 +65,13 @@ INSERT INTO lehre.tbl_kalender (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') ; + +INSERT INTO lehre.tbl_kalender_lehreinheit +(lehreinheit_id, kalender_id) +VALUES +(51001, 9), +(51003, 10), +(51002, 11); -- //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -62,6 +81,12 @@ INSERT INTO lehre.tbl_kalender (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') ; + +INSERT INTO lehre.tbl_kalender_lehreinheit +(lehreinheit_id, kalender_id) +VALUES +(51001, 12), +(51002, 13); -- //////////////////////////////////////////////////////////////////////////////////////////////////// -- Calendar setup for API event creation tests @@ -70,6 +95,12 @@ INSERT INTO lehre.tbl_kalender (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') ; + +INSERT INTO lehre.tbl_kalender_lehreinheit +(lehreinheit_id, kalender_id) +VALUES +(51003, 14), +(51005, 15); -- //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -93,48 +124,47 @@ VALUES INSERT INTO lehre.tbl_kalender_ort (location, ort_kurzbz, kalender_id) VALUES -(NULL, 'Bro_F7.37', 13), -(NULL, 'Bro_F7.37', 14); - --- //////////////////////////////////////////////////////////////////////////////////////////////////// +(NULL, 'Bro_F7.37', 17), +(NULL, 'Bro_F7.37', 18); INSERT INTO lehre.tbl_kalender_lehreinheit (lehreinheit_id, kalender_id) VALUES -(51001, 1), -(51002, 2), -(51003, 3), -(51003, 4), -(51002, 5), -(51006, 6), -(51002, 7), -(51006, 8), -(51001, 9), -(51003, 10), -(51002, 11), -(51001, 12), -(51002, 13), -(51003, 14), -(51005, 15), (51001, 16), (51001, 17), (51003, 18), (51001, 19), (51003, 20), (51003, 21), -(51004, 22), +(51006, 22), (51004, 23), (51005, 24), -(51003, 25), +(51004, 25), (51006, 26); +-- //////////////////////////////////////////////////////////////////////////////////////////////////// + +-- 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') +; + +INSERT INTO lehre.tbl_kalender_lehreinheit +(lehreinheit_id, kalender_id) +VALUES +(51002, 27), +(51006, 28); + +-- //////////////////////////////////////////////////////////////////////////////////////////////////// INSERT INTO lehre.tbl_kalender_event (kalender_id, titel, beschreibung) -VALUES(21, 'Test reservation', NULL); +VALUES(26, 'Test reservation', NULL); INSERT INTO lehre.tbl_kalender_event_teilnehmer (kalender_id, rolle_kurzbz, uid, studiensemester_kurzbz, gruppe_kurzbz, studiengang_kz, semester, verband, gruppe, studentenlehrverband_id) -VALUES(21, 'teilnehmer', 'demolektor4', NULL, NULL, NULL, NULL, NULL, NULL, NULL); +VALUES(26, '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) 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 d12b11bf9..1a163433e 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,247 +1,139 @@ -import { tempusPage } from "../../../../support/pages/tempus.po"; -import moment from "moment"; +import { tempusApi } from "../../../../support/api/tempusApi"; +import { getDateForDay } from "../../../../support/helpers/date"; -const KALENDER_API = "/index.ci.php/api/frontend/v1/tempus"; const TARGETED_STUDY_PLAN_SHORT_CODE = "STG5"; -const getStudyPlansTree = () => - cy - .request({ - method: "GET", - url: `/index.ci.php/api/frontend/v1/lv/StgTree`, - }) - .then((response) => { - expect(response.status).to.eq(200); - expect(response.body).to.have.nested.property("meta.status", "success"); - expect(response.body.data).to.be.an("array"); - - return response.body.data; - }); - -const getCoursesByStudyPlan = (studyPlanId, semesterShortCode) => - cy - .request({ - method: "GET", - url: `/index.ci.php/api/frontend/v1/tempus/coursepicker/getByStg`, - qs: { - stg: studyPlanId, - studiensemester_kurzbz: semesterShortCode, - }, - }) - .then((response) => { - expect(response.status).to.eq(200); - expect(response.body).to.have.nested.property("meta.status", "success"); - expect(response.body.data).to.be.an("array"); - - return response.body.data; - }); - -const getPlannerEvents = (startDate, endDate) => - cy - .request({ - method: "GET", - url: `${KALENDER_API}/Kalender/getPlan`, - qs: { - start_date: startDate, - end_date: endDate, - }, - }) - .then((response) => { - expect(response.status).to.eq(200); - expect(response.body).to.have.nested.property("meta.status", "success"); - expect(response.body.data).to.be.an("array"); - - return response.body.data; - }); - -const createKalenderEvent = (lehreinheitId, startDateTime, endDateTime) => - cy.request({ - method: "POST", - url: `${KALENDER_API}/Kalender/addKalenderEvent`, - body: { - lehreinheit_id: lehreinheitId, - start_date: startDateTime, - end_date: endDateTime, - }, - failOnStatusCode: false, - }); - -const updateKalenderEvent = (kalenderId, startDateTime, endDateTime) => - cy.request({ - method: "POST", - url: `${KALENDER_API}/Kalender/updateKalenderEvent`, - form: true, - body: { - kalender_id: kalenderId, - "updatedInfos[start_time]": startDateTime, - "updatedInfos[end_time]": endDateTime, - }, - failOnStatusCode: false, - }); - - const deleteKalenderEvent = (kalenderId) => - cy.request({ - method: "POST", - url: `${KALENDER_API}/Kalender/deleteEntry`, - form: true, - body: { - kalender_id: kalenderId, - }, - failOnStatusCode: false, - }); - -const getSettingsData = () => ({ - ignore_kollision: false, - kollision_student: false, - ignore_reservierung: false, - ignore_zeitsperre: false, -}); - -const updateSettingsData = (options) => - cy.request({ - method: "POST", - url: `${KALENDER_API}/config/set`, - failOnStatusCode: false, - headers: { "Cache-Control": "no-cache", Pragma: "no-cache" }, - body: { ...options }, - }); - - function getDateForDay(dayName) { - const days = { - monday: 0, - tuesday: 1, - wednesday: 2, - thursday: 3, - friday: 4, - saturday: 5, - sunday: 6, - }; - - const dayIndex = days[dayName.toLowerCase()]; - - if (dayIndex === undefined) { - throw new Error(`Invalid day name: ${dayName}`); - } - - return moment() - .startOf('isoWeek') - .add(dayIndex, 'days') - .format('YYYY-MM-DD'); -} - describe("Tempus Kalender API", () => { beforeEach(() => { cy.login(); - getPlannerEvents(getDateForDay("monday"), getDateForDay("monday")).then((events) => { - events.forEach((event) => { - deleteKalenderEvent(event.kalender_id); + tempusApi + .getPlannerEvents(getDateForDay("monday"), getDateForDay("monday")) + .then((events) => { + events.forEach((event) => { + tempusApi.deleteKalenderEvent(event.kalender_id); + }); }); - }); - getPlannerEvents(getDateForDay("tuesday"), getDateForDay("tuesday")).then((events) => { - events.forEach((event) => { - if (event.type === "lehreinheit" && event.beginn === "20:15:00" && event.ende === "21:00:00") { - updateKalenderEvent(event.kalender_id, `${event.datum} 19:30`, `${event.datum} 20:15`); - } + tempusApi + .getPlannerEvents(getDateForDay("tuesday"), getDateForDay("tuesday")) + .then((events) => { + events.forEach((event) => { + if ( + event.type === "lehreinheit" && + event.beginn === "20:15:00" && + event.ende === "21:00:00" + ) { + tempusApi.updateKalenderEvent( + event.kalender_id, + `${event.datum} 19:30`, + `${event.datum} 20:15`, + ); + } + }); }); - }); }); it("event creation works for non collision case", () => { - getStudyPlansTree().then((stgTree) => { - let studyPlan = stgTree.find((plan) => plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE)); + tempusApi.getStudyPlansTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE), + ); expect(studyPlan, "study plan for test event creation").to.exist; - getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026").then( - (courses) => { - let course = courses.find( - (course) => - course.lehrfach === "MAT", - ); + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026") + .then((courses) => { + let course = courses.find((course) => course.lehrfach === "MAT"); expect(course, "course for test event creation").to.exist; - updateSettingsData(getSettingsData()).then((response) => { - const lehreinheitId = course.lehreinheit_id[0]; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; + tempusApi + .updateSettingsData(tempusApi.getSettingsData()) + .then((response) => { + const lehreinheitId = course.lehreinheit_id[0]; + expect(lehreinheitId, "lehreinheit id for test event creation").to + .exist; - const startDateTime = `${getDateForDay("monday")} 17:50`; - const endDateTime = `${getDateForDay("monday")} 18:35`; + const startDateTime = `${getDateForDay("monday")} 17:50`; + const endDateTime = `${getDateForDay("monday")} 18:35`; - createKalenderEvent(lehreinheitId, startDateTime, endDateTime).then( - (response) => { - console.log(response); - expect(response.status).to.eq(200); - expect(response.body).to.have.nested.property( - "meta.status", - "success", - ); - }, - ); - }); - }, - ); + 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", () => { - getStudyPlansTree().then((stgTree) => { - let studyPlan = stgTree.find((plan) => plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE)); + tempusApi.getStudyPlansTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE), + ); expect(studyPlan, "study plan for test event creation").to.exist; - getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026").then( - (courses) => { - let course = courses.find( - (course) => - course.lektoren.some((lector) => lector.kurzbz === "DemoLKT1"), + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026") + .then((courses) => { + let course = courses.find((course) => + course.lektoren.some((lector) => lector.kurzbz === "DemoLKT1"), ); expect(course, "course for test event creation").to.exist; - updateSettingsData(getSettingsData()).then((response) => { - const lehreinheitId = course.lehreinheit_id[0]; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; + tempusApi + .updateSettingsData(tempusApi.getSettingsData()) + .then((response) => { + const lehreinheitId = course.lehreinheit_id[0]; + expect(lehreinheitId, "lehreinheit id for test event creation").to + .exist; - const startDateTime = `${getDateForDay("saturday")} 18:35`; - const endDateTime = `${getDateForDay("saturday")} 19:20`; + const startDateTime = `${getDateForDay("saturday")} 18:35`; + const endDateTime = `${getDateForDay("saturday")} 19:20`; - createKalenderEvent(lehreinheitId, startDateTime, endDateTime).then( - (response) => { - console.log(response.body.errors); - expect(response.status).to.eq(500); - expect(response.body).to.have.nested.property( - "meta.status", - "error", - ); - expect(response.body.errors).to.be.an("array"); + tempusApi + .createKalenderEvent(lehreinheitId, startDateTime, endDateTime) + .then((response) => { + console.log(response.body.errors); + 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.message - .toLowerCase() - .includes("zeitsperre kollision") || - error.message.toLowerCase().includes("time lock collision"), - ); - expect( - hasTimeLockCollisionError, - "response contains time lock collision error", - ).to.be.true; - }, - ); - }); - }, - ); + let hasTimeLockCollisionError = response.body.errors.some( + (error) => + error.message + .toLowerCase() + .includes("zeitsperre kollision") || + error.message + .toLowerCase() + .includes("time lock collision"), + ); + expect( + hasTimeLockCollisionError, + "response contains time lock collision error", + ).to.be.true; + }); + }); + }); }); }); it("prohibited event creation due to student group collision", () => { - getStudyPlansTree().then((stgTree) => { - let studyPlan = stgTree.find( - (plan) => plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE) + tempusApi.getStudyPlansTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE), ); expect(studyPlan, "study plan for test event creation").to.exist; - getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026").then( - (courses) => { + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026") + .then((courses) => { let course = courses.find( (course) => course.lehrfach === "ENG" && @@ -249,23 +141,306 @@ describe("Tempus Kalender API", () => { ); expect(course, "course for test event creation").to.exist; - updateSettingsData(getSettingsData()).then((response) => { - const lehreinheitId = course.lehreinheit_id[0]; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; + tempusApi + .updateSettingsData(tempusApi.getSettingsData()) + .then((response) => { + const lehreinheitId = course.lehreinheit_id[0]; + expect(lehreinheitId, "lehreinheit id for test event creation").to + .exist; - const startDateTime = `${getDateForDay("wednesday")} 18:35`; - const endDateTime = `${getDateForDay("wednesday")} 19:20`; + const startDateTime = `${getDateForDay("wednesday")} 18:35`; + const endDateTime = `${getDateForDay("wednesday")} 19:20`; - createKalenderEvent(lehreinheitId, startDateTime, endDateTime).then( - (response) => { - console.log(response.body.errors); + tempusApi + .createKalenderEvent(lehreinheitId, startDateTime, endDateTime) + .then((response) => { + console.log(response.body.errors); + 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.message + .toLowerCase() + .includes("verband kollision") || + error.message.toLowerCase().includes("student 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.getStudyPlansTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE), + ); + expect(studyPlan, "study plan for test event creation").to.exist; + + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026") + .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[0]; + 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) => { + console.log(response.body.errors); + 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.message + .toLowerCase() + .includes("studierende kollision") || + error.message + .toLowerCase() + .includes("student collision"), + ); + expect( + hasStudentCollisionError, + "response contains student collision error", + ).to.be.true; + }); + }); + }); + }); + }); + }); + + it("prohibited event creation due to lector collision", () => { + tempusApi.getStudyPlansTree().then((stgTree) => { + let studyPlan = stgTree.find((plan) => + plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE), + ); + expect(studyPlan, "study plan for test event creation").to.exist; + + tempusApi + .getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026") + .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[0]; + 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) => { + console.log(response.body.errors); + 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.message + .toLowerCase() + .includes("lektorin kollision") || + error.message + .toLowerCase() + .includes("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.message.toLowerCase().includes("raum kollision") || + error.message.toLowerCase().includes("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"); + console.log(response.body.errors); let hasStudentGroupCollisionError = response.body.errors.some( (error) => error.message.toLowerCase().includes("verband kollision") || @@ -275,452 +450,268 @@ describe("Tempus Kalender API", () => { hasStudentGroupCollisionError, "response contains student collision error", ).to.be.true; - }, - ); - }); - }, - ); - }); - }); - - it("prohibited event creation due to direct student collision", () => { - let settingsData = getSettingsData(); - settingsData.kollision_student = true; - - getStudyPlansTree().then((stgTree) => { - let studyPlan = stgTree.find( - (plan) => plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE) - ); - expect(studyPlan, "study plan for test event creation").to.exist; - - getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026").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; - - updateSettingsData(settingsData).then((response) => { - getPlannerEvents(getDateForDay("monday"), getDateForDay("monday")).then((events) => { - const lehreinheitId = course.lehreinheit_id[0]; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; - - const startDateTime = `${getDateForDay("wednesday")} 18:35`; - const endDateTime = `${getDateForDay("wednesday")} 19:20`; - - createKalenderEvent( - lehreinheitId, - startDateTime, - endDateTime, - ).then((response) => { - console.log(response.body.errors); - 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.message - .toLowerCase() - .includes("studierende kollision") || - error.message.toLowerCase().includes("student collision"), - ); - expect( - hasStudentCollisionError, - "response contains student collision error", - ).to.be.true; }); - }); }); - }, - ); - }); - }); - - it("prohibited event creation due to lector collision", () => { - getStudyPlansTree().then((stgTree) => { - let studyPlan = stgTree.find( - (plan) => plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE) - ); - expect(studyPlan, "study plan for test event creation").to.exist; - - getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026").then( - (courses) => { - let course = courses.find( - (course) => - course.lektoren.some((lector) => lector.kurzbz === "DemoLKT4"), - ); - expect(course, "course for test event creation").to.exist; - - updateSettingsData(getSettingsData()).then((response) => { - getPlannerEvents(getDateForDay("monday"), getDateForDay("monday")).then((events) => { - const lehreinheitId = course.lehreinheit_id[0]; - expect(lehreinheitId, "lehreinheit id for test event creation").to - .exist; - - const startDateTime = `${getDateForDay("thursday")} 18:35`; - const endDateTime = `${getDateForDay("thursday")} 19:20`; - - createKalenderEvent( - lehreinheitId, - startDateTime, - endDateTime, - ).then((response) => { - console.log(response.body.errors); - 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.message.toLowerCase().includes("lektorin kollision") || - error.message.toLowerCase().includes("lector collision"), - ); - expect( - hasLectorCollisionError, - "response contains lector collision error", - ).to.be.true; - }); - }); - }); - }, - ); - }); - }); - - it("event update works for non collision case", () => { - updateSettingsData(getSettingsData()).then((response) => { - 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`; - - 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", () => { - updateSettingsData(getSettingsData()).then((response) => { - 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`; - - 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.message.toLowerCase().includes("raum kollision") || - error.message.toLowerCase().includes("room collision"), - ); - expect( - hasRoomCollisionError, - "response contains room collision error", - ).to.be.true; - }); - }); - }); - }); - - it("prohibited event update due to student group collision", () => { - updateSettingsData(getSettingsData()).then((response) => { - 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`; - - 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"); - console.log(response.body.errors); - let hasStudentGroupCollisionError = response.body.errors.some( - (error) => - error.message.toLowerCase().includes("verband kollision") || - error.message.toLowerCase().includes("student collision"), - ); - expect( - hasStudentGroupCollisionError, - "response contains student collision error", - ).to.be.true; - }); - }); - }); }); it("prohibited event update due to direct student collision", () => { - let settingsData = getSettingsData(); + let settingsData = tempusApi.getSettingsData(); settingsData.kollision_student = true; - updateSettingsData(settingsData).then((response) => { - 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" - ); - 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`; - - 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"); - console.log(response.body.errors); - let hasDirectStudentCollisionError = response.body.errors.some( - (error) => - error.message.toLowerCase().includes("studierende kollision") || - error.message.toLowerCase().includes("student collision"), + 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", ); expect( - hasDirectStudentCollisionError, - "response contains student collision error", - ).to.be.true; + 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"); + console.log(response.body.errors); + let hasDirectStudentCollisionError = response.body.errors.some( + (error) => + error.message + .toLowerCase() + .includes("studierende kollision") || + error.message.toLowerCase().includes("student collision"), + ); + expect( + hasDirectStudentCollisionError, + "response contains student collision error", + ).to.be.true; + }); }); - }); }); }); it("prohibited event update due to lector collision", () => { - let settingsData = getSettingsData(); + let settingsData = tempusApi.getSettingsData(); settingsData.kollision_student = false; - updateSettingsData(settingsData).then((response) => { - getPlannerEvents(getDateForDay("saturday"), getDateForDay("saturday")).then((events) => { - console.log(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`; - - 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"); - console.log(response.body.errors); - let hasLectorCollisionError = response.body.errors.some( - (error) => - error.message.toLowerCase().includes("lektorin kollision") || - error.message.toLowerCase().includes("lector collision"), + tempusApi.updateSettingsData(settingsData).then((response) => { + tempusApi + .getPlannerEvents(getDateForDay("saturday"), getDateForDay("saturday")) + .then((events) => { + console.log(events); + const sourceEvent = events.find( + (event) => + event.type === "lehreinheit" && + event.beginn === "19:30:00" && + event.ende === "20:15:00", ); expect( - hasLectorCollisionError, - "response contains lector collision error", - ).to.be.true; + 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"); + console.log(response.body.errors); + let hasLectorCollisionError = response.body.errors.some( + (error) => + error.message.toLowerCase().includes("lektorin kollision") || + error.message.toLowerCase().includes("lector collision"), + ); + expect( + hasLectorCollisionError, + "response contains lector collision error", + ).to.be.true; + }); }); - }); }); }); it("prohibited event update due to lector - zeitsperre collision", () => { - let settingsData = getSettingsData(); + let settingsData = tempusApi.getSettingsData(); settingsData.kollision_student = false; - updateSettingsData(settingsData).then((response) => { - 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`; - - 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.message.toLowerCase().includes("zeitsperre kollision") || - error.message.toLowerCase().includes("time lock collision"), + 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( - hasTimeLockCollisionError, - "response contains time lock collision error", - ).to.be.true; + 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.message + .toLowerCase() + .includes("zeitsperre kollision") || + error.message.toLowerCase().includes("time lock collision"), + ); + expect( + hasTimeLockCollisionError, + "response contains time lock collision error", + ).to.be.true; + }); }); - }); }); }); it("prohibited event update due to lector - reservation collision", () => { - let settingsData = getSettingsData(); + let settingsData = tempusApi.getSettingsData(); settingsData.kollision_student = false; - updateSettingsData(settingsData).then((response) => { - 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`; - - 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"); - console.log(response.body.errors); - let hasReservationCollisionError = response.body.errors.some( - (error) => - error.message.toLowerCase().includes("reservierung kollision") || - error.message.toLowerCase().includes("reservation collision"), + 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( - hasReservationCollisionError, - "response contains reservation collision error", - ).to.be.true; + 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"); + console.log(response.body.errors); + let hasReservationCollisionError = response.body.errors.some( + (error) => + error.message + .toLowerCase() + .includes("reservierung kollision") || + error.message.toLowerCase().includes("reservation collision"), + ); + expect( + hasReservationCollisionError, + "response contains reservation collision error", + ).to.be.true; + }); }); - }); }); }); it("prohibited reservation update due to reservation - lector collision", () => { - let settingsData = getSettingsData(); + let settingsData = tempusApi.getSettingsData(); settingsData.kollision_student = false; - updateSettingsData(settingsData).then((response) => { - 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 === "DemoLKT3"), - ); - 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`; - - 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"); - console.log(response.body.errors); - let hasReservationCollisionError = response.body.errors.some( - (error) => - error.message.toLowerCase().includes("lektorin kollision") || - error.message.toLowerCase().includes("reservation collision"), + 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( - hasReservationCollisionError, - "response contains reservation collision error", - ).to.be.true; + 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"); + console.log(response.body.errors); + let hasReservationCollisionError = response.body.errors.some( + (error) => + error.message.toLowerCase().includes("lektorin kollision") || + error.message.toLowerCase().includes("reservation collision"), + ); + expect( + hasReservationCollisionError, + "response contains reservation collision error", + ).to.be.true; + }); }); - }); }); }); }); 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 233e704ca..2d6bbb597 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,8 +1,19 @@ import { waitForOk } from "../../../../support/helpers/network"; +import { getDateForDay } from "../../../../support/helpers/date"; import { tempusPage } from "../../../../support/pages/tempus.po"; +import { tempusApi } from "../../../../support/api/tempusApi"; const TARGETED_STUDY_PLAN_SHORT_CODE = "STG5"; +const deleteMondayEvents = () => + tempusApi + .getPlannerEvents(getDateForDay("monday"), getDateForDay("monday")) + .then((events) => { + events.forEach((event) => { + tempusApi.deleteKalenderEvent(event.kalender_id); + }); + }); + context("Tempus course picker tests", () => { before(() => { tempusPage.visitAndWaitForPlanner(); @@ -11,7 +22,6 @@ context("Tempus course picker tests", () => { beforeEach(() => { tempusPage.visitAndWaitForPlanner(); - return tempusPage.clearMondayFirstColumnAfterTest(); }); it("can select one course and show preview of its events", () => { @@ -51,14 +61,15 @@ context("Tempus course picker tests", () => { }); it("can drag and drop one course event into the calendar", () => { - tempusPage.clearMondayFirstColumnBeforeAndAfter(); - + deleteMondayEvents(); tempusPage.getCalendarSection().should("exist"); tempusPage.waitForCalendarToFinishLoading(); tempusPage.selectCourseByName(TARGETED_STUDY_PLAN_SHORT_CODE); waitForOk("@fetchCoursePickerCourses"); + cy.wait(1000); + tempusPage.getCalendarEvents().then(($events) => { cy.wrap($events.length).as("initialEventCount"); }); @@ -72,7 +83,6 @@ context("Tempus course picker tests", () => { tempusPage.waitForCalendarToFinishLoading(); cy.get("@initialEventCount").then((initialEventCount) => { - console.log("Initial event count:", initialEventCount); tempusPage .getCalendarEvents() .should("have.length", initialEventCount + 1); 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 c3365796f..c616b3aa5 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,25 +1,42 @@ import { waitForOk } from "../../../../support/helpers/network"; -import { LEKTOR, STUDENT, tempusPage } from "../../../../support/pages/tempus.po"; +import { getDateForDay } from "../../../../support/helpers/date"; +import { tempusApi } from "../../../../support/api/tempusApi"; +import { + LEKTOR, + STUDENT, + tempusPage, +} from "../../../../support/pages/tempus.po"; const TARGETED_STUDY_PLAN_SHORT_CODE = "STG5"; context("Tempus event mutation tests", () => { beforeEach(() => { tempusPage.visitAndWaitForPlanner(); - return tempusPage.clearMondayFirstColumnAfterTest(); + + tempusApi + .getPlannerEvents(getDateForDay("monday"), getDateForDay("monday")) + .then((events) => { + events.forEach((event) => { + tempusApi.deleteKalenderEvent(event.kalender_id); + }); + }); }); it("room change on planner preview updates planner event, but keeps original room on other previews", () => { - tempusPage.clearMondayFirstColumnBeforeAndAfter(); - tempusPage.syncAndReloadPlanner(); tempusPage - .getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime("Wednesday", "08:00:00") + .getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime( + "Wednesday", + "08:00:00", + ) .should("have.length.greaterThan", 0); tempusPage - .getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime("Wednesday", "08:00:00") + .getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime( + "Wednesday", + "08:00:00", + ) .first() .invoke("attr", "data-fhc-draggable-value") .then((eventJSON) => { @@ -29,8 +46,8 @@ context("Tempus event mutation tests", () => { const eventId = eventData?.id; const originalRoom = eventData?.orig?.ort_kurzbz; expect(eventId, "planner event id").to.exist; - expect(originalRoom, "original event room").to.be.a("string").and.not - .be.empty; + expect(originalRoom, "original event room").to.be.a("string").and.not.be + .empty; tempusPage.expectCalendarEventRoom(eventId, originalRoom); @@ -83,16 +100,20 @@ context("Tempus event mutation tests", () => { }); it("sync after planner preview room change loads new room on all previews", () => { - tempusPage.clearMondayFirstColumnBeforeAndAfter(); - tempusPage.syncAndReloadPlanner(); tempusPage - .getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime("Wednesday", "08:00:00") + .getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime( + "Wednesday", + "08:00:00", + ) .should("have.length.greaterThan", 0); tempusPage - .getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime("Wednesday", "08:00:00") + .getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime( + "Wednesday", + "08:00:00", + ) .first() .invoke("attr", "data-fhc-draggable-value") .then((eventJSON) => { @@ -102,8 +123,8 @@ context("Tempus event mutation tests", () => { const eventId = eventData?.id; const originalRoom = eventData?.orig?.ort_kurzbz; expect(eventId, "planner event id").to.exist; - expect(originalRoom, "original event room").to.be.a("string").and.not - .be.empty; + expect(originalRoom, "original event room").to.be.a("string").and.not.be + .empty; tempusPage .getCalendarEventById(eventId) @@ -170,8 +191,6 @@ context("Tempus event mutation tests", () => { }); it("event deletion on planner preview preservers event on planner, but shows it as unsynced on lektor and student preview", () => { - tempusPage.clearMondayFirstColumnBeforeAndAfter(); - tempusPage.syncAndReloadPlanner(); tempusPage @@ -205,8 +224,6 @@ context("Tempus event mutation tests", () => { }); it("syncing event deletion on planner preview removes event from other previews", () => { - tempusPage.clearMondayFirstColumnBeforeAndAfter(); - tempusPage.syncAndReloadPlanner(); tempusPage @@ -240,8 +257,6 @@ context("Tempus event mutation tests", () => { }); it("can bottom resize an event on planner preview", () => { - tempusPage.clearMondayFirstColumnBeforeAndAfter(); - tempusPage.getCalendarSection().should("exist"); tempusPage.waitForCalendarToFinishLoading(); @@ -273,11 +288,11 @@ context("Tempus event mutation tests", () => { .realMouseUp(); cy.wait("@updateCalendarEvent").then((interception) => { - console.log("updatedEventId", interception.response.body); expect(interception.response.statusCode).to.eq(200); expect(interception.response.body.data.retval).to.exist; const updatedEventId = - interception.response.body.data.retval?.kalender_id ?? interception.response.body.data.retval; + interception.response.body.data.retval?.kalender_id ?? + interception.response.body.data.retval; cy.wrap(updatedEventId).as("updatedEventId"); }); waitForOk("@fetchPlanData"); @@ -302,8 +317,6 @@ context("Tempus event mutation tests", () => { }); it.skip("can top resize an event on planner preview", () => { - tempusPage.clearMondayFirstColumnBeforeAndAfter(); - tempusPage.getCalendarSection().should("exist"); tempusPage.waitForCalendarToFinishLoading(); @@ -335,12 +348,12 @@ context("Tempus event mutation tests", () => { .realMouseUp(); cy.wait("@updateCalendarEvent").then((interception) => { - console.log("updatedEventId top", interception.response.body); expect(interception.response.statusCode).to.eq(200); expect(interception.response.body.data.retval).to.exist; const updatedEventId = - interception.response.body.data.retval?.kalender_id ?? interception.response.body.data.retval; + interception.response.body.data.retval?.kalender_id ?? + interception.response.body.data.retval; cy.wrap(updatedEventId).as("updatedEventId"); }); @@ -366,21 +379,35 @@ context("Tempus event mutation tests", () => { }); it.skip("can drag and drop one course event into the calendar when Stundenraster is disabled", () => { - tempusPage.clearMondayFirstColumnBeforeAndAfter(); + 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.dropCourseOnCalendarPart(0, 1); + + 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"); @@ -395,13 +422,15 @@ context("Tempus event mutation tests", () => { }); it.skip("can drag and drop an existing event when Stundenraster is disabled", () => { - tempusPage.clearMondayFirstColumnBeforeAndAfter(); - tempusPage.syncAndReloadPlanner(); + tempusPage.waitForCalendarToFinishLoading(); + tempusPage.disableStundenraster(); + cy.wait(1000); + tempusPage - .getCalendarEventsByTimeRange("08:00:00", "08:45:00") + .getCalendarEventsByWeekdayAndStartTime("Wednesday", "11:20:00") .first() .invoke("attr", "data-fhc-draggable-value") .then((eventJSON) => { @@ -410,10 +439,14 @@ context("Tempus event mutation tests", () => { const eventId = JSON.parse(eventJSON)?.id; expect(eventId).to.exist; - tempusPage.getEventGridRow(eventId).as("originalGridRow"); - tempusPage.dropEventOnCalendarPart(eventId, 6, { - scrollIntoView: true, - }); + 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); @@ -429,11 +462,14 @@ context("Tempus event mutation tests", () => { cy.get("@updatedEventId").then((updatedEventId) => { tempusPage.getCalendarEventById(updatedEventId).should("be.visible"); - cy.get("@originalGridRow").then((originalGridRow) => { - tempusPage.getEventGridRow(updatedEventId).then((updatedGridRow) => { - expect(updatedGridRow).to.not.eq(originalGridRow); + 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 bdccb2b30..a6f0c0c3a 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 @@ -89,14 +89,10 @@ context("Tempus filter tests", () => { waitForOk("@fetchPlanData"); tempusPage.waitForCalendarToFinishLoading(); - tempusPage - .getSelectedRoomIndicator(selectedRoom) - .should("be.visible"); + tempusPage.getSelectedRoomIndicator(selectedRoom).should("be.visible"); tempusPage.getCalendarEvents().should("have.length.greaterThan", 0); - tempusPage - .getSelectedRoomRemoveButton(selectedRoom) - .click(); + tempusPage.getSelectedRoomRemoveButton(selectedRoom).click(); waitForOk("@fetchPlanData"); tempusPage.waitForCalendarToFinishLoading(); @@ -119,7 +115,9 @@ context("Tempus filter tests", () => { .then((eventJSON) => { expect(eventJSON).to.exist; - const selectedLecturer = tempusPage.getFirstLecturer(JSON.parse(eventJSON)); + const selectedLecturer = tempusPage.getFirstLecturer( + JSON.parse(eventJSON), + ); expect(selectedLecturer?.kurzbz, "first event lecturer").to.exist; const lecturerSearch = @@ -183,7 +181,9 @@ context("Tempus filter tests", () => { .then((eventJSON) => { expect(eventJSON).to.exist; - const selectedLecturer = tempusPage.getFirstLecturer(JSON.parse(eventJSON)); + const selectedLecturer = tempusPage.getFirstLecturer( + JSON.parse(eventJSON), + ); expect(selectedLecturer?.kurzbz, "first event lecturer").to.exist; const lecturerSearch = @@ -247,7 +247,9 @@ context("Tempus filter tests", () => { .then((eventJSON) => { expect(eventJSON).to.exist; - const selectedLecturer = tempusPage.getFirstLecturer(JSON.parse(eventJSON)); + const selectedLecturer = tempusPage.getFirstLecturer( + JSON.parse(eventJSON), + ); expect(selectedLecturer?.kurzbz, "first event lecturer").to.exist; const lecturerSearch = @@ -296,7 +298,9 @@ context("Tempus filter tests", () => { .then((eventJSON) => { expect(eventJSON).to.exist; - const selectedLecturer = tempusPage.getFirstLecturer(JSON.parse(eventJSON)); + const selectedLecturer = tempusPage.getFirstLecturer( + JSON.parse(eventJSON), + ); expect(selectedLecturer?.kurzbz, "first event lecturer").to.exist; const lecturerSearch = @@ -330,15 +334,15 @@ context("Tempus filter tests", () => { .getSelectedLecturerWishToggle(selectedLecturerName) .should("be.visible") .click(); - tempusPage - .getLecturerWishOverlays() - .should("have.length", 0) + tempusPage.getLecturerWishOverlays().should("have.length", 0); tempusPage .getSelectedLecturerWishToggle(selectedLecturerName) .should("be.visible") .click(); - tempusPage.getLecturerWishOverlays().should("have.length.greaterThan", 0); + 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 d20b2291e..fb4d0d943 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,4 +1,6 @@ import { waitForOk } from "../../../../support/helpers/network"; +import { getDateForDay } from "../../../../support/helpers/date"; +import { tempusApi } from "../../../../support/api/tempusApi"; import { LEKTOR, PLANER, @@ -9,7 +11,14 @@ import { context("Tempus role preview tests", () => { beforeEach(() => { tempusPage.visitAndWaitForPlanner(); - return tempusPage.clearMondayFirstColumnAfterTest(); + + tempusApi + .getPlannerEvents(getDateForDay("monday"), getDateForDay("monday")) + .then((events) => { + events.forEach((event) => { + tempusApi.deleteKalenderEvent(event.kalender_id); + }); + }); }); it("shows the same number of calendar events for all role previews", () => { @@ -36,8 +45,6 @@ context("Tempus role preview tests", () => { }); it("on planner event change shows unchanged event on other roles", () => { - tempusPage.clearMondayFirstColumnBeforeAndAfter(); - tempusPage.syncAndReloadPlanner(); tempusPage @@ -89,8 +96,6 @@ context("Tempus role preview tests", () => { }); it("sync after planner preview event change loads event in same way on all previews", () => { - tempusPage.clearMondayFirstColumnBeforeAndAfter(); - tempusPage.syncAndReloadPlanner(); tempusPage @@ -142,8 +147,6 @@ context("Tempus role preview tests", () => { }); it.skip("live unlock after planner preview event change loads event in same way on planner and lektor, but not on student preview", () => { - tempusPage.clearMondayFirstColumnBeforeAndAfter(); - tempusPage.syncAndReloadPlanner(); tempusPage diff --git a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.smoke.cy.js b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.smoke.cy.js index a4a722ec7..b8c7db85b 100644 --- a/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.smoke.cy.js +++ b/tests/cypress/cypress/e2e/specs/ui/tempus/tempus.smoke.cy.js @@ -5,7 +5,7 @@ context("Tempus smoke tests", () => { beforeEach(() => { tempusPage.visitAndWaitForPlanner(); }); - + it("can access Tempus page with valid credentials", () => { tempusPage.getTempusOverview().should("be.visible"); }); @@ -75,13 +75,10 @@ context("Tempus smoke tests", () => { tempusPage .getReservationDragHandle() .scrollIntoView() - .drag( - tempusPage.selectors.calendarBaseGrid, - { - waitForAnimations: false, - animationDistanceThreshold: 0, - }, - ); + .drag(tempusPage.selectors.calendarBaseGrid, { + waitForAnimations: false, + animationDistanceThreshold: 0, + }); tempusPage.getReservationModal().should("be.visible"); }); diff --git a/tests/cypress/cypress/support/api/tempusApi.js b/tests/cypress/cypress/support/api/tempusApi.js new file mode 100644 index 000000000..852e2b146 --- /dev/null +++ b/tests/cypress/cypress/support/api/tempusApi.js @@ -0,0 +1,105 @@ +const KALENDER_API = "/index.ci.php/api/frontend/v1/tempus"; + +export const tempusApi = { + getStudyPlansTree: () => + cy + .request({ + method: "GET", + url: `/index.ci.php/api/frontend/v1/lv/StgTree`, + }) + .then((response) => { + expect(response.status).to.eq(200); + expect(response.body).to.have.nested.property("meta.status", "success"); + expect(response.body.data).to.be.an("array"); + + return response.body.data; + }), + + getCoursesByStudyPlan: (studyPlanId, semesterShortCode) => + cy + .request({ + method: "GET", + url: `/index.ci.php/api/frontend/v1/tempus/coursepicker/getByStg`, + qs: { + stg: studyPlanId, + studiensemester_kurzbz: semesterShortCode, + }, + }) + .then((response) => { + expect(response.status).to.eq(200); + expect(response.body).to.have.nested.property("meta.status", "success"); + expect(response.body.data).to.be.an("array"); + + return response.body.data; + }), + + getPlannerEvents: (startDate, endDate) => + cy + .request({ + method: "GET", + url: `${KALENDER_API}/Kalender/getPlan`, + qs: { + start_date: startDate, + end_date: endDate, + }, + }) + .then((response) => { + expect(response.status).to.eq(200); + expect(response.body).to.have.nested.property("meta.status", "success"); + expect(response.body.data).to.be.an("array"); + + return response.body.data; + }), + + createKalenderEvent: (lehreinheitId, startDateTime, endDateTime) => + cy.request({ + method: "POST", + url: `${KALENDER_API}/Kalender/addKalenderEvent`, + body: { + lehreinheit_id: lehreinheitId, + start_date: startDateTime, + end_date: endDateTime, + }, + failOnStatusCode: false, + }), + + updateKalenderEvent: (kalenderId, startDateTime, endDateTime) => + cy.request({ + method: "POST", + url: `${KALENDER_API}/Kalender/updateKalenderEvent`, + form: true, + body: { + kalender_id: kalenderId, + "updatedInfos[start_time]": startDateTime, + "updatedInfos[end_time]": endDateTime, + }, + failOnStatusCode: false, + }), + + deleteKalenderEvent: (kalenderId) => + cy.request({ + method: "POST", + url: `${KALENDER_API}/Kalender/deleteEntry`, + form: true, + body: { + kalender_id: kalenderId, + }, + failOnStatusCode: false, + }), + + getSettingsData: () => ({ + ignore_kollision: false, + kollision_student: false, + ignore_reservierung: false, + ignore_zeitsperre: false, + }), + + updateSettingsData: (options) => + cy.request({ + method: "POST", + url: `${KALENDER_API}/config/set`, + failOnStatusCode: false, + headers: { "Cache-Control": "no-cache", Pragma: "no-cache" }, + body: { ...options }, + }), +}; diff --git a/tests/cypress/cypress/support/helpers/date.js b/tests/cypress/cypress/support/helpers/date.js new file mode 100644 index 000000000..dd3078615 --- /dev/null +++ b/tests/cypress/cypress/support/helpers/date.js @@ -0,0 +1,21 @@ +import moment from "moment"; + +export function getDateForDay(dayName) { + const days = { + monday: 0, + tuesday: 1, + wednesday: 2, + thursday: 3, + friday: 4, + saturday: 5, + sunday: 6, + }; + + const dayIndex = days[dayName.toLowerCase()]; + + if (dayIndex === undefined) { + throw new Error(`Invalid day name: ${dayName}`); + } + + return moment().startOf("isoWeek").add(dayIndex, "days").format("YYYY-MM-DD"); +} \ No newline at end of file diff --git a/tests/cypress/cypress/support/pages/tempus.po.js b/tests/cypress/cypress/support/pages/tempus.po.js index c20069e31..3e87fc8bf 100644 --- a/tests/cypress/cypress/support/pages/tempus.po.js +++ b/tests/cypress/cypress/support/pages/tempus.po.js @@ -6,13 +6,13 @@ 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", @@ -26,230 +26,14 @@ class TempusPage { parkingSlot: "div[data-cy='tempus'] #parkingslot", }; - cleanupMondayFirstColumnAfterTest = false; - - visit = () => cy.visit("/index.ci.php/tempus", { - onBeforeLoad(win) { - win.localStorage.removeItem("tempus_parking"); - win.localStorage.removeItem("tempus_searchtypes"); - win.sessionStorage.removeItem("tempus_searchstr"); - }, - }); - - 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(".fhc-calendar-base-grid"); - getCoursePicker = () => this.getTempusOverview().find(".course-picker"); - getPreviewRoleOptionsHolder = () => this.getTempusOverview().find("[data-cy='previewRoleOptionsHolder']"); - getAllCoursesSliderBtn = () => this.getSidebarMenu().find("button[title='Verband']").first(); - getCourseTreeRows = () => this.getSlideInCoursesMenu().find(".p-treetable-tbody tr"); - getCoursePickerRows = () => this.getCoursePicker().find(".course-picker-row"); - getCoursePickerSearchInput = () => this.getCoursePicker().find("input"); - getCalendarEventsPerWeekHolders = () => this.getCalendarBaseGrid().find(".fhc-calendar-base-grid-line"); - getCalendarEvents = () => this.getCalendarSection().then(($calendar) => { - return $calendar.find(".fhc-calendar-base-grid-line-event"); - }); - getLecturerWishOverlays = () => this.getCalendarSection().find(".bg-lecturer-wish"); - getCalendarEventsWithRoom = () => this.getCalendarEvents().filter((index, event) => { - const eventData = JSON.parse(event.getAttribute("data-fhc-draggable-value")); - return !!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 !!eventData?.orig?.ort_kurzbz; - }); - 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"); - - getCalendarEventById = (id) => this.getCalendarEvents().filter(`div[data-id="event-${id}"]`); - getCalendarPartDropTarget = (partIndex) => - `${this.selectors.calendarBaseGrid} .part-body:nth-of-type(${partIndex})`; - dropEventOnCalendarPart = (eventId, partIndex, options = {}) => { - const event = this.getCalendarEventById(eventId); - - return event.should("be.visible").drag( - this.getCalendarPartDropTarget(partIndex), - { - waitForAnimations: false, - animationDistanceThreshold: 0, - ...options, + visit = () => + cy.visit("/index.ci.php/tempus", { + onBeforeLoad(win) { + win.localStorage.removeItem("tempus_parking"); + win.localStorage.removeItem("tempus_searchtypes"); + win.sessionStorage.removeItem("tempus_searchstr"); }, - ); - }; - 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, - }, - ); - }; - getEventGridRowFromStyle = (style) => - /grid-row:\s*([^;]+)/.exec(style)?.[1]?.trim(); - getEventGridRow = (id) => - this.getCalendarEventById(id) - .invoke("attr", "style") - .then((style) => this.getEventGridRowFromStyle(style)); - getCalendarEventsByWeekday = (weekday) => this.getCalendarEventsPerWeekHolders().eq(weekdayToGridRowMap[weekday] - 1).find(".fhc-calendar-base-grid-line-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; - }); - getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime = (weekday, startTime) => - this.getCalendarEventsByWeekdayAndStartTime(weekday, startTime).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?.retval; - - return retval?.kalender_id ?? retval; - }; - getMondayFirstColumnEventData = ($body) => - [ - ...$body - .find(`${this.selectors.calendarBaseGrid} .fhc-calendar-base-grid-line`) - .first() - .find(".fhc-calendar-base-grid-line-event"), - ] - .map((event) => { - const eventJSON = event.getAttribute("data-fhc-draggable-value"); - - 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); - getRaumauswahlModal = () => - cy.contains(".bootstrap-modal.show .modal-title", "Raumauswahl") - .closest(".bootstrap-modal.show"); - getRaumauswahlRoomOptions = () => - this.getRaumauswahlModal().find(".list-group-item"); - getCalendarEventRoom = (id) => - this.getCalendarEventById(id).find(".event-place"); - 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(".fhc-calendar-base-grid-line-event"); - getPreviewRoleButton = (role) => this.getPreviewRoleOptionsHolder().contains("button", role); - - getSemesterSetterButton = () => this.getSidebarMenu().find(".stv-studiensemester button").last(); - - openCoursesMenu = () => { - this.getAllCoursesSliderBtn().click(); - this.getSlideInCoursesMenu().should("be.visible"); - }; - - selectFirstCourse = () => { - this.openCoursesMenu(); - this.getCourseTreeRows().first().click(); - }; - - selectCourseByName = (courseShortName) => { - this.openCoursesMenu(); - this.getCourseTreeRows().contains(courseShortName).click(); - } - - selectPreviewRole = (role) => { - this.getPreviewRoleButton(role).click(); - }; - - syncAndReloadPlanner = () => { - this.selectPreviewRole(SYNC); - waitForOk("@syncCalendar"); - waitForOk("@fetchPlanData"); - this.waitForCalendarToFinishLoading(); - }; - - selectRoleAndWait = (role) => { - this.selectPreviewRole(role); - waitForOk(roleFetchAliases[role]); - this.waitForCalendarToFinishLoading(); - }; - - expectCalendarEventRoom = (eventId, expectedRoom) => { - this.getCalendarEventRoom(eventId) - .scrollIntoView() - .should("be.visible") - .invoke("text") - .then((roomText) => { - expect(roomText.trim(), "event room").to.eq(expectedRoom); - }); - }; setupIntercepts = () => { cy.intercept({ method: "GET", url: "**/StgTree" }).as("fetchCourseTree"); @@ -310,6 +94,254 @@ class TempusPage { }).as("deleteCalendarEvent"); }; + 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(".fhc-calendar-base-grid"); + getCoursePicker = () => this.getTempusOverview().find(".course-picker"); + getPreviewRoleOptionsHolder = () => + this.getTempusOverview().find("[data-cy='previewRoleOptionsHolder']"); + getAllCoursesSliderBtn = () => + this.getSidebarMenu().find("button[title='Verband']").first(); + getCourseTreeRows = () => + this.getSlideInCoursesMenu().find(".p-treetable-tbody tr"); + getCoursePickerRows = () => this.getCoursePicker().find(".course-picker-row"); + getCoursePickerSearchInput = () => this.getCoursePicker().find("input"); + getCalendarEventsPerWeekHolders = () => + this.getCalendarBaseGrid().find(".fhc-calendar-base-grid-line"); + getCalendarEvents = () => + this.getCalendarSection().then(($calendar) => { + return $calendar.find(".fhc-calendar-base-grid-line-event"); + }); + getLecturerWishOverlays = () => + this.getCalendarSection().find(".bg-lecturer-wish"); + getCalendarEventsWithRoom = () => + this.getCalendarEvents().filter((index, event) => { + const eventData = JSON.parse( + event.getAttribute("data-fhc-draggable-value"), + ); + return !!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 !!eventData?.orig?.ort_kurzbz; + }); + 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"); + + getCalendarEventById = (id) => + this.getCalendarEvents().filter(`div[data-id="event-${id}"]`); + getCalendarPartDropTarget = (partIndex) => + `${this.selectors.calendarBaseGrid} .part-body:nth-of-type(${partIndex})`; + getEventGridRowFromStyle = (style) => + /grid-row:\s*([^;]+)/.exec(style)?.[1]?.trim(); + getEventGridRow = (id) => + this.getCalendarEventById(id) + .invoke("attr", "style") + .then((style) => this.getEventGridRowFromStyle(style)); + getCalendarEventsByWeekday = (weekday) => + this.getCalendarEventsPerWeekHolders() + .eq(weekdayToGridRowMap[weekday] - 1) + .find(".fhc-calendar-base-grid-line-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; + }); + getCalendarEventsWithLehreinheitAndRoomByWeekdayAndStartTime = ( + weekday, + startTime, + ) => + this.getCalendarEventsByWeekdayAndStartTime(weekday, startTime).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?.retval; + + return retval?.kalender_id ?? retval; + }; + getMondayFirstColumnEventData = ($body) => + [ + ...$body + .find(`${this.selectors.calendarBaseGrid} .fhc-calendar-base-grid-line`) + .first() + .find(".fhc-calendar-base-grid-line-event"), + ] + .map((event) => { + const eventJSON = event.getAttribute("data-fhc-draggable-value"); + + 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); + getRaumauswahlModal = () => + cy + .contains(".bootstrap-modal.show .modal-title", "Raumauswahl") + .closest(".bootstrap-modal.show"); + getRaumauswahlRoomOptions = () => + this.getRaumauswahlModal().find(".list-group-item"); + getCalendarEventRoom = (id) => + this.getCalendarEventById(id).find(".event-place"); + 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(".fhc-calendar-base-grid-line-event"); + getPreviewRoleButton = (role) => + this.getPreviewRoleOptionsHolder().contains("button", role); + + getSemesterSetterButton = () => + this.getSidebarMenu().find(".stv-studiensemester button").last(); + + openCoursesMenu = () => { + this.getAllCoursesSliderBtn().click(); + this.getSlideInCoursesMenu().should("be.visible"); + }; + + selectFirstCourse = () => { + this.openCoursesMenu(); + this.getCourseTreeRows().first().click(); + }; + + selectCourseByName = (courseShortName) => { + this.openCoursesMenu(); + this.getCourseTreeRows().contains(courseShortName).click(); + }; + + selectPreviewRole = (role) => { + this.getPreviewRoleButton(role).click(); + }; + + syncAndReloadPlanner = () => { + this.selectPreviewRole(SYNC); + waitForOk("@syncCalendar"); + waitForOk("@fetchPlanData"); + this.waitForCalendarToFinishLoading(); + }; + + selectRoleAndWait = (role) => { + this.selectPreviewRole(role); + waitForOk(roleFetchAliases[role]); + this.waitForCalendarToFinishLoading(); + }; + + expectCalendarEventRoom = (eventId, expectedRoom) => { + this.getCalendarEventRoom(eventId) + .scrollIntoView() + .should("be.visible") + .invoke("text") + .then((roomText) => { + expect(roomText.trim(), "event room").to.eq(expectedRoom); + }); + }; + visitAndWaitForPlanner = () => { cy.login(); this.setupIntercepts(); @@ -320,74 +352,6 @@ class TempusPage { this.waitForCalendarToFinishLoading(); }; - reloadPlannerForCleanup = () => { - this.visit(); - waitForOk("@fetchCourseTree"); - waitForOk("@fetchPlanData"); - - return this.waitForCalendarToFinishLoading(); - }; - - deleteKalenderEvent = (kalenderId) => - cy.request({ - method: "POST", - url: "/index.ci.php/api/frontend/v1/tempus/Kalender/deleteEntry", - form: true, - body: { - kalender_id: kalenderId, - }, - failOnStatusCode: false, - }); - - clearMondayFirstColumn = () => { - this.reloadPlannerForCleanup(); - - return cy.get("body").then(($body) => { - const calendarIds = [ - ...new Set( - this.getMondayFirstColumnEventData($body) - .map(this.getKalenderId) - .filter(Boolean), - ), - ]; - - if (!calendarIds.length) { - return; - } - - return cy - .wrap(calendarIds, { log: false }) - .each((kalenderId) => { - return this.deleteKalenderEvent(kalenderId).then((response) => { - if (response.status !== 200) { - Cypress.log({ - name: "tempus cleanup", - message: `Could not delete calendar event ${kalenderId}: ${response.status}`, - }); - } - }); - }) - .then(() => { - return this.reloadPlannerForCleanup(); - }); - }); - }; - - clearMondayFirstColumnBeforeAndAfter = () => { - this.cleanupMondayFirstColumnAfterTest = true; - - return this.clearMondayFirstColumn(); - }; - - clearMondayFirstColumnAfterTest = () => { - const shouldClearMondayFirstColumn = this.cleanupMondayFirstColumnAfterTest; - this.cleanupMondayFirstColumnAfterTest = false; - - if (shouldClearMondayFirstColumn) { - return this.clearMondayFirstColumn(); - } - }; - disableStundenraster = () => { this.getStundenrasterToggle().then(($toggle) => { if ($toggle.find(".fa-toggle-on").length) { @@ -395,7 +359,9 @@ class TempusPage { } }); - this.getStundenrasterToggle().find("i").should("have.class", "fa-toggle-off"); + this.getStundenrasterToggle() + .find("i") + .should("have.class", "fa-toggle-off"); }; waitForCalendarToFinishLoading = () => { @@ -404,10 +370,35 @@ class TempusPage { setCurrentSemester = () => { this.getSemesterSetterButton().click(); - //waitForOk("@getCurrentSemester"); - //waitForOk("@setSemester"); - } + }; + dropEventOnCalendarPart = (eventId, partIndex, options = {}) => { + const event = this.getCalendarEventById(eventId); + + return event + .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();