Add tempus test file split

This commit is contained in:
Ivymaster
2026-05-31 23:17:22 +02:00
parent 40c18d3603
commit 64b6e4a009
8 changed files with 1404 additions and 1356 deletions
@@ -0,0 +1,76 @@
import { waitForOk } from "../../../../support/helpers/network";
import { tempusPage } from "../../../../support/pages/tempus.po";
context("Tempus course picker tests", () => {
beforeEach(() => {
tempusPage.visitAndWaitForPlanner();
});
afterEach(() => {
return tempusPage.clearMondayFirstColumnAfterTest();
});
it("can select one course and show preview of its events", () => {
tempusPage.getSlideInCoursesMenu().should("exist");
tempusPage.getCourseTreeRows().should("have.length.greaterThan", 0);
tempusPage.getCoursePicker().should("exist");
tempusPage.getCoursePickerRows().should("have.length", 0);
tempusPage.selectFirstCourse();
waitForOk("@fetchCoursePickerCourses");
tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0);
});
it("can search for a course event in the course picker", () => {
tempusPage.selectFirstCourse();
waitForOk("@fetchCoursePickerCourses");
tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0);
tempusPage
.getCoursePickerRows()
.last()
.find("div:first span:first")
.invoke("text")
.as("randomCourseText");
cy.get("@randomCourseText").then((randomCourseText) => {
tempusPage.getCoursePickerSearchInput().type(randomCourseText);
tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0);
tempusPage
.getCoursePickerRows()
.first()
.should("contain.text", randomCourseText);
});
});
it("can drag and drop one course event into the calendar", () => {
tempusPage.clearMondayFirstColumnBeforeAndAfter();
tempusPage.getCalendarSection().should("exist");
tempusPage.waitForCalendarToFinishLoading();
tempusPage.selectFirstCourse();
waitForOk("@fetchCoursePickerCourses");
tempusPage.getCalendarEvents().then(($events) => {
cy.wrap($events.length).as("initialEventCount");
});
tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0);
tempusPage.dropCourseOnCalendarPart(0, 10);
waitForOk("@addCalendarEvent");
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
cy.get("@initialEventCount").then((initialEventCount) => {
tempusPage
.getCalendarEvents()
.should("have.length", initialEventCount + 1);
});
});
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,433 @@
import { waitForOk } from "../../../../support/helpers/network";
import { LEKTOR, STUDENT, tempusPage } from "../../../../support/pages/tempus.po";
context("Tempus event mutation tests", () => {
beforeEach(() => {
tempusPage.visitAndWaitForPlanner();
});
afterEach(() => {
return tempusPage.clearMondayFirstColumnAfterTest();
});
it("room change on planner preview updates planner event, but keeps original room on other previews", () => {
tempusPage.clearMondayFirstColumnBeforeAndAfter();
tempusPage.syncAndReloadPlanner();
tempusPage
.getCalendarEventsWithLehreinheitAndRoom()
.should("have.length.greaterThan", 0);
tempusPage
.getCalendarEventsWithLehreinheitAndRoom()
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
const eventData = JSON.parse(eventJSON);
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;
tempusPage.expectCalendarEventRoom(eventId, originalRoom);
tempusPage
.getCalendarEventById(eventId)
.should("be.visible")
.rightclick();
tempusPage.getEventContextMenuOption("Raumauswahl").click();
waitForOk("@fetchRoomSuggestions");
tempusPage
.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;
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.selectRoleAndWait(LEKTOR);
tempusPage.expectCalendarEventRoom(eventId, originalRoom);
tempusPage.selectRoleAndWait(STUDENT);
tempusPage.expectCalendarEventRoom(eventId, originalRoom);
});
});
});
});
it("sync after planner preview room change loads new room on all previews", () => {
tempusPage.clearMondayFirstColumnBeforeAndAfter();
tempusPage.syncAndReloadPlanner();
tempusPage
.getCalendarEventsWithLehreinheitAndRoom()
.should("have.length.greaterThan", 0);
tempusPage
.getCalendarEventsWithLehreinheitAndRoom()
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
const eventData = JSON.parse(eventJSON);
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;
tempusPage
.getCalendarEventById(eventId)
.scrollIntoView()
.should("be.visible")
.rightclick();
tempusPage.getEventContextMenuOption("Raumauswahl").click();
waitForOk("@fetchRoomSuggestions");
tempusPage
.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;
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);
});
});
});
});
it("can drop event from calendar into parking slot", () => {
tempusPage.getEventParkingSlot().should("exist");
tempusPage.getParkedEvents().should("have.length", 0);
tempusPage
.getCalendarEvents()
.first()
.drag(tempusPage.selectors.parkingSlot);
tempusPage.getParkedEvents().should("have.length", 1);
});
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
.getCalendarEvents()
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
let eventId = JSON.parse(eventJSON)?.id;
expect(eventId).to.exist;
tempusPage
.getCalendarEventById(eventId)
.should("be.visible")
.rightclick();
tempusPage.getEventContextMenuOption("Delete").click();
cy.wait("@deleteCalendarEvent");
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
tempusPage.getCalendarEventById(eventId).should("be.visible");
tempusPage.selectRoleAndWait(LEKTOR);
tempusPage.getCalendarEventById(eventId).should("not.exist");
tempusPage.selectRoleAndWait(STUDENT);
tempusPage.getCalendarEventById(eventId).should("not.exist");
});
});
it("syncing event deletion on planner preview removes event from other previews", () => {
tempusPage.clearMondayFirstColumnBeforeAndAfter();
tempusPage.syncAndReloadPlanner();
tempusPage
.getCalendarEvents()
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
let eventId = JSON.parse(eventJSON)?.id;
expect(eventId).to.exist;
tempusPage
.getCalendarEventById(eventId)
.should("be.visible")
.rightclick();
tempusPage.getEventContextMenuOption("Delete").click();
cy.wait("@deleteCalendarEvent");
waitForOk("@fetchPlanData");
tempusPage.syncAndReloadPlanner();
tempusPage.getCalendarEventById(eventId).should("not.exist");
tempusPage.selectRoleAndWait(LEKTOR);
tempusPage.getCalendarEventById(eventId).should("not.exist");
tempusPage.selectRoleAndWait(STUDENT);
tempusPage.getCalendarEventById(eventId).should("not.exist");
});
});
it("can bottom resize an event on planner preview", () => {
tempusPage.clearMondayFirstColumnBeforeAndAfter();
tempusPage.getCalendarSection().should("exist");
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getCalendarEventsByStartTime("08:00:00")
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
cy.wrap(JSON.parse(eventJSON)).its("id").as("eventId");
cy.wrap(JSON.parse(eventJSON).orig)
.its("beginn")
.as("originalEventStart");
cy.wrap(JSON.parse(eventJSON).orig).its("ende").as("originalEventEnd");
});
cy.get("@eventId").then((eventId) => {
tempusPage
.getCalendarEventById(eventId)
.find(".fhc-resize-bar--bottom")
.first()
.realHover()
.realMouseDown("center", {
button: "left",
})
.realMouseMove(0, 120)
.realMouseUp();
cy.wait("@updateCalendarEvent").then((interception) => {
expect(interception.response.statusCode).to.eq(200);
const updatedEventId =
interception.response.body.data.retval.kalender_id;
cy.wrap(updatedEventId).as("updatedEventId");
});
waitForOk("@fetchPlanData");
cy.get("@updatedEventId").then((updatedEventId) => {
tempusPage
.getCalendarEventById(updatedEventId)
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
let newEventStart = JSON.parse(eventJSON)?.orig?.beginn;
let newEventEnd = JSON.parse(eventJSON)?.orig?.ende;
cy.get("@originalEventStart").then((originalEventStart) => {
expect(newEventStart).to.eq(originalEventStart);
});
cy.get("@originalEventEnd").then((originalEventEnd) => {
expect(newEventEnd).to.not.eq(originalEventEnd);
});
});
});
});
});
it("can top resize an event on planner preview", () => {
tempusPage.clearMondayFirstColumnBeforeAndAfter();
tempusPage.getCalendarSection().should("exist");
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getCalendarEventsByStartTime("09:40:00")
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
cy.wrap(JSON.parse(eventJSON)).its("id").as("eventId");
cy.wrap(JSON.parse(eventJSON).orig)
.its("beginn")
.as("originalEventStart");
cy.wrap(JSON.parse(eventJSON).orig).its("ende").as("originalEventEnd");
});
cy.get("@eventId").then((eventId) => {
tempusPage
.getCalendarEventById(eventId)
.find(".fhc-resize-bar--top")
.first()
.realHover()
.realMouseDown("center", {
button: "left",
})
.realMouseMove(0, -40)
.realMouseUp();
cy.wait("@updateCalendarEvent").then((interception) => {
expect(interception.response.statusCode).to.eq(200);
const updatedEventId =
interception.response.body.data.retval.kalender_id;
cy.wrap(updatedEventId).as("updatedEventId");
});
waitForOk("@fetchPlanData");
cy.get("@updatedEventId").then((updatedEventId) => {
tempusPage
.getCalendarEventById(updatedEventId)
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
let newEventStart = JSON.parse(eventJSON)?.orig?.beginn;
let newEventEnd = JSON.parse(eventJSON)?.orig?.ende;
cy.get("@originalEventStart").then((originalEventStart) => {
expect(newEventStart).to.not.eq(originalEventStart);
});
cy.get("@originalEventEnd").then((originalEventEnd) => {
expect(newEventEnd).to.eq(originalEventEnd);
});
});
});
});
});
it("can drag and drop one course event into the calendar when Stundenraster is disabled", () => {
tempusPage.clearMondayFirstColumnBeforeAndAfter();
tempusPage.getCalendarSection().should("exist");
tempusPage.waitForCalendarToFinishLoading();
tempusPage.disableStundenraster();
tempusPage.selectFirstCourse();
waitForOk("@fetchCoursePickerCourses");
tempusPage.getCalendarEvents().then(($events) => {
cy.wrap($events.length).as("initialEventCount");
});
tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0);
tempusPage.dropCourseOnCalendarPart(0, 1);
waitForOk("@addCalendarEvent");
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
cy.get("@initialEventCount").then((initialEventCount) => {
tempusPage
.getCalendarEvents()
.should("have.length", initialEventCount + 1);
});
});
it("can drag and drop an event on part 6 when Stundenraster is disabled", () => {
tempusPage.clearMondayFirstColumnBeforeAndAfter();
tempusPage.syncAndReloadPlanner();
tempusPage.disableStundenraster();
tempusPage
.getCalendarEventsByTimeRange("08:00:00", "08:45:00")
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
const eventId = JSON.parse(eventJSON)?.id;
expect(eventId).to.exist;
tempusPage.getEventGridRow(eventId).as("originalGridRow");
tempusPage.dropEventOnCalendarPart(eventId, 6, {
scrollIntoView: true,
});
cy.wait("@updateCalendarEvent").then((interception) => {
expect(interception.response.statusCode).to.eq(200);
const updatedEventId = tempusPage.getUpdatedKalenderId(interception);
expect(updatedEventId, "updated planner event id").to.exist;
cy.wrap(updatedEventId).as("updatedEventId");
});
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
cy.get("@updatedEventId").then((updatedEventId) => {
tempusPage.getCalendarEventById(updatedEventId).should("be.visible");
cy.get("@originalGridRow").then((originalGridRow) => {
tempusPage.getEventGridRow(updatedEventId).then((updatedGridRow) => {
expect(updatedGridRow).to.not.eq(originalGridRow);
});
});
});
});
});
});
@@ -0,0 +1,349 @@
import { waitForOk } from "../../../../support/helpers/network";
import { tempusPage } from "../../../../support/pages/tempus.po";
context("Tempus filter tests", () => {
beforeEach(() => {
tempusPage.visitAndWaitForPlanner();
});
afterEach(() => {
return tempusPage.clearMondayFirstColumnAfterTest();
});
it("filters calendar events by selecting the first event room in the navbar", () => {
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getCalendarEventsWithRoom()
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
const selectedRoom = JSON.parse(eventJSON)?.orig?.ort_kurzbz;
expect(selectedRoom, "first event room").to.be.a("string").and.not.be
.empty;
expect(
selectedRoom.length,
"room search query length",
).to.be.greaterThan(1);
tempusPage.getNavbarSearchInput().clear().type(selectedRoom, {
parseSpecialCharSequences: false,
});
waitForOk("@searchbarSearch");
tempusPage
.getNavbarRoomSearchResult(selectedRoom)
.should("be.visible")
.click();
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
tempusPage.getSelectedRoomIndicator(selectedRoom).should("be.visible");
tempusPage.getCalendarEvents().should("have.length.greaterThan", 0);
tempusPage.getCalendarEvents().each(($event) => {
const eventData = tempusPage.getCalendarEventData($event);
expect(eventData?.orig?.ort_kurzbz, "event data room").to.eq(
selectedRoom,
);
cy.wrap($event)
.find(".event-place")
.invoke("text")
.then((eventPlace) => {
expect(eventPlace.trim(), "event body room").to.eq(selectedRoom);
});
});
});
});
it("removes the selected room filter", () => {
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getCalendarEventsWithRoom()
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
const selectedRoom = JSON.parse(eventJSON)?.orig?.ort_kurzbz;
expect(selectedRoom, "first event room").to.be.a("string").and.not.be
.empty;
expect(
selectedRoom.length,
"room search query length",
).to.be.greaterThan(1);
tempusPage.getCalendarEvents().then(($events) => {
const originalEventCount = $events.length;
cy.wrap(originalEventCount).as("originalEventCount");
});
tempusPage.getNavbarSearchInput().clear().type(selectedRoom, {
parseSpecialCharSequences: false,
});
waitForOk("@searchbarSearch");
tempusPage
.getNavbarRoomSearchResult(selectedRoom)
.should("be.visible")
.click();
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getSelectedRoomIndicator(selectedRoom)
.should("be.visible");
tempusPage.getCalendarEvents().should("have.length.greaterThan", 0);
tempusPage
.getSelectedRoomRemoveButton(selectedRoom)
.click();
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
tempusPage.getSelectedRoomIndicator(selectedRoom).should("not.exist");
cy.get("@originalEventCount").then((originalEventCount) => {
tempusPage
.getCalendarEvents()
.should("have.length", originalEventCount);
});
});
});
it("filters calendar events by selecting the first event lecturer in the navbar", () => {
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getCalendarEventsWithLecturer()
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
const selectedLecturer = tempusPage.getFirstLecturer(JSON.parse(eventJSON));
expect(selectedLecturer?.kurzbz, "first event lecturer").to.exist;
const lecturerSearch =
selectedLecturer.mitarbeiter_uid ??
selectedLecturer.uid ??
selectedLecturer.kurzbz;
expect(lecturerSearch, "lecturer search query").to.be.a("string").and
.not.be.empty;
tempusPage.getNavbarSearchInput().clear().type(lecturerSearch, {
parseSpecialCharSequences: false,
});
waitForOk("@searchbarSearch");
tempusPage
.getFirstNavbarEmployeeSearchResult()
.should("be.visible")
.invoke("text")
.then((lecturerName) => {
const selectedLecturerName = lecturerName.trim();
tempusPage.getFirstNavbarEmployeeSearchResult().click();
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getSelectedLecturerIndicator(selectedLecturerName)
.should("be.visible");
tempusPage.getCalendarEvents().should("have.length.greaterThan", 0);
tempusPage.getCalendarEvents().each(($event) => {
const eventData = tempusPage.getCalendarEventData($event);
const eventLecturers = eventData?.orig?.lektor ?? [];
expect(
eventLecturers.map((lecturer) => lecturer.kurzbz),
"event data lecturers",
).to.include(selectedLecturer.kurzbz);
cy.wrap($event)
.find(".event-lectors")
.then(($lecturers) => {
const bodyLecturers = [...$lecturers].map((lecturer) =>
lecturer.innerText.trim(),
);
expect(bodyLecturers, "event body lecturers").to.include(
selectedLecturer.kurzbz,
);
});
});
});
});
});
it("removes the selected lecturer filter", () => {
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getCalendarEventsWithLecturer()
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
const selectedLecturer = tempusPage.getFirstLecturer(JSON.parse(eventJSON));
expect(selectedLecturer?.kurzbz, "first event lecturer").to.exist;
const lecturerSearch =
selectedLecturer.mitarbeiter_uid ??
selectedLecturer.uid ??
selectedLecturer.kurzbz;
expect(lecturerSearch, "lecturer search query").to.be.a("string").and
.not.be.empty;
tempusPage.getCalendarEvents().then(($events) => {
const originalEventCount = $events.length;
cy.wrap(originalEventCount).as("originalEventCount");
});
tempusPage.getNavbarSearchInput().clear().type(lecturerSearch, {
parseSpecialCharSequences: false,
});
waitForOk("@searchbarSearch");
tempusPage
.getFirstNavbarEmployeeSearchResult()
.should("be.visible")
.invoke("text")
.then((lecturerName) => {
const selectedLecturerName = lecturerName.trim();
tempusPage.getFirstNavbarEmployeeSearchResult().click();
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getSelectedLecturerIndicator(selectedLecturerName)
.should("be.visible");
tempusPage.getCalendarEvents().should("have.length.greaterThan", 0);
tempusPage
.getSelectedLecturerRemoveButton(selectedLecturerName)
.click();
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getSelectedLecturerIndicator(selectedLecturerName)
.should("not.exist");
cy.get("@originalEventCount").then((originalEventCount) => {
tempusPage
.getCalendarEvents()
.should("have.length", originalEventCount);
});
});
});
});
it("hides calendar events when the selected lecturer plan toggle is deselected", () => {
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getCalendarEventsWithLecturer()
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
const selectedLecturer = tempusPage.getFirstLecturer(JSON.parse(eventJSON));
expect(selectedLecturer?.kurzbz, "first event lecturer").to.exist;
const lecturerSearch =
selectedLecturer.mitarbeiter_uid ??
selectedLecturer.uid ??
selectedLecturer.kurzbz;
expect(lecturerSearch, "lecturer search query").to.be.a("string").and
.not.be.empty;
tempusPage.getNavbarSearchInput().clear().type(lecturerSearch, {
parseSpecialCharSequences: false,
});
waitForOk("@searchbarSearch");
tempusPage
.getFirstNavbarEmployeeSearchResult()
.should("be.visible")
.invoke("text")
.then((lecturerName) => {
const selectedLecturerName = lecturerName.trim();
tempusPage.getFirstNavbarEmployeeSearchResult().click();
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getSelectedLecturerIndicator(selectedLecturerName)
.should("be.visible");
tempusPage.getCalendarEvents().should("have.length.greaterThan", 0);
tempusPage
.getSelectedLecturerPlanToggle(selectedLecturerName)
.click();
tempusPage.getCalendarEvents().should("not.exist");
});
});
});
it("shows lecturer wish overlays when the selected lecturer wish toggle is disabled", () => {
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getCalendarEventsWithLecturer()
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
const selectedLecturer = tempusPage.getFirstLecturer(JSON.parse(eventJSON));
expect(selectedLecturer?.kurzbz, "first event lecturer").to.exist;
const lecturerSearch =
selectedLecturer.mitarbeiter_uid ??
selectedLecturer.uid ??
selectedLecturer.kurzbz;
expect(lecturerSearch, "lecturer search query").to.be.a("string").and
.not.be.empty;
tempusPage.getNavbarSearchInput().clear().type(lecturerSearch, {
parseSpecialCharSequences: false,
});
waitForOk("@searchbarSearch");
tempusPage
.getFirstNavbarEmployeeSearchResult()
.should("be.visible")
.invoke("text")
.then((lecturerName) => {
const selectedLecturerName = lecturerName.trim();
tempusPage.getFirstNavbarEmployeeSearchResult().click();
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getSelectedLecturerIndicator(selectedLecturerName)
.should("be.visible");
tempusPage
.getSelectedLecturerWishToggle(selectedLecturerName)
.should("be.visible")
.click();
tempusPage
.getLecturerWishOverlays()
.should("have.length", 0)
tempusPage
.getSelectedLecturerWishToggle(selectedLecturerName)
.should("be.visible")
.click();
tempusPage.getLecturerWishOverlays().should("have.length.greaterThan", 0);
});
});
});
});
@@ -0,0 +1,257 @@
import { waitForOk } from "../../../../support/helpers/network";
import { LEKTOR, PLANER, STUDENT, tempusPage } from "../../../../support/pages/tempus.po";
context("Tempus role preview tests", () => {
beforeEach(() => {
tempusPage.visitAndWaitForPlanner();
});
afterEach(() => {
return tempusPage.clearMondayFirstColumnAfterTest();
});
it("shows the same number of calendar events for all role previews", () => {
const rolePreviews = [PLANER, LEKTOR, STUDENT];
const eventCounts = {};
tempusPage.syncAndReloadPlanner();
cy.wrap(rolePreviews)
.each((role) => {
tempusPage.selectRoleAndWait(role);
tempusPage.getCalendarEvents().then(($events) => {
eventCounts[role] = $events.length;
});
})
.then(() => {
const expectedCount = eventCounts[rolePreviews[0]];
Object.entries(eventCounts).forEach(([role, count]) => {
expect(count, `${role} calendar event count`).to.eq(expectedCount);
});
});
});
it("on planner event change shows unchanged event on other roles", () => {
tempusPage.clearMondayFirstColumnBeforeAndAfter();
tempusPage.syncAndReloadPlanner();
cy.get(".fhc-calendar-base-grid > div")
.last()
.invoke("css", "overflow", "hidden");
cy.wait(500);
tempusPage
.getCalendarEventsByTimeRange("08:00:00", "08:45:00")
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
let eventId = JSON.parse(eventJSON)?.id;
expect(eventId).to.exist;
tempusPage.dropEventOnCalendarPart(eventId, 3, {
scrollIntoView: true,
});
cy.wait("@updateCalendarEvent").then((interception) => {
expect(interception.response.statusCode).to.eq(200);
const updatedEventId =
interception.response.body.data.retval.kalender_id;
cy.wrap(updatedEventId).as("updatedEventId");
});
waitForOk("@fetchPlanData");
cy.get("@updatedEventId").then((updatedEventId) => {
tempusPage.getEventGridRow(updatedEventId).then((gridRowStyle) => {
tempusPage.selectRoleAndWait(LEKTOR);
tempusPage.getEventGridRow(eventId).then((lecturerGridRow) => {
expect(lecturerGridRow).to.not.eq(gridRowStyle);
});
tempusPage.selectRoleAndWait(STUDENT);
tempusPage.getEventGridRow(eventId).then((studentGridRow) => {
expect(studentGridRow).to.not.eq(gridRowStyle);
});
});
});
});
cy.get(".fhc-calendar-base-grid > div:last-child()").invoke(
"css",
"overflow",
"auto",
);
});
it("sync after planner preview event change loads event in same way on all previews", () => {
tempusPage.clearMondayFirstColumnBeforeAndAfter();
tempusPage.syncAndReloadPlanner();
tempusPage
.getCalendarEventsByTimeRange("08:00:00", "08:45:00")
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
let eventId = JSON.parse(eventJSON)?.id;
expect(eventId).to.exist;
tempusPage.dropEventOnCalendarPart(eventId, 4, {
scrollIntoView: true,
});
cy.wait("@updateCalendarEvent").then((interception) => {
expect(interception.response.statusCode).to.eq(200);
const updatedEventId =
interception.response.body.data.retval.kalender_id;
cy.wrap(updatedEventId).as("updatedEventId");
});
waitForOk("@fetchPlanData");
tempusPage.syncAndReloadPlanner();
cy.get("@updatedEventId").then((updatedEventId) => {
tempusPage.getEventGridRow(updatedEventId).then((gridRowStyle) => {
tempusPage.selectRoleAndWait(LEKTOR);
tempusPage
.getEventGridRow(updatedEventId)
.then((lecturerGridRow) => {
expect(lecturerGridRow).to.eq(gridRowStyle);
});
tempusPage.selectRoleAndWait(STUDENT);
tempusPage
.getEventGridRow(updatedEventId)
.then((studentGridRow) => {
expect(studentGridRow).to.eq(gridRowStyle);
});
});
});
});
});
it("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
.getCalendarEventsByTimeRange("08:00:00", "08:45:00")
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
let eventId = JSON.parse(eventJSON)?.id;
expect(eventId).to.exist;
tempusPage.dropEventOnCalendarPart(eventId, 5, {
scrollIntoView: true,
});
cy.wait("@updateCalendarEvent")
.its("response.body.data.retval.kalender_id")
.as("updatedEventId");
waitForOk("@fetchPlanData");
tempusPage.waitForCalendarToFinishLoading();
cy.get("@updatedEventId").then((updatedEventId) => {
tempusPage
.getCalendarEventById(updatedEventId)
.should("exist")
.rightclick();
tempusPage.getEventContextMenuOption("Freischalten für Live").click();
waitForOk("@syncCalendarToStudent");
tempusPage.getEventGridRow(updatedEventId).then((gridRowStyle) => {
tempusPage.selectRoleAndWait(LEKTOR);
tempusPage
.getEventGridRow(updatedEventId)
.then((lecturerGridRow) => {
expect(lecturerGridRow).to.eq(gridRowStyle);
});
tempusPage.selectRoleAndWait(STUDENT);
tempusPage.getEventGridRow(eventId).then((studentGridRow) => {
expect(studentGridRow).to.not.eq(gridRowStyle);
});
});
});
});
});
it("event change on lector preview is prohibited", () => {
tempusPage.syncAndReloadPlanner();
tempusPage.selectRoleAndWait(LEKTOR);
tempusPage
.getCalendarEventsByTimeRange("08:00:00", "08:45:00")
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
let eventId = JSON.parse(eventJSON)?.id;
expect(eventId).to.exist;
tempusPage.dropEventOnCalendarPart(eventId, 15);
cy.get("@updateCalendarEvent").should("not.exist");
tempusPage.getEventGridRow(eventId).then((gridRowStyle) => {
tempusPage.selectRoleAndWait(LEKTOR);
tempusPage.getEventGridRow(eventId).then((lecturerGridRow) => {
expect(lecturerGridRow).to.eq(gridRowStyle);
});
tempusPage.selectRoleAndWait(STUDENT);
tempusPage.getEventGridRow(eventId).then((studentGridRow) => {
expect(studentGridRow).to.eq(gridRowStyle);
});
});
});
});
it("event change on student preview is prohibited", () => {
tempusPage.syncAndReloadPlanner();
tempusPage.selectRoleAndWait(STUDENT);
tempusPage
.getCalendarEventsByTimeRange("08:00:00", "08:45:00")
.first()
.invoke("attr", "data-fhc-draggable-value")
.then((eventJSON) => {
expect(eventJSON).to.exist;
let eventId = JSON.parse(eventJSON)?.id;
expect(eventId).to.exist;
tempusPage.dropEventOnCalendarPart(eventId, 15);
cy.get("@updateCalendarEvent").should("not.exist");
tempusPage.getEventGridRow(eventId).then((gridRowStyle) => {
tempusPage.selectRoleAndWait(LEKTOR);
tempusPage.getEventGridRow(eventId).then((lecturerGridRow) => {
expect(lecturerGridRow).to.eq(gridRowStyle);
});
tempusPage.selectRoleAndWait(STUDENT);
tempusPage.getEventGridRow(eventId).then((studentGridRow) => {
expect(studentGridRow).to.eq(gridRowStyle);
});
});
});
});
});
@@ -0,0 +1,92 @@
import { waitForOk } from "../../../../support/helpers/network";
import { tempusPage } from "../../../../support/pages/tempus.po";
context("Tempus smoke tests", () => {
beforeEach(() => {
tempusPage.visitAndWaitForPlanner();
});
afterEach(() => {
return tempusPage.clearMondayFirstColumnAfterTest();
});
it("can access Tempus page with valid credentials", () => {
tempusPage.getTempusOverview().should("be.visible");
});
it("shows all expected page elements", () => {
tempusPage.getTempusOverview().should("be.visible");
tempusPage.getSidebarMenu().should("exist");
tempusPage.getSlideInCoursesMenu().should("exist");
tempusPage.getCalendarSection().should("be.visible");
tempusPage.getPreviewRoleOptionsHolder().should("be.visible");
});
it("can open courses menu", () => {
tempusPage.getSlideInCoursesMenu().should("exist").should("be.hidden");
tempusPage.openCoursesMenu();
tempusPage.getCourseTreeRows().should("have.length.greaterThan", 0);
});
it("shows event details modal when clicking a calendar event", () => {
tempusPage.waitForCalendarToFinishLoading();
tempusPage.getCalendarEvents().should("have.length.greaterThan", 0);
tempusPage.getCalendarEvents().first().click();
tempusPage.getCalendarEventModal().should("be.visible");
});
it("shows event context menu when right clicking a calendar event", () => {
tempusPage.waitForCalendarToFinishLoading();
tempusPage.getCalendarEvents().should("have.length.greaterThan", 0);
tempusPage.getCalendarEvents().first().rightclick();
tempusPage.getEventContextMenu().should("be.visible");
});
it("shows Raumauswahl modal when selecting Raumauswahl from event context menu", () => {
tempusPage.waitForCalendarToFinishLoading();
tempusPage
.getCalendarEventsWithLehreinheit()
.should("have.length.greaterThan", 0);
tempusPage.getCalendarEventsWithLehreinheit().first().rightclick();
tempusPage.getEventContextMenuOption("Raumauswahl").click();
waitForOk("@fetchRoomSuggestions");
tempusPage.getRaumauswahlModal().should("be.visible");
});
it("shows history modal when selecting History from event context menu", () => {
tempusPage.waitForCalendarToFinishLoading();
tempusPage.getCalendarEvents().should("have.length.greaterThan", 0);
tempusPage.getCalendarEvents().first().rightclick();
tempusPage.getEventContextMenuOption("History").click();
waitForOk("@fetchEventHistory");
tempusPage.getHistoryModal().should("be.visible");
});
it.skip("shows reservation modal when dropping reservation handle on calendar", () => {
tempusPage.waitForCalendarToFinishLoading();
tempusPage.getCalendarBaseGrid().should("be.visible");
cy.wait(1000);
tempusPage
.getReservationDragHandle()
.drag(
tempusPage.selectors.calendarBaseGrid + " .part-body:nth-of-type(18)",
{
waitForAnimations: false,
animationDistanceThreshold: 0,
},
);
cy.wait(3000);
tempusPage.getReservationModal().should("be.visible");
});
});
@@ -0,0 +1,2 @@
export const waitForOk = (alias) =>
cy.wait(alias).its("response.statusCode").should("eq", 200);
@@ -1,9 +1,24 @@
import { waitForOk } from "../helpers/network";
export const PLANER = "Planer";
export const LEKTOR = "Lektor";
export const STUDENT = "Student";
export const SYNC = "Sync";
const roleFetchAliases = {
[PLANER]: "@fetchPlanData",
[LEKTOR]: "@fetchLecturerPlanData",
[STUDENT]: "@fetchStudentPlanData",
};
class TempusPage {
selectors = {
calendarBaseGrid: "div[data-cy='tempus'] .fhc-calendar-base-grid",
parkingSlot: "div[data-cy='tempus'] #parkingslot",
};
cleanupMondayFirstColumnAfterTest = false;
visit = () => cy.visit("/index.ci.php/tempus", {
onBeforeLoad(win) {
win.localStorage.removeItem("tempus_parking");
@@ -118,6 +133,34 @@ class TempusPage {
const eventData = JSON.parse(event.getAttribute("data-fhc-draggable-value"));
return eventData?.orig?.beginn === startTime && eventData?.orig?.ende === endTime;
});
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']");
@@ -152,6 +195,158 @@ class TempusPage {
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");
cy.intercept({
method: "GET",
url: /\/tempus\/Kalender\/getPlan(?:\?|$)/,
}).as("fetchPlanData");
cy.intercept({
method: "GET",
url: /\/tempus\/Kalender\/getPlanLecturer(?:\?|$)/,
}).as("fetchLecturerPlanData");
cy.intercept({
method: "GET",
url: /\/tempus\/Kalender\/getPlanStudent(?:\?|$)/,
}).as("fetchStudentPlanData");
cy.intercept({ method: "GET", url: "**/tempus/Kalender/getHistory**" }).as(
"fetchEventHistory",
);
cy.intercept({
method: "GET",
url: "**/tempus/Kalender/getRaumvorschlag**",
}).as("fetchRoomSuggestions");
cy.intercept({
method: "GET",
url: "**/tempus/coursepicker/getByStg**",
}).as("fetchCoursePickerCourses");
cy.intercept({
method: "POST",
url: "**/searchbar/search**",
}).as("searchbarSearch");
cy.intercept({
method: "POST",
url: "**/tempus/Kalender/addKalenderEvent**",
}).as("addCalendarEvent");
cy.intercept({
method: "POST",
url: "**/tempus/Kalender/updateKalenderEvent**",
}).as("updateCalendarEvent");
cy.intercept({
method: "POST",
url: "**/tempus/Kalender/sync**",
}).as("syncCalendar");
cy.intercept({
method: "POST",
url: "**/tempus/Kalender/syncToStudent**",
}).as("syncCalendarToStudent");
cy.intercept({
method: "POST",
url: "**/tempus/Kalender/deleteEntry**",
}).as("deleteCalendarEvent");
};
visitAndWaitForPlanner = () => {
cy.login();
this.setupIntercepts();
this.visit();
waitForOk("@fetchCourseTree");
waitForOk("@fetchPlanData");
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) {