improve test

This commit is contained in:
Ross
2023-07-03 09:00:45 +01:00
parent 100945478b
commit 1ade42d7ba
2 changed files with 534 additions and 468 deletions
+36 -463
View File
@@ -19,7 +19,7 @@ from physics.views import GenericExamViews as PhysicsExamViews
from physics.models import Category, UserAnswer, Exam, Question
from generic.models import CidUser, CidUserGroup, UserUserGroup
from rad.test_helpers import AssertNotFound, create_cid_user_and_groups
from rad.test_helpers import AssertNotFound, ExamTester, create_cid_user_and_groups, create_exam
from django.contrib.auth.models import User
@@ -27,27 +27,6 @@ from django.contrib.auth.models import User
APP_NAME = "physics"
def create_exam(db):
exam: Exam = PhysicsExamViews.Exam.objects.create(
name="Cid Exam", exam_mode=True, active=True
)
group1: CidUserGroup = CidUserGroup.objects.get(name="Group1")
usergroup1: UserUserGroup = UserUserGroup.objects.get(name="Group1")
exam.cid_user_groups.add(group1)
exam.valid_cid_users.add(*group1.ciduser_set.all())
# exam.valid_user_users.add(user1)
exam.valid_user_users.add(*usergroup1.users.all())
assert exam in group1.physics_cid_user_groups.all()
assert exam
return exam
def create_category(db):
category = Category.objects.create(category="test category")
@@ -96,193 +75,55 @@ def create_question(exam, answer=None):
def test_exams(db, client):
create_cid_user_and_groups(db)
exam = create_exam(db)
create_category(db)
generated_questions = [
create_question(exam),
create_question(exam),
create_question(exam),
]
exam_tester = ExamTester(db, client, APP_NAME, PhysicsExamViews)
active_exams = client.get(reverse(f"{APP_NAME}:active_exams"))
assert active_exams.status_code == 200
assert len(json.loads(active_exams.content)["exams"]) == 0
cid_user_1001 = CidUser.objects.get(cid=1001)
cid_user_1000 = CidUser.objects.get(cid=1000)
cid_user_2001 = CidUser.objects.get(cid=2001)
user1 = User.objects.get(username="user1")
user2 = User.objects.get(username="user2")
exam_tester.create_questions(create_question)
users_tested = 1
# for cid_user in [cid_user_1001, cid_user_1000, user1, user2]:
for cid_user in [cid_user_1001, cid_user_1000, user1, user2]:
if isinstance(cid_user, CidUser):
testing_cid_user = True
else:
testing_cid_user = False
current_user = cid_user
client.force_login(cid_user)
for cid_user in exam_tester.all_users:
exam_tester.load_user(cid_user)
exam = exam_tester.exam
exam.active = False
exam.save()
exam_tester.check_active_exams(0)
exam.active = True
exam.publish_results = False
exam.save()
start_page_res = client.get(
reverse(f"physics:exam_start", kwargs={"pk": exam.pk})
)
print(cid_user)
exam_tester.check_onsite_start_page()
# Check user access to the start page
assert start_page_res.status_code == HTTPStatus.OK
start_page_soup = BeautifulSoup(start_page_res.content, "html.parser")
print(start_page_soup)
if testing_cid_user or cid_user in [user2]:
assert "Enter your CID and passcode" in str(start_page_soup)
else:
assert "Start Exam" in str(start_page_soup)
#check_onsite_start_page
for n, question in enumerate(generated_questions):
if testing_cid_user:
take_url = reverse(
f"physics:exam_take",
kwargs={
"pk": exam.pk,
"sk": n,
"cid": cid_user.cid,
"passcode": cid_user.passcode,
},
)
else:
take_url = reverse(
f"physics:exam_take_user",
kwargs={
"pk": exam.pk,
"sk": n,
},
)
exam_tester.check_take_page()
cid_take_res = client.get(take_url)
exam_tester.check_take_overview(answered=0, total=3)
# Check that users that have not been added cannot access the take pages
if cid_user in [user2]:
assert cid_take_res.status_code == HTTPStatus.NOT_FOUND
continue
else:
assert cid_take_res.status_code == HTTPStatus.OK
cid_take_soup = BeautifulSoup(cid_take_res.content, "html.parser")
# Check correct user is displayed
if testing_cid_user:
display_user = str(cid_user.cid)
else:
display_user = current_user.username
assert display_user in cid_take_soup.find("span", {"id": "user-id"}).string
# Check review mode alert not visible
assert cid_take_soup.find("div", {"class": "review-mode-alert"}) is None
# Check that relevant buttons are being displayed
assert cid_take_soup.find("button", {"name": "finish"}) is not None
if n < len(generated_questions) - 1:
assert cid_take_soup.find("button", {"name": "next"}) is not None
if n > 0:
assert cid_take_soup.find("button", {"name": "previous"}) is not None
assert cid_take_soup.find("span", {"id": "question-number"}).string == str(
n + 1
) # + 1 for 0 offset
assert cid_take_soup.find("span", {"id": "exam-length"}).string == str(
len(generated_questions)
)
# Check that stem text is displayed
assert (
cid_take_soup.find("span", {"id": "question-stem"}).string
== question.stem
)
assert cid_take_soup.find("label", {"for": "id_a"}).string == question.a
assert cid_take_soup.find("label", {"for": "id_b"}).string == question.b
assert cid_take_soup.find("label", {"for": "id_c"}).string == question.c
assert cid_take_soup.find("label", {"for": "id_d"}).string == question.d
assert cid_take_soup.find("label", {"for": "id_e"}).string == question.e
# As we haven't submitted any answers they should all be blank
assert (
cid_take_soup.find("input", {"type": "checkbox", "checked": True})
is None
)
if testing_cid_user:
take_overview_url = reverse(
f"physics:exam_take_overview",
kwargs={
"pk": exam.pk,
"cid": cid_user.cid,
"passcode": cid_user.passcode,
},
)
else:
take_overview_url = reverse(
f"physics:exam_take_overview_user",
kwargs={
"pk": exam.pk,
},
)
cid_take_overview_res = client.get(take_overview_url)
# Check that users that have not been added cannot access the take pages
if cid_user in [user2]:
assert cid_take_overview_res.status_code == HTTPStatus.NOT_FOUND
else:
assert cid_take_overview_res.status_code == HTTPStatus.OK
cid_take_overview_soup = BeautifulSoup(
cid_take_overview_res.content, "html.parser"
)
assert (
"0 out of 3 questions answered"
in cid_take_overview_soup.find(
"div", attrs={"class": "overview-text"}
).string
)
assert (
len(
cid_take_overview_soup.find_all(
"button", attrs={"class": "unanswered"}
)
)
== 3
)
# Loop through questions again to test submissions
# All physics questions have 5 parts (and require a csrf token)
questions_len = len(generated_questions) - 1
for n, question in enumerate(generated_questions):
if testing_cid_user:
questions_len = len(exam_tester.generated_questions) - 1
for n, question in enumerate(exam_tester.generated_questions):
if exam_tester.testing_cid_user:
question_url = reverse(
f"physics:exam_take",
f"{APP_NAME}:exam_take",
kwargs={
"pk": exam.pk,
"sk": n,
"cid": cid_user.cid,
"passcode": cid_user.passcode,
"cid": exam_tester.current_user.cid,
"passcode": exam_tester.current_user.passcode,
},
)
else:
question_url = reverse(
f"physics:exam_take_user",
f"{APP_NAME}:exam_take_user",
kwargs={
"pk": exam.pk,
"sk": n,
@@ -291,7 +132,7 @@ def test_exams(db, client):
cid_take_res = client.get(question_url)
if cid_user in [user2]:
if cid_user in exam_tester.invalid_users:
assert cid_take_res.status_code == HTTPStatus.NOT_FOUND
continue
else:
@@ -341,255 +182,29 @@ def test_exams(db, client):
assert len(cid_user_answers) == users_tested
if testing_cid_user:
cid_user_answer = cid_user_answers.filter(cid=cid_user.cid)[0]
if exam_tester.testing_cid_user:
cid_user_answer = cid_user_answers.filter(cid=exam_tester.current_user.cid)[0]
else:
cid_user_answer = cid_user_answers.filter(user=current_user)[0]
cid_user_answer = cid_user_answers.filter(user=exam_tester.current_user)[0]
assert all(cid_user_answer.get_answers())
# Recheck the overview page (now that we have submitted answers)
if testing_cid_user:
take_overview_url = reverse(
f"physics:exam_take_overview",
kwargs={
"pk": exam.pk,
"cid": cid_user.cid,
"passcode": cid_user.passcode,
},
)
else:
take_overview_url = reverse(
f"physics:exam_take_overview_user",
kwargs={
"pk": exam.pk,
},
)
exam_tester.check_take_overview(3, 3)
cid_take_overview_res = client.get(take_overview_url)
if cid_user in [user2]:
assert cid_take_overview_res.status_code == HTTPStatus.NOT_FOUND
else:
assert cid_take_overview_res.status_code == HTTPStatus.OK
exam_tester.check_cid_scores_page()
cid_take_overview_soup = BeautifulSoup(
cid_take_overview_res.content, "html.parser"
)
assert (
"3 out of 3 questions answered"
in cid_take_overview_soup.find(
"div", attrs={"class": "overview-text"}
).string
)
assert (
len(
cid_take_overview_soup.find_all(
"button", attrs={"class": "unanswered"}
)
)
== 0
)
exam_tester.check_cid_scores_user_page()
if testing_cid_user:
# Get overview scores page (invalid passcode)
AssertNotFound(
client,
reverse(
f"cid_scores", kwargs={"cid": cid_user.cid, "passcode": "AAAA"}
),
)
cid_scores_url = reverse(
f"cid_scores",
kwargs={"cid": cid_user.cid, "passcode": cid_user.passcode},
)
else:
cid_scores_url = reverse(f"user_scores")
# Get overview scores page
cid_scores_res = client.get(cid_scores_url)
assert cid_scores_res.status_code == HTTPStatus.OK
cid_scores_soup = BeautifulSoup(cid_scores_res.content, "html.parser")
if cid_user in [user2]:
# page should load but we shouldn't be able to find the exam
with pytest.raises(AttributeError):
search_exam = (
cid_scores_soup.find("div", {"id": "exam-assigned"})
.find("ul", {"class": exam.app_name.lower()})
.find_all("li", attrs={"data-exam-id": exam.pk})
)
else:
search_exam = (
cid_scores_soup.find("div", {"id": "exam-assigned"})
.find("ul", {"class": exam.app_name.lower()})
.find_all("li", attrs={"data-exam-id": exam.pk})
)
assert search_exam
assert exam.name in str(search_exam)
assert "Active" in str(search_exam)
# assert "Active" in assigned_exams # check it is active
invalid_exam = cid_scores_soup.find_all(
"li", attrs={"data-exam-id": exam.pk + 5}
)
assert not invalid_exam # Check we can't find an invalid exam
# Check that we have a results link
results_exam = (
cid_scores_soup.find("div", {"id": "exam-results"})
.find("ul", {"class": exam.app_name})
.find_all("li", attrs={"data-exam-id": exam.pk})
)
assert results_exam
assert exam.name in str(results_exam)
assert exam.name + " test" not in str(results_exam)
assert "Results Published" not in str(
results_exam
) # It should not be published yet
if testing_cid_user:
AssertNotFound(
client,
reverse(
f"{exam.app_name}:exam_scores_cid_user",
kwargs={"pk": exam.pk, "cid": cid_user.cid, "passcode": "AAAA"},
),
)
AssertNotFound(
client,
reverse(
f"{exam.app_name}:exam_scores_cid_user",
kwargs={
"pk": exam.pk,
"cid": cid_user_2001.cid,
"passcode": cid_user_2001.passcode,
},
),
)
exam_scores_url = reverse(
f"{exam.app_name}:exam_scores_cid_user",
kwargs={
"pk": exam.pk,
"cid": cid_user.cid,
"passcode": cid_user.passcode,
},
)
else:
exam_scores_url = reverse(
f"{exam.app_name}:exam_scores_user",
kwargs={"pk": exam.pk},
)
# Load the exam results page
cid_exam_scores_res = client.get(exam_scores_url)
if cid_user in [user2]:
assert cid_exam_scores_res.status_code == HTTPStatus.NOT_FOUND
# The rest of the tests are for valid users
if exam_tester.current_user in exam_tester.invalid_users:
continue
else:
assert cid_exam_scores_res.status_code == HTTPStatus.OK
cid_exam_scores_soup = BeautifulSoup(cid_exam_scores_res.content, "html.parser")
# Check that we have an alert that exams are not published
alert = cid_exam_scores_soup.find("div", {"class": "alert"})
assert "Results are not currently published." in str(alert)
# Check that we are showing enough questions / answers
answer_lis = cid_exam_scores_soup.find_all("li", {"class": "question-part"})
assert len(answer_lis) == 5 * len(generated_questions)
submitted_answers = cid_exam_scores_soup.find_all(
"span", {"class": "submitted-user-answer"}
)
assert len(submitted_answers) == 5 * len(generated_questions)
for ans in submitted_answers:
assert ans.text.strip() == "True"
# Check no correct answers are shown
assert not cid_exam_scores_soup.find_all("span", {"class": "correct-answer"})
# Add another question to the exam
extra_question = create_question(exam)
generated_questions.append(extra_question)
# Load the exam results page (again)
cid_exam_scores_res = client.get(exam_scores_url)
cid_exam_scores_soup = BeautifulSoup(cid_exam_scores_res.content, "html.parser")
answer_lis = cid_exam_scores_soup.find_all("li", {"class": "question-part"})
assert len(answer_lis) == 5 * len(generated_questions)
submitted_answers = cid_exam_scores_soup.find_all(
"span", {"class": "submitted-user-answer"}
)
assert len(submitted_answers) == 5 * len(generated_questions)
for ans in submitted_answers[:-5]:
assert ans.text.strip() == "True"
# The new question will not have any answers
for ans in submitted_answers[-5:]:
assert ans.text.strip() == ""
# Publish the results!
exam.publish_results = True
exam.save()
# Load the exam results page (again)
cid_exam_scores_res = client.get(exam_scores_url)
cid_exam_scores_soup = BeautifulSoup(cid_exam_scores_res.content, "html.parser")
assert (
cid_exam_scores_soup.find("div", {"class": "alert"}) is None
) # Check our warning banner is gone
# Check that we are displaying the correct answers (correctly)
correct_answers = cid_exam_scores_soup.find_all(
"span", {"class": "correct-answer"}
)
assert len(correct_answers) == 5 * len(generated_questions)
n = 0
for question in generated_questions:
for ans in question.get_answers():
assert correct_answers[n].text.strip() == f"Correct answer: {ans}"
n = n + 1
submitted_answers = cid_exam_scores_soup.find_all(
"span", {"class": "submitted-user-answer"}
)
assert len(submitted_answers) == 5 * len(generated_questions)
for ans in submitted_answers[:-5]:
assert ans.text.strip() == "True"
# The new question will not have any answers
for ans in submitted_answers[-5:]:
assert ans.text.strip() == ""
assert (
cid_exam_scores_soup.find("div", {"class": "score-overview"})
.find("span", {"id": "total-score"})
.string
== "9"
)
assert (
cid_exam_scores_soup.find("div", {"class": "score-overview"})
.find("span", {"id": "max-score"})
.string
== "20"
)
# answer the final question
if testing_cid_user:
extra_question = exam_tester.generated_questions[-1]
if exam_tester.testing_cid_user:
cid_user_answer = UserAnswer(
question=extra_question,
a=True,
@@ -608,54 +223,12 @@ def test_exams(db, client):
c=True,
d=False,
e=True,
user=current_user,
user=exam_tester.current_user,
exam=exam,
)
cid_user_answer.save()
cid_exam_scores_res = client.get(exam_scores_url)
cid_exam_scores_soup = BeautifulSoup(cid_exam_scores_res.content, "html.parser")
exam_tester.check_cid_scores_user_page2()
# As we have answered correctly the new score should be increased by 5
assert (
cid_exam_scores_soup.find("div", {"class": "score-overview"})
.find("span", {"id": "total-score"})
.string
== "14"
)
# Check what happens when exam is not active
exam.active = False
exam.save()
start_page_res = client.get(
reverse(f"physics:exam_start", kwargs={"pk": exam.pk})
)
start_page_soup = BeautifulSoup(start_page_res.content, "html.parser")
assert "Exam is currently inactive" in start_page_soup.text
if testing_cid_user:
cid_take_url = reverse(
f"physics:exam_take",
kwargs={
"pk": exam.pk,
"sk": 0,
"cid": cid_user.cid,
"passcode": cid_user.passcode,
},
)
else:
cid_take_url = reverse(
f"physics:exam_take_user",
kwargs={
"pk": exam.pk,
"sk": 0,
},
)
cid_take_res = client.get(cid_take_url)
cid_take_soup = BeautifulSoup(cid_take_res.content, "html.parser")
assert "Exam is currently inactive" in cid_take_soup.text
generated_questions.pop(-1).delete()
users_tested = users_tested + 1
+498 -5
View File
@@ -1,12 +1,22 @@
from http import HTTPStatus
import json
from typing import Callable
from generic.models import CidUser, CidUserGroup, UserUserGroup
from bs4 import BeautifulSoup
import pytest
from generic.models import CidUser, CidUserGroup, UserUserGroup, ExamBase
from generic.views import ExamViews
from django.contrib.auth.models import User
from django.urls import reverse
def AssertNotFound(client, url):
"""Helper to quickly test for urls that should return a 404 (NOT FOUND) error"""
response = client.get(url)
assert response.status_code == HTTPStatus.NOT_FOUND, f"Response content: {response.content}"
assert (
response.status_code == HTTPStatus.NOT_FOUND
), f"Response content: {response.content}"
def create_cid_user_and_groups(db):
@@ -21,9 +31,492 @@ def create_cid_user_and_groups(db):
assert cid_user_1001.cid == 1001
# Create UserUsers
user1 = User.objects.create_user(username="user1", email="test@email.com", password="test1234")
user2 = User.objects.create_user(username="user2", email="test2@email.com", password="test1234")
user1 = User.objects.create_user(
username="user1", email="test@email.com", password="test1234"
)
user2 = User.objects.create_user(
username="user2", email="test2@email.com", password="test1234"
)
usergroup1 = UserUserGroup.objects.create(name="Group1")
usergroup1.users.add(user1)
usergroup2 = UserUserGroup.objects.create(name="Group2")
usergroup2.users.add(user2)
usergroup2.users.add(user2)
def create_exam(db, ExamViews: ExamViews):
exam: ExamBase = ExamViews.Exam.objects.create(
name="Cid Exam", exam_mode=True, active=True
)
cidgroup1: CidUserGroup = CidUserGroup.objects.get(name="Group1")
usergroup1: UserUserGroup = UserUserGroup.objects.get(name="Group1")
exam.cid_user_groups.add(cidgroup1)
exam.valid_cid_users.add(*cidgroup1.ciduser_set.all())
# exam.valid_user_users.add(user1)
exam.valid_user_users.add(*usergroup1.users.all())
assert exam
return exam
class ExamTester:
def __init__(self, db, client, app_name, ExamViews) -> None:
self.db = db
self.client = client
self.app_name = app_name
create_cid_user_and_groups(db)
self.exam = exam = create_exam(db, ExamViews)
cidgroup1: CidUserGroup = CidUserGroup.objects.get(name="Group1")
assert exam in cidgroup1.physics_cid_user_groups.all()
cid_user_1001 = CidUser.objects.get(cid=1001)
cid_user_1000 = CidUser.objects.get(cid=1000)
self.cid_user_2001 = cid_user_2001 = CidUser.objects.get(cid=2001)
user1 = User.objects.get(username="user1")
user2 = User.objects.get(username="user2")
self.all_users = [cid_user_1000, cid_user_1001, cid_user_2001, user1, user2]
self.cid_users = [cid_user_1000, cid_user_1001, cid_user_2001]
self.invalid_users = [cid_user_2001, user2]
self.current_user = None
self.generated_questions = []
def load_user(self, user):
self.client.logout()
self.current_user = user
if isinstance(self.current_user, CidUser):
self.testing_cid_user = True
else:
self.testing_cid_user = False
self.client.force_login(user)
def create_questions(self, create_question_func: Callable):
self.create_question_func = create_question_func
self.generated_questions = [
create_question_func(self.exam),
create_question_func(self.exam),
create_question_func(self.exam),
]
def add_question(self):
self.generated_questions.append(self.create_question_func(self.exam))
def check_active_exams(self, n):
active_exams = self.client.get(reverse(f"{self.app_name}:active_exams"))
assert active_exams.status_code == 200
assert len(json.loads(active_exams.content)["exams"]) == n, f"Current user: {self.current_user}"
def check_onsite_start_page(self):
start_page_res = self.client.get(
reverse(f"{self.app_name}:exam_start", kwargs={"pk": self.exam.pk})
)
# Check user access to the start page
assert start_page_res.status_code == HTTPStatus.OK
start_page_soup = BeautifulSoup(start_page_res.content, "html.parser")
if (
self.current_user in self.cid_users
or self.current_user in self.invalid_users
):
assert "Enter your CID and passcode" in str(start_page_soup)
else:
assert "Start Exam" in str(start_page_soup)
def check_take_page(self):
for n, question in enumerate(self.generated_questions):
if self.testing_cid_user:
take_url = reverse(
f"{self.app_name}:exam_take",
kwargs={
"pk": self.exam.pk,
"sk": n,
"cid": self.current_user.cid,
"passcode": self.current_user.passcode,
},
)
else:
take_url = reverse(
f"{self.app_name}:exam_take_user",
kwargs={
"pk": self.exam.pk,
"sk": n,
},
)
cid_take_res = self.client.get(take_url)
# Check that users that have not been added cannot access the take pages
if self.current_user in self.invalid_users:
assert cid_take_res.status_code == HTTPStatus.NOT_FOUND
continue
else:
assert cid_take_res.status_code == HTTPStatus.OK, f"Current user: {self.current_user}"
cid_take_soup = BeautifulSoup(cid_take_res.content, "html.parser")
# Check correct user is displayed
if self.testing_cid_user:
display_user = str(self.current_user.cid)
else:
display_user = self.current_user.username
assert display_user in cid_take_soup.find("span", {"id": "user-id"}).string
# Check review mode alert not visible
assert cid_take_soup.find("div", {"class": "review-mode-alert"}) is None
# Check that relevant buttons are being displayed
assert cid_take_soup.find("button", {"name": "finish"}) is not None
if n < len(self.generated_questions) - 1:
assert cid_take_soup.find("button", {"name": "next"}) is not None
if n > 0:
assert cid_take_soup.find("button", {"name": "previous"}) is not None
assert cid_take_soup.find("span", {"id": "question-number"}).string == str(
n + 1
) # + 1 for 0 offset
assert cid_take_soup.find("span", {"id": "exam-length"}).string == str(
len(self.generated_questions)
)
# Check that stem text is displayed
assert (
cid_take_soup.find("span", {"id": "question-stem"}).string
== question.stem
)
assert cid_take_soup.find("label", {"for": "id_a"}).string == question.a
assert cid_take_soup.find("label", {"for": "id_b"}).string == question.b
assert cid_take_soup.find("label", {"for": "id_c"}).string == question.c
assert cid_take_soup.find("label", {"for": "id_d"}).string == question.d
assert cid_take_soup.find("label", {"for": "id_e"}).string == question.e
# As we haven't submitted any answers they should all be blank
assert (
cid_take_soup.find("input", {"type": "checkbox", "checked": True})
is None
)
def check_take_overview(self, answered, total):
if self.testing_cid_user:
take_overview_url = reverse(
f"{self.app_name}:exam_take_overview",
kwargs={
"pk": self.exam.pk,
"cid": self.current_user.cid,
"passcode": self.current_user.passcode,
},
)
else:
take_overview_url = reverse(
f"{self.app_name}:exam_take_overview_user",
kwargs={
"pk": self.exam.pk,
},
)
cid_take_overview_res = self.client.get(take_overview_url)
# Check that users that have not been added cannot access the take pages
if self.current_user in self.invalid_users:
assert cid_take_overview_res.status_code == HTTPStatus.NOT_FOUND
else:
assert cid_take_overview_res.status_code == HTTPStatus.OK
cid_take_overview_soup = BeautifulSoup(
cid_take_overview_res.content, "html.parser"
)
print(self.generated_questions)
assert (
f"{answered} out of 3 questions answered"
in cid_take_overview_soup.find(
"div", attrs={"class": "overview-text"}
).string
)
assert (
len(
cid_take_overview_soup.find_all(
"button", attrs={"class": "unanswered"}
)
)
== total - answered
)
def check_cid_scores_page(self):
if self.testing_cid_user:
# Get overview scores page (invalid passcode)
AssertNotFound(
self.client,
reverse(
f"cid_scores",
kwargs={"cid": self.current_user.cid, "passcode": "AAAA"},
),
)
cid_scores_url = reverse(
f"cid_scores",
kwargs={
"cid": self.current_user.cid,
"passcode": self.current_user.passcode,
},
)
else:
cid_scores_url = reverse(f"user_scores")
# Get overview scores page
cid_scores_res = self.client.get(cid_scores_url)
assert cid_scores_res.status_code == HTTPStatus.OK
cid_scores_soup = BeautifulSoup(cid_scores_res.content, "html.parser")
if self.current_user in self.invalid_users:
# page should load but we shouldn't be able to find the exam
with pytest.raises(AttributeError):
search_exam = (
cid_scores_soup.find("div", {"id": "exam-assigned"})
.find("ul", {"class": self.exam.app_name.lower()})
.find_all("li", attrs={"data-exam-id": self.exam.pk})
)
else:
search_exam = (
cid_scores_soup.find("div", {"id": "exam-assigned"})
.find("ul", {"class": self.exam.app_name.lower()})
.find_all("li", attrs={"data-exam-id": self.exam.pk})
)
assert search_exam
assert self.exam.name in str(search_exam)
assert "Active" in str(search_exam)
# assert "Active" in assigned_exams # check it is active
invalid_exam = cid_scores_soup.find_all(
"li", attrs={"data-exam-id": self.exam.pk + 5}
)
assert not invalid_exam # Check we can't find an invalid exam
# Check that we have a results link
results_exam = (
cid_scores_soup.find("div", {"id": "exam-results"})
.find("ul", {"class": self.exam.app_name})
.find_all("li", attrs={"data-exam-id": self.exam.pk})
)
assert results_exam
assert self.exam.name in str(results_exam)
assert self.exam.name + " test" not in str(results_exam)
assert "Results Published" not in str(
results_exam
) # It should not be published yet
def check_cid_scores_user_page(self):
if self.testing_cid_user:
AssertNotFound(
self.client,
reverse(
f"{self.exam.app_name}:exam_scores_cid_user",
kwargs={
"pk": self.exam.pk,
"cid": self.current_user.cid,
"passcode": "AAAA",
},
),
)
AssertNotFound(
self.client,
reverse(
f"{self.exam.app_name}:exam_scores_cid_user",
kwargs={
"pk": self.exam.pk,
"cid": self.cid_user_2001.cid,
"passcode": self.cid_user_2001.passcode,
},
),
)
exam_scores_url = reverse(
f"{self.exam.app_name}:exam_scores_cid_user",
kwargs={
"pk": self.exam.pk,
"cid": self.current_user.cid,
"passcode": self.current_user.passcode,
},
)
else:
exam_scores_url = reverse(
f"{self.exam.app_name}:exam_scores_user",
kwargs={"pk": self.exam.pk},
)
self.exam_scores_url = exam_scores_url
# Load the exam results page
cid_exam_scores_res = self.client.get(exam_scores_url)
if self.current_user in self.invalid_users:
assert cid_exam_scores_res.status_code == HTTPStatus.NOT_FOUND
return
else:
assert cid_exam_scores_res.status_code == HTTPStatus.OK
cid_exam_scores_soup = BeautifulSoup(cid_exam_scores_res.content, "html.parser")
# Check that we have an alert that exams are not published
alert = cid_exam_scores_soup.find("div", {"class": "alert"})
assert "Results are not currently published." in str(alert)
# Check that we are showing enough questions / answers
answer_lis = cid_exam_scores_soup.find_all("li", {"class": "question-part"})
assert len(answer_lis) == 5 * len(self.generated_questions)
submitted_answers = cid_exam_scores_soup.find_all(
"span", {"class": "submitted-user-answer"}
)
assert len(submitted_answers) == 5 * len(self.generated_questions)
for ans in submitted_answers:
assert ans.text.strip() == "True"
# Check no correct answers are shown
assert not cid_exam_scores_soup.find_all("span", {"class": "correct-answer"})
# Add another question to the exam
self.add_question()
# Load the exam results page (again)
cid_exam_scores_res = self.client.get(exam_scores_url)
cid_exam_scores_soup = BeautifulSoup(cid_exam_scores_res.content, "html.parser")
answer_lis = cid_exam_scores_soup.find_all("li", {"class": "question-part"})
assert len(answer_lis) == 5 * len(self.generated_questions)
submitted_answers = cid_exam_scores_soup.find_all(
"span", {"class": "submitted-user-answer"}
)
assert len(submitted_answers) == 5 * len(self.generated_questions)
for ans in submitted_answers[:-5]:
assert ans.text.strip() == "True"
# The new question will not have any answers
for ans in submitted_answers[-5:]:
assert ans.text.strip() == ""
# Publish the results!
self.exam.publish_results = True
self.exam.save()
# Load the exam results page (again)
cid_exam_scores_res = self.client.get(exam_scores_url)
cid_exam_scores_soup = BeautifulSoup(cid_exam_scores_res.content, "html.parser")
assert (
cid_exam_scores_soup.find("div", {"class": "alert"}) is None
) # Check our warning banner is gone
# Check that we are displaying the correct answers (correctly)
correct_answers = cid_exam_scores_soup.find_all(
"span", {"class": "correct-answer"}
)
assert len(correct_answers) == 5 * len(self.generated_questions)
n = 0
for question in self.generated_questions:
for ans in question.get_answers():
assert correct_answers[n].text.strip() == f"Correct answer: {ans}"
n = n + 1
submitted_answers = cid_exam_scores_soup.find_all(
"span", {"class": "submitted-user-answer"}
)
assert len(submitted_answers) == 5 * len(self.generated_questions)
for ans in submitted_answers[:-5]:
assert ans.text.strip() == "True"
# The new question will not have any answers
for ans in submitted_answers[-5:]:
assert ans.text.strip() == ""
assert (
cid_exam_scores_soup.find("div", {"class": "score-overview"})
.find("span", {"id": "total-score"})
.string
== "9"
)
assert (
cid_exam_scores_soup.find("div", {"class": "score-overview"})
.find("span", {"id": "max-score"})
.string
== "20"
)
def check_cid_scores_user_page2(self):
cid_exam_scores_res = self.client.get(self.exam_scores_url)
cid_exam_scores_soup = BeautifulSoup(cid_exam_scores_res.content, "html.parser")
# As we have answered correctly the new score should be increased by 5
assert (
cid_exam_scores_soup.find("div", {"class": "score-overview"})
.find("span", {"id": "total-score"})
.string
== "14"
), f"Current user: {self.current_user}"
# Check what happens when exam is not active
self.exam.active = False
self.exam.save()
start_page_res = self.client.get(
reverse(f"{self.app_name}:exam_start", kwargs={"pk": self.exam.pk})
)
start_page_soup = BeautifulSoup(start_page_res.content, "html.parser")
assert "Exam is currently inactive" in start_page_soup.text
if self.testing_cid_user:
cid_take_url = reverse(
f"{self.app_name}:exam_take",
kwargs={
"pk": self.exam.pk,
"sk": 0,
"cid": self.current_user.cid,
"passcode": self.current_user.passcode,
},
)
else:
cid_take_url = reverse(
f"{self.app_name}:exam_take_user",
kwargs={
"pk": self.exam.pk,
"sk": 0,
},
)
cid_take_res = self.client.get(cid_take_url)
cid_take_soup = BeautifulSoup(cid_take_res.content, "html.parser")
assert "Exam is currently inactive" in cid_take_soup.text
# Delete the last question, from both the list
q= self.generated_questions.pop()
# and the database
q.delete()