From 03df64668d980ea2e48ff0ebb1dec89840b5e147 Mon Sep 17 00:00:00 2001 From: Simey Lameze Date: Thu, 21 Aug 2025 14:47:25 +0800 Subject: [PATCH] MDL-85675 behat: add timefinish to quiz attempt generator Adds support for the timefinish attribute to the quiz attempt generator allowing Behat scenarios to specify the exact completion time of an attempt. This is necessary to simulate a scenario where the student finished the attempt few minutes ago for example. This commit also adds two scenarios that automates MDLQA-307. --- mod/quiz/tests/behat/behat_mod_quiz.php | 20 ++++++- mod/quiz/tests/behat/quiz_feedback.feature | 65 ++++++++++++++++++++++ mod/quiz/tests/generator/lib.php | 7 ++- 3 files changed, 87 insertions(+), 5 deletions(-) diff --git a/mod/quiz/tests/behat/behat_mod_quiz.php b/mod/quiz/tests/behat/behat_mod_quiz.php index c23c318df0f..2aa850178bd 100644 --- a/mod/quiz/tests/behat/behat_mod_quiz.php +++ b/mod/quiz/tests/behat/behat_mod_quiz.php @@ -850,15 +850,29 @@ class behat_mod_quiz extends behat_question_base { * @param string $username the username of the user that will attempt. * @param string $quizname the name of the quiz the user will attempt. * @param TableNode $attemptinfo information about the questions to add, as above. + * @param string|null $timefinish if specified, the attempt will be submitted with this * @Given /^user "([^"]*)" has attempted "([^"]*)" with responses:$/ + * @Given /^user "([^"]*)" has attempted "([^"]*)" with responses submitting "([^"]*)":$/ */ - public function user_has_attempted_with_responses($username, $quizname, TableNode $attemptinfo) { + public function user_has_attempted_with_responses($username, $quizname, TableNode $attemptinfo, $timefinish = null) { global $DB; /** @var mod_quiz_generator $quizgenerator */ $quizgenerator = behat_util::get_data_generator()->get_plugin_generator('mod_quiz'); - $quizid = $DB->get_field('quiz', 'id', ['name' => $quizname], MUST_EXIST); + $quiz = $DB->get_record('quiz', ['name' => $quizname], 'id, timeclose', MUST_EXIST); + $quizid = $quiz->id; + $timeclose = $quiz->timeclose; + + // If timefinish is provided, check against timeclose. + if ($timefinish !== null) { + if ($timeclose && $timefinish > $timeclose) { + throw new ExpectationException( + "Attempt submission cannot be after the time the quiz closed.", + $this->getSession() + ); + } + } $user = $DB->get_record('user', ['username' => $username], '*', MUST_EXIST); list($forcedrandomquestions, $forcedvariants) = @@ -870,7 +884,7 @@ class behat_mod_quiz extends behat_question_base { $attempt = $quizgenerator->create_attempt($quizid, $user->id, $forcedrandomquestions, $forcedvariants); - $quizgenerator->submit_responses($attempt->id, $responses, false, true); + $quizgenerator->submit_responses($attempt->id, $responses, false, true, $timefinish); $this->set_user(); } diff --git a/mod/quiz/tests/behat/quiz_feedback.feature b/mod/quiz/tests/behat/quiz_feedback.feature index ed4185780b1..d8738d88b05 100644 --- a/mod/quiz/tests/behat/quiz_feedback.feature +++ b/mod/quiz/tests/behat/quiz_feedback.feature @@ -83,3 +83,68 @@ Feature: Enable deferred or immediate feedback for quiz And the "True" "field" should be disabled And the "False" "field" should be disabled And "Check Question 1" "button" should not exist + + Scenario Outline: Responses, answers and feedback are displayed after attempting a quiz depending on time finished + Given the following "activity" exists: + | activity | quiz | + | name | Quiz 1 | + | course | C1 | + | idnumber | quiz1 | + | maxmarksimmediately | 0 | + | specificfeedbackimmediately | 0 | + | rightanswerimmediately | 0 | + And quiz "Quiz 1" contains the following questions: + | question | page | + | TF1 | 1 | + And user "student1" has attempted "Quiz 1" with responses submitting "": + | slot | response | + | 1 | True | + When I am on the "Quiz 1" "quiz activity" page logged in as student1 + And I click on "Review" "link" + Then I should see "You should have selected true." + And I see "This is the right answer." + And I see "The correct answer is 'True'." + And the following exist in the "quizreviewsummary" table: + | -1- | -2- | + | Marks | 1.00/1.00 | + | Grade | 100.00 out of 100.00 | + + Examples: + | timefinish | visibility | + | ## 1 minute ago ## | should not | + | ## 2 minute ago ## | should | + + Scenario Outline: Responses, answers and feedback cannot be reviewed after attempting a quiz as long as quiz is open + Given the following "activity" exists: + | activity | quiz | + | name | Quiz 1 | + | course | C1 | + | idnumber | quiz1 | + | timeclose | | + | generalfeedbackimmediately | 0 | + | attemptimmediately | 0 | + | overallfeedbackopen | 0 | + | rightansweropen | 0 | + | generalfeedbackopen | 0 | + | specificfeedbackopen | 0 | + | marksopen | 0 | + | maxmarksopen | 0 | + | correctnessopen | 0 | + | attemptopen | 0 | + And quiz "Quiz 1" contains the following questions: + | question | page | + | TF1 | 1 | + And user "student1" has attempted "Quiz 1" with responses: + | slot | response | + | 1 | True | + When I am on the "Quiz 1" "quiz activity" page logged in as student1 + # Confirm the Review link visibility. Should exist if quiz is closed, otherwise, it shouldn't exist. + Then "Review" "link" exist + # Confirm the `Available` text and close date visibility. Should only be visible while quiz is open. + And I see "Available" + And I see "##tomorrow##%d/%m/%y##" + + Examples: + | quizclosedate | reviewlinkvisibility | availabilityvisibility | + | ## tomorrow ## | should not | should | + | ## yesterday ## | should | should not | diff --git a/mod/quiz/tests/generator/lib.php b/mod/quiz/tests/generator/lib.php index da94f9b80b4..ca17457eaa9 100644 --- a/mod/quiz/tests/generator/lib.php +++ b/mod/quiz/tests/generator/lib.php @@ -151,8 +151,9 @@ class mod_quiz_generator extends testing_module_generator { * @param bool $checkbutton if simulate a click on the check button for each question, else simulate save. * This should only be used with behaviours that have a check button. * @param bool $finishattempt if true, the attempt will be submitted. + * @param int|null $timefinish the time to set as the time finished for the attempt. */ - public function submit_responses($attemptid, array $responses, $checkbutton, $finishattempt) { + public function submit_responses($attemptid, array $responses, $checkbutton, $finishattempt, ?int $timefinish = null) { $questiongenerator = $this->datagenerator->get_plugin_generator('core_question'); $attemptobj = quiz_attempt::create($attemptid); @@ -181,7 +182,9 @@ class mod_quiz_generator extends testing_module_generator { } if ($finishattempt) { - $attemptobj->process_submit(time(), false); + // If a timefinish is not specified, use the current time. + $timefinish = $timefinish ?? time(); + $attemptobj->process_submit($timefinish, false); $attemptobj->process_grade_submission(time()); } }