Implement unified grading

This commit is contained in:
Elia Bieri 2024-07-31 11:45:42 +02:00
parent c2c3331539
commit 78d18034fa
8 changed files with 352 additions and 211 deletions

View File

@ -6,6 +6,8 @@ import { useCertificateQuery, useCurrentCourseSession } from "@/composables";
import CompetenceCertificateComponent from "@/pages/competence/CompetenceCertificateComponent.vue"; import CompetenceCertificateComponent from "@/pages/competence/CompetenceCertificateComponent.vue";
import { getCertificates } from "@/services/competence"; import { getCertificates } from "@/services/competence";
import { getPreviousRoute } from "@/router/history"; import { getPreviousRoute } from "@/router/history";
import { mergeCompetenceCertificates } from "./utils";
import { useCourseSessionsStore } from "@/stores/courseSessions";
const props = defineProps<{ const props = defineProps<{
courseSlug: string; courseSlug: string;
@ -15,26 +17,24 @@ const props = defineProps<{
log.debug("CompetenceCertificateDetailPage setup", props); log.debug("CompetenceCertificateDetailPage setup", props);
const courseSession = useCurrentCourseSession(); const store = useCourseSessionsStore();
const certificatesQuery = useCertificateQuery( const certificateQueries = store.allCourseSessions.map((courseSession) => {
props.userId, return useCertificateQuery(props.userId, props.courseSlug, courseSession)
props.courseSlug, .certificatesQuery;
courseSession.value });
).certificatesQuery;
const certificate = computed(() => { const certificate = computed(() => {
const certificates = getCertificates( const competenceCertificatesPerCs = certificateQueries.map((query) => {
certificatesQuery.data.value, return getCertificates(query.data.value, props.userId!)
props.userId ?? null ?.competence_certificates as unknown as CompetenceCertificate[];
); });
const certificates = mergeCompetenceCertificates(competenceCertificatesPerCs.flat());
if (!certificates) { if (!certificates) {
return null; return null;
} }
return ( return certificates.find((cc) => cc.slug.endsWith(props.certificateSlug));
(certificates.competence_certificates as unknown as CompetenceCertificate[]) ?? []
).find((cc) => cc.slug.endsWith(props.certificateSlug));
}); });
</script> </script>

View File

@ -2,11 +2,12 @@
import log from "loglevel"; import log from "loglevel";
import { computed, onMounted } from "vue"; import { computed, onMounted } from "vue";
import type { CompetenceCertificate } from "@/types"; import type { CompetenceCertificate } from "@/types";
import { useCertificateQuery, useCurrentCourseSession } from "@/composables"; import { useCertificateQuery } from "@/composables";
import CompetenceCertificateComponent from "@/pages/competence/CompetenceCertificateComponent.vue"; import CompetenceCertificateComponent from "@/pages/competence/CompetenceCertificateComponent.vue";
import { import {
assignmentsUserPoints, assignmentsUserPoints,
calcCompetencesTotalGrade, calcCompetencesTotalGrade,
mergeCompetenceCertificates,
} from "@/pages/competence/utils"; } from "@/pages/competence/utils";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { getCertificates } from "@/services/competence"; import { getCertificates } from "@/services/competence";
@ -23,48 +24,29 @@ log.debug("CompetenceCertificateListPage setup", props);
const route = useRoute(); const route = useRoute();
const store = useCourseSessionsStore(); const store = useCourseSessionsStore();
console.log(
`Loading competence certificates from ${store.allCourseSessions.length} course sessions:`,
store.allCourseSessions.map((cs) => cs.title)
);
const certificateQueries = store.allCourseSessions.map((courseSession) => { const certificateQueries = store.allCourseSessions.map((courseSession) => {
return useCertificateQuery(props.userId, props.courseSlug, courseSession) return useCertificateQuery(props.userId, props.courseSlug, courseSession)
.certificatesQuery; .certificatesQuery;
}); });
const competenceCertificates = computed(() => { const mergedCertificates = computed(() => {
const competenceCertificates: Record<string, CompetenceCertificate> = {}; const competenceCertificatesPerCs = certificateQueries.map((query) => {
for (const query of certificateQueries) { return getCertificates(query.data.value, props.userId ?? null)
const certificates = ?.competence_certificates as unknown as CompetenceCertificate[];
(getCertificates(query.data.value, props.userId ?? null) });
?.competence_certificates as unknown as CompetenceCertificate[]) ?? []; return mergeCompetenceCertificates(competenceCertificatesPerCs.flat());
for (const certificate of certificates) {
if (!competenceCertificates[certificate.id]) {
// Competence certificate does not exist yet
competenceCertificates[certificate.id] = certificate;
} else {
// Merge with assignment completions of existing competence certificate. If there are multiple completions for the same assignment, keep the latest one.
competenceCertificates[certificate.id].assignments.push(
...certificate.assignments.filter((assignment) => {
const existingAssignment = competenceCertificates[
certificate.id
].assignments.find((a) => a.id === assignment.id);
return (
!existingAssignment ||
dayjs(assignment.completion?.evaluation_submitted_at).isAfter(
dayjs(existingAssignment.completion?.evaluation_submitted_at)
)
);
})
);
}
}
}
return Object.values(competenceCertificates);
}); });
const assignments = computed(() => { const assignments = computed(() => {
return competenceCertificates?.value?.flatMap((cc) => cc.assignments); return mergedCertificates?.value?.flatMap((cc) => cc.assignments);
}); });
const totalGrade = computed(() => { const totalGrade = computed(() => {
return calcCompetencesTotalGrade(competenceCertificates.value ?? []); return calcCompetencesTotalGrade(mergedCertificates.value ?? []);
}); });
const userPointsEvaluatedAssignments = computed(() => { const userPointsEvaluatedAssignments = computed(() => {
@ -121,7 +103,7 @@ onMounted(async () => {
</div> </div>
<div <div
v-for="competenceCertificate in competenceCertificates" v-for="competenceCertificate in mergedCertificates"
:key="competenceCertificate.id" :key="competenceCertificate.id"
> >
<CompetenceCertificateComponent <CompetenceCertificateComponent

View File

@ -4,17 +4,20 @@ import { COMPETENCE_NAVI_CERTIFICATE_QUERY } from "@/graphql/queries";
import { useQuery } from "@urql/vue"; import { useQuery } from "@urql/vue";
import { computed } from "vue"; import { computed } from "vue";
import type { CompetenceCertificate } from "@/types"; import type { CompetenceCertificate } from "@/types";
import { useCurrentCourseSession } from "@/composables"; import { useCertificateQuery, useCurrentCourseSession } from "@/composables";
import { import {
assignmentsUserPoints, assignmentsUserPoints,
calcCompetenceCertificateGrade, calcCompetenceCertificateGrade,
calcCompetencesTotalGrade, calcCompetencesTotalGrade,
competenceCertificateProgressStatusCount, competenceCertificateProgressStatusCount,
mergeCompetenceCertificates,
} from "@/pages/competence/utils"; } from "@/pages/competence/utils";
import ItProgress from "@/components/ui/ItProgress.vue"; import ItProgress from "@/components/ui/ItProgress.vue";
import SelfEvaluationAndFeedbackOverview from "@/components/selfEvaluationFeedback/SelfEvaluationAndFeedbackOverview.vue"; import SelfEvaluationAndFeedbackOverview from "@/components/selfEvaluationFeedback/SelfEvaluationAndFeedbackOverview.vue";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { useCourseSessionsStore } from "@/stores/courseSessions";
import { getCertificates } from "@/services/competence";
const props = defineProps<{ const props = defineProps<{
courseSlug: string; courseSlug: string;
@ -22,25 +25,27 @@ const props = defineProps<{
log.debug("CompetenceIndexPage setup", props); log.debug("CompetenceIndexPage setup", props);
const courseSession = useCurrentCourseSession(); const store = useCourseSessionsStore();
console.log(
const certificatesQuery = useQuery({ `Loading competence certificates from ${store.allCourseSessions.length} course sessions:`,
query: COMPETENCE_NAVI_CERTIFICATE_QUERY, store.allCourseSessions.map((cs) => cs.title)
variables: { );
courseSlug: props.courseSlug, const certificateQueries = store.allCourseSessions.map((courseSession) => {
courseSessionId: courseSession.value.id, return useCertificateQuery(undefined, props.courseSlug, courseSession)
}, .certificatesQuery;
}); });
const competenceCertificates = computed(() => { const mergedCertificates = computed(() => {
return ( const competenceCertificatesPerCs = certificateQueries.map((query) => {
(certificatesQuery.data.value?.competence_certificate_list return getCertificates(query.data.value, null)
?.competence_certificates as unknown as CompetenceCertificate[]) ?? [] ?.competence_certificates as unknown as CompetenceCertificate[];
); });
return mergeCompetenceCertificates(competenceCertificatesPerCs.flat());
}); });
const allAssignments = computed(() => { const allAssignments = computed(() => {
return competenceCertificates.value.flatMap((cc) => cc.assignments); return mergedCertificates.value.flatMap((cc) => cc.assignments);
}); });
const userPointsEvaluatedAssignments = computed(() => { const userPointsEvaluatedAssignments = computed(() => {
@ -49,7 +54,7 @@ const userPointsEvaluatedAssignments = computed(() => {
const currentCourseSession = useCurrentCourseSession(); const currentCourseSession = useCurrentCourseSession();
const isLoaded = computed(() => !certificatesQuery.fetching.value); const isLoaded = computed(() => !certificateQueries.some((q) => q.fetching.value));
const router = useRouter(); const router = useRouter();
</script> </script>
@ -68,7 +73,7 @@ const router = useRouter();
<div v-if="userPointsEvaluatedAssignments > 0"> <div v-if="userPointsEvaluatedAssignments > 0">
{{ $t("a.Erfahrungsnote üK") }}: {{ $t("a.Erfahrungsnote üK") }}:
<span class="font-bold"> <span class="font-bold">
{{ calcCompetencesTotalGrade(competenceCertificates ?? []) }} {{ calcCompetencesTotalGrade(mergedCertificates ?? []) }}
</span> </span>
<span class="rounded-full bg-gray-200 px-2.5 py-0.5 text-sm lg:ml-2"> <span class="rounded-full bg-gray-200 px-2.5 py-0.5 text-sm lg:ml-2">
@ -83,7 +88,7 @@ const router = useRouter();
<div> <div>
<div class="mt-4"> <div class="mt-4">
<div <div
v-for="certificate in competenceCertificates" v-for="certificate in mergedCertificates"
:key="certificate.id" :key="certificate.id"
class="flex flex-col justify-between py-4 lg:flex-row lg:items-center" class="flex flex-col justify-between py-4 lg:flex-row lg:items-center"
:data-cy="`certificate-${certificate.slug}`" :data-cy="`certificate-${certificate.slug}`"

View File

@ -1,6 +1,7 @@
import type { StatusCount } from "@/components/ui/ItProgress.vue"; import type { StatusCount } from "@/components/ui/ItProgress.vue";
import { percentToRoundedGrade } from "@/services/assignmentService"; import { percentToRoundedGrade } from "@/services/assignmentService";
import type { CompetenceCertificate, CompetenceCertificateAssignment } from "@/types"; import type { CompetenceCertificate, CompetenceCertificateAssignment } from "@/types";
import dayjs from "dayjs";
import _ from "lodash"; import _ from "lodash";
export function assignmentsMaxEvaluationPoints( export function assignmentsMaxEvaluationPoints(
@ -84,3 +85,55 @@ export function competenceCertificateProgressStatusCount(
FAIL: 0, FAIL: 0,
} as StatusCount; } as StatusCount;
} }
export function mergeCompetenceCertificates(
competenceCertificates: CompetenceCertificate[]
) {
const groupedCompetenceCertificates: Record<
string,
Array<CompetenceCertificate>
> = {};
competenceCertificates.forEach((certificate) => {
if (!certificate) {
return;
}
if (!groupedCompetenceCertificates[certificate.id]) {
groupedCompetenceCertificates[certificate.id] = [];
}
groupedCompetenceCertificates[certificate.id].push(certificate);
});
console.log(
`Found ${Object.keys(groupedCompetenceCertificates).length} competence certificates over all course sessions`
);
return Object.values(groupedCompetenceCertificates).map((certificates) => {
const mergedCertificate: CompetenceCertificate = {
...certificates[0],
assignments: [],
};
certificates.forEach((certificate) => {
certificate.assignments.forEach((assignment) => {
const existingAssignment = mergedCertificate.assignments.find(
(a) => a.id === assignment.id
);
if (!existingAssignment) {
mergedCertificate.assignments.push(assignment);
} else if (
assignment.completion != null &&
(existingAssignment.completion == null ||
dayjs(existingAssignment.completion.evaluation_submitted_at).isBefore(
assignment.completion.evaluation_submitted_at
))
) {
mergedCertificate.assignments.splice(
mergedCertificate.assignments.findIndex((a) => a.id === assignment.id),
1
);
mergedCertificate.assignments.push(assignment);
}
});
});
return mergedCertificate;
});
}

View File

@ -1,26 +1,26 @@
import { login } from "../helpers"; import { login } from "../helpers"
describe("competenceCertificate.cy.js", () => { describe("competenceCertificate.cy.js", () => {
beforeEach(() => {}); beforeEach(() => { })
it("check without points", () => { it("check without points", () => {
cy.manageCommand("cypress_reset"); cy.manageCommand("cypress_reset")
login("test-student1@example.com", "test"); login("test-student1@example.com", "test")
cy.visit("/course/test-lehrgang/competence"); cy.visit("/course/test-lehrgang/competence")
cy.get('[data-cy="certificate-total-points-text"]').contains( cy.get('[data-cy="certificate-total-points-text"]').contains(
"Der Punktestand wird zu einem späteren Zeitpunkt berechnet." "Der Punktestand wird zu einem späteren Zeitpunkt berechnet."
); )
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
).and("contain", "0 von 2 Kompetenznachweis-Elementen"); ).and("contain", "0 von 2 Kompetenznachweis-Elementen")
// check on certificates page // check on certificates page
cy.get('[data-cy="certificates-show-all-button"]').click(); cy.get('[data-cy="certificates-show-all-button"]').click()
cy.get('[data-cy="certificate-total-points-text"]').contains( cy.get('[data-cy="certificate-total-points-text"]').contains(
"Der Punktestand wird zu einem späteren Zeitpunkt berechnet." "Der Punktestand wird zu einem späteren Zeitpunkt berechnet."
); )
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
@ -29,100 +29,100 @@ describe("competenceCertificate.cy.js", () => {
"contain", "contain",
"Der Punktestand wird zu einem späteren Zeitpunkt berechnet." "Der Punktestand wird zu einem späteren Zeitpunkt berechnet."
) )
.and("contain", "0 von 2 Kompetenznachweis-Elementen"); .and("contain", "0 von 2 Kompetenznachweis-Elementen")
// check certificate detail page // check certificate detail page
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-detail-link"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-detail-link"]'
).click(); ).click()
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"]' '[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"]'
).should("contain", "Höchstpunktzahl"); ).should("contain", "Höchstpunktzahl")
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]' '[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]'
).should("contain", "Höchstpunktzahl"); ).should("contain", "Höchstpunktzahl")
}); })
it("check with finished passed edoniq test", () => { it("check with finished passed edoniq test", () => {
cy.manageCommand( cy.manageCommand(
"cypress_reset --create-assignment-completion --create-edoniq-test-results 19 24 0" "cypress_reset --create-assignment-completion --create-edoniq-test-results 19 24 0"
); )
login("test-student1@example.com", "test"); login("test-student1@example.com", "test")
cy.visit("/course/test-lehrgang/competence"); cy.visit("/course/test-lehrgang/competence")
cy.get('[data-cy="certificate-total-points-text"]').contains( cy.get('[data-cy="certificate-total-points-text"]').contains(
"Erfahrungsnote üK: 5" "Erfahrungsnote üK: 5"
); )
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
) )
.should("contain", "Note: 5") .should("contain", "Note: 5")
.and("contain", "1 von 2 Kompetenznachweis-Elementen"); .and("contain", "1 von 2 Kompetenznachweis-Elementen")
// check on certificates page // check on certificates page
cy.get('[data-cy="certificates-show-all-button"]').click(); cy.get('[data-cy="certificates-show-all-button"]').click()
cy.get('[data-cy="certificate-total-points-text"]') cy.get('[data-cy="certificate-total-points-text"]')
.should("contain", "Erfahrungsnote üK") .should("contain", "Erfahrungsnote üK")
.and("contain", "Zwischenstand"); .and("contain", "Zwischenstand")
cy.get('[data-cy="certificate-total-grade"]').should("contain", "Note: 5"); cy.get('[data-cy="certificate-total-grade"]').should("contain", "Note: 5")
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade"]'
).should("contain", "Note: 5"); ).should("contain", "Note: 5")
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade-percent"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade-percent"]'
).should("contain", "Ungerundete Note: 4.96"); ).should("contain", "Ungerundete Note: 4.96")
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
) )
.and("contain", "Zwischenstand") .and("contain", "Zwischenstand")
.and("contain", "1 von 2 Kompetenznachweis-Elementen"); .and("contain", "1 von 2 Kompetenznachweis-Elementen")
// check certificate detail page // check certificate detail page
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-detail-link"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-detail-link"]'
).click(); ).click()
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"]' '[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"]'
) )
.should("contain", "Höchstpunktzahl") .should("contain", "Höchstpunktzahl")
.and("contain", "Ergebnisse abgegeben"); .and("contain", "Ergebnisse abgegeben")
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]' '[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]'
) )
.should("contain", "19") .should("contain", "19")
.and("contain", "Bewertung freigegeben") .and("contain", "Bewertung freigegeben")
.and("not.contain", "Nicht Bestanden"); .and("not.contain", "Nicht Bestanden")
// it can open learning content page directly // it can open learning content page directly
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"] [data-cy="open-learning-content"]' '[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"] [data-cy="open-learning-content"]'
).click(); ).click()
cy.get('[data-cy="test-result"]') cy.get('[data-cy="test-result"]')
.should("contain", "19 von 24 Punkten") .should("contain", "19 von 24 Punkten")
.and("contain", "79%"); .and("contain", "79%")
}); })
it("check with finished failed edoniq test", () => { it("check with finished failed edoniq test", () => {
cy.manageCommand( cy.manageCommand(
"cypress_reset --create-assignment-completion --create-edoniq-test-results 10 24 0" "cypress_reset --create-assignment-completion --create-edoniq-test-results 10 24 0"
); )
login("test-student1@example.com", "test"); login("test-student1@example.com", "test")
// go to certificate detail page // go to certificate detail page
cy.visit( cy.visit(
"/course/test-lehrgang/competence/certificates/kompetenznachweis-1" "/course/test-lehrgang/competence/certificates/kompetenznachweis-1"
); )
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade"]'
).should("contain", "Note: 3"); ).should("contain", "Note: 3")
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade-percent"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade-percent"]'
).should("contain", "Ungerundete Note: 3.08"); ).should("contain", "Ungerundete Note: 3.08")
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]' '[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]'
@ -130,90 +130,148 @@ describe("competenceCertificate.cy.js", () => {
.should("contain", "10") .should("contain", "10")
.and("contain", "Bewertung freigegeben") .and("contain", "Bewertung freigegeben")
.and("contain", "42%") .and("contain", "42%")
.and("contain", "Nicht bestanden"); .and("contain", "Nicht bestanden")
// it can open learning content page directly // it can open learning content page directly
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"] [data-cy="open-learning-content"]' '[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"] [data-cy="open-learning-content"]'
).click(); ).click()
cy.get('[data-cy="test-result"]') cy.get('[data-cy="test-result"]')
.should("contain", "10 von 24 Punkten") .should("contain", "10 von 24 Punkten")
.and("contain", "42%") .and("contain", "42%")
.and("contain", "Nicht bestanden"); .and("contain", "Nicht bestanden")
}); })
it("check with finished edoniq test and finished casework", () => { it("check with finished edoniq test and finished casework", () => {
cy.manageCommand( cy.manageCommand(
"cypress_reset --create-assignment-evaluation --create-edoniq-test-results 19 24 0" "cypress_reset --create-assignment-evaluation --create-edoniq-test-results 19 24 0"
); )
login("test-student1@example.com", "test"); login("test-student1@example.com", "test")
cy.visit("/course/test-lehrgang/competence"); cy.visit("/course/test-lehrgang/competence")
cy.get('[data-cy="certificate-total-points-text"]').contains( cy.get('[data-cy="certificate-total-points-text"]').contains(
"Erfahrungsnote üK: 5.5" "Erfahrungsnote üK: 5.5"
); )
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
) )
.should("contain", "Note: 5.5") .should("contain", "Note: 5.5")
.and("contain", "2 von 2 Kompetenznachweis-Elementen"); .and("contain", "2 von 2 Kompetenznachweis-Elementen")
// check on certificates page // check on certificates page
cy.get('[data-cy="certificates-show-all-button"]').click(); cy.get('[data-cy="certificates-show-all-button"]').click()
cy.get('[data-cy="certificate-total-points-text"]') cy.get('[data-cy="certificate-total-points-text"]')
.should("contain", "Erfahrungsnote üK") .should("contain", "Erfahrungsnote üK")
.and("contain", "Note: 5.5") .and("contain", "Note: 5.5")
.and("not.contain", "Zwischenstand"); .and("not.contain", "Zwischenstand")
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
) )
.and("not.contain", "Zwischenstand") .and("not.contain", "Zwischenstand")
.and("contain", "2 von 2 Kompetenznachweis-Elementen"); .and("contain", "2 von 2 Kompetenznachweis-Elementen")
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade"]'
).should("contain", "Note: 5.5"); ).should("contain", "Note: 5.5")
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade-percent"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade-percent"]'
).should("contain", "Ungerundete Note: 5.48"); ).should("contain", "Ungerundete Note: 5.48")
// check certificate detail page // check certificate detail page
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-detail-link"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-detail-link"]'
).click(); ).click()
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"]' '[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"]'
) )
.should("contain", "24") .should("contain", "24")
.and("contain", "von 24 Punkten") .and("contain", "von 24 Punkten")
.and("contain", "Bewertung freigegeben"); .and("contain", "Bewertung freigegeben")
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]' '[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]'
) )
.should("contain", "19") .should("contain", "19")
.and("contain", "von 24 Punkten") .and("contain", "von 24 Punkten")
.and("contain", "Bewertung freigegeben"); .and("contain", "Bewertung freigegeben")
}); })
it("check with finished edoniq test and finished casework in different course sessions", () => {
const TEST_TRAINER2_USER_ID = "299941ae-1e4b-4f45-8180-876c3ad340b4"
const TEST_STUDENT2_USER_ID = "19c40d94-15cc-4198-aaad-ef707c4b0900"
const TEST_COURSE_SESSION_ZURICH_ID = -2
cy.manageCommand(
`cypress_reset --create-assignment-evaluation --assignment-evaluation-user-id ${TEST_TRAINER2_USER_ID} --assignment-completion-user-id ${TEST_STUDENT2_USER_ID} --edoniq-user-id ${TEST_STUDENT2_USER_ID} --edoniq-course-session-id '${TEST_COURSE_SESSION_ZURICH_ID}' --create-edoniq-test-results 19 24 0`
)
login("test-student2@example.com", "test")
cy.visit("/course/test-lehrgang/competence")
cy.get('[data-cy="certificate-total-points-text"]').contains(
"Erfahrungsnote üK: 5.5"
)
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
)
.should("contain", "Note: 5.5")
.and("contain", "2 von 2 Kompetenznachweis-Elementen")
// check on certificates page
cy.get('[data-cy="certificates-show-all-button"]').click()
cy.get('[data-cy="certificate-total-points-text"]')
.should("contain", "Erfahrungsnote üK")
.and("contain", "Note: 5.5")
.and("not.contain", "Zwischenstand")
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
)
.and("not.contain", "Zwischenstand")
.and("contain", "2 von 2 Kompetenznachweis-Elementen")
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade"]'
).should("contain", "Note: 5.5")
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade-percent"]'
).should("contain", "Ungerundete Note: 5.48")
// check certificate detail page
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-detail-link"]'
).click()
cy.get(
'[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"]'
)
.should("contain", "24")
.and("contain", "von 24 Punkten")
.and("contain", "Bewertung freigegeben")
cy.get(
'[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]'
)
.should("contain", "19")
.and("contain", "von 24 Punkten")
.and("contain", "Bewertung freigegeben")
})
it("check with finished edoniq test with deducted points", () => { it("check with finished edoniq test with deducted points", () => {
cy.manageCommand( cy.manageCommand(
"cypress_reset --create-assignment-completion --create-edoniq-test-results 19 24 8" "cypress_reset --create-assignment-completion --create-edoniq-test-results 19 24 8"
); )
login("test-student1@example.com", "test"); login("test-student1@example.com", "test")
// go to certificate detail page // go to certificate detail page
cy.visit( cy.visit(
"/course/test-lehrgang/competence/certificates/kompetenznachweis-1" "/course/test-lehrgang/competence/certificates/kompetenznachweis-1"
); )
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade"]'
).should("contain", "Note: 3.5"); ).should("contain", "Note: 3.5")
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade-percent"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade-percent"]'
).should("contain", "Ungerundete Note: 3.29"); ).should("contain", "Ungerundete Note: 3.29")
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]' '[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]'
@ -222,61 +280,61 @@ describe("competenceCertificate.cy.js", () => {
.and("contain", "Bewertung freigegeben") .and("contain", "Bewertung freigegeben")
.and("contain", "46%") .and("contain", "46%")
.and("contain", "mit Abzug") .and("contain", "mit Abzug")
.and("contain", "Nicht bestanden"); .and("contain", "Nicht bestanden")
// it can open learning content page directly // it can open learning content page directly
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"] [data-cy="open-learning-content"]' '[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"] [data-cy="open-learning-content"]'
).click(); ).click()
cy.get('[data-cy="test-result"]') cy.get('[data-cy="test-result"]')
.should("contain", "11 von 24 Punkten") .should("contain", "11 von 24 Punkten")
.and("contain", "46%") .and("contain", "46%")
.and("contain", "Punkte aus Bewertung: 19") .and("contain", "Punkte aus Bewertung: 19")
.and("contain", "Abgezogene Punkte: 8") .and("contain", "Abgezogene Punkte: 8")
.and("contain", "Grund: Edoniq Punkteabzug Test") .and("contain", "Grund: Edoniq Punkteabzug Test")
.and("contain", "Nicht bestanden"); .and("contain", "Nicht bestanden")
}); })
it("check with finished casework and points deducted", () => { it("check with finished casework and points deducted", () => {
cy.manageCommand( cy.manageCommand(
"cypress_reset --create-assignment-evaluation --assignment-evaluation-scores 4,6,4,3,2 --assignment-points-deducted 5" "cypress_reset --create-assignment-evaluation --assignment-evaluation-scores 4,6,4,3,2 --assignment-points-deducted 5"
); )
login("test-student1@example.com", "test"); login("test-student1@example.com", "test")
cy.visit("/course/test-lehrgang/competence"); cy.visit("/course/test-lehrgang/competence")
cy.get('[data-cy="certificate-total-points-text"]').contains( cy.get('[data-cy="certificate-total-points-text"]').contains(
"Erfahrungsnote üK: 4" "Erfahrungsnote üK: 4"
); )
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
) )
.should("contain", "Note: 4") .should("contain", "Note: 4")
.and("contain", "1 von 2 Kompetenznachweis-Elementen"); .and("contain", "1 von 2 Kompetenznachweis-Elementen")
// check on certificates page // check on certificates page
cy.get('[data-cy="certificates-show-all-button"]').click(); cy.get('[data-cy="certificates-show-all-button"]').click()
cy.get('[data-cy="certificate-total-points-text"]') cy.get('[data-cy="certificate-total-points-text"]')
.should("contain", "Erfahrungsnote üK") .should("contain", "Erfahrungsnote üK")
.and("contain", "Note: 4") .and("contain", "Note: 4")
.and("contain", "Zwischenstand"); .and("contain", "Zwischenstand")
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
) )
.and("contain", "Zwischenstand") .and("contain", "Zwischenstand")
.and("contain", "1 von 2 Kompetenznachweis-Elementen"); .and("contain", "1 von 2 Kompetenznachweis-Elementen")
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade"]'
).should("contain", "Note: 4"); ).should("contain", "Note: 4")
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade-percent"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-grade-percent"]'
).should("contain", "Ungerundete Note: 3.92"); ).should("contain", "Ungerundete Note: 3.92")
// check certificate detail page // check certificate detail page
cy.get( cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-detail-link"]' '[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-detail-link"]'
).click(); ).click()
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"]' '[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"]'
@ -285,28 +343,28 @@ describe("competenceCertificate.cy.js", () => {
.and("contain", "von 24 Punkten") .and("contain", "von 24 Punkten")
.and("contain", "58%") .and("contain", "58%")
.and("contain", "mit Abzug") .and("contain", "mit Abzug")
.and("contain", "Bewertung freigegeben"); .and("contain", "Bewertung freigegeben")
cy.get( cy.get(
'[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"] [data-cy="open-learning-content"]' '[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"] [data-cy="open-learning-content"]'
).click(); ).click()
cy.get('[data-cy="user-points"]').should("contain", "14"); cy.get('[data-cy="user-points"]').should("contain", "14")
cy.get('[data-cy="total-points"]').should( cy.get('[data-cy="total-points"]').should(
"contain", "contain",
"von 24 Punkten (58%)" "von 24 Punkten (58%)"
); )
cy.get('[data-cy="points-deducted"]') cy.get('[data-cy="points-deducted"]')
.should("contain", "Punkte aus Bewertung: 19") .should("contain", "Punkte aus Bewertung: 19")
.and("contain", "Abgezogene Punkte: 5") .and("contain", "Abgezogene Punkte: 5")
.and("contain", "Grund: Assignment Punkteabzug Test"); .and("contain", "Grund: Assignment Punkteabzug Test")
}); })
it("should display link to details", () => { it("should display link to details", () => {
cy.manageCommand("cypress_reset"); cy.manageCommand("cypress_reset")
login("test-student1@example.com", "test"); login("test-student1@example.com", "test")
cy.visit("/course/test-lehrgang/competence/self-evaluation-and-feedback"); cy.visit("/course/test-lehrgang/competence/self-evaluation-and-feedback")
cy.get('[data-cy^="self-eval-"][data-cy$="-detail-url"]:first').contains( cy.get('[data-cy^="self-eval-"][data-cy$="-detail-url"]:first').contains(
"Selbsteinschätzung anschauen" "Selbsteinschätzung anschauen"
); )
}); })
}); })

