diff --git a/completion/tests/behat/passgrade_completion_criteria_gradeitem_visibility.feature b/completion/tests/behat/passgrade_completion_criteria_gradeitem_visibility.feature new file mode 100644 index 00000000000..0e948611732 --- /dev/null +++ b/completion/tests/behat/passgrade_completion_criteria_gradeitem_visibility.feature @@ -0,0 +1,137 @@ +@core @core_completion @javascript +Feature: Students will be shown relevant completion state based on grade item visibility. + In order to understand completion states of course modules + As a student + I need to see relevant completion information for various combination of activity passgrade settings + + Background: + Given the following "courses" exist: + | fullname | shortname | category | enablecompletion | + | Course 1 | C1 | 0 | 1 | + And the following "users" exist: + | username | firstname | lastname | email | + | teacher1 | Teacher | Frist | teacher1@example.com | + | student1 | Student | First | student1@example.com | + | student2 | Student | Second | student2@example.com | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | student1 | C1 | student | + | student2 | C1 | student | + And the following "activity" exists: + | activity | assign | + | course | C1 | + | name | Test assignment name | + | intro | Submit your online text | + | assignsubmission_onlinetext_enabled | 1 | + | assignsubmission_file_enabled | 0 | + | completion | 2 | + | completionpassgrade | 1 | + | completionusegrade | 1 | + | gradepass | 50 | + And I am on the "Course 1" course page logged in as teacher1 + And "Student First" user has not completed "Test assignment name" activity + And I log out + And I am on the "Course 1" course page logged in as student1 + And the "Receive a grade" completion condition of "Test assignment name" is displayed as "todo" + And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "todo" + And I log out + + Scenario: Passing grade and receive a grade completions for visible grade item (passgrade completion enabled) + Given I am on the "Course 1" course page logged in as teacher1 + And I navigate to "View > Grader report" in the course gradebook + And I turn editing mode on + And I give the grade "21" to the user "Student First" for the grade item "Test assignment name" + And I give the grade "50" to the user "Student Second" for the grade item "Test assignment name" + And I press "Save changes" + And I am on "Course 1" course homepage + And "Student First" user has completed "Test assignment name" activity + And "Student Second" user has completed "Test assignment name" activity + And I log out + When I am on the "Course 1" course page logged in as student1 + And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done" + And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "failed" + And I log out + And I am on the "Course 1" course page logged in as student2 + Then the "Receive a grade" completion condition of "Test assignment name" is displayed as "done" + And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "done" + + Scenario: Passing grade and receive a grade completions for hidden grade item (passgrade completion enabled) + Given I am on the "Course 1" course page logged in as teacher1 + And I navigate to "Setup > Gradebook setup" in the course gradebook + And I hide the grade item "Test assignment name" + And I navigate to "View > Grader report" in the course gradebook + And I turn editing mode on + And I give the grade "21" to the user "Student First" for the grade item "Test assignment name" + And I give the grade "50" to the user "Student Second" for the grade item "Test assignment name" + And I press "Save changes" + And I am on "Course 1" course homepage + And "Student First" user has not completed "Test assignment name" activity + And "Student Second" user has completed "Test assignment name" activity + And I log out + And I am on the "Course 1" course page logged in as student1 + And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done" + And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "todo" + And I log out + And I am on the "Course 1" course page logged in as student2 + And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done" + And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "done" + + Scenario: Receive a grade completion for visible grade item (passgrade completion disabled) + Given I am on the "Test assignment name" Activity page logged in as teacher1 + When I navigate to "Settings" in current page administration + And I set the following fields to these values: + | completionpassgrade | 0 | + And I press "Save and display" + And I log out + And I am on the "Course 1" course page logged in as student1 + And the "Receive a grade" completion condition of "Test assignment name" is displayed as "todo" + And I should not see "Receive a passing grade" + And I log out + And I am on the "Course 1" course page logged in as teacher1 + And I navigate to "View > Grader report" in the course gradebook + And I turn editing mode on + And I give the grade "21" to the user "Student First" for the grade item "Test assignment name" + And I give the grade "50" to the user "Student Second" for the grade item "Test assignment name" + And I press "Save changes" + And I am on "Course 1" course homepage + And "Student First" user has completed "Test assignment name" activity + And "Student Second" user has completed "Test assignment name" activity + And I log out + When I am on the "Course 1" course page logged in as student1 + # Once MDL-75582 is fixed "failed" should be changed to "done" + And the "Receive a grade" completion condition of "Test assignment name" is displayed as "failed" + And I should not see "Receive a passing grade" + And I log out + And I am on the "Course 1" course page logged in as student2 + Then the "Receive a grade" completion condition of "Test assignment name" is displayed as "done" + + Scenario: Receive a grade completion for hidden grade item (passgrade completion disabled) + Given I am on the "Test assignment name" Activity page logged in as teacher1 + When I navigate to "Settings" in current page administration + And I set the following fields to these values: + | completionpassgrade | 0 | + And I press "Save and display" + And I log out + And I am on the "Course 1" course page logged in as student1 + And the "Receive a grade" completion condition of "Test assignment name" is displayed as "todo" + And I should not see "Receive a passing grade" + And I log out + And I am on the "Course 1" course page logged in as teacher1 + And I navigate to "Setup > Gradebook setup" in the course gradebook + And I hide the grade item "Test assignment name" + And I navigate to "View > Grader report" in the course gradebook + And I turn editing mode on + And I give the grade "21" to the user "Student First" for the grade item "Test assignment name" + And I give the grade "50" to the user "Student Second" for the grade item "Test assignment name" + And I press "Save changes" + And I am on "Course 1" course homepage + And "Student First" user has completed "Test assignment name" activity + And "Student Second" user has completed "Test assignment name" activity + And I log out + When I am on the "Course 1" course page logged in as student1 + Then the "Receive a grade" completion condition of "Test assignment name" is displayed as "done" + And I should not see "Receive a passing grade" + And I log out + And I am on the "Course 1" course page logged in as student2 + And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done" diff --git a/lib/completionlib.php b/lib/completionlib.php index aae0552e349..26056518181 100644 --- a/lib/completionlib.php +++ b/lib/completionlib.php @@ -88,6 +88,11 @@ define('COMPLETION_COMPLETE_PASS', 2); */ define('COMPLETION_COMPLETE_FAIL', 3); +/** + * Indicates that the user has received a failing grade for a hidden grade item. + */ +define('COMPLETION_COMPLETE_FAIL_HIDDEN', 4); + /** * The effect of this change to completion status is unknown. * A completion effect changes (used only in update_state) @@ -784,7 +789,8 @@ class completion_info { $this->internal_systemerror("Unexpected result: multiple grades for item '{$item->id}', user '{$userid}'"); } - return self::internal_get_grade_state($item, reset($grades)); + $returnpassfail = !empty($cm->completionpassgrade); + return self::internal_get_grade_state($item, reset($grades), $returnpassfail); } return COMPLETION_INCOMPLETE; @@ -1113,6 +1119,9 @@ class completion_info { if (empty($data->coursemoduleid)) { $cacheddata[$data->cmid] = $defaultdata; + if ($data->viewed) { + $cacheddata[$data->cmid]['viewed'] = $data->viewed; + } $cacheddata[$data->cmid]['coursemoduleid'] = $data->cmid; } else { unset($data->cmid); @@ -1171,12 +1180,16 @@ class completion_info { $newstate = COMPLETION_COMPLETE_PASS; } - // The activity is using 'passing grade' criteria therefore fail indication should be on this criteria. - // The user has received a (failing) grade so 'completiongrade' should properly indicate this. - if ($newstate == COMPLETION_COMPLETE_FAIL) { + // No need to show failing status for the completiongrade condition when passing grade condition is set. + if (in_array($newstate, [COMPLETION_COMPLETE_FAIL, COMPLETION_COMPLETE_FAIL_HIDDEN])) { $data['completiongrade'] = COMPLETION_COMPLETE; - } + // If the grade received by the user is a failing grade for a hidden grade item, + // the 'Require passing grade' criterion is considered incomplete. + if ($newstate == COMPLETION_COMPLETE_FAIL_HIDDEN) { + $newstate = COMPLETION_INCOMPLETE; + } + } $data['passgrade'] = $newstate; } } @@ -1547,9 +1560,10 @@ class completion_info { * * @param grade_item $item an instance of grade_item * @param grade_grade $grade an instance of grade_grade + * @param bool $returnpassfail If course module has pass grade completion criteria * @return int Completion state e.g. COMPLETION_INCOMPLETE */ - public static function internal_get_grade_state($item, $grade) { + public static function internal_get_grade_state($item, $grade, bool $returnpassfail = false) { // If no grade is supplied or the grade doesn't have an actual value, then // this is not complete. if (!$grade || (is_null($grade->finalgrade) && is_null($grade->rawgrade))) { @@ -1557,15 +1571,19 @@ class completion_info { } // Conditions to show pass/fail: + // a) Completion criteria to achieve pass grade is enabled + // or // a) Grade has pass mark (default is 0.00000 which is boolean true so be careful) // b) Grade is visible (neither hidden nor hidden-until) - if ($item->gradepass && $item->gradepass > 0.000009 && !$item->hidden) { + if ($item->gradepass && $item->gradepass > 0.000009 && ($returnpassfail || !$item->hidden)) { // Use final grade if set otherwise raw grade $score = !is_null($grade->finalgrade) ? $grade->finalgrade : $grade->rawgrade; // We are displaying and tracking pass/fail if ($score >= $item->gradepass) { return COMPLETION_COMPLETE_PASS; + } else if ($item->hidden) { + return COMPLETION_COMPLETE_FAIL_HIDDEN; } else { return COMPLETION_COMPLETE_FAIL; } diff --git a/lib/tests/completionlib_test.php b/lib/tests/completionlib_test.php index 43c0cfe151f..b0d963b6e0a 100644 --- a/lib/tests/completionlib_test.php +++ b/lib/tests/completionlib_test.php @@ -1319,6 +1319,30 @@ class completionlib_test extends advanced_testcase { $this->assertEquals( COMPLETION_COMPLETE, completion_info::internal_get_grade_state($item, $grade)); + + // Item is hidden, but returnpassfail is true and the grade is passing. + $item->hidden = 1; + $item->gradepass = 4; + $grade->finalgrade = 5.0; + $this->assertEquals( + COMPLETION_COMPLETE_PASS, + completion_info::internal_get_grade_state($item, $grade, true)); + + // Item is hidden, but returnpassfail is true and the grade is failing. + $item->hidden = 1; + $item->gradepass = 4; + $grade->finalgrade = 3.0; + $this->assertEquals( + COMPLETION_COMPLETE_FAIL_HIDDEN, + completion_info::internal_get_grade_state($item, $grade, true)); + + // Item is not hidden, but returnpassfail is true and the grade is failing. + $item->hidden = 0; + $item->gradepass = 4; + $grade->finalgrade = 3.0; + $this->assertEquals( + COMPLETION_COMPLETE_FAIL, + completion_info::internal_get_grade_state($item, $grade, true)); } /** diff --git a/lib/upgrade.txt b/lib/upgrade.txt index d007f8a840a..c8ce3dde023 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -3,6 +3,9 @@ information provided here is intended especially for developers. === 4.2 === +* A new constant COMPLETION_COMPLETE_FAIL_HIDDEN is introduced to mark that user has received a failing grade + for a hidden grade item. This state returned by internal_get_grade_state() and is only used by get_core_completion_state() + for processing the passgrade completion data. * \single_button constructor signature has been changed to manage more types than just primary buttons. The boolean "primary" parameter has been deprecated and replaced by a more generic type allowing to use Bootstrap styles of buttons (danger, warning...). The constructor will still manage the boolean primary diff --git a/mod/quiz/tests/behat/quiz_activity_completion_unlocked.feature b/mod/quiz/tests/behat/quiz_activity_completion_unlocked.feature index 0977e63965f..b1e35f074a1 100644 --- a/mod/quiz/tests/behat/quiz_activity_completion_unlocked.feature +++ b/mod/quiz/tests/behat/quiz_activity_completion_unlocked.feature @@ -31,7 +31,7 @@ Feature: Activity completion in the quiz activity with unlocked and re-grading. | idnumber | quiz1 | | name | Test quiz name | | section | 1 | - | gradepass | 10.00 | + | gradepass | 8 | | grade | 10 | | grademethod | 1 | | completion | 2 | @@ -54,14 +54,21 @@ Feature: Activity completion in the quiz activity with unlocked and re-grading. And I am on "Course 1" course homepage And I follow "Test quiz name" And the "Receive a grade" completion condition of "Test quiz name" is displayed as "done" - And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "failed" + And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "done" And I log out - When I am on the "Test quiz name" "quiz activity" page logged in as teacher1 + When I am on the "Course 1" course page logged in as teacher1 + And I navigate to "Reports > Activity completion" in current page administration + And "Completed (achieved pass grade)" "icon" should exist in the "Student 1" "table_row" + And I am on the "Test quiz name" "quiz activity" page And I navigate to "Settings" in current page administration And I expand all fieldsets And I press "Unlock completion settings" And I set the following fields to these values: - | gradepass | 8 | + | gradepass | 10 | And I press "Save and return to course" And I navigate to "Reports > Activity completion" in current page administration - Then "Completed (achieved pass grade)" "icon" should exist in the "Student 1" "table_row" + Then "Completed (achieved pass grade)" "icon" should not exist in the "Student 1" "table_row" + And I log out + And I am on the "Test quiz name" "quiz activity" page logged in as student1 + And the "Receive a grade" completion condition of "Test quiz name" is displayed as "done" + And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "failed"