From d31029bbb964ab91e85e010707c998deb41e67bb Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Wed, 19 Nov 2025 14:20:35 +0000 Subject: [PATCH 01/74] Scenario: Create coursework assignment with double marking --- tests/behat/double_marking_blind.feature | 93 ++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 tests/behat/double_marking_blind.feature diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature new file mode 100644 index 00000000..385ccb96 --- /dev/null +++ b/tests/behat/double_marking_blind.feature @@ -0,0 +1,93 @@ +@mod @mod_coursework @workbench @javascript +Feature: Double marking - blind + In order to ensure double marking works correctly + As an admin + I want to perform the full coursework workflow with blind marking. + + Background: + Given the following "custom field categories" exist: + | name | component | area | itemid | + | CLC | core_course | course | 0 | + And the following "custom fields" exist: + | name | shortname | category | type | + | Course Year | course_year | CLC | text | + And the following "courses" exist: + | fullname | shortname | format | customfield_course_year | + | Course 1 | C1 | topics | ##now##%Y## | + And the following "roles" exist: + | shortname | name | archetype | + | courseworkmarker | courseworkmarker | teacher | + And the following "users" exist: + | username | firstname | lastname | email | + | teacher1 | teacher | 1 | teacher1@example.com | + | marker1 | marker | 1 | marker1@example.com | + | marker2 | marker | 2 | marker2@example.com | + | marker3 | marker | 3 | marker3@example.com | + | student1 | Student | 1 | student1@example.com | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | + + Scenario: Create coursework assignment with double marking + Given I am on the "Course 1" "course" page logged in as "admin" + When I add a coursework activity to course "Course 1" section "2" and I fill the form with: + | Coursework title | Coursework – Double marking blind | + | Formative or summative? | Summative - counts towards the final module mark | + | Description | Test coursework description | + | Display description on course page | Yes | + | Start date | ##now## | + | Deadline for submissions: | ##now + 15 minutes## | + | Use marking deadline | Yes | + | Types of file that students are allowed to submit | pdf | + | Enable plagiarism flagging | Yes | + | Number of times each submission should initially be marked. | 2 | + | Marker allocation enabled | Yes | + | Marker allocation strategy | Manual | + | Automatic agreement of marks | percentage distance | + | Automatic agreement range | 10 | + | View initial markers' grades | No | + | Auto-populate agreed feedback comment | Yes | + | Blind marking | Yes | + | Marker anonymity | Yes | + | Blind marking | Yes | + + Then I should see "Coursework – Double marking blind" + + Scenario: Add assessors + Given I am on the "Course 1" "course" page logged in as "admin" + When I add a coursework activity to course "Course 1" section "2" and I fill the form with: + | Coursework title | Coursework – Double marking blind | + | Formative or summative? | Summative - counts towards the final module mark | + | Description | Test coursework description | + | Display description on course page | Yes | + | Start date | ##now## | + | Deadline for submissions: | ##now + 15 minutes## | + | Use marking deadline | Yes | + | Types of file that students are allowed to submit | pdf | + | Enable plagiarism flagging | Yes | + | Number of times each submission should initially be marked. | 2 | + | Marker allocation enabled | Yes | + | Marker allocation strategy | Manual | + | Automatic agreement of marks | percentage distance | + | Automatic agreement range | 10 | + | View initial markers' grades | No | + | Auto-populate agreed feedback comment | Yes | + | Blind marking | Yes | + | Marker anonymity | Yes | + | Blind marking | Yes | + And I follow "Coursework – Double marking blind" + And I follow "Add markers" + And I follow "courseworkmarker" + + When I set the field "Existing users" to "marker 1 (marker1@example.com)" + When I set the field "Existing users" to "marker 2 (marker2@example.com)" + When I set the field "Existing users" to "marker 3 (marker3@example.com)" + And I press "Add" + + Then I should see "Assign role 'courseworkmarker' in Coursework" + + And I wait "30" seconds \ No newline at end of file From 3327655dffe361700c52031d54621878ce2db6f3 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Wed, 19 Nov 2025 14:53:44 +0000 Subject: [PATCH 02/74] Scenario: Add markers --- tests/behat/double_marking_blind.feature | 34 +++++++++++++++--------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 385ccb96..49876249 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -1,4 +1,4 @@ -@mod @mod_coursework @workbench @javascript +@mod @mod_coursework @workbench Feature: Double marking - blind In order to ensure double marking works correctly As an admin @@ -26,10 +26,10 @@ Feature: Double marking - blind | student1 | Student | 1 | student1@example.com | And the following "course enrolments" exist: | user | course | role | - | teacher1 | C1 | editingteacher | - | marker1 | C1 | courseworkmarker | - | marker2 | C1 | courseworkmarker | - | marker3 | C1 | courseworkmarker | + | teacher1 | C1 | teacher | + | marker1 | C1 | teacher | + | marker2 | C1 | teacher | + | marker3 | C1 | teacher | | student1 | C1 | student | Scenario: Create coursework assignment with double marking @@ -57,7 +57,7 @@ Feature: Double marking - blind Then I should see "Coursework – Double marking blind" - Scenario: Add assessors + Scenario: Add markers Given I am on the "Course 1" "course" page logged in as "admin" When I add a coursework activity to course "Course 1" section "2" and I fill the form with: | Coursework title | Coursework – Double marking blind | @@ -79,15 +79,25 @@ Feature: Double marking - blind | Blind marking | Yes | | Marker anonymity | Yes | | Blind marking | Yes | + And I follow "Coursework – Double marking blind" And I follow "Add markers" And I follow "courseworkmarker" - When I set the field "Existing users" to "marker 1 (marker1@example.com)" - When I set the field "Existing users" to "marker 2 (marker2@example.com)" - When I set the field "Existing users" to "marker 3 (marker3@example.com)" + Then I should see "marker 1" in the "Potential users" "field" + And I should see "marker 2" in the "Potential users" "field" + And I should see "marker 3" in the "Potential users" "field" + + When I set the field "Potential users" to "marker 1 (marker1@example.com)" + And I press "Add" + And I set the field "Potential users" to "marker 2 (marker2@example.com)" + And I press "Add" + And I set the field "Potential users" to "marker 3 (marker3@example.com)" And I press "Add" - Then I should see "Assign role 'courseworkmarker' in Coursework" - - And I wait "30" seconds \ No newline at end of file + Then I should see "marker 1" in the "Existing users" "field" + And I should see "marker 2" in the "Existing users" "field" + And I should see "marker 3" in the "Existing users" "field" + And I should not see "marker 1" in the "Potential users" "field" + And I should not see "marker 2" in the "Potential users" "field" + And I should not see "marker 3" in the "Potential users" "field" From 3974e1e30783865dafc27d4131fb13b57bf27a09 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Thu, 20 Nov 2025 11:32:47 +0000 Subject: [PATCH 03/74] Scenario: Allocate markers --- tests/behat/double_marking_blind.feature | 69 ++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 49876249..3c7c7edc 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -1,4 +1,4 @@ -@mod @mod_coursework @workbench +@mod @mod_coursework Feature: Double marking - blind In order to ensure double marking works correctly As an admin @@ -17,6 +17,7 @@ Feature: Double marking - blind And the following "roles" exist: | shortname | name | archetype | | courseworkmarker | courseworkmarker | teacher | + | uclnoneditingtutor | uclnoneditingtutor | teacher | And the following "users" exist: | username | firstname | lastname | email | | teacher1 | teacher | 1 | teacher1@example.com | @@ -24,6 +25,8 @@ Feature: Double marking - blind | marker2 | marker | 2 | marker2@example.com | | marker3 | marker | 3 | marker3@example.com | | student1 | Student | 1 | student1@example.com | + | student2 | Student | 2 | student2@example.com | + | student3 | Student | 3 | student3@example.com | And the following "course enrolments" exist: | user | course | role | | teacher1 | C1 | teacher | @@ -31,10 +34,12 @@ Feature: Double marking - blind | marker2 | C1 | teacher | | marker3 | C1 | teacher | | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | Scenario: Create coursework assignment with double marking Given I am on the "Course 1" "course" page logged in as "admin" - When I add a coursework activity to course "Course 1" section "2" and I fill the form with: + And I add a coursework activity to course "Course 1" section "2" and I fill the form with: | Coursework title | Coursework – Double marking blind | | Formative or summative? | Summative - counts towards the final module mark | | Description | Test coursework description | @@ -59,7 +64,7 @@ Feature: Double marking - blind Scenario: Add markers Given I am on the "Course 1" "course" page logged in as "admin" - When I add a coursework activity to course "Course 1" section "2" and I fill the form with: + And I add a coursework activity to course "Course 1" section "2" and I fill the form with: | Coursework title | Coursework – Double marking blind | | Formative or summative? | Summative - counts towards the final module mark | | Description | Test coursework description | @@ -101,3 +106,61 @@ Feature: Double marking - blind And I should not see "marker 1" in the "Potential users" "field" And I should not see "marker 2" in the "Potential users" "field" And I should not see "marker 3" in the "Potential users" "field" + + Scenario: Allocate markers + Given I am on the "Course 1" "course" page logged in as "admin" + And I add a coursework activity to course "Course 1" section "2" and I fill the form with: + | Coursework title | Coursework – Double marking blind | + | Formative or summative? | Summative - counts towards the final module mark | + | Description | Test coursework description | + | Display description on course page | Yes | + | Start date | ##now## | + | Deadline for submissions: | ##now + 15 minutes## | + | Use marking deadline | Yes | + | Types of file that students are allowed to submit | pdf | + | Enable plagiarism flagging | Yes | + | Number of times each submission should initially be marked. | 2 | + | Marker allocation enabled | Yes | + | Marker allocation strategy | Manual | + | Automatic agreement of marks | percentage distance | + | Automatic agreement range | 10 | + | View initial markers' grades | No | + | Auto-populate agreed feedback comment | Yes | + | Blind marking | Yes | + | Marker anonymity | Yes | + | Blind marking | Yes | + + And I follow "Coursework – Double marking blind" + And I follow "Add markers" + And I follow "courseworkmarker" + + When I set the field "Potential users" to "marker 1 (marker1@example.com)" + And I press "Add" + And I set the field "Potential users" to "marker 2 (marker2@example.com)" + And I press "Add" + And I set the field "Potential users" to "marker 3 (marker3@example.com)" + And I press "Add" + + When I follow "Allocate markers" + And I set the field "Allocation strategy" to "Manual" + And I press "Apply" + Then I should see "Please make sure markers are allocated" + + When I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_1']//select" to "marker 1" + And I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_2']//select" to "marker 2" + And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_1']//select" to "marker 1" + And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_2']//select" to "marker 2" + And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_1']//select" to "marker 1" + And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_2']//select" to "marker 2" + And I press "Save" + + Then I should see "marker 1" in the "Student 1" "table_row" + And I should see "marker 2" in the "Student 1" "table_row" + And I should not see "marker 3" in the "Student 1" "table_row" + And I should see "marker 1" in the "Student 2" "table_row" + And I should see "marker 2" in the "Student 2" "table_row" + And I should not see "marker 3" in the "Student 2" "table_row" + And I should see "marker 1" in the "Student 3" "table_row" + And I should see "marker 2" in the "Student 3" "table_row" + And I should not see "marker 3" in the "Student 3" "table_row" + From 6a82714f6cd1b80f6efbcb4cfd8cc4c837bb3ba7 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Thu, 20 Nov 2025 12:23:52 +0000 Subject: [PATCH 04/74] Scenario: Check anonymity --- tests/behat/double_marking_blind.feature | 55 ++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 3c7c7edc..830438e9 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -164,3 +164,58 @@ Feature: Double marking - blind And I should see "marker 2" in the "Student 3" "table_row" And I should not see "marker 3" in the "Student 3" "table_row" + Scenario: Check anonymity + Given I am on the "Course 1" "course" page logged in as "admin" + And I add a coursework activity to course "Course 1" section "2" and I fill the form with: + | Coursework title | Coursework – Double marking blind | + | Formative or summative? | Summative - counts towards the final module mark | + | Description | Test coursework description | + | Display description on course page | Yes | + | Start date | ##now## | + | Deadline for submissions: | ##now + 15 minutes## | + | Use marking deadline | Yes | + | Types of file that students are allowed to submit | pdf | + | Enable plagiarism flagging | Yes | + | Number of times each submission should initially be marked. | 2 | + | Marker allocation enabled | Yes | + | Marker allocation strategy | Manual | + | Automatic agreement of marks | percentage distance | + | Automatic agreement range | 10 | + | View initial markers' grades | No | + | Auto-populate agreed feedback comment | Yes | + | Blind marking | Yes | + | Marker anonymity | Yes | + | Blind marking | Yes | + + Then I follow "Coursework – Double marking blind" + And I follow "Add markers" + And I follow "courseworkmarker" + + And I set the field "Potential users" to "marker 1 (marker1@example.com)" + And I press "Add" + And I set the field "Potential users" to "marker 2 (marker2@example.com)" + And I press "Add" + And I set the field "Potential users" to "marker 3 (marker3@example.com)" + And I press "Add" + + Then I follow "Allocate markers" + And I set the field "Allocation strategy" to "Manual" + And I press "Apply" + Then I should see "Please make sure markers are allocated" + + Then I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_1']//select" to "marker 1" + And I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_2']//select" to "marker 2" + And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_1']//select" to "marker 1" + And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_2']//select" to "marker 2" + And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_1']//select" to "marker 1" + And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_2']//select" to "marker 2" + And I press "Save" + + And I log out + And I am on the "Course 1" "course" page logged in as "marker1" + And I follow "Coursework – Double marking blind" + Then I should see "Submissions" + And I should see "Hidden" + And I should not see "Student 1" + And I should not see "Student 2" + And I should not see "Student 3" From ffdf7166be842f1bb63b45bfff9d0477a6bae253 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Thu, 20 Nov 2025 15:57:15 +0000 Subject: [PATCH 05/74] cleanup --- tests/behat/double_marking_blind.feature | 76 +++++++++++------------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 830438e9..696115c9 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -49,16 +49,15 @@ Feature: Double marking - blind | Use marking deadline | Yes | | Types of file that students are allowed to submit | pdf | | Enable plagiarism flagging | Yes | - | Number of times each submission should initially be marked. | 2 | - | Marker allocation enabled | Yes | - | Marker allocation strategy | Manual | - | Automatic agreement of marks | percentage distance | - | Automatic agreement range | 10 | - | View initial markers' grades | No | - | Auto-populate agreed feedback comment | Yes | - | Blind marking | Yes | - | Marker anonymity | Yes | - | Blind marking | Yes | + | Number of times each submission should initially be marked. | 2 | + | Marker allocation enabled | Yes | + | Marker allocation strategy | Manual | + | Automatic agreement of marks | percentage distance | + | Automatic agreement range | 10 | + | View initial markers' grades | No | + | Auto-populate agreed feedback comment | Yes | + | Blind marking | Yes | + | Marker anonymity | Yes | Then I should see "Coursework – Double marking blind" @@ -74,16 +73,15 @@ Feature: Double marking - blind | Use marking deadline | Yes | | Types of file that students are allowed to submit | pdf | | Enable plagiarism flagging | Yes | - | Number of times each submission should initially be marked. | 2 | - | Marker allocation enabled | Yes | - | Marker allocation strategy | Manual | - | Automatic agreement of marks | percentage distance | - | Automatic agreement range | 10 | - | View initial markers' grades | No | - | Auto-populate agreed feedback comment | Yes | - | Blind marking | Yes | - | Marker anonymity | Yes | - | Blind marking | Yes | + | Number of times each submission should initially be marked. | 2 | + | Marker allocation enabled | Yes | + | Marker allocation strategy | Manual | + | Automatic agreement of marks | percentage distance | + | Automatic agreement range | 10 | + | View initial markers' grades | No | + | Auto-populate agreed feedback comment | Yes | + | Blind marking | Yes | + | Marker anonymity | Yes | And I follow "Coursework – Double marking blind" And I follow "Add markers" @@ -119,16 +117,15 @@ Feature: Double marking - blind | Use marking deadline | Yes | | Types of file that students are allowed to submit | pdf | | Enable plagiarism flagging | Yes | - | Number of times each submission should initially be marked. | 2 | - | Marker allocation enabled | Yes | - | Marker allocation strategy | Manual | - | Automatic agreement of marks | percentage distance | - | Automatic agreement range | 10 | - | View initial markers' grades | No | - | Auto-populate agreed feedback comment | Yes | - | Blind marking | Yes | - | Marker anonymity | Yes | - | Blind marking | Yes | + | Number of times each submission should initially be marked. | 2 | + | Marker allocation enabled | Yes | + | Marker allocation strategy | Manual | + | Automatic agreement of marks | percentage distance | + | Automatic agreement range | 10 | + | View initial markers' grades | No | + | Auto-populate agreed feedback comment | Yes | + | Blind marking | Yes | + | Marker anonymity | Yes | And I follow "Coursework – Double marking blind" And I follow "Add markers" @@ -176,16 +173,15 @@ Feature: Double marking - blind | Use marking deadline | Yes | | Types of file that students are allowed to submit | pdf | | Enable plagiarism flagging | Yes | - | Number of times each submission should initially be marked. | 2 | - | Marker allocation enabled | Yes | - | Marker allocation strategy | Manual | - | Automatic agreement of marks | percentage distance | - | Automatic agreement range | 10 | - | View initial markers' grades | No | - | Auto-populate agreed feedback comment | Yes | - | Blind marking | Yes | - | Marker anonymity | Yes | - | Blind marking | Yes | + | Number of times each submission should initially be marked. | 2 | + | Marker allocation enabled | Yes | + | Marker allocation strategy | Manual | + | Automatic agreement of marks | percentage distance | + | Automatic agreement range | 10 | + | View initial markers' grades | No | + | Auto-populate agreed feedback comment | Yes | + | Blind marking | Yes | + | Marker anonymity | Yes | Then I follow "Coursework – Double marking blind" And I follow "Add markers" From 0dd0220b195c7d621b4d70751e8a330872336ea3 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Thu, 20 Nov 2025 17:27:46 +0000 Subject: [PATCH 06/74] using new behat step 'And there is a double-blind marking coursework' --- tests/behat/behat_mod_coursework.php | 22 +++++ tests/behat/double_marking_blind.feature | 115 ++++++++--------------- 2 files changed, 59 insertions(+), 78 deletions(-) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 8d3a9edd..32af0aa6 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -1581,6 +1581,28 @@ public function there_is_a_coursework() { $this->coursework = coursework::find($generator->create_instance($coursework)->id); } + /** + * @Given /^there is a double-blind marking coursework$/ + */ + public function there_is_a_double_blind_marking_coursework() { + + /** + * @var $generator mod_coursework_generator + */ + $generator = testing_util::get_data_generator()->get_plugin_generator('mod_coursework'); + + $coursework = new stdClass(); + $coursework->course = $this->course; + $coursework->startdate = time(); + $coursework->deadline = strtotime('+15 minutes'); + $coursework->numberofgraders = 2; + $coursework->blindmarking = true; + $coursework->allocationenabled = true; + $coursework->filetypes = "pdf"; + + $this->coursework = coursework::find($generator->create_instance($coursework)->id); + } + /** * @Then /^I should see the title of the coursework on the page$/ */ diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 696115c9..dac6d588 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -1,4 +1,4 @@ -@mod @mod_coursework +@mod @mod_coursework @double-marking-blind Feature: Double marking - blind In order to ensure double marking works correctly As an admin @@ -11,9 +11,6 @@ Feature: Double marking - blind And the following "custom fields" exist: | name | shortname | category | type | | Course Year | course_year | CLC | text | - And the following "courses" exist: - | fullname | shortname | format | customfield_course_year | - | Course 1 | C1 | topics | ##now##%Y## | And the following "roles" exist: | shortname | name | archetype | | courseworkmarker | courseworkmarker | teacher | @@ -27,18 +24,10 @@ Feature: Double marking - blind | student1 | Student | 1 | student1@example.com | | student2 | Student | 2 | student2@example.com | | student3 | Student | 3 | student3@example.com | - And the following "course enrolments" exist: - | user | course | role | - | teacher1 | C1 | teacher | - | marker1 | C1 | teacher | - | marker2 | C1 | teacher | - | marker3 | C1 | teacher | - | student1 | C1 | student | - | student2 | C1 | student | - | student3 | C1 | student | Scenario: Create coursework assignment with double marking - Given I am on the "Course 1" "course" page logged in as "admin" + Given there is a course + And I am on the "Course 1" "course" page logged in as "admin" And I add a coursework activity to course "Course 1" section "2" and I fill the form with: | Coursework title | Coursework – Double marking blind | | Formative or summative? | Summative - counts towards the final module mark | @@ -62,28 +51,16 @@ Feature: Double marking - blind Then I should see "Coursework – Double marking blind" Scenario: Add markers - Given I am on the "Course 1" "course" page logged in as "admin" - And I add a coursework activity to course "Course 1" section "2" and I fill the form with: - | Coursework title | Coursework – Double marking blind | - | Formative or summative? | Summative - counts towards the final module mark | - | Description | Test coursework description | - | Display description on course page | Yes | - | Start date | ##now## | - | Deadline for submissions: | ##now + 15 minutes## | - | Use marking deadline | Yes | - | Types of file that students are allowed to submit | pdf | - | Enable plagiarism flagging | Yes | - | Number of times each submission should initially be marked. | 2 | - | Marker allocation enabled | Yes | - | Marker allocation strategy | Manual | - | Automatic agreement of marks | percentage distance | - | Automatic agreement range | 10 | - | View initial markers' grades | No | - | Auto-populate agreed feedback comment | Yes | - | Blind marking | Yes | - | Marker anonymity | Yes | + Given there is a course + And there is a double-blind marking coursework + And the following "course enrolments" exist: + | user | course | role | + | marker1 | C1 | teacher | + | marker2 | C1 | teacher | + | marker3 | C1 | teacher | - And I follow "Coursework – Double marking blind" + And I am on the "Course 1" "course" page logged in as "admin" + And I follow "Coursework 1" And I follow "Add markers" And I follow "courseworkmarker" @@ -106,28 +83,19 @@ Feature: Double marking - blind And I should not see "marker 3" in the "Potential users" "field" Scenario: Allocate markers - Given I am on the "Course 1" "course" page logged in as "admin" - And I add a coursework activity to course "Course 1" section "2" and I fill the form with: - | Coursework title | Coursework – Double marking blind | - | Formative or summative? | Summative - counts towards the final module mark | - | Description | Test coursework description | - | Display description on course page | Yes | - | Start date | ##now## | - | Deadline for submissions: | ##now + 15 minutes## | - | Use marking deadline | Yes | - | Types of file that students are allowed to submit | pdf | - | Enable plagiarism flagging | Yes | - | Number of times each submission should initially be marked. | 2 | - | Marker allocation enabled | Yes | - | Marker allocation strategy | Manual | - | Automatic agreement of marks | percentage distance | - | Automatic agreement range | 10 | - | View initial markers' grades | No | - | Auto-populate agreed feedback comment | Yes | - | Blind marking | Yes | - | Marker anonymity | Yes | + Given there is a course + And there is a double-blind marking coursework + And the following "course enrolments" exist: + | user | course | role | + | marker1 | C1 | teacher | + | marker2 | C1 | teacher | + | marker3 | C1 | teacher | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | - And I follow "Coursework – Double marking blind" + And I am on the "Course 1" "course" page logged in as "admin" + And I follow "Coursework 1" And I follow "Add markers" And I follow "courseworkmarker" @@ -162,28 +130,19 @@ Feature: Double marking - blind And I should not see "marker 3" in the "Student 3" "table_row" Scenario: Check anonymity - Given I am on the "Course 1" "course" page logged in as "admin" - And I add a coursework activity to course "Course 1" section "2" and I fill the form with: - | Coursework title | Coursework – Double marking blind | - | Formative or summative? | Summative - counts towards the final module mark | - | Description | Test coursework description | - | Display description on course page | Yes | - | Start date | ##now## | - | Deadline for submissions: | ##now + 15 minutes## | - | Use marking deadline | Yes | - | Types of file that students are allowed to submit | pdf | - | Enable plagiarism flagging | Yes | - | Number of times each submission should initially be marked. | 2 | - | Marker allocation enabled | Yes | - | Marker allocation strategy | Manual | - | Automatic agreement of marks | percentage distance | - | Automatic agreement range | 10 | - | View initial markers' grades | No | - | Auto-populate agreed feedback comment | Yes | - | Blind marking | Yes | - | Marker anonymity | Yes | + Given there is a course + And there is a double-blind marking coursework + And the following "course enrolments" exist: + | user | course | role | + | marker1 | C1 | teacher | + | marker2 | C1 | teacher | + | marker3 | C1 | teacher | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + And I am on the "Course 1" "course" page logged in as "admin" - Then I follow "Coursework – Double marking blind" + Then I follow "Coursework 1" And I follow "Add markers" And I follow "courseworkmarker" @@ -209,7 +168,7 @@ Feature: Double marking - blind And I log out And I am on the "Course 1" "course" page logged in as "marker1" - And I follow "Coursework – Double marking blind" + And I follow "Coursework 1" Then I should see "Submissions" And I should see "Hidden" And I should not see "Student 1" From c11656df2e431fe228b28245513604fa66dfd38d Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Thu, 20 Nov 2025 19:19:58 +0000 Subject: [PATCH 07/74] Scenario: Add extension to a student --- tests/behat/behat_mod_coursework.php | 1 + tests/behat/double_marking_blind.feature | 55 ++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 32af0aa6..227739d9 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -1598,6 +1598,7 @@ public function there_is_a_double_blind_marking_coursework() { $coursework->numberofgraders = 2; $coursework->blindmarking = true; $coursework->allocationenabled = true; + $coursework->extensionsenabled = true; $coursework->filetypes = "pdf"; $this->coursework = coursework::find($generator->create_instance($coursework)->id); diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index dac6d588..4b6e8104 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -174,3 +174,58 @@ Feature: Double marking - blind And I should not see "Student 1" And I should not see "Student 2" And I should not see "Student 3" + + @javascript + Scenario: Add extension to a student + Given there is a course + And there is a double-blind marking coursework + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | teacher | + | marker1 | C1 | teacher | + | marker2 | C1 | teacher | + | marker3 | C1 | teacher | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + And I am on the "Course 1" "course" page logged in as "admin" + + Then I follow "Coursework 1" + And I follow "Add markers" + And I follow "courseworkmarker" + + And I set the field "Potential users" to "marker 1 (marker1@example.com)" + And I press "Add" + And I set the field "Potential users" to "marker 2 (marker2@example.com)" + And I press "Add" + And I set the field "Potential users" to "marker 3 (marker3@example.com)" + And I press "Add" + + Then I follow "Allocate markers" + And I set the field "Allocation strategy" to "Manual" + And I press "Apply" + Then I should see "Please make sure markers are allocated" + + Then I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_1']//select" to "marker 1" + And I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_2']//select" to "marker 2" + And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_1']//select" to "marker 1" + And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_2']//select" to "marker 2" + And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_1']//select" to "marker 1" + And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_2']//select" to "marker 2" + And I press "Save" + + And I press "Actions" + And I wait until the page is ready + And I click on "Submission extension" "link" + And I wait until the page is ready + And I set the following fields to these values: + | extended_deadline[day] | 1 | + | extended_deadline[month] | January | + | extended_deadline[year] | 2027 | + | extended_deadline[hour] | 08 | + | extended_deadline[minute] | 00 | + And I click on "Save" "button" in the "Extended deadline" "dialogue" + And I should see "1 January 2027, 8:00 AM" in the "Student 1" "table_row" + Then I visit the coursework page + And I should see "1 January 2027, 8:00 AM" in the "Student 1" "table_row" + From e7897f4eac9ae891e5d25f9471a55a57b49a2c4d Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Fri, 21 Nov 2025 20:02:41 +0000 Subject: [PATCH 08/74] Scenario: Student can submit a PDF file Scenario: Student with extension can submit after deadline w/o being late Scenario: Student has no extension so submission is late Added custom Behat step: - Set an extension deadline for a student in a coursework. - For matching a late submitted date ignoring the time part --- tests/behat/behat_mod_coursework.php | 78 ++++++++++++++++++++ tests/behat/double_marking_blind.feature | 72 +++++++++++++++++- tests/files_for_uploading/Test_document.pdf | Bin 0 -> 12769 bytes 3 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 tests/files_for_uploading/Test_document.pdf diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 227739d9..2aa6f877 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -1582,6 +1582,10 @@ public function there_is_a_coursework() { } /** + * Create a coursework assessment with double-blind marking enabled. + * + * Example: And there is a double-blind marking coursework + * * @Given /^there is a double-blind marking coursework$/ */ public function there_is_a_double_blind_marking_coursework() { @@ -1599,6 +1603,7 @@ public function there_is_a_double_blind_marking_coursework() { $coursework->blindmarking = true; $coursework->allocationenabled = true; $coursework->extensionsenabled = true; + $coursework->allowlatesubmissions = true; $coursework->filetypes = "pdf"; $this->coursework = coursework::find($generator->create_instance($coursework)->id); @@ -3383,6 +3388,25 @@ public function i_should_see_submitted_date($date) { } } + /** + * For matching a late submitted date ignoring the time part + * + * Exmple: I should see late submitted date 4 July 2025 + * + * @Given /^I should see late submitted date "(?P(?:[^"]|\\")*)"$/ + */ + public function i_should_see_late_submitted_date($date) { + $page = $this->getsession()->getpage(); + $match = $page->find('xpath', "//li[starts-with(normalize-space(string()), 'Submitted Late $date')]"); + + if (!$match) { + throw new ExpectationException( + "Should have seen expected submitted date $date, but it was not there", + $this->getsession() + ); + } + } + /** * @Given /^sample marking includes student for stage (\d)$/ */ @@ -3644,4 +3668,58 @@ public function i_set_the_field_to_replacing_line_breaks($field, $value) { $value = str_replace('\n', chr(10), $value); $this->execute([behat_forms::class, 'i_set_the_field_to'], [$field, $value]); } + + /** + * Sets an extension deadline for a student in a coursework. + * + * Example: And the coursework extension for "Student 1" in "Coursework 1" is "1 January 2027 08:00" + * Example: And the coursework extension for "Student 1" in "Coursework 1" is "## + 1 month ##" + * + * @Given /^the coursework extension for "(?P(?:[^"]|\\")*)" in "(?P(?:[^"]|\\")*)" is "(?P(?:[^"]|\\")*)"$/ + */ + public function set_extension_for_user($fullname, $cwname, $datestr) { + global $DB; + + // Find the coursework by name. + $cw = $DB->get_record('coursework', ['name' => $cwname], '*', MUST_EXIST); + + // Find user by full name (firstname + lastname). + [$first, $last] = explode(' ', $fullname, 2); + + $user = $DB->get_record('user', [ + 'firstname' => $first, + 'lastname' => $last + ]); + + if (!$user) { + throw new Exception("Could not find user with name '{$fullname}'."); + } + + if (is_int($datestr)) { + $timestamp = $datestr; + } else { + $timestamp = strtotime($datestr); + } + + // See if an extension already exists. + $existing = $DB->get_record('coursework_extensions', [ + 'courseworkid' => $cw->id, + 'allocatableid' => $user->id, + 'allocatabletype' => 'user' + ]); + + $record = new stdClass(); + $record->courseworkid = $cw->id; + $record->allocatableid = $user->id; + $record->allocatabletype = 'user'; + $record->extended_deadline = $timestamp; + $record->createdbyid = 2; // Admin ID. + + if ($existing) { + $record->id = $existing->id; + $DB->update_record('coursework_extensions', $record); + } else { + $DB->insert_record('coursework_extensions', $record); + } + } } diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 4b6e8104..313c7de5 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -167,6 +167,7 @@ Feature: Double marking - blind And I press "Save" And I log out + And I am on the "Course 1" "course" page logged in as "marker1" And I follow "Coursework 1" Then I should see "Submissions" @@ -181,7 +182,6 @@ Feature: Double marking - blind And there is a double-blind marking coursework And the following "course enrolments" exist: | user | course | role | - | teacher1 | C1 | teacher | | marker1 | C1 | teacher | | marker2 | C1 | teacher | | marker3 | C1 | teacher | @@ -229,3 +229,73 @@ Feature: Double marking - blind Then I visit the coursework page And I should see "1 January 2027, 8:00 AM" in the "Student 1" "table_row" + @javascript @_file_upload + Scenario: Student can submit a PDF file + Given there is a course + And there is a double-blind marking coursework + And the following "course enrolments" exist: + | user | course | role | + | student1 | C1 | student | + + When I am on the "Course 1" "course" page logged in as "student1" + + And I follow "Coursework 1" + When I visit the coursework page + And I click on "Upload your submission" "link" + And I upload "mod/coursework/tests/files_for_uploading/Test_document.pdf" file to "Upload a file" filemanager + And I save the submission + Then I should be on the coursework page + And I should see the file on the page + And I should see the edit submission button + And I should see submission status "Submitted" + And I should see submitted date "##today##%d %B %Y##" + + @javascript @_file_upload + Scenario: Student with extension can submit after deadline w/o being late + Given there is a course + And there is a double-blind marking coursework + And the following "course enrolments" exist: + | user | course | role | + | student1 | C1 | student | + + # The coursework deadline has passed + Given the coursework deadline date is "##-5 minutes##" + And the coursework extension for "Student 1" in "Coursework 1" is "## + 1 month ##" + + # Student has extension so late submission is in time + When I am on the "Course 1" "course" page logged in as "student1" + And I follow "Coursework 1" + When I visit the coursework page + And I click on "Upload your submission" "link" + And I upload "mod/coursework/tests/files_for_uploading/Test_document.pdf" file to "Upload a file" filemanager + And I save the submission + Then I should be on the coursework page + And I should see the file on the page + And I should see the edit submission button + And I should see submission status "Submitted" + And I should see submitted date "##today##%d %B %Y##" + + @javascript @_file_upload + Scenario: Student has no extension so submission is late + Given there is a course + And there is a double-blind marking coursework + And the following "course enrolments" exist: + | user | course | role | + | student1 | C1 | student | + + # The coursework deadline has passed + And the coursework deadline date is "##-5 minutes##" + + When I am on the "Course 1" "course" page logged in as "student1" + And I follow "Coursework 1" + When I visit the coursework page + And I click on "Upload your submission" "link" + And I upload "mod/coursework/tests/files_for_uploading/Test_document.pdf" file to "Upload a file" filemanager + And I save the submission + Then I should be on the coursework page + And I should see the file on the page + And I should see submission status "Submitted" + And I should see "late" + And I should see late submitted date "##today##%d %B %Y##" + + diff --git a/tests/files_for_uploading/Test_document.pdf b/tests/files_for_uploading/Test_document.pdf new file mode 100644 index 0000000000000000000000000000000000000000..020ac8e5ff3edbb7fb391cb4d9cd8cc70320d531 GIT binary patch literal 12769 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 literal 0 HcmV?d00001 From 6a1c2b286e0040a8edc0990b1905113d55bef2e2 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Sun, 23 Nov 2025 18:13:50 +0000 Subject: [PATCH 09/74] No 'formative or summative' setting --- tests/behat/double_marking_blind.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 313c7de5..71caf113 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -30,7 +30,6 @@ Feature: Double marking - blind And I am on the "Course 1" "course" page logged in as "admin" And I add a coursework activity to course "Course 1" section "2" and I fill the form with: | Coursework title | Coursework – Double marking blind | - | Formative or summative? | Summative - counts towards the final module mark | | Description | Test coursework description | | Display description on course page | Yes | | Start date | ##now## | From 148714efd26b1c46c204031303bf4113adc995e3 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Sun, 23 Nov 2025 21:05:44 +0000 Subject: [PATCH 10/74] addressed GHA issues --- tests/behat/behat_mod_coursework.php | 4 ++-- tests/behat/double_marking_blind.feature | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 2aa6f877..04bd77ab 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -3688,7 +3688,7 @@ public function set_extension_for_user($fullname, $cwname, $datestr) { $user = $DB->get_record('user', [ 'firstname' => $first, - 'lastname' => $last + 'lastname' => $last, ]); if (!$user) { @@ -3705,7 +3705,7 @@ public function set_extension_for_user($fullname, $cwname, $datestr) { $existing = $DB->get_record('coursework_extensions', [ 'courseworkid' => $cw->id, 'allocatableid' => $user->id, - 'allocatabletype' => 'user' + 'allocatabletype' => 'user', ]); $record = new stdClass(); diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 71caf113..25191533 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -296,5 +296,3 @@ Feature: Double marking - blind And I should see submission status "Submitted" And I should see "late" And I should see late submitted date "##today##%d %B %Y##" - - From 07829342719a897094789e3f0cb6373aef7b7f4f Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Mon, 24 Nov 2025 15:04:38 +0000 Subject: [PATCH 11/74] added Behat steps to create a submission and/or finalise it for a given student --- tests/behat/behat_mod_coursework.php | 65 ++++++++++++++++++++++++ tests/behat/double_marking_blind.feature | 1 - 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 04bd77ab..48e87789 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -2722,6 +2722,35 @@ public function another_student_has_another_submission() { $this->othersubmission = $generator->create_submission($submission, $this->coursework); } + /** + * Creates a submission for a given student. + * + * Example: And the student "Student 1" has a submission + * + * @Given /^the student "(?P(?:[^"]|\\")*)" has a submission$/ + */ + public function student_has_a_submission($studentname) { + global $DB; + + // Find the user by full name (or username if you prefer) + [$firstname, $lastname] = explode(' ', $studentname, 2); + $user = $DB->get_record('user', [ + 'firstname' => $firstname, + 'lastname' => $lastname + ], '*', MUST_EXIST); + + /** + * @var $generator mod_coursework_generator + */ + $generator = testing_util::get_data_generator()->get_plugin_generator('mod_coursework'); + + $submission = new stdClass(); + $submission->allocatableid = $user->id; + $submission->allocatabletype = 'user'; // Always 'user' for a student. + + $this->submission = $generator->create_submission($submission, $this->coursework); + } + /** * @Given /^the group has a submission$/ */ @@ -2778,6 +2807,42 @@ public function the_submission_is_finalised($negate = false) { $this->submission->save(); } + /** + * Finalises (or un-finalises) a submission for a given student. + * + * Example: And the submission for "Student 1" is finalised + * Example: And the submission for "Student 1" is not finalised + * + * @Given /^the submission for "(?P(?:[^"]|\\")*)" is (not )?finalised$/ + */ + public function submission_for_student_is_finalised($studentname, $negate = false) { + global $DB; + + // Find the user by full name (first + last) + [$firstname, $lastname] = explode(' ', $studentname, 2); + $user = $DB->get_record('user', [ + 'firstname' => $firstname, + 'lastname' => $lastname + ], '*', MUST_EXIST); + + // Find the submission record + $record = $DB->get_record('coursework_submissions', [ + 'allocatableid' => $user->id, + 'allocatabletype' => 'user', + 'courseworkid' => $this->coursework->id + ], '*', MUST_EXIST); + + // Load the submission object + $submission = submission::build($record); + + // Set finalised status + $submission->finalisedstatus = $negate + ? submission::FINALISED_STATUS_NOT_FINALISED + : submission::FINALISED_STATUS_FINALISED; + + // Save using the submission class + $submission->save(); + } /** * @Then /^the file upload button should not be visible$/ */ diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 25191533..39fc7830 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -287,7 +287,6 @@ Feature: Double marking - blind When I am on the "Course 1" "course" page logged in as "student1" And I follow "Coursework 1" - When I visit the coursework page And I click on "Upload your submission" "link" And I upload "mod/coursework/tests/files_for_uploading/Test_document.pdf" file to "Upload a file" filemanager And I save the submission From 288c92f995f4dac4b6f17f8bed1660812421a189 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Tue, 25 Nov 2025 19:05:29 +0000 Subject: [PATCH 12/74] Scenario: Manager can submit on behalf of students. --- tests/behat/double_marking_blind.feature | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 39fc7830..f16d357c 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -295,3 +295,50 @@ Feature: Double marking - blind And I should see submission status "Submitted" And I should see "late" And I should see late submitted date "##today##%d %B %Y##" + + @javascript @_file_upload + Scenario: Manager can submit on behalf of students. + Given there is a course + And there is a double-blind marking coursework + And the following "course enrolments" exist: + | user | course | role | + | marker1 | C1 | teacher | + | marker2 | C1 | teacher | + | marker3 | C1 | teacher | + | student1 | C1 | student | + + And the student "Student 1" has a submission + And the submission for "Student 1" is finalised + + When I am on the "Course 1" "course" page logged in as "admin" + And I follow "Coursework 1" + Then I should see "Agree marking" + + # Unfinalise a submission. + And I press "Actions" + And I wait until the page is ready + And I click on "Unfinalise submission" "link" + And I wait until the page is ready + Then I should see "Are you sure you want to unfinalise the submission" + And I press "Yes" + Then I should not see "Agree marking" + + # Submit on behalf. + When I press "Actions" + And I wait until the page is ready + And I click on "Edit submission on behalf of this student" "link" + And I wait until the page is ready + Then I should see "Edit your submission" + And I should see "myfile.txt" + And I follow "myfile.txt" + And I wait until "Delete" "button" exists + # Delete previous file + # And I click on "Delete" "button" - does not work + And I click on "//div[contains(@class,'fp-select')]//button[contains(@class,'fp-file-delete')]" "xpath" + Then I should see "Are you sure you want to delete this file?" + And I press "Yes" + # Now upload a new file + And I upload "mod/coursework/tests/files_for_uploading/TestPDF1.pdf" file to "Upload a file" filemanager + And I save the submission + Then I should be on the coursework page + And I should not see "myfile.txt" From c66f97f67f7ec500d9ebb61c466bd31b3d152114 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Wed, 26 Nov 2025 11:58:58 +0000 Subject: [PATCH 13/74] added behat step i_assign_user_as_role_for_student_in_coursework() --- tests/behat/behat_mod_coursework.php | 89 ++++++++++++++++++---- tests/behat/double_marking_blind.feature | 95 +++++++----------------- 2 files changed, 100 insertions(+), 84 deletions(-) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 48e87789..3ee2071d 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -3748,17 +3748,7 @@ public function set_extension_for_user($fullname, $cwname, $datestr) { // Find the coursework by name. $cw = $DB->get_record('coursework', ['name' => $cwname], '*', MUST_EXIST); - // Find user by full name (firstname + lastname). - [$first, $last] = explode(' ', $fullname, 2); - - $user = $DB->get_record('user', [ - 'firstname' => $first, - 'lastname' => $last, - ]); - - if (!$user) { - throw new Exception("Could not find user with name '{$fullname}'."); - } + $user = $this->get_user_from_username($fullname); if (is_int($datestr)) { $timestamp = $datestr; @@ -3774,11 +3764,11 @@ public function set_extension_for_user($fullname, $cwname, $datestr) { ]); $record = new stdClass(); - $record->courseworkid = $cw->id; - $record->allocatableid = $user->id; - $record->allocatabletype = 'user'; + $record->courseworkid = $cw->id; + $record->allocatableid = $user->id; + $record->allocatabletype = 'user'; $record->extended_deadline = $timestamp; - $record->createdbyid = 2; // Admin ID. + $record->createdbyid = 2; // Admin ID. if ($existing) { $record->id = $existing->id; @@ -3787,4 +3777,73 @@ public function set_extension_for_user($fullname, $cwname, $datestr) { $DB->insert_record('coursework_extensions', $record); } } + + /** + * Assigns a user as a given assessor slot for a student within a coursework. + * + * Example: + * And I assign user "marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + * + * @Given /^I assign user "(?P(?:[^"]|\\")*)" as "(?P(?:[^"]|\\")*)" for "(?P(?:[^"]|\\")*)" in coursework "(?P(?:[^"]|\\")*)"$/ + */ + public function i_assign_user_as_role_for_student_in_coursework($marker, $role, $student, $cwname) { + global $DB; + + // Find the coursework by name. + $cw = $DB->get_record('coursework', ['name' => $cwname], '*', MUST_EXIST); + + $assignnr = (strstr($role, '2') || strstr($role, 'two')) ? 2 : 1; + + $marker = $this->get_user_from_username($marker); + $student = $this->get_user_from_username($student); + + // See if an allocation already exists. + $existing = $DB->get_record('coursework_allocation_pairs', [ + 'courseworkid' => $cw->id, + 'allocatableid' => $student->id, + 'allocatableuser' => $student->id, + 'stageidentifier' => 'assessor_' . $assignnr, + 'allocatabletype' => 'user', + ]); + + $record = new stdClass(); + $record->courseworkid = $cw->id; + $record->allocatableid = $student->id; + $record->allocatableuser = $student->id; + $record->assessorid = $marker->id; + $record->stageidentifier = 'assessor_' . $assignnr; + $record->allocatabletype = 'user'; + $record->ismanual = 1; + + if ($existing) { + $record->id = $existing->id; + $DB->update_record('coursework_allocation_pairs', $record); + } else { + $DB->insert_record('coursework_allocation_pairs', $record); + } + } + + /** + * Return a user record from a given full name ("firstname lastname") + * + * @param $fullname + * @return mixed|stdClass + * @throws dml_exception + */ + private function get_user_from_username($fullname) { + global $DB; + + // Find user by full name (firstname + lastname). + [$first, $last] = explode(' ', $fullname, 2); + + $user = $DB->get_record('user', [ + 'firstname' => $first, + 'lastname' => $last, + ]); + + if (!$user) { + throw new Exception("Could not find user with name '{$fullname}'."); + } + return $user; + } } diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index f16d357c..6a8858d1 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -86,26 +86,16 @@ Feature: Double marking - blind And there is a double-blind marking coursework And the following "course enrolments" exist: | user | course | role | - | marker1 | C1 | teacher | - | marker2 | C1 | teacher | - | marker3 | C1 | teacher | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | | student1 | C1 | student | | student2 | C1 | student | | student3 | C1 | student | And I am on the "Course 1" "course" page logged in as "admin" And I follow "Coursework 1" - And I follow "Add markers" - And I follow "courseworkmarker" - - When I set the field "Potential users" to "marker 1 (marker1@example.com)" - And I press "Add" - And I set the field "Potential users" to "marker 2 (marker2@example.com)" - And I press "Add" - And I set the field "Potential users" to "marker 3 (marker3@example.com)" - And I press "Add" - - When I follow "Allocate markers" + And I follow "Allocate markers" And I set the field "Allocation strategy" to "Manual" And I press "Apply" Then I should see "Please make sure markers are allocated" @@ -133,37 +123,20 @@ Feature: Double marking - blind And there is a double-blind marking coursework And the following "course enrolments" exist: | user | course | role | - | marker1 | C1 | teacher | - | marker2 | C1 | teacher | - | marker3 | C1 | teacher | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | | student1 | C1 | student | | student2 | C1 | student | | student3 | C1 | student | And I am on the "Course 1" "course" page logged in as "admin" - Then I follow "Coursework 1" - And I follow "Add markers" - And I follow "courseworkmarker" - - And I set the field "Potential users" to "marker 1 (marker1@example.com)" - And I press "Add" - And I set the field "Potential users" to "marker 2 (marker2@example.com)" - And I press "Add" - And I set the field "Potential users" to "marker 3 (marker3@example.com)" - And I press "Add" - - Then I follow "Allocate markers" - And I set the field "Allocation strategy" to "Manual" - And I press "Apply" - Then I should see "Please make sure markers are allocated" - - Then I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_1']//select" to "marker 1" - And I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_2']//select" to "marker 2" - And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_1']//select" to "marker 1" - And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_2']//select" to "marker 2" - And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_1']//select" to "marker 1" - And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_2']//select" to "marker 2" - And I press "Save" + And I assign user "marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "marker 2" as "Assessor 2" for "Student 1" in coursework "Coursework 1" + And I assign user "marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" + And I assign user "marker 2" as "Assessor 2" for "Student 2" in coursework "Coursework 1" + And I assign user "marker 1" as "Assessor 1" for "Student 3" in coursework "Coursework 1" + And I assign user "marker 2" as "Assessor 2" for "Student 3" in coursework "Coursework 1" And I log out @@ -181,38 +154,22 @@ Feature: Double marking - blind And there is a double-blind marking coursework And the following "course enrolments" exist: | user | course | role | - | marker1 | C1 | teacher | - | marker2 | C1 | teacher | - | marker3 | C1 | teacher | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | | student1 | C1 | student | | student2 | C1 | student | | student3 | C1 | student | And I am on the "Course 1" "course" page logged in as "admin" - Then I follow "Coursework 1" - And I follow "Add markers" - And I follow "courseworkmarker" - - And I set the field "Potential users" to "marker 1 (marker1@example.com)" - And I press "Add" - And I set the field "Potential users" to "marker 2 (marker2@example.com)" - And I press "Add" - And I set the field "Potential users" to "marker 3 (marker3@example.com)" - And I press "Add" - - Then I follow "Allocate markers" - And I set the field "Allocation strategy" to "Manual" - And I press "Apply" - Then I should see "Please make sure markers are allocated" - - Then I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_1']//select" to "marker 1" - And I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_2']//select" to "marker 2" - And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_1']//select" to "marker 1" - And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_2']//select" to "marker 2" - And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_1']//select" to "marker 1" - And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_2']//select" to "marker 2" - And I press "Save" + And I assign user "marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "marker 2" as "Assessor 2" for "Student 1" in coursework "Coursework 1" + And I assign user "marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" + And I assign user "marker 2" as "Assessor 2" for "Student 2" in coursework "Coursework 1" + And I assign user "marker 1" as "Assessor 1" for "Student 3" in coursework "Coursework 1" + And I assign user "marker 2" as "Assessor 2" for "Student 3" in coursework "Coursework 1" + And I follow "Coursework 1" And I press "Actions" And I wait until the page is ready And I click on "Submission extension" "link" @@ -302,9 +259,9 @@ Feature: Double marking - blind And there is a double-blind marking coursework And the following "course enrolments" exist: | user | course | role | - | marker1 | C1 | teacher | - | marker2 | C1 | teacher | - | marker3 | C1 | teacher | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | | student1 | C1 | student | And the student "Student 1" has a submission From d08a62ff19ae58cb69704b06c0f840ea6421ff77 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Wed, 26 Nov 2025 12:55:01 +0000 Subject: [PATCH 14/74] added Behat step i_click_add_mark_for_marker_in_row() added Behat step i_should_see_mark_in_row() --- tests/behat/behat_mod_coursework.php | 36 ++++++++++++++++++++++++ tests/behat/double_marking_blind.feature | 6 ++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 3ee2071d..f80bb552 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -3846,4 +3846,40 @@ private function get_user_from_username($fullname) { } return $user; } + + /** + * Clicks the "Add mark" button for a specific marker in a row. + * + * Example: And I click the "Add mark" button for marker "Marker 2" in row "1" + * + * @Given /^I click the "Add mark" button for marker "(?P(?:[^"]|\\")*)" in row "(?P\d+)"$/ + */ + public function i_click_add_mark_for_marker_in_row($marker_name, $row_number) { + $xpath = "(//tr[contains(@class,'mod-coursework-submissions-row')])[$row_number]". + "//li[.//a[normalize-space()='$marker_name']]". + "//a[@data-mark-action='addfeedback']"; + + $this->getSession()->getPage()->find('xpath', $xpath)->click(); + } + + /** + * Checks for a specific mark in a specific row. + * + * Example: Then I should see the mark "70" in row "1" + * + * @Then /^I should see the mark "(?P\d+)" in row "(?P\d+)"$/ + */ + public function i_should_see_mark_in_row($mark, $rownumber) { + $xpath = "(//table[contains(@class,'mod-coursework-submissions-table')]/tbody/tr)[$rownumber]//a[@data-mark-action='editfeedback']"; + + $element = $this->getSession()->getPage()->find('xpath', $xpath); + + if (!$element) { + throw new Exception("Mark element not found in row $rownumber"); + } + + if (trim($element->getText()) !== $mark) { + throw new Exception("Expected mark '$mark' but found '".$element->getText()."' in row $rownumber"); + } + } } diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 6a8858d1..107b4a51 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -214,11 +214,11 @@ Feature: Double marking - blind | user | course | role | | student1 | C1 | student | - # The coursework deadline has passed + # The coursework deadline has passed 5 minutes ago Given the coursework deadline date is "##-5 minutes##" - And the coursework extension for "Student 1" in "Coursework 1" is "## + 1 month ##" # Student has extension so late submission is in time + And the coursework extension for "Student 1" in "Coursework 1" is "## + 1 month ##" When I am on the "Course 1" "course" page logged in as "student1" And I follow "Coursework 1" When I visit the coursework page @@ -239,7 +239,7 @@ Feature: Double marking - blind | user | course | role | | student1 | C1 | student | - # The coursework deadline has passed + # The coursework deadline has passed 5 minutes ago And the coursework deadline date is "##-5 minutes##" When I am on the "Course 1" "course" page logged in as "student1" From 0247374fc3220ee4f0b1cf4e9ea45917eed3af92 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Wed, 26 Nov 2025 12:59:56 +0000 Subject: [PATCH 15/74] added test PDF files, addressed Code Checker issues --- tests/behat/behat_mod_coursework.php | 6 +++--- tests/files_for_uploading/TestPDF1.pdf | Bin 0 -> 14763 bytes tests/files_for_uploading/TestPDF2.pdf | Bin 0 -> 15337 bytes tests/files_for_uploading/TestPDF3.pdf | Bin 0 -> 15162 bytes 4 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 tests/files_for_uploading/TestPDF1.pdf create mode 100644 tests/files_for_uploading/TestPDF2.pdf create mode 100644 tests/files_for_uploading/TestPDF3.pdf diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index f80bb552..16b62b04 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -2736,7 +2736,7 @@ public function student_has_a_submission($studentname) { [$firstname, $lastname] = explode(' ', $studentname, 2); $user = $DB->get_record('user', [ 'firstname' => $firstname, - 'lastname' => $lastname + 'lastname' => $lastname, ], '*', MUST_EXIST); /** @@ -2822,14 +2822,14 @@ public function submission_for_student_is_finalised($studentname, $negate = fals [$firstname, $lastname] = explode(' ', $studentname, 2); $user = $DB->get_record('user', [ 'firstname' => $firstname, - 'lastname' => $lastname + 'lastname' => $lastname, ], '*', MUST_EXIST); // Find the submission record $record = $DB->get_record('coursework_submissions', [ 'allocatableid' => $user->id, 'allocatabletype' => 'user', - 'courseworkid' => $this->coursework->id + 'courseworkid' => $this->coursework->id, ], '*', MUST_EXIST); // Load the submission object diff --git a/tests/files_for_uploading/TestPDF1.pdf b/tests/files_for_uploading/TestPDF1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b9ad05143c677e76145a7d89a8a1f3d360449d7f GIT binary patch literal 14763 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%0An zPBRG)e#)9nteeesmFD~IY&e(2S8NqBrSJYlL+HIl_swDcUQ%o%Pgw(P=66*A{y;PB z&!){y1DeO=SwdGmY4pk4GpFy9WePcMFu!}NFHv>8V9> za;%lPHowL_YoD$Efje%dICawVZA_hH52bDH^&9(!er@+D=c)KJWz^om&rUS4OcmSN zc8N$`@u}q$=G#lV!%Ioyc4u-zQBsXPUkGYAGK_YqKK6VGmkYp1Gi6G9IvWPb2FmRo z2uZKztE#L8h6aw4;Q9Ozbomm9b)I(^AZ%jV&YltwC|CGd6Xjl6?5+aOQ83SMqdP!_ z5u3L0O3`P@LGv?(9jgG*_P5Zpq)V5Mx#TPY)u|)-AEa-(vyqy>AqTF{RefQUJ(V`xT-w5%qObrXQRP)(62kY>IF+r!q<8ep8ZuGw(^Lg+8Tgw$RmA;7 zoiut`^IS3}kFLnF*kh<#X`Er~mPY2|5aBEA{KLmy*~Juz1l; zgpK5Bec|n7)H!Z9ZF3Rv0ga!81g}WhS{})|VEHvJ8SZi9WY**-5-xK;+k=XWc-#w~ zkfRQ=Xq%B5V%>_l3V)5l0Ws37Yz2M$ntn#ZWvN>hm@a3C>`2#OTAyKI*0jaTw0NfM z3-;HZm!$tiZTIgd;MA<$pmI1mkfW))JyZ_IP7f7;x;UD-n?jGp(b*fDDyjlB%w1fq z9UTB1JS^-0Jvvc$YdbTjic*yKogO_v+1=R1%?AKIr}fv7FE2NGG*%IJH!DYIb9rMo zH!EvnSAe3EwVMyLXEEqeI;ijyK&R>GV)oB6v}@3xQ&@DM_Z(~--0V=v9y>1w9~-X@ z8{1px2il>$quKwt%D*XFyE;P3Px&S=f+)yQ`1>m1HP7dgKvp*NW;h#26 z4qm8K@4wsF*f{>v#swAl{f~N_9Gp;n?Eh>F?frk)IJwyV!!O$(4eS4`$I1O4HZC?c zsA%`U`{3mH&+&0_aQ)A=>|E?nJ>-A2b#pO>N)uiFIsmC^?PCsIE9eP6M@Og@@^3w^ zw1b5s04kpROPnhWf@*CA*tvPx`PkTa*myZP`MBP3u=8?59dVeOnDH3DGhyQqLi@j0 c`CE1C>IMbOUqNE$;^g2)qoEO3ltBCc0A<_*D*ylh literal 0 HcmV?d00001 diff --git a/tests/files_for_uploading/TestPDF2.pdf b/tests/files_for_uploading/TestPDF2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3c8f031c8408b6cc187df72b94d8538b9e969d1b GIT binary patch literal 15337 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 b{+3+3xV`}9FDJ2c@$vJcQBzAQNum9JNcqkv literal 0 HcmV?d00001 diff --git a/tests/files_for_uploading/TestPDF3.pdf b/tests/files_for_uploading/TestPDF3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..03695b0a434d997da64fb7244c13002131e78c90 GIT binary patch literal 15162 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 OXYR)>?2UkKfp-4T~Lt9&7I zp<-~s_0=9dR#~fl_>VEPyMj)i+GSEqd$?3 zq0Kd=Z`E2ej~OWIr*|g2Kde(-QSVC$ao%KK&W9mKCg-Yi7qL5b7cnzB@tg1N_e3Fr z!}|CPaDnlCNNU4wWoJhT4?$McH^k0t?KtLh^j@<5vG&9M$6hDlExrr33!e+2OBv&Y zC-QAZADhay*D3jw{G8*rHqZ*(PmDm^{Z1UurI60rs3XBuy;YJ`yVX~#@~IC3`&}RT zM?5=RYY(i4OKO*fg$y%@PrMA@TXc?V%Ny*-(bl>@JwdtJ^@I1F_pSHw(i-2<+t)(x zgh;&J^_ZU|@Oj;uc?=&tJ3cqvI9)hjIbS<3bS?a<51>3qV>?Z|<2zc~opXp=Y&R`B zPmKS*9ItjIZTl!KXGQ8rxjh&9PN+FB9^(xSld{tzvY0AWxOGqM1dQBus1LlO+%YYCVXo*!J0>to zQ(@bzK8vA8MnpwVk0uCM9vbCe3WY*3t%OW_!wpQ*s>s6&) zU}^VR%dhVff!+BYmM4)?2R&~|yZ0&7YQ9V74WbL&>VJT>eZ~&w-VhLbqT;({F-pwP z!_@pWCG||WDf^xII&5U^96!n25Tv18l7k%V^ik(uzaquan(!Ci^JWQQ+Dv0C8kt)?twW$b)bkAusD;wSXk`FjjpCM4=3QFuSlX-y?EQ$(+{0 zZ~|fDJQeEY=tFV)u={TMy!+bv`1-^`>q6^7f?Lmu@1EkDGR0Us|zg)p${GC!|mJXGw&I(x6N()25c&|()7R5i7vdk%71|Xd6e<*A4EF)X3HchP4Ym!g4TcY%50(#(4`vR2 z4t5T14n`YZ8&(@m47nDD6*&m$5Q!C@6%i>!AtW|5HUvEsUFYU9XfL4rBE&t^JtWA4 zupW0F)&Y4OsTEc~l%>zg1h*b%9;O=kKE$(6&jhocL6{kq<6d2Zu7{m>m4w~`*eoOw1($7&Q#A-d;mdAO-*{Rmf?RAX|WEB0(S z>eW;=k9&yO8lH>n3BNdSZ1%y7@|xy>#s4Ty?N?%SihfH~rmn!K2XlHu(us7W@-iZZ zZIN=5L4-#2aNuW7Gt#?DnO0?GBOWs$f#O(G>6U7#Ak>yX#$2L1EScH_UFjHKyEvP2w9*>QB& z_mtnK&XKgH*O&%6z%P#SuC3_pUM1m8=$Do9HGaKqi*U4DoL_JdTEy{Psn%!`?J)krDi%niui#o%NyHwYuL8v4D0x z)BMCjS|+x3ll^?lq2HI-ocXU}jYefZoGscK7ul_SqU}vO6gB4>59W&wiM>KZ`p7M? zD;f?#4vbV(tUY$cb5ux+lRFnm_8d~~7dFjaR3zOi@JT_=5|85|HG`$HWWJZes_Lj|e5c(*6)a=b2Nf+_oaP-zD?)fwn7bDY~IO$CWmd*}LD1uM64!!KgK3DJr<^ zaxcb>!sMokn$Rqa`O9^~6Va!rc?sU)AHUR>!{&v846KZcYfo)hqUHwZUz#S zJRNchXXym)e@~7j<_WfPb@(+p_Zf6Lk6UM-k^49_YTet4&Ng4)>%8=Xr%D@9yH=;y z!PZ&%CV43K2O+DCJ?5=`_6`rvcrKT}*1(thPU04x8O^k*K>V$#&!tL?ELjG^6+kgI zZwD=_NcyETBI`C?7CQ4(iMlB}yr20yvp#l0KMSf8-qMY!YiEp1+|74%Z z+rxFcaLXMP9GF6$Sf=p3AD!acXI%JcS-ApeCqlBVIvF)XrdW6X_;AQ}E95gqA8qq`*MgQ*rb_Vt`~j z-bftHmdla+rcWCq{strXjaI(ZUYw3cR%;#6#HJw`rn>AtUUq?_4ds1C`tYLL-rGbL z399K8y!XvHEUuARb$yE@$wEHkrb!#87w>|Sxb(UQ!bYL{CrA~XlTI6XpV5Bd#?iQM zY$cl#9pEkdX61wVZ~5MhxJjRFe#^< z-soyb%ehzhdKEi^E)RU@@$%cMfra?Hg##@9DNwIgc-;){uI*OQW8fJH78hTu(cKN}uDz1GA(5LE3 zNmKS1tr>wS_KumkV4LI=!4Ru(j3USH?{R*pI~E>1T1<`R@G*=SPN@g#!B3Rqp|*r3 z{df)(vLug{W&ef%PcbgI9Mx?={3G5$QdU|_6PIEL>au0nPnog-Qe8!)d) zaF%R}5;M}25#m(P8<$lLLfwkc(UVjVr@2ijQ>oE@sV!P<=NFkxt~mR|&}C#{zG4~= z55E-l`qQTRf&fDWNZ-@e-ln!~23K$Ws`$)ndkc#sQ=q1#2(7A(K&Y&&b!wxv!yZ{M zO8Pzn1LHmb-rim?U9rED=yci}+b0{|lE}c5dVcNa@ZyUBlH$m8c@5g8&k~6qu2b)o zJKH;0TtzM133Mh)9P5#BVfHvT$O zj>NOXL&Gs6tyC{pZ7)lgqj*L7MU8E9;8*T0$#<0m<>~jKU&UL4&dEv7c!49s?&Mbd zvZtrmj-`YmsF%boqG4>Gt^^vw>BS@tf`MI@EluPnyUr6}X9lE~kI_DP-GH#w@C(&Q6 zZLFlbHd|fDu_FdU`FP2~Tg){6pC`?71uQNvH6mZ<$vf4pUZXW0v>TpOV91@lK=Mb) zITnvXCgqsbfHC%NHoITEJx_;zex#;m32iPKUz_EwzKamo2jXoFNtAtkhx&n->?QjI z%9Xe0xfi?GHD~YDw0DbHLoC{w8bu5UQ#FZXRkbR8?Eo{PlYNeza_0O=HvC>+vc@QA zvd?Xqs%??L%rlRX(vV=L;_Eu$E1Q>)GraRO^trbj7gS2BHl+4gZ-=63SR-*GZe*RM z$GU_^_xD|>_cN)#>Wq2l5ZwufmmvH1(pAYsOcH;x=+>7n{bYtAwN(UqbanhJ6LCA$ zM#a#5VYgohfv(UA$;#c%v|)vUP7kxwgG7yS1H%|m?Wsr&kF0a`zma@ z26^UQe*vAf+p4ro|GAvIcbgj=w0qCP3SlkB>^b~)bpyiG1 zq*ziau9uBlg>!g(gmEXF`^aE3cy%@hp+=n+=quy5ACk(Y6u~N89w%2O!6KX2n`y7y z2&RR16U$weLgL`pN&cXiXKiPMd>NxTIad^_MOU`*Uj8C zUkAn`Z!ZGT`lqaBsk=pAi_o(jVSVB^vh|rhzv^aaMIvE;g%s-tDObRVD&}__6lney zo%vjxYgu;EvF7rs>XbK-caILz1-J?%udt2EBiE@mFnXF3?x1%6JR#6FqA#P+iz z^GjnBgQ#_1UW@>A9dWLWdq*RBx! zL9bFyr!;Aee5IPyNy~avA9|0?o=Czh<}KPq_9;`X>F1c()}qtixRp5Y<_y%L8?Iss z$6VNv$6Biw!y}W;%tQ)5ZK&Z_dT;nP!y0R9-&K<=xUma#d~|n7c4{-Lqewo#*538r z$VrdEb)xPmmcQoiifOmetxKHp{eH0}x1c+O zOHYtKmJ-t_yf@is$Mh=Cp!PL088y=>jY7wlspRwT*p8on;tKkfm6<(*k1{Rn-$|9F zslPBk|IF$56`gbJT>UD>sLTfQz9EHaiu4W7Ufsb_MZ)bgQ5Yp1&vKI8T)vMa>C@6m z%jAl-?VA?>QR+iJ`#&~B|dIC4%?s8&G&b+Iyu95_Dv(CmmFRf^ZOC>tRBUu zf@)+~l?Q_k;TNJ`;>U2Fh_=nd1bUslUq7p_O!LW+7BjIVtTg^#nxc2@50 z4C%!bM?cBEqkC?-5bMO+krS3aV5;H;#g=QX36^6|h;{viV71a0D z%{FlaPoJ3g>X*%?%YRry-0A5{M~K~CZ0gPU(eMsA@#~hg3A}7j@}G{rxgzM%iskzX zzrgy1LUeuirfJt3ZOpW-LS*8blpmJXh`Qw^S#?5Lc4FSaH+SPVB54x|8lpmKj#jbU zOf&J_)07?TUkZn(9!{_;5rfF^6Q5)X zzP;mp{M^+0^~Sm5)hk{WMn;x#c2-@txSXDVnd*1&>JxSoJx8Si3ie#7Rf5h&hF+X2 zCfg0{q}(?NigWZD%s>5Rf8t9`()Yd;DnfVF<>#!{VEAB;>$-T}()r@&th~0RM2T69 zJOih>9^nEYg{l`L#z8BGyUIrPz6=|eVevB!*T$KNx(~t{+OrEqx281g_=9g2qhw=0 zp|!G4HvU4)W<^vijTQ|){+2QYAB{lZEaCT(OAp0;nLDns9^1ScQ^bH4lLuRh){7g@ z*dIeb1lA3wjr7DPnVEChgH*ewtT||9rBIcTeFOLGBF-ezS%>UZtb_Jt`X95lZJm*P zd!i8oYzyRtc`wc@dyeK;IX67!ryCpT6xZXv)}SoT4$1{I#5*}|k@O}BT>e~##OCYh z2O!gc(-anSt zw%@qqnR@Zn3ZuKDrjWO()%(7>g^SBRmV{nFU8Dj@KbeP-XCZ|o=U`>QjfS$0s;sr6 zk;HsDfuj@Fd~?V=A#s|6L|er`wYyX&+Vdi9e_Ke)L9Z55^6eP%s|;-2T0y-I$?t8* zl|9}*mTX9SFv2}j*#$}7x9p)}TLYz~su-^aN{Ex=dz+hoT0ih;+iVVy>>s5P zxOn*qE6_tNj&|0LmzH)o-I?@9>)JN~o|yw@w81=o&*$pAPZ*OEgX3p!y_kB-&YN2H z$5jW&`;}GWzR(7eUh}OrY_*BXoZbE`?OYhJ3eB2 zRKVPLnAvSMUTGwVocle`BX=N4i|9m!JSJv>JS98VgqzNyEa6i^VhqP%Cob+%Lu86X zf!BfqN!UU?llk!Z{_RhUGS#xAc&jiG0j?6Om}+IE@4^|$L-wQca-Uwu#K?bs40_XV z@y+J6lt1Y9Hr2~|kZ$oR_lWSz#3WH+9G!mQQf?vNuK%2u0In<2QV8UDverD}kbr#R z318}ayZXqN(VhKt*B^Hm0{PVqlHd7y!#U`v>8hhAoN@E_=sc5ieDad+-VP1NDKuir zb%yzJaoMF<+0JmR=0t0#tZJ6gI+D)|{m6Y7rrmP2{s|M`c>%lXuChc#b;IH1$@Xne zIYO9|49nlOp_7BbAA{p~kj6WXlH)^Az}>YSO$xxchun30n^=3gEmwqzMGh?2I&P$q zi*uUauA$RR3lS}}<$dS#p&&@_gf=(e+K~M`ce{}Ib)H@2%cPiKuu;_11T52=sC<>mlD>Tr^vsXP;tUj=odNRuqw;~e>~H(Qi`&7DJ2n?em}!|`=X22)0M2O>B<7Os=6CuQX2H+F-oX(9hh*lB zriV5`7e#5MU4m1S(P2r9wd1s@#O!8r)wT=Vwk$!o2(}Li+b%s%#OE1AHh-yR)U|HKgauu;rZZ4TvL% zBdq9G7~cgL>~x4iD-<9l7+oew+v!GAy`ylJqy2+KzvGFYL>+ZNt zMggpzLI%Gg)>l34y(aJ2MmT2qCRPr|(hKe1a5Yt<%DEEP&RgUx?|BXT#Bepm40nF- z*}52`^PJtuHYek4;#sy*Zrs~QSvMEiP;aD<_bf|fvR^C8;yusmmUkD+`N+Cf)FBqN zAmST}nQWy}7a4HNkiUsb%{L{J zc&bb+sv$xa?)-+WpOfr$`P2p68c@DGzc|@ZW{764yv_TUo6%>isLp8fl#hmdPRF~| zY1+gN$L}7)e>fTME7`}*ns6Kf7VnTBk=Tas`!|VEi5Xpy98n|p8{f(Ig?A4la|I}i9fln^pf`&HwsJC6ysENcV**dUm;a(fqNhAs^wyX zhEEqv3PE13U2NGqpLtV)q6 znf@-$J-cc9i`?L=8`I^x#?|DZll;JXtGiSidNw(saJ}!J6rkTnde`y~b0yuDVXZ>e zt-k~r#7bRk5N!4DA0km)4;4C3s^1X{&Wwn?B6yv47*O{nv}s~AUj0b@=xpc~W|wQ0 zZzpKa%l;r|BZ+K!ylkn&q)(+W`htLJHdYlD<$M*r2ZjCN%O)*|HxbYGI=_w znl7W7pD!G|c7ljCs^-q`&*DsjEQ%OU^M2R?E=Ir7@e*8>(lt)3CJpRHQC&r2i&5E( z^kWqlrG?2zCUC^KSwi`WwvsVnrWwy}s*S>Q@ixy)+S1J4@^($r1h0;wUoNAdo#EE` z{o!U|shql?H9pA|T@Td(MuYmJeSjk&+o*d+n_`XLR3`mZi_x;sLehRrLV|*)MR7aV z(%#nd$4{`voy+Nm5XHv*slb|)ky*knVRI3^Dz4>hlf;Ctr!?Db4(~V|ebp=EW|i#> zqIY;-SH9k{gZv ze=Z;|4-ZsXYX$t<#sy8}`%?>a`rF3E#SPt;-`78F?ChLS+2jARaSK32$p3ER;$nwN zpa0$Vr}V#UT-<#B;g_99fcJm*<>H2Fc>h;lZubAuj#mJxZ~o)yf7Zdx1=V`~yN!dJ zhy7n{9&V;kNvGSNd{lK?KTGIdK{FwpouL}iKN?RqIVUS;AXIevN8~IAhH93DxlK*^ zIL)|C`OGbOx!8I5p_!1Td>jHC=2m Date: Wed, 26 Nov 2025 13:11:31 +0000 Subject: [PATCH 16/74] Scenario: Mark the assignments --- tests/behat/double_marking_blind.feature | 59 ++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 107b4a51..b055792e 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -299,3 +299,62 @@ Feature: Double marking - blind And I save the submission Then I should be on the coursework page And I should not see "myfile.txt" + + @javascript @_file_upload + Scenario: Mark the assignments + Given there is a course + And there is a double-blind marking coursework + And the following "course enrolments" exist: + | user | course | role | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + + And I am on the "Course 1" "course" page logged in as "admin" + And I assign user "marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "marker 2" as "Assessor 2" for "Student 1" in coursework "Coursework 1" + And I assign user "marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" + And I assign user "marker 2" as "Assessor 2" for "Student 2" in coursework "Coursework 1" + And I assign user "marker 1" as "Assessor 2" for "Student 3" in coursework "Coursework 1" + And I assign user "marker 2" as "Assessor 1" for "Student 3" in coursework "Coursework 1" + + And the student "Student 1" has a submission + And the submission for "Student 1" is finalised + And the student "Student 2" has a submission + And the submission for "Student 2" is finalised + And the student "Student 3" has a submission + And the submission for "Student 3" is finalised + + And I log out + And I am on the "Course 1" "course" page logged in as "marker1" + And I follow "Coursework 1" + + When I click the "Add mark" button for marker "marker 1" in row "1" + Then I should see "Marking for Hidden" + When I set the following fields to these values: + | Mark | 70 | + | Comment | Test comment 1 | + And I upload "mod/coursework/tests/files_for_uploading/Test_document.pdf" file to "Upload a file" filemanager + And I press "Save as draft" + + When I click the "Add mark" button for marker "marker 1" in row "2" + Then I should see "Marking for Hidden" + When I set the following fields to these values: + | Mark | 70 | + | Comment | Test comment 2 | + And I press "Save as draft" + + When I click the "Add mark" button for marker "marker 1" in row "3" + Then I should see "Marking for Hidden" + When I set the following fields to these values: + | Mark | 70 | + | Comment | Test comment 3 | + And I press "Save as draft" + + Then I should see "Submissions" + Then I should see the mark "70" in row "1" + Then I should see the mark "70" in row "2" + Then I should see the mark "70" in row "3" From fab04ba55d25a3c5e3d0b156912b72af1016a422 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Wed, 26 Nov 2025 17:06:46 +0000 Subject: [PATCH 17/74] addressed more Code Checker issues --- tests/behat/behat_mod_coursework.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 16b62b04..86f9a5be 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -3852,11 +3852,11 @@ private function get_user_from_username($fullname) { * * Example: And I click the "Add mark" button for marker "Marker 2" in row "1" * - * @Given /^I click the "Add mark" button for marker "(?P(?:[^"]|\\")*)" in row "(?P\d+)"$/ + * @Given /^I click the "Add mark" button for marker "(?P(?:[^"]|\\")*)" in row "(?P\d+)"$/ */ - public function i_click_add_mark_for_marker_in_row($marker_name, $row_number) { - $xpath = "(//tr[contains(@class,'mod-coursework-submissions-row')])[$row_number]". - "//li[.//a[normalize-space()='$marker_name']]". + public function i_click_add_mark_for_marker_in_row($markername, $rownumber) { + $xpath = "(//tr[contains(@class,'mod-coursework-submissions-row')])[$rownumber]" . + "//li[.//a[normalize-space()='$markername']]" . "//a[@data-mark-action='addfeedback']"; $this->getSession()->getPage()->find('xpath', $xpath)->click(); @@ -3879,7 +3879,7 @@ public function i_should_see_mark_in_row($mark, $rownumber) { } if (trim($element->getText()) !== $mark) { - throw new Exception("Expected mark '$mark' but found '".$element->getText()."' in row $rownumber"); + throw new Exception("Expected mark '$mark' but found '" . $element->getText() . "' in row $rownumber"); } } } From cf63821e79b9f58fbeb631aae6c48fdf2427056c Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Mon, 8 Dec 2025 19:11:05 +0000 Subject: [PATCH 18/74] defining courseworkmarker role capabilities --- tests/behat/behat_mod_coursework.php | 45 ++++++++++++++++++++++++ tests/behat/double_marking_blind.feature | 26 ++++++++++---- 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 86f9a5be..507ea0db 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -3882,4 +3882,49 @@ public function i_should_see_mark_in_row($mark, $rownumber) { throw new Exception("Expected mark '$mark' but found '" . $element->getText() . "' in row $rownumber"); } } + + /** + * Assigns capabilities to a role. + * + * Example usage in .feature: + * And the role "courseworkmarker" has the following capabilities: + * | capability | permission | + * | mod/coursework:addgeneralfeedback | allow | + * + * @Given /^the role "(?P(?:[^"]|\\")*)" has the following capabilities:$/ + * @param string $rolename Role shortname + * @param Behat\Gherkin\Node\TableNode $table + */ + public function role_has_capabilities($rolename, \Behat\Gherkin\Node\TableNode $table) { + global $DB; + + $role = $DB->get_record('role', ['shortname' => $rolename]); + if (!$role) { + throw new Exception("Role with shortname '$rolename' does not exist."); + } + + $context = context_system::instance(); + + foreach ($table->getHash() as $row) { + $capability = $row['capability']; + $permission = strtolower($row['permission'] ?? 'allow'); + + switch ($permission) { + case 'allow': + $permissionvalue = CAP_ALLOW; + break; + case 'prevent': + $permissionvalue = CAP_PREVENT; + break; + case 'prohibit': + $permissionvalue = CAP_PROHIBIT; + break; + default: + throw new Exception("Unknown permission '$permission' for capability '$capability'."); + } + + // Assign the capability to the role in system context. + assign_capability($capability, $permissionvalue, $role->id, $context->id); + } + } } diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index b055792e..fb57d03d 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -13,8 +13,22 @@ Feature: Double marking - blind | Course Year | course_year | CLC | text | And the following "roles" exist: | shortname | name | archetype | - | courseworkmarker | courseworkmarker | teacher | - | uclnoneditingtutor | uclnoneditingtutor | teacher | + | courseworkmarker | courseworkmarker | | + | norole | norole | | + And the role "courseworkmarker" has the following capabilities: + | capability | permission | + | mod/coursework:addallocatedagreedgrade | allow | + | mod/coursework:addgeneralfeedback | allow | + | mod/coursework:addinitialgrade | allow | + | mod/coursework:addplagiarismflag | allow | + | mod/coursework:editagreedgrade | allow | + | mod/coursework:editallocatedagreedgrade | allow | + | mod/coursework:editinitialgrade | allow | + | mod/coursework:grade | allow | + | mod/coursework:receivesubmissionnotifications | allow | + | mod/coursework:updateplagiarismflag | allow | + | mod/coursework:view | allow | + | mod/coursework:viewextensions | allow | And the following "users" exist: | username | firstname | lastname | email | | teacher1 | teacher | 1 | teacher1@example.com | @@ -53,10 +67,10 @@ Feature: Double marking - blind Given there is a course And there is a double-blind marking coursework And the following "course enrolments" exist: - | user | course | role | - | marker1 | C1 | teacher | - | marker2 | C1 | teacher | - | marker3 | C1 | teacher | + | user | course | role | + | marker1 | C1 | teacher | + | marker2 | C1 | student | + | marker3 | C1 | norole | And I am on the "Course 1" "course" page logged in as "admin" And I follow "Coursework 1" From bd3323230a80882173717851128a90acbef332b0 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Tue, 9 Dec 2025 13:25:55 +0000 Subject: [PATCH 19/74] 'percentage distance' => 'Percentage distance' --- tests/behat/double_marking_blind.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index fb57d03d..c44ec24f 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -54,7 +54,7 @@ Feature: Double marking - blind | Number of times each submission should initially be marked. | 2 | | Marker allocation enabled | Yes | | Marker allocation strategy | Manual | - | Automatic agreement of marks | percentage distance | + | Automatic agreement of marks | Percentage distance | | Automatic agreement range | 10 | | View initial markers' grades | No | | Auto-populate agreed feedback comment | Yes | From 4d149219a417183961ca7865bf1e7bdaf23df850 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Wed, 10 Dec 2025 18:39:46 +0000 Subject: [PATCH 20/74] defining correct roles for courseworkexamoffice, courseworkmarker and courseworkmoderator --- tests/behat/behat_mod_coursework.php | 127 +++++++++ tests/behat/double_marking_blind.feature | 330 ++++++++++++++--------- 2 files changed, 330 insertions(+), 127 deletions(-) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 507ea0db..44200813 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -3927,4 +3927,131 @@ public function role_has_capabilities($rolename, \Behat\Gherkin\Node\TableNode $ assign_capability($capability, $permissionvalue, $role->id, $context->id); } } + + /** + * Inserts a grade directly into coursework_feedbacks table. + * + * @When /^the submission from "(?P[^"]*)" for coursework "(?P[^"]*)" is marked by "(?P[^"]*)" with:$/ + */ + public function mark_coursework_submission_directly( + string $studentfullname, + string $courseworkname, + string $markerfullname, + TableNode $table + ) { + global $DB; + + // Resolve student. + [$studentfirstname, $studentlastname] = explode(' ', $studentfullname, 2); + if (!$student = $DB->get_record('user', ['firstname' => $studentfirstname, 'lastname' => $studentlastname])) { + throw new ExpectationException("Student '$studentfullname' not found", $this->getSession()); + } + + // Resolve marker. + [$markerfirstname, $markerlastname] = explode(' ', $markerfullname, 2); + if (!$marker = $DB->get_record('user', ['firstname' => $markerfirstname, 'lastname' => $markerlastname])) { + throw new ExpectationException("Marker '$markerfullname' not found", $this->getSession()); + } + + // Resolve coursework module by name. + if (!$coursework = $DB->get_record('coursework', ['name' => $courseworkname])) { + throw new ExpectationException("Coursework '$courseworkname' not found", $this->getSession()); + } + + // Resolve submission for this student. + $submission = $DB->get_record('coursework_submissions', [ + 'courseworkid' => $coursework->id, + 'allocatableid' => $student->id, + ]); + if (!$submission) { + throw new ExpectationException("Submission for '$studentfullname' not found", $this->getSession()); + } + + // Resolve marker allocation. + $allocation = $DB->get_record('coursework_allocation_pairs', [ + 'courseworkid' => $coursework->id, + 'assessorid' => $marker->id, + 'allocatableid' => $student->id, + ]); + if (!$allocation) { + throw new ExpectationException("Marker '$markerfullname' for '$studentfullname' not found", $this->getSession()); + } + + // Extract the provided table values + $data = $table->getRowsHash(); + + $mark = isset($data['Mark']) ? floatval($data['Mark']) : null; + $comment = $data['Comment'] ?? ''; + + if ($mark === null) { + throw new ExpectationException("Missing 'Mark' value in table", $this->getSession()); + } + + // Check if there is already a feedback record. + $existing = $DB->get_record('coursework_feedbacks', [ + 'submissionid' => $submission->id, + 'assessorid' => $marker->id, + 'stageidentifier' => $allocation->stageidentifier, + ]); + + // Insert/update feedback record. + $feedback = new stdClass(); + $feedback->submissionid = $submission->id; + $feedback->assessorid = $marker->id; + $feedback->stageidentifier = $allocation->stageidentifier; + $feedback->grade = $mark; + $feedback->feedbackcomment = $comment; + $feedback->lasteditedbyuser = $marker->id; + $feedback->timecreated = time(); + $feedback->timemodified = time(); + + if ($existing) { + $feedback->id = $existing->id; + $DB->update_record('coursework_feedbacks', $feedback); + } else { + $DB->insert_record('coursework_feedbacks', $feedback); + } + } + + /** + * Allows one role to assign another role. + * + * Example: + * Given the role "Manager" is allowed to assign role "Teacher". + * + * @Given /^the role "(?P(?:[^"]|\\")*)" is allowed to assign role "(?P(?:[^"]|\\")*)"$/ + */ + public function allow_role_to_assign_role(string $fromrolename, string $torolename) { + global $DB; + + // Get roles by shortname or fullname. + $fromrole = $DB->get_record('role', ['shortname' => $fromrolename]); + if (!$fromrole) { + $fromrole = $DB->get_record('role', ['name' => $fromrolename]); + } + if (!$fromrole) { + throw new Exception("Role '$fromrole' could not be found."); + } + + $torole = $DB->get_record('role', ['shortname' => $torolename]); + if (!$torole) { + $torole = $DB->get_record('role', ['name' => $torolename]); + } + if (!$torole) { + throw new Exception("Role '$torole' could not be found."); + } + + // Check if record already exists. + $exists = $DB->record_exists('role_allow_assign', [ + 'roleid' => $fromrole->id, + 'allowassign' => $torole->id, + ]); + + if (!$exists) { + $record = new stdClass(); + $record->roleid = $fromrole->id; + $record->allowassign = $torole->id; + $DB->insert_record('role_allow_assign', $record); + } + } } diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index c44ec24f..b19b2a69 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -8,13 +8,50 @@ Feature: Double marking - blind Given the following "custom field categories" exist: | name | component | area | itemid | | CLC | core_course | course | 0 | + And the following "custom fields" exist: | name | shortname | category | type | | Course Year | course_year | CLC | text | + And the following "roles" exist: - | shortname | name | archetype | - | courseworkmarker | courseworkmarker | | - | norole | norole | | + | shortname | name | archetype | + | courseworkexamoffice | courseworkexamoffice | | + | courseworkmarker | courseworkmarker | | + | courseworkmoderator | courseworkmoderator | | + | norole | norole | | + + And the role "courseworkexamoffice" has the following capabilities: + | capability | permission | + | mod/coursework:addinstance | allow | + | moodle/role:assign | allow | + | mod/coursework:addagreedgrade | allow | + | mod/coursework:addallocatedagreedgrade | allow | + | mod/coursework:addgeneralfeedback | allow | + | mod/coursework:addinitialgrade | allow | + | mod/coursework:addplagiarismflag | allow | + | mod/coursework:administergrades | allow | + | mod/coursework:allocate | allow | + | mod/coursework:canexportfinalgrades | allow | + | mod/coursework:editagreedgrade | allow | + | mod/coursework:editallocatedagreedgrade | allow | + | mod/coursework:editinitialgrade | allow | + | mod/coursework:editpersonaldeadline | allow | + | mod/coursework:grade | allow | + | mod/coursework:grantextensions | allow | + | mod/coursework:moderate | allow | + | mod/coursework:publish | allow | + | mod/coursework:receivesubmissionnotifications | allow | + | mod/coursework:revertfinalised | allow | + | mod/coursework:submitonbehalfof | allow | + | mod/coursework:updateplagiarismflag | allow | + | mod/coursework:view | allow | + | mod/coursework:viewallgradesatalltimes | allow | + | mod/coursework:viewallstudents | allow | + | mod/coursework:viewanonymous | allow | + | mod/coursework:viewextensions | allow | + | moodle/course:manageactivities | allow | + | moodle/calendar:manageentries | allow | + And the role "courseworkmarker" has the following capabilities: | capability | permission | | mod/coursework:addallocatedagreedgrade | allow | @@ -29,19 +66,39 @@ Feature: Double marking - blind | mod/coursework:updateplagiarismflag | allow | | mod/coursework:view | allow | | mod/coursework:viewextensions | allow | + + And the role "courseworkmoderator" has the following capabilities: + | capability | permission | + | mod/coursework:addplagiarismflag | allow | + | mod/coursework:grade | allow | + | mod/coursework:moderate | allow | + | mod/coursework:updateplagiarismflag | allow | + | mod/coursework:view | allow | + | mod/coursework:viewallgradesatalltimes | allow | + | mod/coursework:viewextensions | allow | + + And the role "courseworkexamoffice" is allowed to assign role "courseworkmoderator" + And the role "courseworkexamoffice" is allowed to assign role "courseworkmarker" + And the following "users" exist: - | username | firstname | lastname | email | - | teacher1 | teacher | 1 | teacher1@example.com | - | marker1 | marker | 1 | marker1@example.com | - | marker2 | marker | 2 | marker2@example.com | - | marker3 | marker | 3 | marker3@example.com | - | student1 | Student | 1 | student1@example.com | - | student2 | Student | 2 | student2@example.com | - | student3 | Student | 3 | student3@example.com | + | username | firstname | lastname | email | + | teacher1 | Teacher | 1 | teacher1@example.com | + | manager | Assessment | Manager | manager@example.com | + | marker1 | Marker | 1 | marker1@example.com | + | marker2 | Marker | 2 | marker2@example.com | + | marker3 | Marker | 3 | marker3@example.com | + | moderator1 | Moderator | 1 | moderator1@example.com | + | student1 | Student | 1 | student1@example.com | + | student2 | Student | 2 | student2@example.com | + | student3 | Student | 3 | student3@example.com | - Scenario: Create coursework assignment with double marking Given there is a course - And I am on the "Course 1" "course" page logged in as "admin" + And the following "course enrolments" exist: + | user | course | role | + | manager | C1 | courseworkexamoffice | + + Scenario: Create coursework assignment with double marking + Given I am on the "Course 1" "course" page logged in as "manager" And I add a coursework activity to course "Course 1" section "2" and I fill the form with: | Coursework title | Coursework – Double marking blind | | Description | Test coursework description | @@ -64,93 +121,90 @@ Feature: Double marking - blind Then I should see "Coursework – Double marking blind" Scenario: Add markers - Given there is a course - And there is a double-blind marking coursework + Given there is a double-blind marking coursework And the following "course enrolments" exist: - | user | course | role | - | marker1 | C1 | teacher | - | marker2 | C1 | student | - | marker3 | C1 | norole | + | user | course | role | + | marker1 | C1 | teacher | + | marker2 | C1 | student | + | marker3 | C1 | norole | - And I am on the "Course 1" "course" page logged in as "admin" + And I am on the "Course 1" "course" page logged in as "manager" And I follow "Coursework 1" And I follow "Add markers" And I follow "courseworkmarker" - Then I should see "marker 1" in the "Potential users" "field" - And I should see "marker 2" in the "Potential users" "field" - And I should see "marker 3" in the "Potential users" "field" + Then I should see "Marker 1" in the "Potential users" "field" + And I should see "Marker 2" in the "Potential users" "field" + And I should see "Marker 3" in the "Potential users" "field" - When I set the field "Potential users" to "marker 1 (marker1@example.com)" + When I set the field "Potential users" to "Marker 1" And I press "Add" - And I set the field "Potential users" to "marker 2 (marker2@example.com)" + And I set the field "Potential users" to "Marker 2" And I press "Add" - And I set the field "Potential users" to "marker 3 (marker3@example.com)" + And I set the field "Potential users" to "Marker 3" And I press "Add" - Then I should see "marker 1" in the "Existing users" "field" - And I should see "marker 2" in the "Existing users" "field" - And I should see "marker 3" in the "Existing users" "field" - And I should not see "marker 1" in the "Potential users" "field" - And I should not see "marker 2" in the "Potential users" "field" - And I should not see "marker 3" in the "Potential users" "field" + Then I should see "Marker 1" in the "Existing users" "field" + And I should see "Marker 2" in the "Existing users" "field" + And I should see "Marker 3" in the "Existing users" "field" + And I should not see "Marker 1" in the "Potential users" "field" + And I should not see "Marker 2" in the "Potential users" "field" + And I should not see "Marker 3" in the "Potential users" "field" Scenario: Allocate markers - Given there is a course - And there is a double-blind marking coursework + Given there is a double-blind marking coursework And the following "course enrolments" exist: - | user | course | role | - | marker1 | C1 | courseworkmarker | - | marker2 | C1 | courseworkmarker | - | marker3 | C1 | courseworkmarker | - | student1 | C1 | student | - | student2 | C1 | student | - | student3 | C1 | student | - - And I am on the "Course 1" "course" page logged in as "admin" + | user | course | role | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + + And I am on the "Course 1" "course" page logged in as "manager" And I follow "Coursework 1" And I follow "Allocate markers" And I set the field "Allocation strategy" to "Manual" And I press "Apply" Then I should see "Please make sure markers are allocated" - When I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_1']//select" to "marker 1" - And I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_2']//select" to "marker 2" - And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_1']//select" to "marker 1" - And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_2']//select" to "marker 2" - And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_1']//select" to "marker 1" - And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_2']//select" to "marker 2" + When I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_1']//select" to "Marker 1" + And I set the field with xpath "//tr[contains(.,'Student 1')]//td[@class='assessor_2']//select" to "Marker 2" + And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_1']//select" to "Marker 1" + And I set the field with xpath "//tr[contains(.,'Student 2')]//td[@class='assessor_2']//select" to "Marker 2" + And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_1']//select" to "Marker 1" + And I set the field with xpath "//tr[contains(.,'Student 3')]//td[@class='assessor_2']//select" to "Marker 2" And I press "Save" - Then I should see "marker 1" in the "Student 1" "table_row" - And I should see "marker 2" in the "Student 1" "table_row" - And I should not see "marker 3" in the "Student 1" "table_row" - And I should see "marker 1" in the "Student 2" "table_row" - And I should see "marker 2" in the "Student 2" "table_row" - And I should not see "marker 3" in the "Student 2" "table_row" - And I should see "marker 1" in the "Student 3" "table_row" - And I should see "marker 2" in the "Student 3" "table_row" - And I should not see "marker 3" in the "Student 3" "table_row" + Then I should see "Marker 1" in the "Student 1" "table_row" + And I should see "Marker 2" in the "Student 1" "table_row" + And I should not see "Marker 3" in the "Student 1" "table_row" + And I should see "Marker 1" in the "Student 2" "table_row" + And I should see "Marker 2" in the "Student 2" "table_row" + And I should not see "Marker 3" in the "Student 2" "table_row" + And I should see "Marker 1" in the "Student 3" "table_row" + And I should see "Marker 2" in the "Student 3" "table_row" + And I should not see "Marker 3" in the "Student 3" "table_row" Scenario: Check anonymity - Given there is a course - And there is a double-blind marking coursework + Given there is a double-blind marking coursework And the following "course enrolments" exist: - | user | course | role | - | marker1 | C1 | courseworkmarker | - | marker2 | C1 | courseworkmarker | - | marker3 | C1 | courseworkmarker | - | student1 | C1 | student | - | student2 | C1 | student | - | student3 | C1 | student | - And I am on the "Course 1" "course" page logged in as "admin" - - And I assign user "marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" - And I assign user "marker 2" as "Assessor 2" for "Student 1" in coursework "Coursework 1" - And I assign user "marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" - And I assign user "marker 2" as "Assessor 2" for "Student 2" in coursework "Coursework 1" - And I assign user "marker 1" as "Assessor 1" for "Student 3" in coursework "Coursework 1" - And I assign user "marker 2" as "Assessor 2" for "Student 3" in coursework "Coursework 1" + | user | course | role | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + And I am on the "Course 1" "course" page logged in as "manager" + + And I assign user "Marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 2" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 2" for "Student 2" in coursework "Coursework 1" + And I assign user "Marker 1" as "Assessor 1" for "Student 3" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 2" for "Student 3" in coursework "Coursework 1" And I log out @@ -164,24 +218,23 @@ Feature: Double marking - blind @javascript Scenario: Add extension to a student - Given there is a course - And there is a double-blind marking coursework + Given there is a double-blind marking coursework And the following "course enrolments" exist: - | user | course | role | - | marker1 | C1 | courseworkmarker | - | marker2 | C1 | courseworkmarker | - | marker3 | C1 | courseworkmarker | - | student1 | C1 | student | - | student2 | C1 | student | - | student3 | C1 | student | - And I am on the "Course 1" "course" page logged in as "admin" - - And I assign user "marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" - And I assign user "marker 2" as "Assessor 2" for "Student 1" in coursework "Coursework 1" - And I assign user "marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" - And I assign user "marker 2" as "Assessor 2" for "Student 2" in coursework "Coursework 1" - And I assign user "marker 1" as "Assessor 1" for "Student 3" in coursework "Coursework 1" - And I assign user "marker 2" as "Assessor 2" for "Student 3" in coursework "Coursework 1" + | user | course | role | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + And I am on the "Course 1" "course" page logged in as "manager" + + And I assign user "Marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 2" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 2" for "Student 2" in coursework "Coursework 1" + And I assign user "Marker 1" as "Assessor 1" for "Student 3" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 2" for "Student 3" in coursework "Coursework 1" And I follow "Coursework 1" And I press "Actions" @@ -201,8 +254,7 @@ Feature: Double marking - blind @javascript @_file_upload Scenario: Student can submit a PDF file - Given there is a course - And there is a double-blind marking coursework + Given there is a double-blind marking coursework And the following "course enrolments" exist: | user | course | role | | student1 | C1 | student | @@ -222,8 +274,7 @@ Feature: Double marking - blind @javascript @_file_upload Scenario: Student with extension can submit after deadline w/o being late - Given there is a course - And there is a double-blind marking coursework + Given there is a double-blind marking coursework And the following "course enrolments" exist: | user | course | role | | student1 | C1 | student | @@ -247,8 +298,7 @@ Feature: Double marking - blind @javascript @_file_upload Scenario: Student has no extension so submission is late - Given there is a course - And there is a double-blind marking coursework + Given there is a double-blind marking coursework And the following "course enrolments" exist: | user | course | role | | student1 | C1 | student | @@ -269,21 +319,20 @@ Feature: Double marking - blind @javascript @_file_upload Scenario: Manager can submit on behalf of students. - Given there is a course - And there is a double-blind marking coursework + Given there is a double-blind marking coursework And the following "course enrolments" exist: - | user | course | role | - | marker1 | C1 | courseworkmarker | - | marker2 | C1 | courseworkmarker | - | marker3 | C1 | courseworkmarker | - | student1 | C1 | student | + | user | course | role | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | And the student "Student 1" has a submission And the submission for "Student 1" is finalised - When I am on the "Course 1" "course" page logged in as "admin" + When I am on the "Course 1" "course" page logged in as "manager" And I follow "Coursework 1" - Then I should see "Agree marking" + Then I should see "Add mark" # Unfinalise a submission. And I press "Actions" @@ -316,24 +365,23 @@ Feature: Double marking - blind @javascript @_file_upload Scenario: Mark the assignments - Given there is a course - And there is a double-blind marking coursework + Given there is a double-blind marking coursework And the following "course enrolments" exist: - | user | course | role | - | marker1 | C1 | courseworkmarker | - | marker2 | C1 | courseworkmarker | - | marker3 | C1 | courseworkmarker | - | student1 | C1 | student | - | student2 | C1 | student | - | student3 | C1 | student | - - And I am on the "Course 1" "course" page logged in as "admin" - And I assign user "marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" - And I assign user "marker 2" as "Assessor 2" for "Student 1" in coursework "Coursework 1" - And I assign user "marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" - And I assign user "marker 2" as "Assessor 2" for "Student 2" in coursework "Coursework 1" - And I assign user "marker 1" as "Assessor 2" for "Student 3" in coursework "Coursework 1" - And I assign user "marker 2" as "Assessor 1" for "Student 3" in coursework "Coursework 1" + | user | course | role | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + + And I am on the "Course 1" "course" page logged in as "manager" + And I assign user "Marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 2" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 2" for "Student 2" in coursework "Coursework 1" + And I assign user "Marker 1" as "Assessor 2" for "Student 3" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 1" for "Student 3" in coursework "Coursework 1" And the student "Student 1" has a submission And the submission for "Student 1" is finalised @@ -346,7 +394,7 @@ Feature: Double marking - blind And I am on the "Course 1" "course" page logged in as "marker1" And I follow "Coursework 1" - When I click the "Add mark" button for marker "marker 1" in row "1" + When I click the "Add mark" button for marker "Marker 1" in row "1" Then I should see "Marking for Hidden" When I set the following fields to these values: | Mark | 70 | @@ -354,14 +402,14 @@ Feature: Double marking - blind And I upload "mod/coursework/tests/files_for_uploading/Test_document.pdf" file to "Upload a file" filemanager And I press "Save as draft" - When I click the "Add mark" button for marker "marker 1" in row "2" + When I click the "Add mark" button for marker "Marker 1" in row "2" Then I should see "Marking for Hidden" When I set the following fields to these values: | Mark | 70 | | Comment | Test comment 2 | And I press "Save as draft" - When I click the "Add mark" button for marker "marker 1" in row "3" + When I click the "Add mark" button for marker "Marker 1" in row "3" Then I should see "Marking for Hidden" When I set the following fields to these values: | Mark | 70 | @@ -372,3 +420,31 @@ Feature: Double marking - blind Then I should see the mark "70" in row "1" Then I should see the mark "70" in row "2" Then I should see the mark "70" in row "3" + + Scenario: Verify assignment shows in marking + Given there is a double-blind marking coursework + And the following "course enrolments" exist: + | user | course | role | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | student1 | C1 | student | + + And I assign user "Marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 2" for "Student 1" in coursework "Coursework 1" + + And the student "Student 1" has a submission + And the submission for "Student 1" is finalised + + And the submission from "Student 1" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 70 | + | Comment | Excellent work! | + + And the submission from "Student 1" for coursework "Coursework 1" is marked by "Marker 2" with: + | Mark | 65 | + | Comment | Nice! | + + And I am on the "Course 1" "course" page logged in as "student1" + And I follow "Coursework 1" + Then I should see "Submission" + And I should see "In marking" + And I should not see "Edit your submission" From a2a022c9d35dbe2f7af283834421c993c2875069 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Thu, 11 Dec 2025 17:09:02 +0000 Subject: [PATCH 21/74] Scenario: Moderate the assessment --- tests/behat/behat_mod_coursework.php | 308 +++++++++++++++++------ tests/behat/double_marking_blind.feature | 83 +++++- 2 files changed, 299 insertions(+), 92 deletions(-) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 44200813..bf309e28 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -1599,7 +1599,7 @@ public function there_is_a_double_blind_marking_coursework() { $coursework->course = $this->course; $coursework->startdate = time(); $coursework->deadline = strtotime('+15 minutes'); - $coursework->numberofgraders = 2; + $coursework->numberofmarkers = 2; $coursework->blindmarking = true; $coursework->allocationenabled = true; $coursework->extensionsenabled = true; @@ -1609,6 +1609,35 @@ public function there_is_a_double_blind_marking_coursework() { $this->coursework = coursework::find($generator->create_instance($coursework)->id); } + /** + * Create a coursework assessment with moderation and blind marking enabled. + * + * Example: And there is a blind marking moderation coursework + * + * @Given /^there is a blind marking moderation coursework$/ + */ + public function there_is_a_blind_marking_moderation_coursework() { + + /** + * @var $generator mod_coursework_generator + */ + $generator = testing_util::get_data_generator()->get_plugin_generator('mod_coursework'); + + $coursework = new stdClass(); + $coursework->course = $this->course; + $coursework->startdate = time(); + $coursework->deadline = strtotime('+30 minutes'); + $coursework->numberofmarkers = 1; + $coursework->blindmarking = true; + $coursework->allocationenabled = true; + $coursework->extensionsenabled = true; + $coursework->allowlatesubmissions = true; + $coursework->moderationagreementenabled = true; + $coursework->filetypes = "pdf"; + + $this->coursework = coursework::find($generator->create_instance($coursework)->id); + } + /** * @Then /^I should see the title of the coursework on the page$/ */ @@ -2722,35 +2751,6 @@ public function another_student_has_another_submission() { $this->othersubmission = $generator->create_submission($submission, $this->coursework); } - /** - * Creates a submission for a given student. - * - * Example: And the student "Student 1" has a submission - * - * @Given /^the student "(?P(?:[^"]|\\")*)" has a submission$/ - */ - public function student_has_a_submission($studentname) { - global $DB; - - // Find the user by full name (or username if you prefer) - [$firstname, $lastname] = explode(' ', $studentname, 2); - $user = $DB->get_record('user', [ - 'firstname' => $firstname, - 'lastname' => $lastname, - ], '*', MUST_EXIST); - - /** - * @var $generator mod_coursework_generator - */ - $generator = testing_util::get_data_generator()->get_plugin_generator('mod_coursework'); - - $submission = new stdClass(); - $submission->allocatableid = $user->id; - $submission->allocatabletype = 'user'; // Always 'user' for a student. - - $this->submission = $generator->create_submission($submission, $this->coursework); - } - /** * @Given /^the group has a submission$/ */ @@ -2807,42 +2807,6 @@ public function the_submission_is_finalised($negate = false) { $this->submission->save(); } - /** - * Finalises (or un-finalises) a submission for a given student. - * - * Example: And the submission for "Student 1" is finalised - * Example: And the submission for "Student 1" is not finalised - * - * @Given /^the submission for "(?P(?:[^"]|\\")*)" is (not )?finalised$/ - */ - public function submission_for_student_is_finalised($studentname, $negate = false) { - global $DB; - - // Find the user by full name (first + last) - [$firstname, $lastname] = explode(' ', $studentname, 2); - $user = $DB->get_record('user', [ - 'firstname' => $firstname, - 'lastname' => $lastname, - ], '*', MUST_EXIST); - - // Find the submission record - $record = $DB->get_record('coursework_submissions', [ - 'allocatableid' => $user->id, - 'allocatabletype' => 'user', - 'courseworkid' => $this->coursework->id, - ], '*', MUST_EXIST); - - // Load the submission object - $submission = submission::build($record); - - // Set finalised status - $submission->finalisedstatus = $negate - ? submission::FINALISED_STATUS_NOT_FINALISED - : submission::FINALISED_STATUS_FINALISED; - - // Save using the submission class - $submission->save(); - } /** * @Then /^the file upload button should not be visible$/ */ @@ -3782,7 +3746,7 @@ public function set_extension_for_user($fullname, $cwname, $datestr) { * Assigns a user as a given assessor slot for a student within a coursework. * * Example: - * And I assign user "marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + * And I assign user "Marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" * * @Given /^I assign user "(?P(?:[^"]|\\")*)" as "(?P(?:[^"]|\\")*)" for "(?P(?:[^"]|\\")*)" in coursework "(?P(?:[^"]|\\")*)"$/ */ @@ -3792,7 +3756,12 @@ public function i_assign_user_as_role_for_student_in_coursework($marker, $role, // Find the coursework by name. $cw = $DB->get_record('coursework', ['name' => $cwname], '*', MUST_EXIST); - $assignnr = (strstr($role, '2') || strstr($role, 'two')) ? 2 : 1; + if (strtolower($role) === "moderator") { + $stageidentifier = "moderator"; + } else { + $assignnr = (strstr($role, '2') || strstr($role, 'two')) ? 2 : 1; + $stageidentifier = 'assessor_' . $assignnr; + } $marker = $this->get_user_from_username($marker); $student = $this->get_user_from_username($student); @@ -3802,7 +3771,7 @@ public function i_assign_user_as_role_for_student_in_coursework($marker, $role, 'courseworkid' => $cw->id, 'allocatableid' => $student->id, 'allocatableuser' => $student->id, - 'stageidentifier' => 'assessor_' . $assignnr, + 'stageidentifier' => $stageidentifier, 'allocatabletype' => 'user', ]); @@ -3811,7 +3780,7 @@ public function i_assign_user_as_role_for_student_in_coursework($marker, $role, $record->allocatableid = $student->id; $record->allocatableuser = $student->id; $record->assessorid = $marker->id; - $record->stageidentifier = 'assessor_' . $assignnr; + $record->stageidentifier = $stageidentifier; $record->allocatabletype = 'user'; $record->ismanual = 1; @@ -3941,17 +3910,8 @@ public function mark_coursework_submission_directly( ) { global $DB; - // Resolve student. - [$studentfirstname, $studentlastname] = explode(' ', $studentfullname, 2); - if (!$student = $DB->get_record('user', ['firstname' => $studentfirstname, 'lastname' => $studentlastname])) { - throw new ExpectationException("Student '$studentfullname' not found", $this->getSession()); - } - - // Resolve marker. - [$markerfirstname, $markerlastname] = explode(' ', $markerfullname, 2); - if (!$marker = $DB->get_record('user', ['firstname' => $markerfirstname, 'lastname' => $markerlastname])) { - throw new ExpectationException("Marker '$markerfullname' not found", $this->getSession()); - } + $student = $this->get_user_from_username($studentfullname); + $marker = $this->get_user_from_username($markerfullname); // Resolve coursework module by name. if (!$coursework = $DB->get_record('coursework', ['name' => $courseworkname])) { @@ -3982,6 +3942,7 @@ public function mark_coursework_submission_directly( $mark = isset($data['Mark']) ? floatval($data['Mark']) : null; $comment = $data['Comment'] ?? ''; + $finalised = $data['Finalised'] ?? ''; if ($mark === null) { throw new ExpectationException("Missing 'Mark' value in table", $this->getSession()); @@ -4002,6 +3963,7 @@ public function mark_coursework_submission_directly( $feedback->grade = $mark; $feedback->feedbackcomment = $comment; $feedback->lasteditedbyuser = $marker->id; + $feedback->finalised = $finalised; $feedback->timecreated = time(); $feedback->timemodified = time(); @@ -4054,4 +4016,188 @@ public function allow_role_to_assign_role(string $fromrolename, string $torolena $DB->insert_record('role_allow_assign', $record); } } + + /** + * Creates a submission for a given student and coursework. + * + * Example: And the student "Student 1" has a submission for coursework "Coursework 1" + * + * @Given /^the student "(?P(?:[^"]|\\")*)" has a submission for coursework "(?P[^"]+)"$/ + */ + public function student_has_a_submission_for_coursework($studentfullname, $courseworkname) { + global $DB; + + $student = $this->get_user_from_username($studentfullname); + + // Resolve coursework. + if (!$coursework = $DB->get_record('coursework', ['name' => $courseworkname], '*')) { + throw new \moodle_exception("Coursework '{$courseworkname}' not found."); + } + // Get a coursework object. + $coursework = coursework::build($coursework); + + /** + * @var $generator mod_coursework_generator + */ + $generator = testing_util::get_data_generator()->get_plugin_generator('mod_coursework'); + + $submission = new stdClass(); + $submission->allocatableid = $student->id; + $submission->allocatabletype = 'user'; // Always 'user' for a student. + + $this->submission = $generator->create_submission($submission, $coursework); + } + + /** + * Finalises (or un-finalises) a submission to a coursework for a given student. + * + * Example: And the submission for "Student 1" in "Coursework 1" is finalised + * Example: And the submission for "Student 1" in "Coursework 1" is not finalised + * + * @Given /^the submission for "(?P(?:[^"]|\\")*)" in "(?P[^"]+)" is (not )?finalised$/ + */ + public function submission_for_student_in_coursework_is_finalised($studentfullname, $courseworkname, $negate = false) { + global $DB; + + $student = $this->get_user_from_username($studentfullname); + + // Resolve coursework. + if (!$coursework = $DB->get_record('coursework', ['name' => $courseworkname], '*')) { + throw new \moodle_exception("Coursework '{$courseworkname}' not found."); + } + + // Get student's submission. + if (!$submission = $DB->get_record('coursework_submissions', [ + 'allocatableid' => $student->id, + 'allocatabletype' => 'user', + 'courseworkid' => $coursework->id, + ])) { + throw new \moodle_exception("Submission for '{$studentfullname}' not found in '{$courseworkname}'."); + } + + // Set finalised status. + $submission->finalisedstatus = $negate + ? submission::FINALISED_STATUS_NOT_FINALISED + : submission::FINALISED_STATUS_FINALISED; + + // Save using the submission class. + $DB->update_record('coursework_submissions', $submission); + } + + /** + * Finalise a marker's feedback for a student's submission. + * + * Example: + * And the feedback for "Student 1" by "Marker 1" in "Coursework 1" is finalised + * + * @Given /^the feedback for "(?P[^"]+)" by "(?P[^"]+)" in "(?P[^"]+)" is finalised$/ + */ + public function finalise_feedback($studentfullname, $markerfullname, $courseworkname) { + global $DB; + + $student = $this->get_user_from_username($studentfullname); + $marker = $this->get_user_from_username($markerfullname); + + // Resolve coursework. + if (!$coursework = $DB->get_record('coursework', ['name' => $courseworkname], '*')) { + throw new \moodle_exception("Coursework '{$courseworkname}' not found."); + } + + // Get student's submission. + if (!$submission = $DB->get_record('coursework_submissions', [ + 'allocatableid' => $student->id, + 'allocatabletype' => 'user', + 'courseworkid' => $coursework->id, + ])) { + throw new \moodle_exception("Submission for '{$studentfullname}' not found in '{$courseworkname}'."); + } + + // Get marker’s feedback record. + if (!$feedback = $DB->get_record('coursework_feedbacks', [ + 'submissionid' => $submission->id, + 'assessorid' => $marker->id + ])) { + throw new \moodle_exception("Feedback by '{$markerfullname}' for '{$studentfullname}' not found."); + } + + // Update field. + $feedback->finalised = 1; + $DB->update_record('coursework_feedbacks', $feedback); + } + + /** + * Clicks a link inside the given table row. + * + * Example: + * Given I follow "Agree marking" in row "2" + * + * @Given /^I follow "(?P[^"]*)" in row "(?P\d+)"$/ + */ + public function i_follow_in_row($linktext, $rownumber) { + $session = $this->getSession(); + $page = $session->getPage(); + + // Find the table — assume there is only one submissions table on screen. + $table = $page->find('css', 'table.mod-coursework-submissions-table'); + if (!$table) { + throw new ExpectationException("Could not find submissions table.", $session); + } + + // Get all table body rows. + $rows = $table->findAll('css', 'tbody tr'); + if (empty($rows)) { + throw new ExpectationException("No table rows found in submissions table.", $session); + } + + $index = (int)$rownumber - 1; + if (!isset($rows[$index])) { + throw new ExpectationException("Row {$rownumber} does not exist.", $session); + } + + $row = $rows[$index]; + + // Try to find the link by exact text. + $link = $row->findLink($linktext); + if (!$link) { + // Maybe it's a button with that label. + $link = $row->find('named', ['button', $linktext]); + } + + if (!$link) { + throw new ExpectationException( + "Could not find a link or button '{$linktext}' in row {$rownumber}.", + $session + ); + } + + // Click it. + $link->click(); + } + + /** + * @Then /^I should see "(?P[^"]*)" in row "(?P\d+)"$/ + */ + public function i_should_see_text_in_row($text, $rownumber) { + $session = $this->getSession(); + $page = $session->getPage(); + + // Find the table body. + $tbody = $page->find('css', 'table.mod-coursework-submissions-table tbody'); + if (!$tbody) { + throw new Exception('Could not find coursework submissions table.'); + } + + // Get all rows. + $rows = $tbody->findAll('css', 'tr'); + if (!isset($rows[$rownumber - 1])) { + throw new Exception("Row {$rownumber} does not exist in the submissions table."); + } + + $row = $rows[$rownumber - 1]; + + // Check text inside the row. + if (strpos($row->getText(), $text) === false) { + throw new Exception("The text '{$text}' was not found in row {$rownumber}.\nRow contents: " . $row->getText()); + } + } } diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index b19b2a69..0dea6eac 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -1,4 +1,4 @@ -@mod @mod_coursework @double-marking-blind +@mod @mod_coursework @double-marking-blind @mod_coursework_dmb Feature: Double marking - blind In order to ensure double marking works correctly As an admin @@ -327,8 +327,8 @@ Feature: Double marking - blind | marker3 | C1 | courseworkmarker | | student1 | C1 | student | - And the student "Student 1" has a submission - And the submission for "Student 1" is finalised + And the student "Student 1" has a submission for coursework "Coursework 1" + And the submission for "Student 1" in "Coursework 1" is finalised When I am on the "Course 1" "course" page logged in as "manager" And I follow "Coursework 1" @@ -383,12 +383,12 @@ Feature: Double marking - blind And I assign user "Marker 1" as "Assessor 2" for "Student 3" in coursework "Coursework 1" And I assign user "Marker 2" as "Assessor 1" for "Student 3" in coursework "Coursework 1" - And the student "Student 1" has a submission - And the submission for "Student 1" is finalised - And the student "Student 2" has a submission - And the submission for "Student 2" is finalised - And the student "Student 3" has a submission - And the submission for "Student 3" is finalised + And the student "Student 1" has a submission for coursework "Coursework 1" + And the submission for "Student 1" in "Coursework 1" is finalised + And the student "Student 2" has a submission for coursework "Coursework 1" + And the submission for "Student 2" in "Coursework 1" is finalised + And the student "Student 3" has a submission for coursework "Coursework 1" + And the submission for "Student 3" in "Coursework 1" is finalised And I log out And I am on the "Course 1" "course" page logged in as "marker1" @@ -432,8 +432,8 @@ Feature: Double marking - blind And I assign user "Marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" And I assign user "Marker 2" as "Assessor 2" for "Student 1" in coursework "Coursework 1" - And the student "Student 1" has a submission - And the submission for "Student 1" is finalised + And the student "Student 1" has a submission for coursework "Coursework 1" + And the submission for "Student 1" in "Coursework 1" is finalised And the submission from "Student 1" for coursework "Coursework 1" is marked by "Marker 1" with: | Mark | 70 | @@ -448,3 +448,64 @@ Feature: Double marking - blind Then I should see "Submission" And I should see "In marking" And I should not see "Edit your submission" + + Scenario: Moderate the assessment + Given there is a blind marking moderation coursework + And the following "course enrolments" exist: + | user | course | role | + | moderator1 | C1 | courseworkmoderator | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + + And I assign user "Marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 2" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 1" for "Student 3" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 3" in coursework "Coursework 1" + + And the student "Student 1" has a submission for coursework "Coursework 1" + And the submission for "Student 1" in "Coursework 1" is finalised + And the student "Student 2" has a submission for coursework "Coursework 1" + And the submission for "Student 2" in "Coursework 1" is finalised + And the student "Student 3" has a submission for coursework "Coursework 1" + And the submission for "Student 3" in "Coursework 1" is finalised + + And the submission from "Student 1" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 70 | + | Comment | Excellent work! | + | Finalised | 1 | + + And the submission from "Student 2" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 75 | + | Comment | Superb work! | + | Finalised | 1 | + + And the submission from "Student 3" for coursework "Coursework 1" is marked by "Marker 2" with: + | Mark | 50 | + | Comment | I've seen worse... | + | Finalised | 1 | + +# Alternative separate step to finalise a feedback. +# And the feedback for "Student 1" by "Marker 1" in "Coursework 1" is finalised + + And I am on the "Course 1" "course" page logged in as "moderator1" + And I follow "Coursework 1" + And I follow "Agree marking" in row "1" + Then I should see "Moderation for" + And I set the field "Moderation agreement" to "Agreed" + And I press "Save changes" + And I follow "Agree marking" in row "2" + Then I should see "Moderation for" + And I set the field "Moderation agreement" to "Disagreed" + And I set the field "Comment" to "I don't like it!" + And I press "Save changes" + Then I should see "Agreed" in row "1" + Then I should see "Disagreed" in row "2" + When I follow "Disagreed" + And I wait until the page is ready + Then I should see "I don't like it!" From 91e9eb6ba6a39575b0e90f94bcc2208cb063cff5 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Fri, 12 Dec 2025 13:31:18 +0000 Subject: [PATCH 22/74] Scenario: Check moderation --- tests/behat/behat_mod_coursework.php | 85 +++++++++++++++++++++++- tests/behat/double_marking_blind.feature | 67 +++++++++++++++++++ 2 files changed, 151 insertions(+), 1 deletion(-) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index bf309e28..113baf7a 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -3937,7 +3937,7 @@ public function mark_coursework_submission_directly( throw new ExpectationException("Marker '$markerfullname' for '$studentfullname' not found", $this->getSession()); } - // Extract the provided table values + // Extract the provided table values. $data = $table->getRowsHash(); $mark = isset($data['Mark']) ? floatval($data['Mark']) : null; @@ -4200,4 +4200,87 @@ public function i_should_see_text_in_row($text, $rownumber) { throw new Exception("The text '{$text}' was not found in row {$rownumber}.\nRow contents: " . $row->getText()); } } + + /** + * Inserts a moderation directly into coursework_mod_agreements table. + * + * @When /^the submission from "(?P[^"]*)" for coursework "(?P[^"]*)" is moderated by "(?P[^"]*)" with:$/ + */ + public function moderate_coursework_submission_directly( + string $studentfullname, + string $courseworkname, + string $moderatorfullname, + TableNode $table + ) { + global $DB; + + $student = $this->get_user_from_username($studentfullname); + $moderator = $this->get_user_from_username($moderatorfullname); + + // Resolve coursework module by name. + if (!$coursework = $DB->get_record('coursework', ['name' => $courseworkname])) { + throw new ExpectationException("Coursework '$courseworkname' not found", $this->getSession()); + } + + // Resolve submission for this student. + $submission = $DB->get_record('coursework_submissions', [ + 'courseworkid' => $coursework->id, + 'allocatableid' => $student->id, + ]); + if (!$submission) { + throw new ExpectationException("Submission for '$studentfullname' not found", $this->getSession()); + } + + // Resolve moderator allocation. + $allocation = $DB->get_record('coursework_allocation_pairs', [ + 'courseworkid' => $coursework->id, + 'assessorid' => $moderator->id, + 'allocatableid' => $student->id, + 'stageidentifier' => 'moderator', + ]); + if (!$allocation) { + throw new ExpectationException("Moderator '$moderatorfullname' for '$studentfullname' not found", $this->getSession()); + } + + // Resolve feedback. + $params = ['submissionid' => $submission->id]; + $sql = "SELECT * + FROM {coursework_feedbacks} + WHERE submissionid = :submissionid + AND stageidentifier LIKE 'assessor_%'"; + $feedback = $DB->get_record_sql($sql, $params); + + if (!$feedback) { + throw new ExpectationException("Feedback for '$studentfullname' not found", $this->getSession()); + } + + // Extract the provided table values. + $data = $table->getRowsHash(); + $agreementtext = $data['Agreement'] ?? ''; + $comment = $data['Comment'] ?? ''; + + // Check if there is already an agreement record. + $existing = $DB->get_record('coursework_mod_agreements', [ + 'feedbackid' => $feedback->id, + 'moderatorid' => $moderator->id, + ]); + + // Insert/update agreement record. + $agreement = new stdClass(); + $agreement->feedbackid = $feedback->id; + $agreement->moderatorid = $moderator->id; + $agreement->agreement = $agreementtext; + $agreement->modcomment = $comment; + $agreement->modcommentformat = 1; + $agreement->lasteditedby = $moderator->id; + $agreement->timecreated = time(); + $agreement->timemodified = time(); + + if ($existing) { + $agreement->id = $existing->id; + $DB->update_record('coursework_mod_agreements', $agreement); + } else { + $DB->insert_record('coursework_mod_agreements', $agreement); + } + } } diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 0dea6eac..1d056f21 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -509,3 +509,70 @@ Feature: Double marking - blind When I follow "Disagreed" And I wait until the page is ready Then I should see "I don't like it!" + + Scenario: Check moderation + Given there is a blind marking moderation coursework + And the following "course enrolments" exist: + | user | course | role | + | moderator1 | C1 | courseworkmoderator | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + + And I assign user "Marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 2" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 1" for "Student 3" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 3" in coursework "Coursework 1" + + And the student "Student 1" has a submission for coursework "Coursework 1" + And the submission for "Student 1" in "Coursework 1" is finalised + And the student "Student 2" has a submission for coursework "Coursework 1" + And the submission for "Student 2" in "Coursework 1" is finalised + And the student "Student 3" has a submission for coursework "Coursework 1" + And the submission for "Student 3" in "Coursework 1" is finalised + + And the submission from "Student 1" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 70 | + | Comment | Excellent work! | + | Finalised | 1 | + + And the submission from "Student 2" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 75 | + | Comment | Superb work! | + | Finalised | 1 | + + And the submission from "Student 3" for coursework "Coursework 1" is marked by "Marker 2" with: + | Mark | 50 | + | Comment | I've seen worse... | + | Finalised | 1 | + + And the submission from "Student 1" for coursework "Coursework 1" is moderated by "Moderator 1" with: + | Agreement | agreed | + + And the submission from "Student 2" for coursework "Coursework 1" is moderated by "Moderator 1" with: + | Agreement | disagreed | + | Comment | I don't like it at all! | + + And I am on the "Course 1" "course" page logged in as "marker1" + And I follow "Coursework 1" + Then I should see "Agreed" in row "1" + Then I should see "Disagreed" in row "2" + + # See the moderation + And I follow "Disagreed" in row "2" + And I wait until the page is ready + Then I should see "I don't like it at all!" + And I press "Cancel" + + # Update marking + And I follow "75" in row "2" + When I set the following fields to these values: + | Mark | 65 | + | Comment | Updated mark | + And I press "Save as draft" + Then I should see "65" in row "2" From 3174877505a6f2ea1e783cb289ec4c20e9cc9525 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Fri, 12 Dec 2025 13:48:55 +0000 Subject: [PATCH 23/74] Scenario: Release the grades --- tests/behat/double_marking_blind.feature | 64 +++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 1d056f21..648ca287 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -95,7 +95,7 @@ Feature: Double marking - blind Given there is a course And the following "course enrolments" exist: | user | course | role | - | manager | C1 | courseworkexamoffice | + | manager | C1 | courseworkexamoffice | Scenario: Create coursework assignment with double marking Given I am on the "Course 1" "course" page logged in as "manager" @@ -576,3 +576,65 @@ Feature: Double marking - blind | Comment | Updated mark | And I press "Save as draft" Then I should see "65" in row "2" + + @javascript + Scenario: Release the grades + Given there is a blind marking moderation coursework + And the following "course enrolments" exist: + | user | course | role | + | moderator1 | C1 | courseworkmoderator | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + + And I assign user "Marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 2" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 1" for "Student 3" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 3" in coursework "Coursework 1" + + And the student "Student 1" has a submission for coursework "Coursework 1" + And the submission for "Student 1" in "Coursework 1" is finalised + And the student "Student 2" has a submission for coursework "Coursework 1" + And the submission for "Student 2" in "Coursework 1" is finalised + And the student "Student 3" has a submission for coursework "Coursework 1" + And the submission for "Student 3" in "Coursework 1" is finalised + + And the submission from "Student 1" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 70 | + | Comment | Excellent work! | + | Finalised | 1 | + + And the submission from "Student 2" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 75 | + | Comment | Superb work! | + | Finalised | 1 | + + And the submission from "Student 3" for coursework "Coursework 1" is marked by "Marker 2" with: + | Mark | 50 | + | Comment | I've seen worse... | + | Finalised | 1 | + + And the submission from "Student 1" for coursework "Coursework 1" is moderated by "Moderator 1" with: + | Agreement | agreed | + + And the submission from "Student 2" for coursework "Coursework 1" is moderated by "Moderator 1" with: + | Agreement | disagreed | + | Comment | I don't like it at all! | + + And I am on the "Course 1" "course" page logged in as "manager" + And I follow "Coursework 1" + Then I should see "Agreed" in row "1" + Then I should see "Disagreed" in row "2" + + When I follow "Release the marks" + Then I should see "Are you sure you want to release all marks?" + And I press "Confirm" + Then I should see "Marks released" + And I should see "Released" in row "1" + And I should see "Released" in row "2" + And I should see "Released" in row "3" From 06a00b938477ec6afe5c4b29e92d7bf437f8e437 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Fri, 12 Dec 2025 14:59:23 +0000 Subject: [PATCH 24/74] Scenario: Student 1 sees the released grades --- tests/behat/double_marking_blind.feature | 63 ++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 648ca287..247fa8a2 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -638,3 +638,66 @@ Feature: Double marking - blind And I should see "Released" in row "1" And I should see "Released" in row "2" And I should see "Released" in row "3" + + @javascript + Scenario: Student 1 sees the released grades + Given there is a blind marking moderation coursework + And the following "course enrolments" exist: + | user | course | role | + | moderator1 | C1 | courseworkmoderator | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + + And I assign user "Marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 2" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 1" for "Student 3" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 3" in coursework "Coursework 1" + + And the student "Student 1" has a submission for coursework "Coursework 1" + And the submission for "Student 1" in "Coursework 1" is finalised + And the student "Student 2" has a submission for coursework "Coursework 1" + And the submission for "Student 2" in "Coursework 1" is finalised + And the student "Student 3" has a submission for coursework "Coursework 1" + And the submission for "Student 3" in "Coursework 1" is finalised + + And the submission from "Student 1" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 70 | + | Comment | Excellent work! | + | Finalised | 1 | + + And the submission from "Student 2" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 75 | + | Comment | Superb work! | + | Finalised | 1 | + + And the submission from "Student 3" for coursework "Coursework 1" is marked by "Marker 2" with: + | Mark | 50 | + | Comment | I've seen worse... | + | Finalised | 1 | + + And the submission from "Student 1" for coursework "Coursework 1" is moderated by "Moderator 1" with: + | Agreement | agreed | + + And the submission from "Student 2" for coursework "Coursework 1" is moderated by "Moderator 1" with: + | Agreement | disagreed | + | Comment | I don't like it at all! | + + And I am on the "Course 1" "course" page logged in as "manager" + And I follow "Coursework 1" + And I press the release marks button + + And I log out + + And I am on the "Course 1" "course" page logged in as "student1" + And I follow "Coursework 1" + Then I should see "Agreed feedback for Student 1" + And I should see "Marker 1" + And I should see "Excellent work!" + And I should see "70" + And I should see "Released" From 524d41bd8ed92a1d10c9c96cecb54a91a84d0ab7 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Fri, 12 Dec 2025 15:00:50 +0000 Subject: [PATCH 25/74] Scenario: Student 2 sees disagreed released grades --- tests/behat/double_marking_blind.feature | 66 ++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 247fa8a2..5a5ddf7a 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -701,3 +701,69 @@ Feature: Double marking - blind And I should see "Excellent work!" And I should see "70" And I should see "Released" + + @javascript + Scenario: Student 2 sees disagreed released grades + Given there is a blind marking moderation coursework + And the following "course enrolments" exist: + | user | course | role | + | moderator1 | C1 | courseworkmoderator | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + + And I assign user "Marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 2" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 1" for "Student 3" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 3" in coursework "Coursework 1" + + And the student "Student 1" has a submission for coursework "Coursework 1" + And the submission for "Student 1" in "Coursework 1" is finalised + And the student "Student 2" has a submission for coursework "Coursework 1" + And the submission for "Student 2" in "Coursework 1" is finalised + And the student "Student 3" has a submission for coursework "Coursework 1" + And the submission for "Student 3" in "Coursework 1" is finalised + + And the submission from "Student 1" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 70 | + | Comment | Excellent work! | + | Finalised | 1 | + + And the submission from "Student 2" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 75 | + | Comment | Superb work! | + | Finalised | 1 | + + And the submission from "Student 3" for coursework "Coursework 1" is marked by "Marker 2" with: + | Mark | 50 | + | Comment | I've seen worse... | + | Finalised | 1 | + + And the submission from "Student 1" for coursework "Coursework 1" is moderated by "Moderator 1" with: + | Agreement | agreed | + + And the submission from "Student 2" for coursework "Coursework 1" is moderated by "Moderator 1" with: + | Agreement | disagreed | + | Comment | I don't like it at all! | + + And I am on the "Course 1" "course" page logged in as "manager" + And I follow "Coursework 1" + And I press the release marks button + Then I should see "Disagreed" in row "2" + And I should see "Released" in row "2" + + And I log out + + # Student can see released feedback even its was not agreed on. + And I am on the "Course 1" "course" page logged in as "student2" + And I follow "Coursework 1" + Then I should see "Agreed feedback for Student 2" + And I should see "Marker 1" + And I should see "Superb work!" + And I should see "75" + And I should see "Released" From a1e2a682210901d65a582b47477a1a575e0244b3 Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Fri, 12 Dec 2025 15:30:09 +0000 Subject: [PATCH 26/74] Scenario: Student 3 does not see unmoderated released grades --- tests/behat/behat_mod_coursework.php | 19 +++++-- tests/behat/double_marking_blind.feature | 66 ++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 113baf7a..3ad11c06 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -4175,9 +4175,9 @@ public function i_follow_in_row($linktext, $rownumber) { } /** - * @Then /^I should see "(?P[^"]*)" in row "(?P\d+)"$/ + * @Then /^I should( not)? see "(?P[^"]*)" in row "(?P\d+)"$/ */ - public function i_should_see_text_in_row($text, $rownumber) { + public function i_should_see_text_in_row($not, $text, $rownumber) { $session = $this->getSession(); $page = $session->getPage(); @@ -4194,10 +4194,21 @@ public function i_should_see_text_in_row($text, $rownumber) { } $row = $rows[$rownumber - 1]; + $rowtext = $row->getText(); + $contains = strpos($rowtext, $text) !== false; // Check text inside the row. - if (strpos($row->getText(), $text) === false) { - throw new Exception("The text '{$text}' was not found in row {$rownumber}.\nRow contents: " . $row->getText()); + // If "not" was present in the step. + if (trim($not) === 'not') { + if ($contains) { + throw new Exception("'{$text}' text was found in row {$rownumber}.\nRow contents: {$rowtext}"); + } + return; // OK. + } + + // Normal positive check. + if (!$contains) { + throw new Exception("'{$text}' was not found in row {$rownumber}.\nRow contents: {$rowtext}"); } } diff --git a/tests/behat/double_marking_blind.feature b/tests/behat/double_marking_blind.feature index 5a5ddf7a..f087fdde 100644 --- a/tests/behat/double_marking_blind.feature +++ b/tests/behat/double_marking_blind.feature @@ -767,3 +767,69 @@ Feature: Double marking - blind And I should see "Superb work!" And I should see "75" And I should see "Released" + + @javascript + Scenario: Student 3 does not see unmoderated released grades + Given there is a blind marking moderation coursework + And the following "course enrolments" exist: + | user | course | role | + | moderator1 | C1 | courseworkmoderator | + | marker1 | C1 | courseworkmarker | + | marker2 | C1 | courseworkmarker | + | marker3 | C1 | courseworkmarker | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + + And I assign user "Marker 1" as "Assessor 1" for "Student 1" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 1" in coursework "Coursework 1" + And I assign user "Marker 1" as "Assessor 1" for "Student 2" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 2" in coursework "Coursework 1" + And I assign user "Marker 2" as "Assessor 1" for "Student 3" in coursework "Coursework 1" + And I assign user "Moderator 1" as "Moderator" for "Student 3" in coursework "Coursework 1" + + And the student "Student 1" has a submission for coursework "Coursework 1" + And the submission for "Student 1" in "Coursework 1" is finalised + And the student "Student 2" has a submission for coursework "Coursework 1" + And the submission for "Student 2" in "Coursework 1" is finalised + And the student "Student 3" has a submission for coursework "Coursework 1" + And the submission for "Student 3" in "Coursework 1" is finalised + + And the submission from "Student 1" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 70 | + | Comment | Excellent work! | + | Finalised | 1 | + + And the submission from "Student 2" for coursework "Coursework 1" is marked by "Marker 1" with: + | Mark | 75 | + | Comment | Superb work! | + | Finalised | 1 | + + And the submission from "Student 3" for coursework "Coursework 1" is marked by "Marker 2" with: + | Mark | 50 | + | Comment | I've seen worse... | + | Finalised | 1 | + + And the submission from "Student 1" for coursework "Coursework 1" is moderated by "Moderator 1" with: + | Agreement | agreed | + + And the submission from "Student 2" for coursework "Coursework 1" is moderated by "Moderator 1" with: + | Agreement | disagreed | + | Comment | I don't like it at all! | + + And I am on the "Course 1" "course" page logged in as "manager" + And I follow "Coursework 1" + And I should not see "Ready for release" in row "3" + And I press the release marks button + And I should see "Released" in row "1" + Then I should see "Disagreed" in row "2" + And I should see "Released" in row "2" + And I should not see "Released" in row "3" + + And I log out + + # Student cannot see released feedback as moderation is still missing. + And I am on the "Course 1" "course" page logged in as "student3" + And I follow "Coursework 1" + Then I should not see "Agreed feedback for Student 3" + And I should not see "Released" From 2a9968269317b95cfead199515ce8bda43cb42df Mon Sep 17 00:00:00 2001 From: Matthias Opitz Date: Fri, 12 Dec 2025 16:03:30 +0000 Subject: [PATCH 27/74] Scenario: Check moderation form --- tests/behat/behat_mod_coursework.php | 24 +++++++++ tests/behat/double_marking_blind.feature | 62 ++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/tests/behat/behat_mod_coursework.php b/tests/behat/behat_mod_coursework.php index 3ad11c06..048b4c51 100644 --- a/tests/behat/behat_mod_coursework.php +++ b/tests/behat/behat_mod_coursework.php @@ -4294,4 +4294,28 @@ public function moderate_coursework_submission_directly( $DB->insert_record('coursework_mod_agreements', $agreement); } } + + /** + * Checks whether a submit button with the given label exists on the page. + * + * @Then /^I should( not)? see a submit button "(?P