View File

@ -50,20 +50,20 @@
// -- This is will overwrite an existing command -- // -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
const _ = Cypress._; const _ = Cypress._
Cypress.Commands.add("manageCommand", (command, preCommand = "") => { Cypress.Commands.add("manageCommand", (command, preCommand = "") => {
const execCommand = `${preCommand} python server/manage.py ${command} --settings=config.settings.test_cypress`; const execCommand = `${preCommand} python server/manage.py ${command} --settings=config.settings.test_cypress`
console.log(execCommand); console.log(execCommand)
// hack to add my asdf python instance to the path // hack to add my asdf python instance to the path
// so I can run the test directly from within IntelliJ // so I can run the test directly from within IntelliJ
let pythonPaths = [ let pythonPaths = [
"/Users/daniel/workspace/vbv_lernwelt/.direnv/python-3.10.6/bin", "/Users/daniel/workspace/vbv_lernwelt/.direnv/python-3.10.6/bin",
"/Users/eliabieri/iterativ/vbv_lernwelt/.direnv/python-3.10.6/bin", "/Users/eliabieri/iterativ/vbv_lernwelt/.direnv/python-3.10/bin",
"/Users/christiancueni/workspace/vbv_lernwelt/.direnv/python-3.10.6/bin", "/Users/christiancueni/workspace/vbv_lernwelt/.direnv/python-3.10.6/bin",
"/Users/renzo/workspace/vbv_lernwelt/.direnv/python-3.10.6/bin", "/Users/renzo/workspace/vbv_lernwelt/.direnv/python-3.10.6/bin",
]; ]
let bashCommand = `PATH=${pythonPaths.join(":")}:$PATH && ${execCommand}`; let bashCommand = `PATH=${pythonPaths.join(":")}:$PATH && ${execCommand}`
return cy return cy
.exec(`bash -c "${bashCommand}"`, { .exec(`bash -c "${bashCommand}"`, {
failOnNonZeroExit: true, failOnNonZeroExit: true,
@ -73,14 +73,14 @@ Cypress.Commands.add("manageCommand", (command, preCommand = "") => {
throw new Error(`Execution of "${command}" failed throw new Error(`Execution of "${command}" failed
Exit code: ${result.code} Exit code: ${result.code}
Stdout:\n${result.stdout} Stdout:\n${result.stdout}
Stderr:\n${result.stderr}`); Stderr:\n${result.stderr}`)
} }
}); })
}); })
Cypress.Commands.add("manageShellCommand", (command) => { Cypress.Commands.add("manageShellCommand", (command) => {
return cy.manageCommand(`shell -c '${command}'`); return cy.manageCommand(`shell -c '${command}'`)
}); })
function loadObjectJson( function loadObjectJson(
key, key,
@ -89,28 +89,28 @@ function loadObjectJson(
serializerModelPath, serializerModelPath,
valueAsString = false valueAsString = false
) { ) {
const djangoModel = _.last(djangoModelPath.split(".")); const djangoModel = _.last(djangoModelPath.split("."))
const djangoModelImportPath = _.initial(djangoModelPath.split(".")).join("."); const djangoModelImportPath = _.initial(djangoModelPath.split(".")).join(".")
const serializerModel = _.last(serializerModelPath.split(".")); const serializerModel = _.last(serializerModelPath.split("."))
const serializerModelImportPath = _.initial( const serializerModelImportPath = _.initial(
serializerModelPath.split(".") serializerModelPath.split(".")
).join("."); ).join(".")
let filterPart = `${key}=${value}`; let filterPart = `${key}=${value}`
if (valueAsString) { if (valueAsString) {
filterPart = `${key}=\\"${value}\\"`; filterPart = `${key}=\\"${value}\\"`
} }
if (_.isArray(key)) { if (_.isArray(key)) {
filterPart = _.zip(key, value) filterPart = _.zip(key, value)
.map(([k, v]) => { .map(([k, v]) => {
if (valueAsString) { if (valueAsString) {
return `${k}=\\"${v}\\"`; return `${k}=\\"${v}\\"`
} else { } else {
return `${k}=${v}`; return `${k}=${v}`
} }
}) })
.join(","); .join(",")
} }
const command = `from ${djangoModelImportPath} import ${djangoModel}; const command = `from ${djangoModelImportPath} import ${djangoModel};
@ -119,13 +119,13 @@ function loadObjectJson(
object = ${djangoModel}.objects.filter(${filterPart}).first(); object = ${djangoModel}.objects.filter(${filterPart}).first();
print(create_json_from_objects(object, ${serializerModel}, many=False)); print(create_json_from_objects(object, ${serializerModel}, many=False));
exit(); exit();
`.replace(/(?:\r\n|\r|\n)/g, ""); `.replace(/(?:\r\n|\r|\n)/g, "")
return cy.manageShellCommand(command).then((result) => { return cy.manageShellCommand(command).then((result) => {
const objectJson = JSON.parse(result.stdout); const objectJson = JSON.parse(result.stdout)
// console.log(command); // console.log(command);
console.log(objectJson); console.log(objectJson)
return objectJson; return objectJson
}); })
} }
Cypress.Commands.add("loadAssignmentCompletion", (key, value) => { Cypress.Commands.add("loadAssignmentCompletion", (key, value) => {
@ -135,8 +135,8 @@ Cypress.Commands.add("loadAssignmentCompletion", (key, value) => {
"vbv_lernwelt.assignment.models.AssignmentCompletion", "vbv_lernwelt.assignment.models.AssignmentCompletion",
"vbv_lernwelt.assignment.serializers.CypressAssignmentCompletionSerializer", "vbv_lernwelt.assignment.serializers.CypressAssignmentCompletionSerializer",
true true
); )
}); })
Cypress.Commands.add("loadSecurityRequestResponseLog", (key, value) => { Cypress.Commands.add("loadSecurityRequestResponseLog", (key, value) => {
return loadObjectJson( return loadObjectJson(
@ -145,8 +145,8 @@ Cypress.Commands.add("loadSecurityRequestResponseLog", (key, value) => {
"vbv_lernwelt.core.models.SecurityRequestResponseLog", "vbv_lernwelt.core.models.SecurityRequestResponseLog",
"vbv_lernwelt.core.serializers.CypressSecurityRequestResponseLogSerializer", "vbv_lernwelt.core.serializers.CypressSecurityRequestResponseLogSerializer",
true true
); )
}); })
Cypress.Commands.add("loadExternalApiRequestLog", (key, value) => { Cypress.Commands.add("loadExternalApiRequestLog", (key, value) => {
return loadObjectJson( return loadObjectJson(
@ -155,8 +155,8 @@ Cypress.Commands.add("loadExternalApiRequestLog", (key, value) => {
"vbv_lernwelt.core.models.ExternalApiRequestLog", "vbv_lernwelt.core.models.ExternalApiRequestLog",
"vbv_lernwelt.core.serializers.CypressExternalApiRequestLogSerializer", "vbv_lernwelt.core.serializers.CypressExternalApiRequestLogSerializer",
true true
); )
}); })
Cypress.Commands.add("loadFeedbackResponse", (key, value) => { Cypress.Commands.add("loadFeedbackResponse", (key, value) => {
return loadObjectJson( return loadObjectJson(
@ -165,8 +165,8 @@ Cypress.Commands.add("loadFeedbackResponse", (key, value) => {
"vbv_lernwelt.feedback.models.FeedbackResponse", "vbv_lernwelt.feedback.models.FeedbackResponse",
"vbv_lernwelt.feedback.serializers.CypressFeedbackResponseSerializer", "vbv_lernwelt.feedback.serializers.CypressFeedbackResponseSerializer",
true true
); )
}); })
Cypress.Commands.add("loadCheckoutInformation", (key, value) => { Cypress.Commands.add("loadCheckoutInformation", (key, value) => {
return loadObjectJson( return loadObjectJson(
@ -175,37 +175,37 @@ Cypress.Commands.add("loadCheckoutInformation", (key, value) => {
"vbv_lernwelt.shop.models.CheckoutInformation", "vbv_lernwelt.shop.models.CheckoutInformation",
"vbv_lernwelt.shop.serializers.CypressCheckoutInformationSerializer", "vbv_lernwelt.shop.serializers.CypressCheckoutInformationSerializer",
true true
); )
}); })
Cypress.Commands.add("makeSelfEvaluation", (answers) => { Cypress.Commands.add("makeSelfEvaluation", (answers) => {
for (let i = 0; i < answers.length; i++) { for (let i = 0; i < answers.length; i++) {
const answer = answers[i]; const answer = answers[i]
if (answer) { if (answer) {
cy.get('[data-cy="success"]').click(); cy.get('[data-cy="success"]').click()
} else { } else {
cy.get('[data-cy="fail"]').click(); cy.get('[data-cy="fail"]').click()
} }
if (i < answers.length - 1) { if (i < answers.length - 1) {
cy.get('[data-cy="next-step"]').click({ force: true }); cy.get('[data-cy="next-step"]').click({ force: true })
} else { } else {
cy.get('[data-cy="complete-and-continue"]').click({ force: true }); cy.get('[data-cy="complete-and-continue"]').click({ force: true })
} }
} }
}); })
Cypress.Commands.add("learningContentMultiLayoutNextStep", () => { Cypress.Commands.add("learningContentMultiLayoutNextStep", () => {
return cy.get('[data-cy="next-step"]').click({ force: true }); return cy.get('[data-cy="next-step"]').click({ force: true })
}); })
Cypress.Commands.add("learningContentMultiLayoutPreviousStep", () => { Cypress.Commands.add("learningContentMultiLayoutPreviousStep", () => {
return cy.get('[data-cy="previous-step"]').click({ force: true }); return cy.get('[data-cy="previous-step"]').click({ force: true })
}); })
Cypress.Commands.add("testLearningContentTitle", (title) => { Cypress.Commands.add("testLearningContentTitle", (title) => {
return cy.get('[data-cy="lc-title"]').should("contain", title); return cy.get('[data-cy="lc-title"]').should("contain", title)
}); })
Cypress.Commands.add("testLearningContentSubtitle", (subtitle) => { Cypress.Commands.add("testLearningContentSubtitle", (subtitle) => {
return cy.get('[data-cy="lc-subtitle"]').should("contain", subtitle); return cy.get('[data-cy="lc-subtitle"]').should("contain", subtitle)
}); })

View File

@ -6,6 +6,7 @@
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"cypress:open": "cypress open", "cypress:open": "cypress open",
"cypress:ci": "cypress-cloud run --parallel --record", "cypress:ci": "cypress-cloud run --parallel --record",
"cypress:install": "cypress install",
"prettier": "npm run prettier --prefix client" "prettier": "npm run prettier --prefix client"
}, },
"devDependencies": { "devDependencies": {

View File

@ -59,12 +59,32 @@ from vbv_lernwelt.shop.models import CheckoutInformation
@click.option( @click.option(
"--create-assignment-completion/--no-create-assignment-completion", "--create-assignment-completion/--no-create-assignment-completion",
default=False, default=False,
help="will create assignment completion data for test-student1@example.com", help="will create assignment completion data for test-student1@example.com by default. Other user can be specified with --assignment-completion-user",
)
@click.option(
"--assignment-completion-user-id",
default=TEST_STUDENT1_USER_ID,
help="user to create assignment completion for. Defaults to test-student1@example.com. Hint: Is only evaluated if --create-assignment-completion is set.",
)
@click.option(
"--assignment-completion-course-session-id",
default=TEST_COURSE_SESSION_BERN_ID,
help="course session to create assignment completion in. Defaults to 'Test Bern 2022 a'. Hint: Is only evaluated if --create-assignment-completion is set.",
) )
@click.option( @click.option(
"--create-assignment-evaluation/--no-create-assignment-evaluation", "--create-assignment-evaluation/--no-create-assignment-evaluation",
default=False, default=False,
help="will create assignment evaluation data for test-student1@example.com", help="will create assignment evaluation data for test-student1@example.com by default. Other user can be specified with --assignment-evaluation-user",
)
@click.option(
"--assignment-evaluation-user-id",
default=TEST_TRAINER1_USER_ID,
help="user to create assignment evaluation for. Defaults to test-trainer1@example.com. Hint: Is only evaluated if --create-assignment-completion is set.",
)
@click.option(
"--assignment-evaluation-course-session-id",
default=TEST_COURSE_SESSION_BERN_ID,
help="course session to create assignment evaluation in. Defaults to 'Test Bern 2022 a'. Hint: Is only evaluated if --create-assignment-completion is set.",
) )
@click.option( @click.option(
"--assignment-evaluation-scores", "--assignment-evaluation-scores",
@ -81,7 +101,17 @@ from vbv_lernwelt.shop.models import CheckoutInformation
type=(int, int, float), type=(int, int, float),
default=(None, None, 0.0), default=(None, None, 0.0),
metavar="USER_POINTS MAX_POINTS POINTS_DEDUCTED", metavar="USER_POINTS MAX_POINTS POINTS_DEDUCTED",
help="Create edoniq result data for test-student1@example.com with user points and max points", help="Create edoniq result data for test-student1@example.com by default with user points and max points. Use --edoniq-user-id to specify a different user.",
)
@click.option(
"--edoniq-user-id",
default=TEST_STUDENT1_USER_ID,
help="User to create edoniq test results for. Defaults to test-student1@example.com. Hint: Is only evaluated if --create-edoniq-test-results is set.",
)
@click.option(
"--edoniq-course-session-id",
default=TEST_COURSE_SESSION_BERN_ID,
help="course session to create edoniq test results in. Defaults to 'Test Bern 2022 a'. Hint: Is only evaluated if --create-edoniq-test-results is set.",
) )
@click.option( @click.option(
"--create-feedback-responses/--no-create-feedback-responses", "--create-feedback-responses/--no-create-feedback-responses",
@ -120,10 +150,16 @@ from vbv_lernwelt.shop.models import CheckoutInformation
) )
def command( def command(
create_assignment_completion, create_assignment_completion,
assignment_completion_user_id,
assignment_completion_course_session_id,
create_assignment_evaluation, create_assignment_evaluation,
assignment_evaluation_user_id,
assignment_evaluation_course_session_id,
assignment_evaluation_scores, assignment_evaluation_scores,
assignment_points_deducted, assignment_points_deducted,
create_edoniq_test_results, create_edoniq_test_results,
edoniq_user_id,
edoniq_course_session_id,
create_feedback_responses, create_feedback_responses,
create_course_completion_performance_criteria, create_course_completion_performance_criteria,
create_attendance_days, create_attendance_days,
@ -170,15 +206,19 @@ def command(
assignment=Assignment.objects.get( assignment=Assignment.objects.get(
slug="test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice" slug="test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"
), ),
course_session=CourseSession.objects.get(id=TEST_COURSE_SESSION_BERN_ID), course_session=CourseSession.objects.get(
user=User.objects.get(id=TEST_STUDENT1_USER_ID), id=assignment_completion_course_session_id
),
user=User.objects.get(id=assignment_completion_user_id),
) )
create_test_assignment_submitted_data( create_test_assignment_submitted_data(
assignment=Assignment.objects.get( assignment=Assignment.objects.get(
slug="test-lehrgang-assignment-mein-kundenstamm" slug="test-lehrgang-assignment-mein-kundenstamm"
), ),
course_session=CourseSession.objects.get(id=TEST_COURSE_SESSION_BERN_ID), course_session=CourseSession.objects.get(
user=User.objects.get(id=TEST_STUDENT1_USER_ID), id=assignment_completion_course_session_id
),
user=User.objects.get(id=assignment_completion_user_id),
) )
if create_assignment_evaluation: if create_assignment_evaluation:
if not assignment_evaluation_scores: if not assignment_evaluation_scores:
@ -195,9 +235,11 @@ def command(
assignment=Assignment.objects.get( assignment=Assignment.objects.get(
slug="test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice" slug="test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"
), ),
course_session=CourseSession.objects.get(id=TEST_COURSE_SESSION_BERN_ID), course_session=CourseSession.objects.get(
assignment_user=User.objects.get(id=TEST_STUDENT1_USER_ID), id=assignment_evaluation_course_session_id
evaluation_user=User.objects.get(id=TEST_TRAINER1_USER_ID), ),
assignment_user=User.objects.get(id=assignment_completion_user_id),
evaluation_user=User.objects.get(id=assignment_evaluation_user_id),
input_scores=assignment_evaluation_scores, input_scores=assignment_evaluation_scores,
points_deducted=assignment_points_deducted, points_deducted=assignment_points_deducted,
) )
@ -211,8 +253,8 @@ def command(
assignment=Assignment.objects.get( assignment=Assignment.objects.get(
slug="test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo" slug="test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"
), ),
course_session=CourseSession.objects.get(id=TEST_COURSE_SESSION_BERN_ID), course_session=CourseSession.objects.get(id=edoniq_course_session_id),
assignment_user=User.objects.get(id=TEST_STUDENT1_USER_ID), assignment_user=User.objects.get(id=edoniq_user_id),
user_points=user_points, user_points=user_points,
max_points=max_points, max_points=max_points,
evaluation_points_deducted=points_deducted, evaluation_points_deducted=points_deducted,