Merged in feature/VBV-339-assignment-cypress-test (pull request #79)
Feature/VBV-339 assignment cypress test UNFINISHED * Create assignment submission test data for cypress test * Add first assignment trainer test * Add first cypress test which checks DB entry with all instrumentation
This commit is contained in:
parent
b313bad031
commit
e130d65f37
|
|
@ -92,7 +92,7 @@ const assignmentCompletion = computed(() => assignmentStore.assignmentCompletion
|
||||||
<div class="h-content flex">
|
<div class="h-content flex">
|
||||||
<div class="h-full w-1/2 overflow-y-auto bg-white">
|
<div class="h-full w-1/2 overflow-y-auto bg-white">
|
||||||
<!-- Left part content goes here -->
|
<!-- Left part content goes here -->
|
||||||
<div class="p-10">
|
<div class="p-10" data-cy="student-submission">
|
||||||
<h3>Ergebnisse</h3>
|
<h3>Ergebnisse</h3>
|
||||||
<div class="my-6 flex items-center">
|
<div class="my-6 flex items-center">
|
||||||
<img
|
<img
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ async function startEvaluation() {
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button class="btn-primary" @click="startEvaluation()">
|
<button class="btn-primary" data-cy="start-evaluation" @click="startEvaluation()">
|
||||||
<span
|
<span
|
||||||
v-if="
|
v-if="
|
||||||
props.assignmentCompletion.completion_status === 'evaluation_in_progress'
|
props.assignmentCompletion.completion_status === 'evaluation_in_progress'
|
||||||
|
|
@ -74,7 +74,9 @@ async function startEvaluation() {
|
||||||
Bewertung fortsetzen
|
Bewertung fortsetzen
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-if="props.assignmentCompletion.completion_status === 'evaluation_submitted'"
|
v-else-if="
|
||||||
|
props.assignmentCompletion.completion_status === 'evaluation_submitted'
|
||||||
|
"
|
||||||
>
|
>
|
||||||
Bewertung ansehen
|
Bewertung ansehen
|
||||||
</span>
|
</span>
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ const evaluateAssignmentCompletionDebounced = useDebounceFn(
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div>
|
<div data-cy="evaluation-task">
|
||||||
<div class="text-bold mb-4 text-sm">
|
<div class="text-bold mb-4 text-sm">
|
||||||
Beurteilungskriterium {{ taskIndex + 1 }} /
|
Beurteilungskriterium {{ taskIndex + 1 }} /
|
||||||
{{ props.assignment.evaluation_tasks.length }}
|
{{ props.assignment.evaluation_tasks.length }}
|
||||||
|
|
@ -91,6 +91,7 @@ const evaluateAssignmentCompletionDebounced = useDebounceFn(
|
||||||
v-for="(subTask, index) in task.value.sub_tasks"
|
v-for="(subTask, index) in task.value.sub_tasks"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="mb-4 flex items-center last:mb-0"
|
class="mb-4 flex items-center last:mb-0"
|
||||||
|
:data-cy="`subtask-${subTask.points}`"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
:id="String(index)"
|
:id="String(index)"
|
||||||
|
|
@ -120,6 +121,7 @@ const evaluateAssignmentCompletionDebounced = useDebounceFn(
|
||||||
label="Begründung"
|
label="Begründung"
|
||||||
:disabled="!props.allowEdit"
|
:disabled="!props.allowEdit"
|
||||||
placeholder="Hier muss zwingend eine Begründung erfasst werden."
|
placeholder="Hier muss zwingend eine Begründung erfasst werden."
|
||||||
|
data-cy="reason-text"
|
||||||
@update:model-value="onUpdateText($event)"
|
@update:model-value="onUpdateText($event)"
|
||||||
></ItTextarea>
|
></ItTextarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ const assignmentDetail = computed(() =>
|
||||||
:key="csu.user_id + csu.session_title"
|
:key="csu.user_id + csu.session_title"
|
||||||
:name="`${csu.first_name} ${csu.last_name}`"
|
:name="`${csu.first_name} ${csu.last_name}`"
|
||||||
:avatar-url="csu.avatar_url"
|
:avatar-url="csu.avatar_url"
|
||||||
|
:data-cy="csu.last_name"
|
||||||
>
|
>
|
||||||
<template #center>
|
<template #center>
|
||||||
<section class="flex w-full justify-between px-8">
|
<section class="flex w-full justify-between px-8">
|
||||||
|
|
@ -130,6 +131,7 @@ const assignmentDetail = computed(() =>
|
||||||
v-if="submissionStatusForUser(csu.user_id)?.progressStatus === 'success'"
|
v-if="submissionStatusForUser(csu.user_id)?.progressStatus === 'success'"
|
||||||
:to="`/course/${props.courseSession.course.slug}/cockpit/assignment/${assignment.assignmentId}/${csu.user_id}`"
|
:to="`/course/${props.courseSession.course.slug}/cockpit/assignment/${assignment.assignmentId}/${csu.user_id}`"
|
||||||
class="w-full text-right underline"
|
class="w-full text-right underline"
|
||||||
|
data-cy="show-results"
|
||||||
>
|
>
|
||||||
Ergebnisse anzeigen
|
Ergebnisse anzeigen
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ module.exports = defineConfig({
|
||||||
viewportWidth: 1280,
|
viewportWidth: 1280,
|
||||||
viewportHeight: 720,
|
viewportHeight: 720,
|
||||||
retries: {
|
retries: {
|
||||||
runMode: 1,
|
runMode: 2,
|
||||||
openMode: 0,
|
openMode: 0,
|
||||||
},
|
},
|
||||||
reporter: "junit",
|
reporter: "junit",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// ids for cypress test data
|
||||||
|
export const ADMIN_USER_ID = -1;
|
||||||
|
export const TEST_TRAINER1_USER_ID = -11;
|
||||||
|
export const TEST_STUDENT1_USER_ID = -21;
|
||||||
|
export const TEST_STUDENT2_USER_ID = -22;
|
||||||
|
|
||||||
|
export const TEST_COURSE_SESSION_BERN_ID = -1;
|
||||||
|
export const TEST_COURSE_SESSION_ZURICH_ID = -2;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { login } from "./helpers";
|
import { login } from "../helpers";
|
||||||
|
|
||||||
describe("student test", () => {
|
describe("student test", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
import { TEST_STUDENT1_USER_ID } from "../../consts";
|
||||||
|
import { login } from "../helpers";
|
||||||
|
|
||||||
|
describe("trainer test", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.manageCommand("cypress_reset --create-completion");
|
||||||
|
login("test-trainer1@example.com", "test");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can open cockpit assignment page and open user assignment", () => {
|
||||||
|
cy.visit("/course/test-lehrgang/cockpit/assignment");
|
||||||
|
|
||||||
|
cy.get('[data-cy="Student1"]').should("contain", "Ergebnisse abgegeben");
|
||||||
|
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
||||||
|
|
||||||
|
cy.get('[data-cy="student-submission"]').should("contain", "Ergebnisse");
|
||||||
|
cy.get('[data-cy="student-submission"]').should("contain", "Student1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can start evaluation and store evaluation results", () => {
|
||||||
|
cy.visit("/course/test-lehrgang/cockpit/assignment");
|
||||||
|
|
||||||
|
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
||||||
|
|
||||||
|
cy.get('[data-cy="start-evaluation"]').click();
|
||||||
|
cy.get('[data-cy="evaluation-task"]').should(
|
||||||
|
"contain",
|
||||||
|
"Beurteilungskriterium 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="subtask-4"]').click();
|
||||||
|
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",
|
||||||
|
"Beurteilungskriterium 2 / 5"
|
||||||
|
);
|
||||||
|
cy.get('[data-cy="subtask-2"]').click();
|
||||||
|
cy.get('[data-cy="reason-text"]').type("Nicht so gut");
|
||||||
|
cy.wait(500);
|
||||||
|
|
||||||
|
// revisit step 1 will show stored data
|
||||||
|
cy.get('[data-cy="previous-step"]').click();
|
||||||
|
cy.get('[data-cy="reason-text"]')
|
||||||
|
.find("textarea")
|
||||||
|
.should("have.value", "Gut gemacht!");
|
||||||
|
|
||||||
|
// even after reload
|
||||||
|
cy.reload();
|
||||||
|
cy.get('[data-cy="reason-text"]')
|
||||||
|
.find("textarea")
|
||||||
|
.should("have.value", "Gut gemacht!");
|
||||||
|
|
||||||
|
// it can access step directly via url
|
||||||
|
cy.url().then((url) => {
|
||||||
|
const step2Url = url.replace("step=1", "step=2");
|
||||||
|
console.log(step2Url);
|
||||||
|
cy.visit(step2Url);
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy="reason-text"]')
|
||||||
|
.find("textarea")
|
||||||
|
.should("have.value", "Nicht so gut");
|
||||||
|
|
||||||
|
// load AssignmentCompletion from DB and check
|
||||||
|
cy.loadAssignmentCompletion(
|
||||||
|
"assignment_user_id",
|
||||||
|
TEST_STUDENT1_USER_ID
|
||||||
|
).then((ac) => {
|
||||||
|
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: 2, text: "Nicht so gut" },
|
||||||
|
});
|
||||||
|
expect(Cypress._.values(ac.completion_data)).to.deep.include({
|
||||||
|
expert_data: { points: 4, text: "Gut gemacht!" },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -52,55 +52,77 @@
|
||||||
|
|
||||||
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);
|
||||||
return cy.exec(execCommand, { failOnNonZeroExit: false }).then(result => {
|
return cy
|
||||||
if(result.code) {
|
.exec(
|
||||||
throw new Error(`Execution of "${command}" failed
|
// hack to add my asdf python instance to the path
|
||||||
|
// so I can run the test directly from within IntelliJ
|
||||||
|
`PATH=/Users/daniel/workspace/vbv_lernwelt/.direnv/python-3.10.6/bin:$PATH && ${execCommand}`,
|
||||||
|
{
|
||||||
|
failOnNonZeroExit: false,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then((result) => {
|
||||||
|
if (result.code) {
|
||||||
|
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(key, value, djangoModelPath, serializerModelPath) {
|
function loadObjectJson(key, value, djangoModelPath, serializerModelPath) {
|
||||||
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(serializerModelPath.split('.')).join('.');
|
const serializerModelImportPath = _.initial(
|
||||||
|
serializerModelPath.split(".")
|
||||||
|
).join(".");
|
||||||
|
|
||||||
let filterPart = `${key}=${value}`;
|
let filterPart = `${key}=${value}`;
|
||||||
if(_.isArray(key)) {
|
if (_.isArray(key)) {
|
||||||
filterPart = _.zip(key, value).map(([k, v]) => {
|
filterPart = _.zip(key, value)
|
||||||
return `${k}=${v}`;
|
.map(([k, v]) => {
|
||||||
}).join(',');
|
return `${k}=${v}`;
|
||||||
|
})
|
||||||
|
.join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
const command = `from ${djangoModelImportPath} import ${djangoModel};
|
const command = `from ${djangoModelImportPath} import ${djangoModel};
|
||||||
from ${serializerModelImportPath} import ${serializerModel};
|
from ${serializerModelImportPath} import ${serializerModel};
|
||||||
from myservice.apps.core.serializers import create_json_from_objects;
|
from vbv_lernwelt.core.serializers import create_json_from_objects;
|
||||||
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()`.replace(/(?:\r\n|\r|\n)/g, '');
|
exit();
|
||||||
return cy.manageShellCommand(command).then(result => {
|
`.replace(/(?:\r\n|\r|\n)/g, "");
|
||||||
|
return cy.manageShellCommand(command).then((result) => {
|
||||||
const objectJson = JSON.parse(result.stdout);
|
const objectJson = JSON.parse(result.stdout);
|
||||||
console.log(objectJson);
|
console.log(objectJson);
|
||||||
return objectJson;
|
return objectJson;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Cypress.Commands.add('makeSelfEvaluation', (answers) => {
|
Cypress.Commands.add("loadAssignmentCompletion", (key, value) => {
|
||||||
|
return loadObjectJson(
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
"vbv_lernwelt.assignment.models.AssignmentCompletion",
|
||||||
|
"vbv_lernwelt.assignment.serializers.AssignmentCompletionSerializer"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
@ -112,7 +134,6 @@ Cypress.Commands.add('makeSelfEvaluation', (answers) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Cypress.Commands.add('loadApiClientRequestResponseLog', (key, value) => {
|
// Cypress.Commands.add('loadApiClientRequestResponseLog', (key, value) => {
|
||||||
// return loadObjectJson(
|
// return loadObjectJson(
|
||||||
// key,
|
// key,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ from django.conf.urls.static import static
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.decorators import user_passes_test
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||||
from django.urls import include, path, re_path
|
from django.urls import include, path, re_path, register_converter
|
||||||
|
from django.urls.converters import IntConverter
|
||||||
from django.views import defaults as default_views
|
from django.views import defaults as default_views
|
||||||
from grapple import urls as grapple_urls
|
from grapple import urls as grapple_urls
|
||||||
from ratelimit.exceptions import Ratelimited
|
from ratelimit.exceptions import Ratelimited
|
||||||
|
|
@ -50,6 +51,20 @@ from wagtail.admin import urls as wagtailadmin_urls
|
||||||
from wagtail.documents import urls as wagtaildocs_urls
|
from wagtail.documents import urls as wagtaildocs_urls
|
||||||
|
|
||||||
|
|
||||||
|
class SignedIntConverter(IntConverter):
|
||||||
|
regex = r"-?\d+"
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
return int(value)
|
||||||
|
|
||||||
|
def to_url(self, value):
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
# Register the converter
|
||||||
|
register_converter(SignedIntConverter, "signed_int")
|
||||||
|
|
||||||
|
|
||||||
def raise_example_error(request):
|
def raise_example_error(request):
|
||||||
"""
|
"""
|
||||||
raise error to check if it gets logged
|
raise error to check if it gets logged
|
||||||
|
|
@ -88,15 +103,17 @@ urlpatterns = [
|
||||||
|
|
||||||
# course
|
# course
|
||||||
path(r"api/course/sessions/", get_course_sessions, name="get_course_sessions"),
|
path(r"api/course/sessions/", get_course_sessions, name="get_course_sessions"),
|
||||||
path(r"api/course/sessions/<course_session_id>/users/", get_course_session_users,
|
path(r"api/course/sessions/<signed_int:course_session_id>/users/",
|
||||||
|
get_course_session_users,
|
||||||
name="get_course_session_users"),
|
name="get_course_session_users"),
|
||||||
path(r"api/course/page/<slug_or_id>/", course_page_api_view,
|
path(r"api/course/page/<slug_or_id>/", course_page_api_view,
|
||||||
name="course_page_api_view"),
|
name="course_page_api_view"),
|
||||||
path(r"api/course/completion/mark/", mark_course_completion_view,
|
path(r"api/course/completion/mark/", mark_course_completion_view,
|
||||||
name="mark_course_completion"),
|
name="mark_course_completion"),
|
||||||
path(r"api/course/completion/<course_session_id>/", request_course_completion,
|
path(r"api/course/completion/<signed_int:course_session_id>/",
|
||||||
|
request_course_completion,
|
||||||
name="request_course_completion"),
|
name="request_course_completion"),
|
||||||
path(r"api/course/completion/<course_session_id>/<int:user_id>/",
|
path(r"api/course/completion/<signed_int:course_session_id>/<signed_int:user_id>/",
|
||||||
request_course_completion_for_user,
|
request_course_completion_for_user,
|
||||||
name="request_course_completion_for_user"),
|
name="request_course_completion_for_user"),
|
||||||
|
|
||||||
|
|
@ -105,15 +122,17 @@ urlpatterns = [
|
||||||
name="upsert_user_assignment_completion"),
|
name="upsert_user_assignment_completion"),
|
||||||
path(r"api/assignment/evaluate/", evaluate_assignment_completion,
|
path(r"api/assignment/evaluate/", evaluate_assignment_completion,
|
||||||
name="evaluate_assignment_completion"),
|
name="evaluate_assignment_completion"),
|
||||||
path(r"api/assignment/<int:assignment_id>/<int:course_session_id>/",
|
path(r"api/assignment/<signed_int:assignment_id>/<signed_int:course_session_id>/",
|
||||||
request_assignment_completion,
|
request_assignment_completion,
|
||||||
name="request_assignment_completion"),
|
name="request_assignment_completion"),
|
||||||
path(r"api/assignment/<int:assignment_id>/<int:course_session_id>/status/",
|
path(
|
||||||
request_assignment_completion_status,
|
r"api/assignment/<signed_int:assignment_id>/<signed_int:course_session_id>/status/",
|
||||||
name="request_assignment_completion_status"),
|
request_assignment_completion_status,
|
||||||
path(r"api/assignment/<int:assignment_id>/<int:course_session_id>/<int:user_id>/",
|
name="request_assignment_completion_status"),
|
||||||
request_assignment_completion_for_user,
|
path(
|
||||||
name="request_assignment_completion_for_user"),
|
r"api/assignment/<signed_int:assignment_id>/<signed_int:course_session_id>/<signed_int:user_id>/",
|
||||||
|
request_assignment_completion_for_user,
|
||||||
|
name="request_assignment_completion_for_user"),
|
||||||
|
|
||||||
# documents
|
# documents
|
||||||
path(r'api/core/document/start/', document_upload_start,
|
path(r'api/core/document/start/', document_upload_start,
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,12 @@ DEFAULT_RICH_TEXT_FEATURES = [
|
||||||
"bold",
|
"bold",
|
||||||
"italic",
|
"italic",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# ids for cypress test data
|
||||||
|
ADMIN_USER_ID = -1
|
||||||
|
TEST_TRAINER1_USER_ID = -11
|
||||||
|
TEST_STUDENT1_USER_ID = -21
|
||||||
|
TEST_STUDENT2_USER_ID = -22
|
||||||
|
|
||||||
|
TEST_COURSE_SESSION_BERN_ID = -1
|
||||||
|
TEST_COURSE_SESSION_ZURICH_ID = -2
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
from django.contrib.auth.hashers import make_password
|
from django.contrib.auth.hashers import make_password
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
|
|
||||||
|
from vbv_lernwelt.core.constants import (
|
||||||
|
ADMIN_USER_ID,
|
||||||
|
TEST_STUDENT1_USER_ID,
|
||||||
|
TEST_STUDENT2_USER_ID,
|
||||||
|
TEST_TRAINER1_USER_ID,
|
||||||
|
)
|
||||||
from vbv_lernwelt.core.models import User
|
from vbv_lernwelt.core.models import User
|
||||||
|
|
||||||
default_users = [
|
default_users = [
|
||||||
|
|
@ -70,12 +76,14 @@ def create_default_users(user_model=User, group_model=Group, default_password=No
|
||||||
avatar_url="",
|
avatar_url="",
|
||||||
password=default_password,
|
password=default_password,
|
||||||
language="de",
|
language="de",
|
||||||
|
id=None,
|
||||||
):
|
):
|
||||||
student_user, created = _get_or_create_user(
|
student_user, created = _get_or_create_user(
|
||||||
user_model=user_model,
|
user_model=user_model,
|
||||||
username=email,
|
username=email,
|
||||||
password=password,
|
password=password,
|
||||||
language=language,
|
language=language,
|
||||||
|
id=id,
|
||||||
)
|
)
|
||||||
student_user.first_name = first_name
|
student_user.first_name = first_name
|
||||||
student_user.last_name = last_name
|
student_user.last_name = last_name
|
||||||
|
|
@ -83,9 +91,9 @@ def create_default_users(user_model=User, group_model=Group, default_password=No
|
||||||
student_user.groups.add(student_group)
|
student_user.groups.add(student_group)
|
||||||
student_user.save()
|
student_user.save()
|
||||||
|
|
||||||
def _create_admin_user(email, first_name, last_name, avatar_url=""):
|
def _create_admin_user(email, first_name, last_name, avatar_url="", id=None):
|
||||||
admin_user, created = _get_or_create_user(
|
admin_user, created = _get_or_create_user(
|
||||||
user_model=user_model, username=email, password=default_password
|
user_model=user_model, username=email, password=default_password, id=id
|
||||||
)
|
)
|
||||||
admin_user.is_superuser = True
|
admin_user.is_superuser = True
|
||||||
admin_user.is_staff = True
|
admin_user.is_staff = True
|
||||||
|
|
@ -107,6 +115,7 @@ def create_default_users(user_model=User, group_model=Group, default_password=No
|
||||||
first_name="Peter",
|
first_name="Peter",
|
||||||
last_name="Adminson",
|
last_name="Adminson",
|
||||||
avatar_url="/static/avatars/avatar_iterativ.png",
|
avatar_url="/static/avatars/avatar_iterativ.png",
|
||||||
|
id=ADMIN_USER_ID,
|
||||||
)
|
)
|
||||||
|
|
||||||
for user_data in default_users:
|
for user_data in default_users:
|
||||||
|
|
@ -232,19 +241,25 @@ def create_default_users(user_model=User, group_model=Group, default_password=No
|
||||||
|
|
||||||
# users for cypress tests
|
# users for cypress tests
|
||||||
_create_student_user(
|
_create_student_user(
|
||||||
|
id=TEST_TRAINER1_USER_ID,
|
||||||
email="test-trainer1@example.com",
|
email="test-trainer1@example.com",
|
||||||
first_name="Test",
|
first_name="Test",
|
||||||
last_name="Trainer1",
|
last_name="Trainer1",
|
||||||
|
avatar_url="/static/avatars/uk1.patrizia.huggel.jpg",
|
||||||
)
|
)
|
||||||
_create_student_user(
|
_create_student_user(
|
||||||
|
id=TEST_STUDENT1_USER_ID,
|
||||||
email="test-student1@example.com",
|
email="test-student1@example.com",
|
||||||
first_name="Test",
|
first_name="Test",
|
||||||
last_name="Student1",
|
last_name="Student1",
|
||||||
|
avatar_url="/static/avatars/uk1.michael.meier.jpg",
|
||||||
)
|
)
|
||||||
_create_student_user(
|
_create_student_user(
|
||||||
|
id=TEST_STUDENT2_USER_ID,
|
||||||
email="test-student2@example.com",
|
email="test-student2@example.com",
|
||||||
first_name="Test",
|
first_name="Test",
|
||||||
last_name="Student2",
|
last_name="Student2",
|
||||||
|
avatar_url="/static/avatars/uk1.lina.egger.jpg",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -252,6 +267,7 @@ def _get_or_create_user(user_model, *args, **kwargs):
|
||||||
username = kwargs.get("username", None)
|
username = kwargs.get("username", None)
|
||||||
password = kwargs.get("password", None)
|
password = kwargs.get("password", None)
|
||||||
language = kwargs.get("language", "de")
|
language = kwargs.get("language", "de")
|
||||||
|
id = kwargs.get("id", None)
|
||||||
created = False
|
created = False
|
||||||
|
|
||||||
user = user_model.objects.filter(username=username).first()
|
user = user_model.objects.filter(username=username).first()
|
||||||
|
|
@ -262,6 +278,7 @@ def _get_or_create_user(user_model, *args, **kwargs):
|
||||||
password=make_password(password),
|
password=make_password(password),
|
||||||
email=username,
|
email=username,
|
||||||
language=language,
|
language=language,
|
||||||
|
id=id,
|
||||||
)
|
)
|
||||||
created = True
|
created = True
|
||||||
return user, created
|
return user, created
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,37 @@
|
||||||
import djclick as click
|
import djclick as click
|
||||||
|
|
||||||
from vbv_lernwelt.assignment.models import AssignmentCompletion
|
from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletion
|
||||||
|
from vbv_lernwelt.core.constants import (
|
||||||
|
TEST_COURSE_SESSION_BERN_ID,
|
||||||
|
TEST_STUDENT1_USER_ID,
|
||||||
|
)
|
||||||
from vbv_lernwelt.core.models import User
|
from vbv_lernwelt.core.models import User
|
||||||
from vbv_lernwelt.course.models import CourseCompletion
|
from vbv_lernwelt.course.creators.test_course import (
|
||||||
|
create_test_assignment_submitted_data,
|
||||||
|
)
|
||||||
|
from vbv_lernwelt.course.models import CourseCompletion, CourseSession
|
||||||
from vbv_lernwelt.notify.models import Notification
|
from vbv_lernwelt.notify.models import Notification
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
def command():
|
@click.option(
|
||||||
|
"--create-completion/--no-create-completion",
|
||||||
|
default=False,
|
||||||
|
help="will create completion data for some users",
|
||||||
|
)
|
||||||
|
def command(create_completion):
|
||||||
print("cypress reset data")
|
print("cypress reset data")
|
||||||
CourseCompletion.objects.all().delete()
|
CourseCompletion.objects.all().delete()
|
||||||
Notification.objects.all().delete()
|
Notification.objects.all().delete()
|
||||||
AssignmentCompletion.objects.all().delete()
|
AssignmentCompletion.objects.all().delete()
|
||||||
User.objects.all().update(language="de")
|
User.objects.all().update(language="de")
|
||||||
|
|
||||||
|
if create_completion:
|
||||||
|
print("create completion data for test course")
|
||||||
|
create_test_assignment_submitted_data(
|
||||||
|
assignment=Assignment.objects.get(
|
||||||
|
slug="test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"
|
||||||
|
),
|
||||||
|
course_session=CourseSession.objects.get(id=TEST_COURSE_SESSION_BERN_ID),
|
||||||
|
user=User.objects.get(id=TEST_STUDENT1_USER_ID),
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from rest_framework.renderers import JSONRenderer
|
||||||
|
|
||||||
from vbv_lernwelt.core.models import User
|
from vbv_lernwelt.core.models import User
|
||||||
from vbv_lernwelt.course.models import CourseSessionUser
|
from vbv_lernwelt.course.models import CourseSessionUser
|
||||||
|
|
||||||
|
|
||||||
|
def create_json_from_objects(objects, serializer_class, many=True) -> str:
|
||||||
|
serializer = serializer_class(objects, many=many)
|
||||||
|
return JSONRenderer().render(serializer.data).decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
class UserSerializer(serializers.ModelSerializer):
|
||||||
course_session_experts = serializers.SerializerMethodField()
|
course_session_experts = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,17 @@ from wagtail.models import Site
|
||||||
|
|
||||||
from vbv_lernwelt.assignment.creators.create_assignments import create_test_assignment
|
from vbv_lernwelt.assignment.creators.create_assignments import create_test_assignment
|
||||||
from vbv_lernwelt.assignment.models import Assignment
|
from vbv_lernwelt.assignment.models import Assignment
|
||||||
|
from vbv_lernwelt.assignment.services import update_assignment_completion
|
||||||
from vbv_lernwelt.competence.factories import (
|
from vbv_lernwelt.competence.factories import (
|
||||||
CompetencePageFactory,
|
CompetencePageFactory,
|
||||||
CompetenceProfilePageFactory,
|
CompetenceProfilePageFactory,
|
||||||
PerformanceCriteriaFactory,
|
PerformanceCriteriaFactory,
|
||||||
)
|
)
|
||||||
from vbv_lernwelt.competence.models import CompetencePage
|
from vbv_lernwelt.competence.models import CompetencePage
|
||||||
|
from vbv_lernwelt.core.constants import (
|
||||||
|
TEST_COURSE_SESSION_BERN_ID,
|
||||||
|
TEST_COURSE_SESSION_ZURICH_ID,
|
||||||
|
)
|
||||||
from vbv_lernwelt.core.models import User
|
from vbv_lernwelt.core.models import User
|
||||||
from vbv_lernwelt.core.tests.helpers import create_locales_for_wagtail
|
from vbv_lernwelt.core.tests.helpers import create_locales_for_wagtail
|
||||||
from vbv_lernwelt.course.consts import COURSE_TEST_ID
|
from vbv_lernwelt.course.consts import COURSE_TEST_ID
|
||||||
|
|
@ -65,11 +70,13 @@ def create_test_course(include_uk=True, include_vv=True, with_sessions=False):
|
||||||
# course sessions
|
# course sessions
|
||||||
cs_bern = CourseSession.objects.create(
|
cs_bern = CourseSession.objects.create(
|
||||||
course_id=COURSE_TEST_ID,
|
course_id=COURSE_TEST_ID,
|
||||||
title="Bern 2022 a",
|
title="Test Bern 2022 a",
|
||||||
|
id=TEST_COURSE_SESSION_BERN_ID,
|
||||||
)
|
)
|
||||||
cs_zurich = CourseSession.objects.create(
|
cs_zurich = CourseSession.objects.create(
|
||||||
course_id=COURSE_TEST_ID,
|
course_id=COURSE_TEST_ID,
|
||||||
title="Zürich 2022 a",
|
title="Test Zürich 2022 a",
|
||||||
|
id=TEST_COURSE_SESSION_ZURICH_ID,
|
||||||
)
|
)
|
||||||
|
|
||||||
trainer1 = User.objects.get(email="test-trainer1@example.com")
|
trainer1 = User.objects.get(email="test-trainer1@example.com")
|
||||||
|
|
@ -100,6 +107,30 @@ def create_test_course(include_uk=True, include_vv=True, with_sessions=False):
|
||||||
return course
|
return course
|
||||||
|
|
||||||
|
|
||||||
|
def create_test_assignment_submitted_data(assignment, course_session, user):
|
||||||
|
if assignment and course_session and user:
|
||||||
|
subtasks = assignment.filter_user_subtasks(subtask_types=["user_text_input"])
|
||||||
|
for index, subtask in enumerate(subtasks):
|
||||||
|
user_text = f"Lorem ipsum dolor sit amet... {index}"
|
||||||
|
|
||||||
|
update_assignment_completion(
|
||||||
|
assignment_user=user,
|
||||||
|
assignment=assignment,
|
||||||
|
course_session=course_session,
|
||||||
|
completion_data={
|
||||||
|
subtask["id"]: {
|
||||||
|
"user_data": {"text": user_text},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
update_assignment_completion(
|
||||||
|
assignment_user=user,
|
||||||
|
assignment=assignment,
|
||||||
|
course_session=course_session,
|
||||||
|
completion_status="submitted",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_test_course_with_categories(apps=None, schema_editor=None):
|
def create_test_course_with_categories(apps=None, schema_editor=None):
|
||||||
if apps is not None:
|
if apps is not None:
|
||||||
Course = apps.get_model("course", "Course")
|
Course = apps.get_model("course", "Course")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue