BUG: fix for failing tests due to ended semester

This commit is contained in:
Ivymaster
2026-07-08 15:33:33 +02:00
parent 1805fc643e
commit a50ee86940
19 changed files with 246 additions and 204 deletions
+3 -1
View File
@@ -1,4 +1,6 @@
node_modules
.env
.env.*
!.env.example
!.env.example
/cypress/screenshots
/cypress/videos
@@ -1,68 +1,34 @@
import { tempusApi } from "../../../../support/api/tempusApi";
import { getDateForDay } from "../../../../support/helpers/date";
import {
getTempusTestSemester,
TEMPUS_TEST_STUDY_PLAN_SHORT_CODE,
} from "../../../../support/helpers/tempusTestData";
const TARGETED_STUDY_PLAN_SHORT_CODE = "STG5";
const resetEventsBeforeTest = () => {
tempusApi
.getPlannerEvents(getDateForDay("monday"), getDateForDay("monday"))
.then((events) => {
events.forEach((event) => {
tempusApi.deleteKalenderEvent(event.kalender_id);
});
});
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`,
);
}
});
});
tempusApi
.getPlannerEvents(getDateForDay("sunday"), getDateForDay("sunday"))
.then((events) => {
events.forEach((event) => {
if (
event.type === "lehreinheit" &&
event.beginn === "18:35:00" &&
event.ende === "19:20:00" &&
event.lektor.some((lector) => lector.kurzbz === "DemoLKT1")
) {
tempusApi.updateKalenderEvent(
event.kalender_id,
`${event.datum} 17:50`,
`${event.datum} 18:35`,
);
}
});
});
};
let TEMPUS_TEST_SEMESTER;
describe("Tempus Kalender API", () => {
before(() => {
cy.login();
getTempusTestSemester().then((semester) => {
TEMPUS_TEST_SEMESTER = semester;
});
});
beforeEach(() => {
cy.login();
resetEventsBeforeTest();
tempusApi.resetTempusScenario();
});
it("event creation works for non collision case", () => {
tempusApi.getStudyPlansTree().then((stgTree) => {
let studyPlan = stgTree.find((plan) =>
plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE),
plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE),
);
expect(studyPlan, "study plan for test event creation").to.exist;
tempusApi
.getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026")
.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;
@@ -94,12 +60,12 @@ describe("Tempus Kalender API", () => {
it("prohibited event creation due to zeitsperre collision", () => {
tempusApi.getStudyPlansTree().then((stgTree) => {
let studyPlan = stgTree.find((plan) =>
plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE),
plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE),
);
expect(studyPlan, "study plan for test event creation").to.exist;
tempusApi
.getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026")
.getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER)
.then((courses) => {
let course = courses.find((course) =>
course.lektoren.some((lector) => lector.kurzbz === "DemoLKT1"),
@@ -142,12 +108,12 @@ describe("Tempus Kalender API", () => {
it("prohibited event creation due to student group collision", () => {
tempusApi.getStudyPlansTree().then((stgTree) => {
let studyPlan = stgTree.find((plan) =>
plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE),
plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE),
);
expect(studyPlan, "study plan for test event creation").to.exist;
tempusApi
.getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026")
.getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER)
.then((courses) => {
let course = courses.find(
(course) =>
@@ -194,12 +160,12 @@ describe("Tempus Kalender API", () => {
tempusApi.getStudyPlansTree().then((stgTree) => {
let studyPlan = stgTree.find((plan) =>
plan.name.includes(TARGETED_STUDY_PLAN_SHORT_CODE),
plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE),
);
expect(studyPlan, "study plan for test event creation").to.exist;
tempusApi
.getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026")
.getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER)
.then((courses) => {
let course = courses.find(
(course) =>
@@ -252,12 +218,12 @@ describe("Tempus Kalender API", () => {
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),
plan.name.includes(TEMPUS_TEST_STUDY_PLAN_SHORT_CODE),
);
expect(studyPlan, "study plan for test event creation").to.exist;
tempusApi
.getCoursesByStudyPlan(studyPlan.studiengang_kz, "SS2026")
.getCoursesByStudyPlan(studyPlan.studiengang_kz, TEMPUS_TEST_SEMESTER)
.then((courses) => {
let course = courses.find((course) =>
course.lektoren.some((lector) => lector.kurzbz === "DemoLKT4"),
@@ -1,19 +1,9 @@
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();
@@ -61,7 +51,7 @@ context("Tempus course picker tests", () => {
});
it("can drag and drop one course event into the calendar", () => {
deleteMondayEvents();
tempusApi.deletePlannerEventsForDay("monday");
tempusPage.getCalendarSection().should("exist");
tempusPage.waitForCalendarToFinishLoading();
@@ -1,5 +1,4 @@
import { waitForOk } from "../../../../support/helpers/network";
import { getDateForDay } from "../../../../support/helpers/date";
import { tempusApi } from "../../../../support/api/tempusApi";
import {
LEKTOR,
@@ -13,13 +12,7 @@ context("Tempus event mutation tests", () => {
beforeEach(() => {
tempusPage.visitAndWaitForPlanner();
tempusApi
.getPlannerEvents(getDateForDay("monday"), getDateForDay("monday"))
.then((events) => {
events.forEach((event) => {
tempusApi.deleteKalenderEvent(event.kalender_id);
});
});
tempusApi.deletePlannerEventsForDay("monday");
});
it("room change on planner preview updates planner event, but keeps original room on other previews", () => {
@@ -51,52 +44,16 @@ context("Tempus event mutation tests", () => {
tempusPage.expectCalendarEventRoom(eventId, originalRoom);
tempusPage
.getCalendarEventById(eventId)
.should("be.visible")
.rightclick();
tempusPage.getEventContextMenuOption("Raumauswahl").click({ force: true });
waitForOk("@fetchRoomSuggestions");
tempusPage.changeEventRoom(eventId, originalRoom).then((result) => {
const { newRoom, updatedEventId } = result;
tempusPage
.getRaumauswahlRoomOptions()
.should("have.length.greaterThan", 0)
.then(($roomOptions) => {
const roomOption = [...$roomOptions].find((option) => {
const room = option.innerText.trim();
tempusPage.expectCalendarEventRoom(updatedEventId, newRoom);
return room && room !== originalRoom;
});
tempusPage.selectRoleAndWait(LEKTOR);
tempusPage.expectCalendarEventRoom(eventId, originalRoom);
expect(roomOption, "different room suggestion").to.exist;
cy.wrap(roomOption.innerText.trim()).as("newRoom");
cy.wrap(roomOption).click();
});
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("@newRoom").then((newRoom) => {
console.log(eventId)
console.log(newRoom)
cy.get("@updatedEventId").then((updatedEventId) => {
tempusPage.expectCalendarEventRoom(updatedEventId, newRoom);
tempusPage.selectRoleAndWait(LEKTOR);
tempusPage.expectCalendarEventRoom(eventId, originalRoom);
tempusPage.selectRoleAndWait(STUDENT);
tempusPage.expectCalendarEventRoom(eventId, originalRoom);
});
tempusPage.selectRoleAndWait(STUDENT);
tempusPage.expectCalendarEventRoom(eventId, originalRoom);
});
});
});
@@ -128,54 +85,19 @@ context("Tempus event mutation tests", () => {
expect(originalRoom, "original event room").to.be.a("string").and.not.be
.empty;
tempusPage
.getCalendarEventById(eventId)
.scrollIntoView()
.should("be.visible")
.rightclick();
tempusPage.getEventContextMenuOption("Raumauswahl").click({ force: true });
waitForOk("@fetchRoomSuggestions");
tempusPage.changeEventRoom(eventId, originalRoom).then((result) => {
const { newRoom, updatedEventId } = result;
tempusPage
.getRaumauswahlRoomOptions()
.should("have.length.greaterThan", 0)
.then(($roomOptions) => {
const roomOption = [...$roomOptions].find((option) => {
const room = option.innerText.trim();
tempusPage.expectCalendarEventRoom(updatedEventId, newRoom);
return room && room !== originalRoom;
});
tempusPage.syncAndReloadPlanner();
tempusPage.expectCalendarEventRoom(updatedEventId, newRoom);
expect(roomOption, "different room suggestion").to.exist;
tempusPage.selectRoleAndWait(LEKTOR);
tempusPage.expectCalendarEventRoom(updatedEventId, newRoom);
cy.wrap(roomOption.innerText.trim()).as("newRoom");
cy.wrap(roomOption).click();
});
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("@newRoom").then((newRoom) => {
cy.get("@updatedEventId").then((updatedEventId) => {
tempusPage.expectCalendarEventRoom(updatedEventId, newRoom);
tempusPage.syncAndReloadPlanner();
tempusPage.expectCalendarEventRoom(updatedEventId, newRoom);
tempusPage.selectRoleAndWait(LEKTOR);
tempusPage.expectCalendarEventRoom(updatedEventId, newRoom);
tempusPage.selectRoleAndWait(STUDENT);
tempusPage.expectCalendarEventRoom(updatedEventId, newRoom);
});
tempusPage.selectRoleAndWait(STUDENT);
tempusPage.expectCalendarEventRoom(updatedEventId, newRoom);
});
});
});
@@ -45,7 +45,7 @@ context("Tempus filter tests", () => {
selectedRoom,
);
cy.wrap($event)
.find(".event-place")
.find("[data-cy='calendar-event-room']")
.invoke("text")
.then((eventPlace) => {
expect(eventPlace.trim(), "event body room").to.eq(selectedRoom);
@@ -1,5 +1,4 @@
import { waitForOk } from "../../../../support/helpers/network";
import { getDateForDay } from "../../../../support/helpers/date";
import { tempusApi } from "../../../../support/api/tempusApi";
import {
LEKTOR,
@@ -12,13 +11,7 @@ context("Tempus role preview tests", () => {
beforeEach(() => {
tempusPage.visitAndWaitForPlanner();
tempusApi
.getPlannerEvents(getDateForDay("monday"), getDateForDay("monday"))
.then((events) => {
events.forEach((event) => {
tempusApi.deleteKalenderEvent(event.kalender_id);
});
});
tempusApi.deletePlannerEventsForDay("monday");
});
it("shows the same number of calendar events for all role previews", () => {
@@ -44,7 +44,7 @@ context("Tempus smoke tests", () => {
tempusPage.getEventContextMenu().should("be.visible");
});
it("shows Raumauswahl modal when selecting Raumauswahl from event context menu", () => {
it("shows room selection modal when selecting 'room selection' from event context menu", () => {
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getCalendarEventsWithLehreinheit()
@@ -54,7 +54,7 @@ context("Tempus smoke tests", () => {
tempusPage.getEventContextMenuOption("Raumauswahl").click({ force: true });
waitForOk("@fetchRoomSuggestions");
tempusPage.getRaumauswahlModal().should("be.visible");
tempusPage.getRoomSelectionModal().should("be.visible");
});
it("shows resources modal when selecting Ressourcen zuordnen from event context menu", () => {
@@ -1,5 +1,25 @@
import { getDateForDay } from "../helpers/date";
const KALENDER_API = "/index.ci.php/api/frontend/v1/tempus";
const updatePlannerEventsForDay = (day, predicate, startTime, endTime) => {
const date = getDateForDay(day);
return tempusApi.getPlannerEvents(date, date).then((events) =>
cy.wrap(events).each((event) => {
if (!predicate(event)) {
return null;
}
return tempusApi.updateKalenderEvent(
event.kalender_id,
`${event.datum} ${startTime}`,
`${event.datum} ${endTime}`,
);
}),
);
};
export const tempusApi = {
getStudyPlansTree: () =>
cy
@@ -15,6 +35,23 @@ export const tempusApi = {
return response.body.data;
}),
getStudySemesters: () =>
cy
.request({
method: "GET",
url: `/index.ci.php/api/frontend/v1/organisation/Studiensemester/getAll`,
qs: {
order: "DESC",
},
})
.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({
@@ -51,6 +88,43 @@ export const tempusApi = {
return response.body.data;
}),
deletePlannerEventsForDay: (day) => {
const date = getDateForDay(day);
return tempusApi.getPlannerEvents(date, date).then((events) =>
cy.wrap(events).each((event) =>
tempusApi.deleteKalenderEvent(event.kalender_id),
),
);
},
resetTempusScenario: () =>
tempusApi
.deletePlannerEventsForDay("monday")
.then(() =>
updatePlannerEventsForDay(
"tuesday",
(event) =>
event.type === "lehreinheit" &&
event.beginn === "20:15:00" &&
event.ende === "21:00:00",
"19:30",
"20:15",
),
)
.then(() =>
updatePlannerEventsForDay(
"sunday",
(event) =>
event.type === "lehreinheit" &&
event.beginn === "18:35:00" &&
event.ende === "19:20:00" &&
event.lektor?.some((lector) => lector.kurzbz === "DemoLKT1"),
"17:50",
"18:35",
),
),
createKalenderEvent: (lehreinheitId, startDateTime, endDateTime) =>
cy.request({
method: "POST",
@@ -0,0 +1,35 @@
import { tempusApi } from "../api/tempusApi";
export const TEMPUS_TEST_STUDY_PLAN_SHORT_CODE = "STG5";
const getLocalDateString = () => {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, "0");
const day = String(today.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
};
const getSemesterStartDate = (semester) => semester.start?.slice(0, 10);
export const getTempusTestSemester = () =>
tempusApi.getStudySemesters().then((semesters) => {
const today = getLocalDateString();
const activeSemester = semesters
.filter((semester) => {
const startDate = getSemesterStartDate(semester);
return startDate && startDate <= today;
})
.sort((a, b) =>
getSemesterStartDate(b).localeCompare(getSemesterStartDate(a)),
)[0];
expect(
activeSemester,
`Tempus test semester starting on or before ${today}`,
).to.exist;
return activeSemester.studiensemester_kurzbz;
});
@@ -22,7 +22,7 @@ const roleFetchAliases = {
class TempusPage {
selectors = {
calendarBaseGrid: "div[data-cy='tempus'] .fhc-calendar-base-grid",
calendarBaseGrid: "div[data-cy='tempus'] [data-cy='calendar-base-grid']",
parkingSlot: "div[data-cy='tempus'] #parkingslot",
};
@@ -108,22 +108,26 @@ class TempusPage {
getCalendarSection = () =>
this.getTempusOverview().find(".fhc-calendar-base");
getCalendarBaseGrid = () =>
this.getCalendarSection().find(".fhc-calendar-base-grid");
this.getCalendarSection().find("[data-cy='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");
this.getSlideInCoursesMenu()
.find("[data-cy='course-tree-row']")
.closest("[role='row']");
getCourseTreeRowByName = (courseShortName) =>
this.getSlideInCoursesMenu()
.contains("[data-cy='course-tree-row']", courseShortName)
.closest("[role='row']");
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");
});
this.getCalendarSection().find("[data-cy='calendar-event']");
getLecturerWishOverlays = () =>
this.getCalendarSection().find(".bg-lecturer-wish");
getCalendarEventsWithRoom = () =>
@@ -195,7 +199,7 @@ class TempusPage {
getCalendarEventById = (id) =>
this.getCalendarEvents().filter(`div[data-id="event-${id}"]`);
getCalendarPartDropTarget = (partIndex) =>
`${this.selectors.calendarBaseGrid} .part-body:nth-of-type(${partIndex})`;
`${this.selectors.calendarBaseGrid} [data-cy='calendar-grid-part'][data-drop-index='${partIndex}']`;
getEventGridRowFromStyle = (style) =>
/grid-row:\s*([^;]+)/.exec(style)?.[1]?.trim();
getEventGridRow = (id) =>
@@ -205,7 +209,7 @@ class TempusPage {
getCalendarEventsByWeekday = (weekday) =>
this.getCalendarEventsPerWeekHolders()
.eq(weekdayToGridRowMap[weekday] - 1)
.find(".fhc-calendar-base-grid-line-event");
.find("[data-cy='calendar-event']");
getCalendarEventsByStartTime = (startTime) =>
this.getCalendarEvents().filter((index, event) => {
const eventData = JSON.parse(
@@ -262,12 +266,54 @@ class TempusPage {
return retval?.kalender_id ?? retval;
};
chooseDifferentRoomForEvent = (eventId, originalRoom) => {
this.getCalendarEventById(eventId)
.scrollIntoView()
.should("be.visible")
.rightclick();
this.getEventContextMenuOption("Raumauswahl").click({ force: true });
waitForOk("@fetchRoomSuggestions");
return this.getRaumauswahlRoomOptions()
.should("have.length.greaterThan", 0)
.then(($roomOptions) => {
const roomOption = [...$roomOptions].find((option) => {
const room = option.innerText.trim();
return room && room !== originalRoom;
});
expect(roomOption, "different room suggestion").to.exist;
const newRoom = roomOption.innerText.trim();
return cy.wrap(roomOption).click().then(() => newRoom);
});
};
waitForUpdatedEventId = () =>
cy.wait("@updateCalendarEvent").then((interception) => {
expect(interception.response.statusCode).to.eq(200);
const updatedEventId = this.getUpdatedKalenderId(interception);
expect(updatedEventId, "updated planner event id").to.exist;
return updatedEventId;
});
changeEventRoom = (eventId, originalRoom) =>
this.chooseDifferentRoomForEvent(eventId, originalRoom).then((newRoom) =>
this.waitForUpdatedEventId().then((updatedEventId) => {
waitForOk("@fetchPlanData");
this.waitForCalendarToFinishLoading();
return cy.wrap({ newRoom, updatedEventId });
}),
);
getMondayFirstColumnEventData = ($body) =>
[
...$body
.find(`${this.selectors.calendarBaseGrid} .fhc-calendar-base-grid-line`)
.first()
.find(".fhc-calendar-base-grid-line-event"),
.find("[data-cy='calendar-event']"),
]
.map((event) => {
const eventJSON = event.getAttribute("data-fhc-draggable-value");
@@ -286,18 +332,18 @@ class TempusPage {
getEventContextMenu = () => cy.get("[data-cy='eventContextMenu']");
getEventContextMenuOption = (option) =>
this.getEventContextMenu().contains("button", option);
getRaumauswahlModal = () =>
getRoomSelectionModal = () =>
cy
.contains(".bootstrap-modal.show .modal-title", "Raumauswahl")
.closest(".bootstrap-modal.show");
getRaumauswahlRoomOptions = () =>
this.getRaumauswahlModal().find(".list-group-item span");
this.getRoomSelectionModal().find(".list-group-item span");
getResourcesModal = () =>
cy
.get("[data-cy='resourcesAssignmentModal']")
.closest(".bootstrap-modal.show");
getCalendarEventRoom = (id) =>
this.getCalendarEventById(id).find(".event-place");
this.getCalendarEventById(id).find("[data-cy='calendar-event-room']");
getStundenrasterToggle = () =>
cy.contains(".form-check-label", "Stundenraster").parent();
getHistoryModal = () => cy.get("[data-cy='historyModal']");
@@ -305,7 +351,7 @@ class TempusPage {
getReservationModal = () => cy.get("[data-cy='reservationModal']");
getEventParkingSlot = () => this.getSidebarMenu().find("#parkingslot");
getParkedEvents = () =>
this.getEventParkingSlot().find(".fhc-calendar-base-grid-line-event");
this.getEventParkingSlot().find("[data-cy='calendar-event']");
getPreviewRoleButton = (role) =>
this.getPreviewRoleOptionsHolder().contains("button", role);
@@ -324,7 +370,7 @@ class TempusPage {
selectCourseByName = (courseShortName) => {
this.openCoursesMenu();
this.getCourseTreeRows().contains(courseShortName).click();
this.getCourseTreeRowByName(courseShortName).click();
};
selectPreviewRole = (role) => {