mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-05 21:09:28 +00:00
WIP: Adding base tempus tests
This commit is contained in:
@@ -146,6 +146,7 @@ export default {
|
||||
/>
|
||||
<ul
|
||||
v-if="contextMenu.show"
|
||||
data-cy="eventContextMenu"
|
||||
class="dropdown-menu show"
|
||||
:style="{ position: 'fixed', top: contextMenu.y + 'px', left: contextMenu.x + 'px', zIndex: 9999 }"
|
||||
>
|
||||
@@ -159,4 +160,4 @@ export default {
|
||||
</teleport>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,6 +247,7 @@ export default {
|
||||
<div
|
||||
class="d-flex align-items-center gap-2 "
|
||||
v-draggable:move.noimage="{ type: 'reservierung', id: null, orig: {} }"
|
||||
data-cy="reservationDragHandle"
|
||||
>
|
||||
<i
|
||||
class="fa-solid fa-calendar-plus text-primary"
|
||||
|
||||
@@ -155,7 +155,7 @@ export default {
|
||||
},
|
||||
// language=HTML
|
||||
template: `
|
||||
<bs-modal ref="modal" class="bootstrap-prompt" dialogClass="modal-xl">
|
||||
<bs-modal ref="modal" class="bootstrap-prompt" dialogClass="modal-xl" data-cy="reservationModal">
|
||||
<template #title>Neue Reservierung</template>
|
||||
<template #default>
|
||||
<div class="row g-3">
|
||||
|
||||
@@ -710,7 +710,7 @@ export default {
|
||||
});
|
||||
},
|
||||
template: `
|
||||
<div class="tempus">
|
||||
<div data-cy="tempus" class="tempus">
|
||||
<header class="navbar navbar-expand-lg navbar-dark bg-dark flex-md-nowrap p-0 shadow">
|
||||
<div class="col-md-4 col-lg-3 col-xl-2 d-flex align-items-center">
|
||||
<button
|
||||
@@ -838,7 +838,7 @@ export default {
|
||||
class="w-100"
|
||||
/>
|
||||
|
||||
<div class="d-flex gap-1 py-1">
|
||||
<div class="d-flex gap-1 py-1" data-cy="previewRoleOptionsHolder">
|
||||
<button
|
||||
class="btn btn-sm"
|
||||
:class="previewRole === 'planer' ? 'btn-dark' : 'btn-outline-dark'"
|
||||
@@ -934,7 +934,7 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
<app-config ref="config" v-model="appconfig" :endpoints="configEndpoints"></app-config>
|
||||
<div id="verbandMenu" ref="verbandMenu" class="offcanvas offcanvas-start col-md p-md-0 h-100" tabindex="-1">
|
||||
<div id="verbandMenu" ref="verbandMenu" class="offcanvas offcanvas-start col-md p-md-0 h-100" tabindex="-1" data-cy="verbandMenu">
|
||||
<div class="offcanvas-header justify-content-end px-1 d-md-none">
|
||||
<h5 class="offcanvas-title" id="verbandMenuLabel">
|
||||
<i class="fa-solid fa-university me-2"></i>Verband
|
||||
@@ -962,7 +962,7 @@ export default {
|
||||
</template>
|
||||
</bs-modal>
|
||||
|
||||
<bs-modal ref="historyModel" class="bootstrap-prompt" dialogClass="modal-lg">
|
||||
<bs-modal ref="historyModel" class="bootstrap-prompt" dialogClass="modal-lg" data-cy="historyModal">
|
||||
<template #title>History</template>
|
||||
<template #default>
|
||||
<table v-if="historyEntries.length" class="table table-bordered table-hover">
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
BASE_URL=https://demo.dev.technikum-wien.at/demoanon
|
||||
USER_NAME=demoadmin
|
||||
USER_PASSWORD=Demo
|
||||
LOGIN_AS_USER=demoadmin
|
||||
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
@@ -0,0 +1,18 @@
|
||||
const { defineConfig } = require("cypress");
|
||||
require("dotenv").config();
|
||||
|
||||
module.exports = defineConfig({
|
||||
allowCypressEnv: true,
|
||||
|
||||
e2e: {
|
||||
baseUrl: process.env.BASE_URL || "http://localhost:8080",
|
||||
defaultCommandTimeout: 40000,
|
||||
pageLoadTimeout: 20000,
|
||||
},
|
||||
env: {
|
||||
adminusername: process.env.USER_NAME || "2",
|
||||
adminpassword: process.env.USER_PASSWORD || "2",
|
||||
loginAsUser: process.env.LOGIN_AS_USER || process.env.USER_NAME || "demoadmin"
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,148 @@
|
||||
import { tempusPage } from "../../../support/pages/tempus.po";
|
||||
|
||||
context("Base tempus tests", () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
|
||||
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/coursepicker/getByStg**" }).as("fetchCoursePickerCourses");
|
||||
|
||||
tempusPage.visit();
|
||||
|
||||
cy.wait("@fetchCourseTree").its("response.statusCode").should("eq", 200);
|
||||
cy.wait("@fetchPlanData").its("response.statusCode").should("eq", 200);
|
||||
});
|
||||
|
||||
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("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();
|
||||
cy.wait("@fetchCoursePickerCourses").its("response.statusCode").should("eq", 200);
|
||||
|
||||
tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0);
|
||||
});
|
||||
|
||||
it("can search for a course event in the course picker", () => {
|
||||
const searchTerm = "PHY1 SO";
|
||||
|
||||
tempusPage.selectFirstCourse();
|
||||
cy.wait("@fetchCoursePickerCourses").its("response.statusCode").should("eq", 200);
|
||||
|
||||
tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0);
|
||||
|
||||
tempusPage.getCoursePickerSearchInput().type(searchTerm);
|
||||
|
||||
tempusPage.getCoursePickerRows().should("have.length.greaterThan", 0);
|
||||
tempusPage.getCoursePickerRows().first().should("contain.text", searchTerm);
|
||||
});
|
||||
|
||||
it("can drag and drop one course event into the calendar", () => {
|
||||
tempusPage.getCalendarSection().should("exist");
|
||||
|
||||
tempusPage.selectFirstCourse();
|
||||
cy.wait("@fetchCoursePickerCourses").its("response.statusCode").should("eq", 200);
|
||||
|
||||
tempusPage.getCoursePickerRows().first().drag(tempusPage.selectors.calendarSection);
|
||||
|
||||
tempusPage.getCalendarEvents().should("have.length", 1);
|
||||
});
|
||||
|
||||
it("shows the same number of calendar events for all role previews", () => {
|
||||
const rolePreviews = [
|
||||
{ label: "Planer", fetchAlias: "@fetchPlanData" },
|
||||
{ label: "Lektor", fetchAlias: "@fetchLecturerPlanData" },
|
||||
{ label: "Student", fetchAlias: "@fetchStudentPlanData" },
|
||||
];
|
||||
const eventCounts = {};
|
||||
|
||||
cy.wrap(rolePreviews).each((rolePreview) => {
|
||||
tempusPage.selectPreviewRole(rolePreview.label);
|
||||
cy.wait(rolePreview.fetchAlias).its("response.statusCode").should("eq", 200);
|
||||
tempusPage.waitForCalendarToFinishLoading();
|
||||
|
||||
tempusPage.getCalendarEvents().then(($events) => {
|
||||
eventCounts[rolePreview.label] = $events.length;
|
||||
});
|
||||
}).then(() => {
|
||||
const expectedCount = eventCounts[rolePreviews[0].label];
|
||||
|
||||
Object.entries(eventCounts).forEach(([role, count]) => {
|
||||
expect(count, `${role} calendar event count`).to.eq(expectedCount);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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 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();
|
||||
cy.wait("@fetchEventHistory").its("response.statusCode").should("eq", 200);
|
||||
|
||||
tempusPage.getHistoryModal().should("be.visible");
|
||||
});
|
||||
|
||||
it("shows reservation modal when dropping reservation handle on calendar", () => {
|
||||
tempusPage.waitForCalendarToFinishLoading();
|
||||
tempusPage.getCalendarSection().should("be.visible");
|
||||
|
||||
tempusPage.getReservationDragHandle().drag(tempusPage.selectors.calendarSection);
|
||||
|
||||
tempusPage.getReservationModal().should("be.visible");
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
|
||||
require("@4tw/cypress-drag-drop");
|
||||
|
||||
Cypress.Commands.add("login", () => {
|
||||
const { adminusername, adminpassword, loginAsUser } = Cypress.env();
|
||||
const userToImpersonate = loginAsUser || adminusername;
|
||||
const auth = {
|
||||
username: adminusername,
|
||||
password: adminpassword,
|
||||
};
|
||||
|
||||
cy.session(
|
||||
["tempus-login", adminusername, userToImpersonate],
|
||||
() => {
|
||||
cy.request({
|
||||
url: "/index.ci.php/tempus",
|
||||
method: "POST",
|
||||
auth,
|
||||
body: {
|
||||
searchstr: userToImpersonate,
|
||||
types: ["employee"],
|
||||
},
|
||||
}).its("status").should("eq", 200);
|
||||
},
|
||||
{
|
||||
cacheAcrossSpecs: true,
|
||||
validate() {
|
||||
cy.request({
|
||||
url: "/index.ci.php/tempus",
|
||||
auth,
|
||||
}).its("status").should("eq", 200);
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
// ***********************************************************
|
||||
// This example support/e2e.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
@@ -0,0 +1,54 @@
|
||||
class TempusPage {
|
||||
selectors = {
|
||||
calendarSection: "div[data-cy='tempus'] .fhc-calendar-base",
|
||||
parkingSlot: "div[data-cy='tempus'] #parkingslot",
|
||||
};
|
||||
|
||||
visit = () => cy.visit("/index.ci.php/tempus", {
|
||||
onBeforeLoad(win) {
|
||||
win.localStorage.removeItem("tempus_parking");
|
||||
},
|
||||
});
|
||||
|
||||
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");
|
||||
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");
|
||||
getCalendarEvents = () => this.getCalendarSection().find(".fhc-calendar-base-grid-line-event");
|
||||
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);
|
||||
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);
|
||||
|
||||
openCoursesMenu = () => {
|
||||
this.getAllCoursesSliderBtn().click();
|
||||
this.getSlideInCoursesMenu().should("be.visible");
|
||||
};
|
||||
|
||||
selectFirstCourse = () => {
|
||||
this.openCoursesMenu();
|
||||
this.getCourseTreeRows().first().click();
|
||||
};
|
||||
|
||||
selectPreviewRole = (role) => {
|
||||
this.getPreviewRoleButton(role).click();
|
||||
};
|
||||
|
||||
waitForCalendarToFinishLoading = () => {
|
||||
this.getCalendarLoadingEvents().should("not.exist");
|
||||
};
|
||||
}
|
||||
|
||||
export const tempusPage = new TempusPage();
|
||||
Generated
+2233
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@4tw/cypress-drag-drop": "^2.3.1",
|
||||
"cypress": "^15.11.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^17.4.2"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user