wip: Add evaluation tests
This commit is contained in:
parent
39ea4d8555
commit
0fc428ff06
|
|
@ -42,6 +42,7 @@ const dropdownSelected = computed<DropdownSelectable>({
|
||||||
border: !props.borderless,
|
border: !props.borderless,
|
||||||
'font-bold': !props.borderless,
|
'font-bold': !props.borderless,
|
||||||
}"
|
}"
|
||||||
|
data-cy="dropdown-select"
|
||||||
>
|
>
|
||||||
<span v-if="dropdownSelected.iconName" class="mr-4">
|
<span v-if="dropdownSelected.iconName" class="mr-4">
|
||||||
<component :is="dropdownSelected.iconName"></component>
|
<component :is="dropdownSelected.iconName"></component>
|
||||||
|
|
@ -75,6 +76,7 @@ const dropdownSelected = computed<DropdownSelectable>({
|
||||||
'relative cursor-default select-none py-2 pl-3 pr-9',
|
'relative cursor-default select-none py-2 pl-3 pr-9',
|
||||||
]"
|
]"
|
||||||
class="flex flex-row items-center"
|
class="flex flex-row items-center"
|
||||||
|
:data-cy="`dropdown-select-option-${item.name}`"
|
||||||
>
|
>
|
||||||
<span v-if="item.iconName" class="mr-4">
|
<span v-if="item.iconName" class="mr-4">
|
||||||
<component :is="item.iconName"></component>
|
<component :is="item.iconName"></component>
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ const text = computed(() => {
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
evaluationTitle: "Feedback",
|
evaluationTitle: "Feedback",
|
||||||
evaluationInstruction: "assignment.evaluationInstrumentDescriptionTextFeedback",
|
evaluationInstruction: "a.assignment.evaluationInstrumentDescriptionTextFeedback",
|
||||||
evaluationStart: "a.Feedback geben",
|
evaluationStart: "a.Feedback geben",
|
||||||
evaluationContinue: "a.Feedback fortsetzen",
|
evaluationContinue: "a.Feedback fortsetzen",
|
||||||
evaluationView: "a.Feedback ansehen",
|
evaluationView: "a.Feedback ansehen",
|
||||||
|
|
@ -80,7 +80,7 @@ async function startEvaluation() {
|
||||||
|
|
||||||
<h3 data-cy="title">{{ $t(text.evaluationTitle) }}</h3>
|
<h3 data-cy="title">{{ $t(text.evaluationTitle) }}</h3>
|
||||||
|
|
||||||
<p v-if="props.dueDate" class="my-4">
|
<p v-if="props.dueDate" class="my-4" data-cy="evaluation-duedate">
|
||||||
{{
|
{{
|
||||||
$t(
|
$t(
|
||||||
"assignment.Du musst die Bewertung bis am x um y Uhr abschliessen und freigeben",
|
"assignment.Du musst die Bewertung bis am x um y Uhr abschliessen und freigeben",
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ const text = computed(() => {
|
||||||
evaluationDescription: "assignment.evaluationInstrumentDescriptionText",
|
evaluationDescription: "assignment.evaluationInstrumentDescriptionText",
|
||||||
evaluationSubmit: "a.Bewertung freigeben",
|
evaluationSubmit: "a.Bewertung freigeben",
|
||||||
evaluationSubmission: "a.Bewertung Freigabe",
|
evaluationSubmission: "a.Bewertung Freigabe",
|
||||||
evaluationForUser: "a.Bewertung von x y",
|
evaluationFromUser: "a.Bewertung von x y",
|
||||||
evaluationSuccess: "a.Deine Bewertung für x y wurde freigegeben.",
|
evaluationSuccess: "a.Deine Bewertung für x y wurde freigegeben.",
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -58,7 +58,7 @@ const text = computed(() => {
|
||||||
evaluationDescription: "a.assignment.evaluationFeedbackDescriptionText",
|
evaluationDescription: "a.assignment.evaluationFeedbackDescriptionText",
|
||||||
evaluationSubmit: "a.Feedback freigeben",
|
evaluationSubmit: "a.Feedback freigeben",
|
||||||
evaluationSubmission: "a.Feedback Freigabe",
|
evaluationSubmission: "a.Feedback Freigabe",
|
||||||
evaluationForUser: "a.Feedback von x y",
|
evaluationFromUser: "a.Feedback von x y",
|
||||||
evaluationSuccess: "a.Dein Feedback für x y wurde freigegeben.",
|
evaluationSuccess: "a.Dein Feedback für x y wurde freigegeben.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +82,9 @@ async function submitEvaluation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function subTaskByPoints(task: AssignmentEvaluationTask, points = 0) {
|
function subTaskByPoints(task: AssignmentEvaluationTask, points = 0) {
|
||||||
return task.value.sub_tasks.find((subTask) => subTask.value.points === points);
|
return task.value.sub_tasks !== undefined
|
||||||
|
? task.value.sub_tasks.find((subTask) => subTask.value.points === points)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function evaluationForTask(task: AssignmentEvaluationTask) {
|
function evaluationForTask(task: AssignmentEvaluationTask) {
|
||||||
|
|
@ -118,14 +120,13 @@ const evaluationUser = computed(() => {
|
||||||
<div>
|
<div>
|
||||||
<h3 v-if="evaluationUser && props.showEvaluationUser" class="mb-6">
|
<h3 v-if="evaluationUser && props.showEvaluationUser" class="mb-6">
|
||||||
{{
|
{{
|
||||||
$t(text.evaluationForUser, {
|
$t(text.evaluationFromUser, {
|
||||||
x: evaluationUser.first_name,
|
x: evaluationUser?.first_name,
|
||||||
y: evaluationUser.last_name,
|
y: evaluationUser?.last_name,
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</h3>
|
</h3>
|
||||||
<h3 v-else class="mb-6" data-cy="sub-title">{{ $t(text.evaluationSubmission) }}</h3>
|
<h3 v-else class="mb-6" data-cy="sub-title">{{ $t(text.evaluationSubmission) }}</h3>
|
||||||
|
|
||||||
<section class="mb-6 border p-6" data-cy="result-section">
|
<section class="mb-6 border p-6" data-cy="result-section">
|
||||||
<section
|
<section
|
||||||
v-if="props.assignment.assignment_type === 'CASEWORK'"
|
v-if="props.assignment.assignment_type === 'CASEWORK'"
|
||||||
|
|
@ -197,8 +198,8 @@ const evaluationUser = computed(() => {
|
||||||
<ItSuccessAlert
|
<ItSuccessAlert
|
||||||
:text="
|
:text="
|
||||||
$t(text.evaluationSuccess, {
|
$t(text.evaluationSuccess, {
|
||||||
x: evaluationUser?.first_name,
|
x: props.assignmentUser.first_name,
|
||||||
y: evaluationUser?.last_name,
|
y: props.assignmentUser.last_name,
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
></ItSuccessAlert>
|
></ItSuccessAlert>
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,12 @@ const assignmentDetail = computed(() => {
|
||||||
return courseSessionDetailResult.findAssignment(props.learningContent.id);
|
return courseSessionDetailResult.findAssignment(props.learningContent.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isPraxisAssignment = computed(() => {
|
||||||
|
return (
|
||||||
|
props.learningContent.content_assignment.assignment_type === "PRAXIS_ASSIGNMENT"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const { gradedUsers, assignmentSubmittedUsers } =
|
const { gradedUsers, assignmentSubmittedUsers } =
|
||||||
await loadAssignmentCompletionStatusData(
|
await loadAssignmentCompletionStatusData(
|
||||||
|
|
@ -130,7 +136,13 @@ function findUserPointsHtml(userId: string) {
|
||||||
>
|
>
|
||||||
<it-icon-check class="h-4/5 w-4/5"></it-icon-check>
|
<it-icon-check class="h-4/5 w-4/5"></it-icon-check>
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-2">{{ $t("a.Bewertung freigegeben") }}</div>
|
<div class="ml-2">
|
||||||
|
{{
|
||||||
|
isPraxisAssignment
|
||||||
|
? $t("a.Feedback freigegeben")
|
||||||
|
: $t("a.Bewertung freigegeben")
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else-if="state.assignmentSubmittedUsers.includes(csu)"
|
v-else-if="state.assignmentSubmittedUsers.includes(csu)"
|
||||||
|
|
@ -146,7 +158,7 @@ function findUserPointsHtml(userId: string) {
|
||||||
|
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div
|
<div
|
||||||
v-if="findGradedUser(csu.user_id)"
|
v-if="findGradedUser(csu.user_id) && !isPraxisAssignment"
|
||||||
v-html="findUserPointsHtml(csu.user_id)"
|
v-html="findUserPointsHtml(csu.user_id)"
|
||||||
></div>
|
></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -343,7 +343,7 @@ export interface AssignmentEvaluationTask {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
max_points: number;
|
max_points: number;
|
||||||
sub_tasks: AssignmentEvaluationSubTask[];
|
sub_tasks?: AssignmentEvaluationSubTask[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ describe("assignmentTrainer.cy.js", () => {
|
||||||
login("test-trainer1@example.com", "test");
|
login("test-trainer1@example.com", "test");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Caswork", () => {
|
||||||
it("can open cockpit assignment page and open user assignment", () => {
|
it("can open cockpit assignment page and open user assignment", () => {
|
||||||
cy.visit("/course/test-lehrgang/cockpit");
|
cy.visit("/course/test-lehrgang/cockpit");
|
||||||
cy.get(
|
cy.get(
|
||||||
|
|
@ -28,6 +29,12 @@ describe("assignmentTrainer.cy.js", () => {
|
||||||
|
|
||||||
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
||||||
|
|
||||||
|
cy.get('[data-cy="title"]').should("contain", "Bewertung");
|
||||||
|
cy.get('[data-cy="evaluation-duedate"]').should("exist");
|
||||||
|
cy.get('[data-cy="instruction"]').should(
|
||||||
|
"contain",
|
||||||
|
"Die Gesamtpunktzahl und die daraus resultierende Note wird auf Grund des hinterlegeten Beurteilungsinstrument berechnet."
|
||||||
|
);
|
||||||
cy.get('[data-cy="start-evaluation"]').click();
|
cy.get('[data-cy="start-evaluation"]').click();
|
||||||
cy.get('[data-cy="evaluation-task"]').should(
|
cy.get('[data-cy="evaluation-task"]').should(
|
||||||
"contain",
|
"contain",
|
||||||
|
|
@ -75,6 +82,7 @@ describe("assignmentTrainer.cy.js", () => {
|
||||||
.find("textarea")
|
.find("textarea")
|
||||||
.should("have.value", "Nicht so gut");
|
.should("have.value", "Nicht so gut");
|
||||||
|
|
||||||
|
cy.wait(500);
|
||||||
// load AssignmentCompletion from DB and check
|
// load AssignmentCompletion from DB and check
|
||||||
cy.loadAssignmentCompletion(
|
cy.loadAssignmentCompletion(
|
||||||
"assignment_user_id",
|
"assignment_user_id",
|
||||||
|
|
@ -194,4 +202,139 @@ describe("assignmentTrainer.cy.js", () => {
|
||||||
expect(completionString).to.include("Begründung Schritt 5");
|
expect(completionString).to.include("Begründung Schritt 5");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//Todo: Move tests to Lernbegleitung once it is implemented
|
||||||
|
describe("Praxis Assignment", () => {
|
||||||
|
it("can start evaluation and store evaluation results", () => {
|
||||||
|
cy.visit("/course/test-lehrgang/cockpit");
|
||||||
|
cy.get('[data-cy="dropdown-select"]').click();
|
||||||
|
cy.get('[data-cy="dropdown-select-option-Reisen"]').click();
|
||||||
|
cy.get(
|
||||||
|
'[data-cy="show-details-btn-test-lehrgang-lp-circle-reisen-lc-mein-kundenstamm"]'
|
||||||
|
).click();
|
||||||
|
|
||||||
|
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
||||||
|
|
||||||
|
cy.get('[data-cy="title"]').should("contain", "Feedback");
|
||||||
|
cy.get('[data-cy="evaluation-duedate]"').should("not.exist");
|
||||||
|
cy.get('[data-cy="instruction"]').should("contain", "Intro für Feedback");
|
||||||
|
cy.get('[data-cy="start-evaluation"]').click();
|
||||||
|
cy.get('[data-cy="evaluation-task"]').should("contain", "Feedback 1 / 5");
|
||||||
|
|
||||||
|
// without text input the button should be disabled
|
||||||
|
cy.get('[data-cy="next-step"]').should("be.disabled");
|
||||||
|
|
||||||
|
// with text you can continue
|
||||||
|
cy.get('[data-cy="reason-text"]').type("Gut gemacht!");
|
||||||
|
// wait for debounce
|
||||||
|
cy.wait(500);
|
||||||
|
cy.get('[data-cy="next-step"]').click();
|
||||||
|
|
||||||
|
cy.get('[data-cy="evaluation-task"]').should("contain", "Feedback 2 / 5");
|
||||||
|
cy.get('[data-cy="reason-text"]').type("Nicht so gut");
|
||||||
|
cy.wait(1000);
|
||||||
|
|
||||||
|
// load AssignmentCompletion from DB and check
|
||||||
|
cy.loadAssignmentCompletion(
|
||||||
|
"assignment_user_id",
|
||||||
|
TEST_STUDENT1_USER_ID
|
||||||
|
).then((ac) => {
|
||||||
|
console.log(ac.completion_status);
|
||||||
|
expect(ac.completion_status).to.equal("EVALUATION_IN_PROGRESS");
|
||||||
|
expect(JSON.stringify(ac.completion_data)).to.include("Nicht so gut");
|
||||||
|
expect(Cypress._.values(ac.completion_data)).to.deep.include({
|
||||||
|
expert_data: { points: 0, text: "Nicht so gut" },
|
||||||
|
});
|
||||||
|
expect(Cypress._.values(ac.completion_data)).to.deep.include({
|
||||||
|
expert_data: { points: 0, text: "Gut gemacht!" },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can make complete evaluation", () => {
|
||||||
|
cy.visit("/course/test-lehrgang/cockpit");
|
||||||
|
cy.get('[data-cy="dropdown-select"]').click();
|
||||||
|
cy.get('[data-cy="dropdown-select-option-Reisen"]').click();
|
||||||
|
cy.get(
|
||||||
|
'[data-cy="show-details-btn-test-lehrgang-lp-circle-reisen-lc-mein-kundenstamm"]'
|
||||||
|
).click();
|
||||||
|
|
||||||
|
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
||||||
|
|
||||||
|
cy.get('[data-cy="start-evaluation"]').click();
|
||||||
|
|
||||||
|
// step 1
|
||||||
|
cy.get('[data-cy="evaluation-task"]').should("contain", "Feedback 1 / 5");
|
||||||
|
cy.get('[data-cy="reason-text"]').type("Begründung Schritt 1");
|
||||||
|
// wait for debounce
|
||||||
|
cy.wait(500);
|
||||||
|
cy.get('[data-cy="next-step"]').click();
|
||||||
|
|
||||||
|
// step 2
|
||||||
|
cy.get('[data-cy="evaluation-task"]').should("contain", "Feedback 2 / 5");
|
||||||
|
cy.get('[data-cy="reason-text"]').type("Begründung Schritt 2");
|
||||||
|
cy.wait(500);
|
||||||
|
cy.get('[data-cy="next-step"]').click();
|
||||||
|
|
||||||
|
// step 3
|
||||||
|
cy.get('[data-cy="evaluation-task"]').should("contain", "Feedback 3 / 5");
|
||||||
|
cy.get('[data-cy="reason-text"]').type("Begründung Schritt 3");
|
||||||
|
cy.wait(500);
|
||||||
|
cy.get('[data-cy="next-step"]').click();
|
||||||
|
|
||||||
|
// step 4
|
||||||
|
cy.get('[data-cy="evaluation-task"]').should("contain", "Feedback 4 / 5");
|
||||||
|
cy.get('[data-cy="reason-text"]').type("Begründung Schritt 4");
|
||||||
|
cy.wait(500);
|
||||||
|
cy.get('[data-cy="next-step"]').click();
|
||||||
|
|
||||||
|
// step 5
|
||||||
|
cy.get('[data-cy="evaluation-task"]').should("contain", "Feedback 5 / 5");
|
||||||
|
cy.get('[data-cy="reason-text"]').type("Begründung Schritt 5");
|
||||||
|
cy.wait(500);
|
||||||
|
cy.get('[data-cy="next-step"]').click();
|
||||||
|
|
||||||
|
// freigabe
|
||||||
|
cy.get('[data-cy="sub-title"]').should("contain", "Feedback Freigabe");
|
||||||
|
cy.get('[data-cy="total-points"]').should("not.exist");
|
||||||
|
cy.get('[data-cy="submit-evaluation"]').click();
|
||||||
|
|
||||||
|
cy.get('[data-cy="result-section"]').should(
|
||||||
|
"contain",
|
||||||
|
"Dein Feedback für Test Student1 wurde freigegeben"
|
||||||
|
);
|
||||||
|
|
||||||
|
// going back to cockpit should show points for student
|
||||||
|
cy.visit("/course/test-lehrgang/cockpit");
|
||||||
|
cy.reload();
|
||||||
|
cy.get('[data-cy="dropdown-select"]').click();
|
||||||
|
cy.get('[data-cy="dropdown-select-option-Reisen"]').click();
|
||||||
|
cy.get(
|
||||||
|
'[data-cy="show-details-btn-test-lehrgang-lp-circle-reisen-lc-mein-kundenstamm"]'
|
||||||
|
).click();
|
||||||
|
|
||||||
|
cy.get('[data-cy="Student1"]').should("contain", "Feedback freigegeben");
|
||||||
|
cy.get('[data-cy="Student1"]').should("not.contain", "Punkte");
|
||||||
|
|
||||||
|
// clicking on results page will go to last step
|
||||||
|
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
||||||
|
cy.url().should("include", "step=6");
|
||||||
|
|
||||||
|
// load AssignmentCompletion from DB and check
|
||||||
|
cy.loadAssignmentCompletion(
|
||||||
|
"assignment_user_id",
|
||||||
|
TEST_STUDENT1_USER_ID
|
||||||
|
).then((ac) => {
|
||||||
|
expect(ac.completion_status).to.equal("EVALUATION_SUBMITTED");
|
||||||
|
expect(ac.evaluation_max_points).to.equal(0);
|
||||||
|
const completionString = JSON.stringify(ac.completion_data);
|
||||||
|
expect(completionString).to.include("Begründung Schritt 1");
|
||||||
|
expect(completionString).to.include("Begründung Schritt 2");
|
||||||
|
expect(completionString).to.include("Begründung Schritt 3");
|
||||||
|
expect(completionString).to.include("Begründung Schritt 4");
|
||||||
|
expect(completionString).to.include("Begründung Schritt 5");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -4294,6 +4294,15 @@ def create_vv_gewinnen_casework(course_id=COURSE_VERSICHERUNGSVERMITTLERIN_ID):
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
assignment.evaluation_tasks.append(
|
||||||
|
(
|
||||||
|
"task",
|
||||||
|
EvaluationTaskBlockFactory(
|
||||||
|
title="Feedback zu Teilaufgabe 5",
|
||||||
|
max_points=0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
assignment.tasks = []
|
assignment.tasks = []
|
||||||
assignment.tasks.append(
|
assignment.tasks.append(
|
||||||
|
|
@ -4515,6 +4524,29 @@ def create_vv_gewinnen_casework(course_id=COURSE_VERSICHERUNGSVERMITTLERIN_ID):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
assignment.tasks.append(
|
||||||
|
(
|
||||||
|
"task",
|
||||||
|
TaskBlockFactory(
|
||||||
|
title="Teilaufgabe 5: Kundentelefonate2",
|
||||||
|
content=StreamValue(
|
||||||
|
TaskContentStreamBlock(),
|
||||||
|
stream_data=[
|
||||||
|
(
|
||||||
|
"user_text_input",
|
||||||
|
UserTextInputBlockFactory(
|
||||||
|
text=RichText(
|
||||||
|
"""
|
||||||
|
<p>Notiere, welche hundert Kunden du nächste Woche für ein Beratungsgespräch telefonisch kontaktieren willst.</p>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
assignment.save()
|
assignment.save()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ def update_assignment_completion(
|
||||||
ac.evaluation_points = evaluation_points
|
ac.evaluation_points = evaluation_points
|
||||||
|
|
||||||
# if no evaluation_passed is provided, we calculate it from the points
|
# if no evaluation_passed is provided, we calculate it from the points
|
||||||
if evaluation_passed is None:
|
if evaluation_passed is None and ac.evaluation_max_points > 0:
|
||||||
if evaluation_points is not None and ac.evaluation_max_points is not None:
|
if evaluation_points is not None and ac.evaluation_max_points is not None:
|
||||||
# if more or equal than 60% of the points are reached, the assignment is passed
|
# if more or equal than 60% of the points are reached, the assignment is passed
|
||||||
ac.evaluation_passed = (evaluation_points / ac.evaluation_max_points) >= 0.6
|
ac.evaluation_passed = (evaluation_points / ac.evaluation_max_points) >= 0.6
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue