first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,113 @@
@core @core_grades @gradereport_user @javascript
Feature: Group searching functionality within the user report.
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "users" exist:
| username | firstname | lastname | email | idnumber |
| teacher1 | Teacher | 1 | teacher1@example.com | t1 |
| student1 | Student | 1 | student1@example.com | s1 |
| student2 | Student | 2 | student2@example.com | s2 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following "groups" exist:
| name | course | idnumber |
| Default <span class="multilang" lang="de">Gruppe</span><span class="multilang" lang="en">group</span> | C1 | dg |
| Tutor <span class="multilang" lang="de">Gruppe</span><span class="multilang" lang="en">group</span> | C1 | tg |
| Marker <span class="multilang" lang="de">Gruppe</span><span class="multilang" lang="en">group</span> | C1 | mg |
And the following "group members" exist:
| user | group |
| student1 | dg |
And the "multilang" filter is "on"
And the "multilang" filter applies to "content and headings"
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
Scenario: A teacher can see the 'group' search widget only when group mode is enabled in the course
Given ".groupsearchwidget" "css_element" should exist
And I am on "Course 1" course homepage
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| id_groupmode | No groups |
And I press "Save and display"
When I navigate to "View > User report" in the course gradebook
Then ".groupsearchwidget" "css_element" should not exist
Scenario: A teacher can search for and find a group to find a user in
Given I confirm "Tutor group" in "group" search within the gradebook widget exists
And I confirm "Marker group" in "group" search within the gradebook widget exists
When I set the field "Search groups" to "tutor"
And I wait "1" seconds
Then I confirm "Tutor group" in "group" search within the gradebook widget exists
And I confirm "Marker group" in "group" search within the gradebook widget does not exist
And I click on "Tutor group" in the "group" search widget
# The search input remains in the field on reload this is in keeping with other search implementations.
And I click on ".groupsearchwidget" "css_element"
And the field "Search groups" matches value "tutor"
Then I set the field "Search groups" to "Turtle"
And I should see "No results for \"Turtle\""
Scenario: A teacher can only see the group members in the 'user' search widget after selecting a group option
# Confirm that all users are initially displayed in the 'user' search widget.
Given I set the field "Search users" to "Student"
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Student 2" in "user" search within the gradebook widget exists
# Select a particular group from the 'group' search widget.
When I click on "Default group" in the "group" search widget
# Confirm that only users which are members of the selected group are displayed in the 'user' search widget.
And I set the field "Search users" to "Student"
Then I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Student 2" in "user" search within the gradebook widget does not exist
And I click on "Tutor group" in the "group" search widget
And I set the field "Search users" to "Student"
And I confirm "Student 1" in "user" search within the gradebook widget does not exist
And I confirm "Student 2" in "user" search within the gradebook widget does not exist
And I click on "All participants" in the "group" search widget
And I set the field "Search users" to "Student"
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Student 2" in "user" search within the gradebook widget exists
@accessibility
Scenario: A teacher can set focus and search using the input with a keyboard
# Basic tests for the page.
Given I click on ".groupsearchwidget" "css_element"
And the page should meet accessibility standards
And the page should meet "wcag131, wcag141, wcag412" accessibility standards
And the page should meet accessibility standards with "wcag131, wcag141, wcag412" extra tests
# Move onto general keyboard navigation testing.
And I click on "Search groups" "field"
And I wait until "Default group" "option_role" exists
And I press the down key
And the focused element is "Search groups" "field"
And ".active" "css_element" should exist in the "All participants" "option_role"
And I press the up key
And the focused element is "Search groups" "field"
And ".active" "css_element" should exist in the "Tutor group" "option_role"
And I press the down key
And the focused element is "Search groups" "field"
And ".active" "css_element" should exist in the "All participants" "option_role"
Then I set the field "Search groups" to "Goodmeme"
And I wait until "Tutor group" "option_role" does not exist
And I press the down key
And the focused element is "Search groups" "field"
And I navigate to "View > User report" in the course gradebook
And I click on ".groupsearchwidget" "css_element"
And I set the field "Search groups" to "Tutor"
And I wait until "All participants" "option_role" does not exist
And I press the down key
And the focused element is "Search groups" "field"
And ".active" "css_element" should exist in the "Tutor group" "option_role"
# Lets check the tabbing order.
And I set the field "Search groups" to "Marker"
And I wait until "Marker group" "option_role" exists
And I press the tab key
And the focused element is "Clear search input" "button"
And I press the enter key
And I wait until the page is ready
And ".groupsearchwidget" "css_element" should exist
@@ -0,0 +1,53 @@
@core @core_grades @gradereport_user @javascript
Feature: User can toggle the visibility of the grade categories within the user grade report.
In order to focus only on the information that I am interested in
As a teacher
I need to be able to easily toggle the visibility of grade categories in the user grade report
Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Course | C1 | 0 |
And the following "users" exist:
| username | firstname | lastname | email | idnumber |
| teacher1 | Teacher | 1 | teacher1@example.com | t1 |
| student1 | Student | 1 | student1@example.com | s1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "grade categories" exist:
| fullname | course |
| Category 1 | C1 |
And the following "activities" exist:
| activity | course | idnumber | name | intro | grade |
| assign | C1 | a1 | Test assignment one | Submit something! | 300 |
And the following "activities" exist:
| activity | course | idnumber | name | gradecategory | grade | gradepass |
| assign | C1 | a2 | Test assignment two | Category 1 | 100 | 50 |
Scenario: A teacher can search for and find a user to view
Given I am on the "Course" "grades > User report > View" page logged in as "teacher1"
And I click on "Student 1" in the "user" search widget
And I should see "Test assignment one" in the "user-grade" "table"
And I should see "Test assignment two" in the "user-grade" "table"
And I should see "Category 1 total" in the "user-grade" "table"
And I should see "Course total" in the "user-grade" "table"
# Hide the grade category 'Category 1'.
When I click on ".toggle-category" "css_element" in the "Category 1" "table_row"
Then I should not see "Test assignment two" in the "user-grade" "table"
And I should not see "Category 1 total" in the "user-grade" "table"
And I should see "Test assignment one" in the "user-grade" "table"
And I should see "Course total" in the "user-grade" "table"
# Show the grade category 'Category 1'.
And I click on ".toggle-category" "css_element" in the "Category 1" "table_row"
And I should see "Test assignment two" in the "user-grade" "table"
And I should see "Category 1 total" in the "user-grade" "table"
And I should see "Test assignment one" in the "user-grade" "table"
And I should see "Course total" in the "user-grade" "table"
# Hide the grade category 'Course'.
And I click on ".toggle-category" "css_element" in the "Course" "table_row"
And I should not see "Test assignment two" in the "user-grade" "table"
And I should not see "Category 1 total" in the "user-grade" "table"
And I should not see "Test assignment one" in the "user-grade" "table"
And I should not see "Course total" in the "user-grade" "table"
@@ -0,0 +1,62 @@
@core @core_grades @gradereport_user @javascript
Feature: Teacher can navigate to the previous or next user report.
In order to get go the previous or next user report
As a teacher
I need to click on the previous/next navigation links
Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Course | C1 | 0 |
And the following "users" exist:
| username | firstname | lastname | email | idnumber |
| teacher1 | Teacher | 1 | teacher1@example.com | t1 |
| student1 | Student | 1 | student1@example.com | s1 |
| student2 | Student | 2 | student2@example.com | s2 |
| student3 | Student | 3 | student3@example.com | s3 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
And the following "activities" exist:
| activity | course | idnumber | name | grade |
| assign | C1 | a1 | Test assignment one | 300 |
And I am on the "Course" "grades > User report > View" page logged in as "teacher1"
Scenario: A teacher can navigate to the next user report
Given I click on "Student 1" in the "user" search widget
And "Student 1" "heading" should exist
And ".previous" "css_element" should not exist in the ".user-navigation" "css_element"
And ".next" "css_element" should exist in the ".user-navigation" "css_element"
And I should see "Student 2" in the ".next" "css_element"
When I click on "Student 2" "link" in the ".next" "css_element"
And "Student 2" "heading" should exist
And ".previous" "css_element" should exist in the ".user-navigation" "css_element"
And I should see "Student 1" in the ".previous" "css_element"
And ".next" "css_element" should exist in the ".user-navigation" "css_element"
And I should see "Student 3" in the ".next" "css_element"
And I click on "Student 3" "link" in the ".next" "css_element"
And "Student 3" "heading" should exist
And ".previous" "css_element" should exist in the ".user-navigation" "css_element"
And I should see "Student 2" in the ".previous" "css_element"
And ".next" "css_element" should not exist in the ".user-navigation" "css_element"
Scenario: A teacher can navigate to the previous user report
Given I click on "Student 3" in the "user" search widget
And "Student 3" "heading" should exist
And ".previous" "css_element" should exist in the ".user-navigation" "css_element"
And I should see "Student 2" in the ".previous" "css_element"
And ".next" "css_element" should not exist in the ".user-navigation" "css_element"
When I click on "Student 2" "link" in the ".previous" "css_element"
And "Student 2" "heading" should exist
And ".previous" "css_element" should exist in the ".user-navigation" "css_element"
And I should see "Student 1" in the ".previous" "css_element"
And ".next" "css_element" should exist in the ".user-navigation" "css_element"
And I should see "Student 3" in the ".next" "css_element"
And I click on "Student 1" "link" in the ".previous" "css_element"
And "Student 1" "heading" should exist
And ".previous" "css_element" should not exist in the ".user-navigation" "css_element"
And ".next" "css_element" should exist in the ".user-navigation" "css_element"
And I should see "Student 2" in the ".next" "css_element"
@@ -0,0 +1,234 @@
@core @core_grades @gradereport_user @javascript
Feature: View the user report as the student will see it
In order to know what grades students will see
As a teacher
I need to be able to view the user report as that other user
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| <span class="multilang" lang="en">Course</span><span class="multilang" lang="de">Kurs</span> 1 & '" | C1 | 0 | 1 |
And the following "users" exist:
| username | firstname | lastname | email | idnumber |
| teacher1 | Teacher | 1 | teacher1@example.com | t1 |
| student1 | Student | 1 | student1@example.com | s1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "grade categories" exist:
| fullname | course |
| Sub category 1 | C1 |
| Sub category 2 | C1 |
And the following "activities" exist:
| activity | course | idnumber | name | intro | gradecategory | grade | gradepass |
| assign | C1 | a1 | Test assignment one | Submit something! | Sub category 1 | 100 | 50 |
| assign | C1 | a2 | Test assignment two | Submit something! | Sub category 1 | 100 | 50 |
| assign | C1 | a3 | Test assignment three | Submit something! | Sub category 2 | 100 | |
| assign | C1 | a4 | Test assignment four | Submit something! | Sub category 2 | 100 | |
And the following "activities" exist:
| activity | course | idnumber | name | intro | grade |
| assign | C1 | a5 | Test assignment five | Submit something! | 100 |
| assign | C1 | a6 | Test assignment six | Submit something! | 100 |
And the "multilang" filter is "on"
And the "multilang" filter applies to "content and headings"
When I am on the "C1" "grades > gradebook setup" page logged in as "teacher1"
And I hide the grade item "Test assignment six" of type "gradeitem" on "setup" page
And I hide the grade item "Sub category 2" of type "category" on "setup" page
And I navigate to "View > Grader report" in the course gradebook
And I turn editing mode on
And I change window size to "large"
And I give the grade "80.00" to the user "Student 1" for the grade item "Test assignment one"
And I give the grade "35.00" to the user "Student 1" for the grade item "Test assignment two"
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment three"
And I give the grade "50.00" to the user "Student 1" for the grade item "Test assignment four"
And I give the grade "21.00" to the user "Student 1" for the grade item "Test assignment five"
And I give the grade "97.00" to the user "Student 1" for the grade item "Test assignment six"
And I press "Save changes"
And I change window size to "medium"
Scenario: View the report as the teacher themselves
Given the following "activities" exist:
| activity | course | idnumber | name | intro | grade |
| quiz | C1 | q1 | Test quiz one | Submit something! | 100 |
When I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I should see "Course 1 & '\""
And I should not see "Course 1 &amp; '\""
And I set the field "View report as" to "Myself"
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 50.00 % | 80.00 | 0100 | 80.00 % | 13.33 % |
| Test assignment two | 50.00 % | 35.00 | 0100 | 35.00 % | 5.83 % |
| Sub category 1 total | 33.33 % | 115.00 | 0200 | 57.50 % | - |
| Test assignment three | 50.00 % | 100.00 | 0100 | 100.00 % | 16.67 % |
| Test assignment four | 50.00 % | 50.00 | 0100 | 50.00 % | 8.33 % |
| Sub category 2 total | 33.33 % | 150.00 | 0200 | 75.00 % | - |
| Test assignment five | 16.67 % | 21.00 | 0100 | 21.00 % | 3.50 % |
| Test assignment six | 16.67 % | 97.00 | 0100 | 97.00 % | 16.17 % |
| Test quiz one | 0.00 %( Empty ) | - | 0100 | - | 0.00 % |
| Course total | - | 383.00 | 0600 | 63.83 % | - |
# Confirm a contextual menu with a link to the Grade analysis page is available for "Test quiz one".
And I open the action menu in "Test quiz one" "table_row"
And "Grade analysis" "link" should exist
Scenario: View the report as the student from both the teachers and students perspective
Given the following "activities" exist:
| activity | course | idnumber | name | intro | grade |
| quiz | C1 | q1 | Test quiz one | Submit something! | 100 |
When I navigate to "View > User report" in the course gradebook
And I click on "Student 1" in the "user" search widget
And I set the field "View report as" to "User"
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | - | 80.00 | 0100 | 80.00 % | - |
| Test assignment two | - | 35.00 | 0100 | 35.00 % | - |
| Sub category 1 total | 33.33 % | - | 0200 | - | - |
| Test assignment five | - | 21.00 | 0100 | 21.00 % | - |
| Test quiz one | - | - | 0100 | - | - |
| Course total | - | - | 0600 | - | - |
And "//i[@aria-label='Pass']" "xpath_element" should exist in the "Test assignment one" "table_row"
And "//i[@aria-label='Fail']" "xpath_element" should exist in the "Test assignment two" "table_row"
And the following should not exist in the "user-grade" table:
| Grade item |
| Test assignment three |
| Test assignment four |
| Sub category 2 total |
| Test assignment six |
# Confirm a contextual menu with a link to the Grade analysis page is available for "Test quiz one".
And I open the action menu in "Test quiz one" "table_row"
And "Grade analysis" "link" should exist
And I log out
And I am on the "C1" "Course" page logged in as "student1"
And I navigate to "User report" in the course gradebook
And the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | - | 80.00 | 0100 | 80.00 % | - |
| Test assignment two | - | 35.00 | 0100 | 35.00 % | - |
| Sub category 1 total | 33.33 % | - | 0200 | - | - |
| Test assignment five | - | 21.00 | 0100 | 21.00 % | - |
| Test quiz one | - | - | 0100 | - | - |
| Course total | - | - | 0600 | - | - |
And "//i[@aria-label='Pass']" "xpath_element" should exist in the "Test assignment one" "table_row"
And "//i[@aria-label='Fail']" "xpath_element" should exist in the "Test assignment two" "table_row"
And the following should not exist in the "user-grade" table:
| Grade item |
| Test assignment three |
| Test assignment four |
| Sub category 2 total |
| Test assignment six |
# Confirm a contextual menu with a link to the Grade analysis page is available for "Test quiz one".
And I open the action menu in "Test quiz one" "table_row"
And "Grade analysis" "link" should exist
Scenario: View the report as the student from both the teachers and students perspective with totals excluding hidden
Given I navigate to "Setup > Course grade settings" in the course gradebook
And I set the field with xpath "//select[@name='report_user_showtotalsifcontainhidden']" to "Show totals excluding hidden items"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
When I click on "Student 1" in the "user" search widget
And I set the field "View report as" to "User"
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 50.00 % | 80.00 | 0100 | 80.00 % | 26.67 % |
| Test assignment two | 50.00 % | 35.00 | 0100 | 35.00 % | 11.67 % |
| Sub category 1 total | 66.67 % | 115.00 | 0200 | 57.50 | - |
| Test assignment five | 33.33 % | 21.00 | 0100 | 21.00 % | 7.00 % |
| Course total | - | 136.00 | 0300 | 45.33 % | - |
And the following should not exist in the "user-grade" table:
| Grade item |
| Test assignment three |
| Test assignment four |
| Sub category 2 total |
| Test assignment six |
And I log out
And I am on the "C1" "Course" page logged in as "student1"
And I navigate to "User report" in the course gradebook
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 50.00 % | 80.00 | 0100 | 80.00 % | 26.67 % |
| Test assignment two | 50.00 % | 35.00 | 0100 | 35.00 % | 11.67 % |
| Sub category 1 total | 66.67 % | 115.00 | 0200 | 57.50 | - |
| Test assignment five | 33.33 % | 21.00 | 0100 | 21.00 % | 7.00 % |
| Course total | - | 136.00 | 0300 | 45.33 % | - |
And the following should not exist in the "user-grade" table:
| Grade item |
| Test assignment three |
| Test assignment four |
| Sub category 2 total |
| Test assignment six |
Scenario: View the report as the student from both the teachers and students perspective with totals including hidden
Given I navigate to "Setup > Course grade settings" in the course gradebook
And I set the field with xpath "//select[@name='report_user_showtotalsifcontainhidden']" to "Show totals including hidden items"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
When I click on "Student 1" in the "user" search widget
And I set the field "View report as" to "User"
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 50.00 % | 80.00 | 0100 | 80.00 % | 13.33 % |
| Test assignment two | 50.00 % | 35.00 | 0100 | 35.00 % | 5.83 % |
| Sub category 1 total | 33.33 % | 115.00 | 0200 | 57.50 % | - |
| Test assignment five | 16.67 % | 21.00 | 0100 | 21.00 % | 3.50 % |
| Course total | - | 383.00 | 0600 | 63.83 % | - |
And the following should not exist in the "user-grade" table:
| Grade item |
| Test assignment three |
| Test assignment four |
| Sub category 2 total |
| Test assignment six |
And I log out
And I am on the "C1" "Course" page logged in as "student1"
And I navigate to "User report" in the course gradebook
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 50.00 % | 80.00 | 0100 | 80.00 % | 13.33 % |
| Test assignment two | 50.00 % | 35.00 | 0100 | 35.00 % | 5.83 % |
| Sub category 1 total | 33.33 % | 115.00 | 0200 | 57.50 % | - |
| Test assignment five | 16.67 % | 21.00 | 0100 | 21.00 % | 3.50 % |
| Course total | - | 383.00 | 0600 | 63.83 % | - |
And the following should not exist in the "user-grade" table:
| Grade item |
| Test assignment three |
| Test assignment four |
| Sub category 2 total |
| Test assignment six |
Scenario: View the report as the student from both the teachers and students perspective when the student can view hidden
Given the following "role capability" exists:
| role | student |
| moodle/grade:viewhidden | allow |
And I am on the "C1" "Course" page logged in as "teacher1"
And I navigate to "Setup > Course grade settings" in the course gradebook
And I set the field with xpath "//select[@name='report_user_showtotalsifcontainhidden']" to "Show totals excluding hidden items"
And I press "Save changes"
And I navigate to "View > User report" in the course gradebook
When I click on "Student 1" in the "user" search widget
And I set the field "View report as" to "User"
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 50.00 % | 80.00 | 0100 | 80.00 % | 13.33 % |
| Test assignment two | 50.00 % | 35.00 | 0100 | 35.00 % | 5.83 % |
| Sub category 1 total | 33.33 % | 115.00 | 0200 | 57.50 % | - |
| Test assignment three | 50.00 % | 100.00 | 0100 | 100.00 % | 16.67 % |
| Test assignment four | 50.00 % | 50.00 | 0100 | 50.00 % | 8.33 % |
| Sub category 2 total | 33.33 % | 150.00 | 0200 | 75.00 % | - |
| Test assignment five | 16.67 % | 21.00 | 0100 | 21.00 % | 3.50 % |
| Test assignment six | 16.67 % | 97.00 | 0100 | 97.00 % | 16.17 % |
| Course total | - | 383.00 | 0600 | 63.83 % | - |
And I log out
And I log in as "student1"
And I am on "C1" course homepage
And I navigate to "User report" in the course gradebook
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test assignment one | 50.00 % | 80.00 | 0100 | 80.00 % | 13.33 % |
| Test assignment two | 50.00 % | 35.00 | 0100 | 35.00 % | 5.83 % |
| Sub category 1 total | 33.33 % | 115.00 | 0200 | 57.50 % | - |
| Test assignment three | 50.00 % | 100.00 | 0100 | 100.00 % | 16.67 % |
| Test assignment four | 50.00 % | 50.00 | 0100 | 50.00 % | 8.33 % |
| Sub category 2 total | 33.33 % | 150.00 | 0200 | 75.00 % | - |
| Test assignment five | 16.67 % | 21.00 | 0100 | 21.00 % | 3.50 % |
| Test assignment six | 16.67 % | 97.00 | 0100 | 97.00 % | 16.17 % |
| Course total | - | 383.00 | 0600 | 63.83 % | - |
@@ -0,0 +1,263 @@
@core @core_grades @gradereport_user @javascript
Feature: Within the User report, a teacher can search for users.
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
| Course 2 | C2 | 0 | 0 |
And the following "users" exist:
| username | firstname | lastname | email | idnumber | phone1 | phone2 | department | institution | city | country |
| teacher1 | Teacher | 1 | teacher1@example.com | t1 | 1234567892 | 1234567893 | ABC1 | ABCD | Perth | AU |
| student1 | Student | 1 | student1@example.com | s1 | 3213078612 | 8974325612 | ABC1 | ABCD | Hanoi | VN |
| student2 | Dummy | User | student2@example.com | s2 | 4365899871 | 7654789012 | ABC2 | ABCD | Tokyo | JP |
| student3 | User | Example | student3@example.com | s3 | 3243249087 | 0875421745 | ABC2 | ABCD | Olney | GB |
| student4 | User | Test | student4@example.com | s4 | 0987532523 | 2149871323 | ABC3 | ABCD | Tokyo | JP |
| student5 | Turtle | Manatee | student5@example.com | s5 | 1239087780 | 9873623589 | ABC3 | ABCD | Perth | AU |
# Note: Add groups etc so we can test that the search ignores those filters as well if we go down the filter dataset path.
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| teacher1 | C2 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
| student4 | C1 | student |
| student5 | C1 | student |
And the following "activities" exist:
| activity | course | idnumber | name |
| assign | C1 | a1 | Test assignment one |
And the following config values are set as admin:
| showuseridentity | idnumber,email,city,country,phone1,phone2,department,institution |
And I change window size to "large"
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
Scenario: A teacher can view and trigger the user search
# Check the placeholder text (no users are initially shown).
Given I should see "Search users"
# Confirm the search is currently inactive and results are unfiltered.
And I should see "Search for a user to view their report"
When I set the field "Search users" to "Turtle"
And "View all results (5)" "option_role" should exist
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget does not exist
And I click on "Turtle Manatee" "list_item"
# Business case: This will trigger a page reload and can not dynamically update the table.
And I wait until the page is ready
And "Turtle Manatee" "heading" should exist
And "Teacher 1" "heading" should not exist
And "Student 1" "heading" should not exist
And "User Example" "heading" should not exist
And "User Test" "heading" should not exist
And "Dummy User" "heading" should not exist
And I set the field "Search users" to "Turt"
And "View all results (5)" "option_role" should exist
And I click on "Clear search input" "button" in the ".user-search" "css_element"
And "View all results (5)" "option_role" should not be visible
Scenario: A teacher can search the user report to find specified users
# Case: Standard search.
Given I click on "Dummy" in the "user" search widget
And "Dummy User" "heading" should exist
And "Teacher 1" "heading" should not exist
And "Student 1" "heading" should not exist
And "User Example" "heading" should not exist
And "User Test" "heading" should not exist
And "Turtle Manatee" "heading" should not exist
# Case: No users found.
When I set the field "Search users" to "Plagiarism"
And I should see "No results for \"Plagiarism\""
# Table remains unchanged as the user had no results to select from the dropdown.
And "Dummy User" "heading" should exist
And "Teacher 1" "heading" should not exist
And "Student 1" "heading" should not exist
And "User Example" "heading" should not exist
And "User Test" "heading" should not exist
And "Turtle Manatee" "heading" should not exist
# Case: Multiple users found and select only one result.
Then I set the field "Search users" to "User"
And "View all results (5)" "option_role" should exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget does not exist
# Check if the matched field names (by lines) includes some identifiable info to help differentiate similar users.
And I confirm "User (student2@example.com)" in "user" search within the gradebook widget exists
And I confirm "User (student3@example.com)" in "user" search within the gradebook widget exists
And I confirm "User (student4@example.com)" in "user" search within the gradebook widget exists
And I click on "Dummy User" "list_item"
And I wait until the page is ready
And "Dummy User" "heading" should exist
And "Teacher 1" "heading" should not exist
And "Student 1" "heading" should not exist
And "User Example" "heading" should not exist
And "User Test" "heading" should not exist
And "Turtle Manatee" "heading" should not exist
# Business case: When searching with multiple partial matches, show the matches in the dropdown + a "View all results for (Bob)"
# Business case cont. When pressing enter with multiple partial matches, behave like when you select the "View all results for (Bob)"
# Case: Multiple users found and select all partial matches.
And I set the field "Search users" to "User"
And "View all results (5)" "option_role" should exist
And I click on "View all results (5)" "option_role"
And I wait until the page is ready
And "Dummy User" "heading" should exist
And "User Example" "heading" should exist
And "User Test" "heading" should exist
And "Student 1" "heading" should exist
And "Turtle Manatee" "heading" should exist
And "Teacher 1" "heading" should not exist
And "Clear" "link" should not exist in the ".user-search" "css_element"
And "Dummy User" "heading" should exist
And "User Example" "heading" should exist
And "User Test" "heading" should exist
And "Student 1" "heading" should exist
And "Turtle Manatee" "heading" should exist
And "Teacher 1" "heading" should not exist
# Case: No users enrolled.
And I am on the "Course 2" "grades > User report > View" page
And I set the field "Search users" to "a"
And I should see "No results for \"a\""
Scenario: A teacher can quickly tell that a search is active on the current table
When I click on "Turtle" in the "user" search widget
# The search input should contain the name of the user we have selected, so that it is clear that the result pertains to a specific user.
Then the field "Search users" matches value "Turtle Manatee"
And I wait until "View all results (5)" "link" does not exist
# Test if we can then further retain the turtle result set and further filter from there.
And I set the field "Search users" to "Turtle plagiarism"
And I wait until "Turtle Manatee" "list_item" does not exist
And I should see "No results for \"Turtle plagiarism\""
Scenario: A teacher can search for values besides the users' name
Given I set the field "Search users" to "student5@example.com"
And "View all results (5)" "option_role" should exist
And "Turtle Manatee" "list_item" should exist
And I set the field "Search users" to "@example.com"
And "View all results (5)" "option_role" should exist
# Note: All learners match this email & showing emails is current default.
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
# Search on the country field.
When I set the field "Search users" to "JP"
And "View all results (5)" "option_role" should exist
And I wait until "Turtle Manatee" "list_item" does not exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
# Search on the city field.
And I set the field "Search users" to "Hanoi"
And I wait until "User Test" "list_item" does not exist
Then I confirm "Student 1" in "user" search within the gradebook widget exists
# Search on the institution field.
And I set the field "Search users" to "ABCD"
And "Dummy User" "list_item" should exist
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
# Search on the department field.
And I set the field "Search users" to "ABC3"
And I wait until "User Example" "list_item" does not exist
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Turtle Manatee" in "user" search within the gradebook widget exists
# Search on the phone1 field.
And I set the field "Search users" to "4365899871"
And I wait until "User Test" "list_item" does not exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
# Search on the phone2 field.
And I set the field "Search users" to "2149871323"
And I wait until "Dummy User" "list_item" does not exist
And I confirm "User Test" in "user" search within the gradebook widget exists
# Search on the institution field then press enter to show the record set.
And I set the field "Search users" to "ABC"
And "Turtle Manatee" "list_item" should exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
And I confirm "Student 1" in "user" search within the gradebook widget exists
And I press the up key
And I press the enter key
And I wait until the page is ready
And "Student 1" "heading" should exist
And "User Example" "heading" should exist
And "User Test" "heading" should exist
And "Dummy User" "heading" should exist
And "Turtle Manatee" "heading" should exist
And "Teacher 1" "heading" should not exist
Scenario: A teacher can only search for fields that he allowed to see
Given the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/course:viewhiddenuserfields | Prohibit | editingteacher | System | |
And the following config values are set as admin:
| hiddenuserfields | email |
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
When I set the field "Search users" to "User"
And "View all results (5)" "option_role" should exist
And I confirm "Dummy User" in "user" search within the gradebook widget exists
And I confirm "User Example" in "user" search within the gradebook widget exists
And I confirm "User Test" in "user" search within the gradebook widget exists
# Email is not shown in results.
And I confirm "User" in "user" search within the gradebook widget exists
And I confirm "example.com" in "user" search within the gradebook widget does not exist
# Email is not searchable.
And I set the field "Search users" to "student5@example.com"
And "View all results (5)" "option_role" should not exist
And I confirm "No results for \"student5@example.com\"" in "user" search within the gradebook widget exists
@accessibility
Scenario: A teacher can set focus and search using the input are with a keyboard
Given I set the field "Search users" to "ABC"
# Basic tests for the page.
And the page should meet accessibility standards with "wcag131, wcag141, wcag412" extra tests
# Move onto general keyboard navigation testing.
When "Turtle Manatee" "option_role" should exist
And I press the down key
And ".active" "css_element" should exist in the "Student 1" "option_role"
And I press the up key
And ".active" "css_element" should exist in the "View all results (5)" "option_role"
And I press the down key
And ".active" "css_element" should exist in the "Student 1" "option_role"
And I press the escape key
And the focused element is "Search users" "field"
Then I set the field "Search users" to "Goodmeme"
And I press the down key
And the focused element is "Search users" "field"
And I navigate to "View > User report" in the course gradebook
And I set the field "Search users" to "ABC"
And "Turtle Manatee" "option_role" should exist
And I press the down key
And ".active" "css_element" should exist in the "Student 1" "option_role"
# Lets check the tabbing order.
And I set the field "Search users" to "ABC"
And I wait until "Clear search input" "button" exists
And I click on "Search users" "field"
And I press the tab key
And the focused element is "Clear search input" "button" in the ".user-search" "css_element"
And I press the tab key
And ".groupsearchwidget" "css_element" should exist
# Ensure we can interact with the input & clear search options with the keyboard.
# Space & Enter have the same handling for triggering the two functionalities.
And I set the field "Search users" to "User"
And I press the down key
And I press the enter key
And I wait to be redirected
And "User Example" "heading" should exist
And "Dummy User" "heading" should not exist
And "Student 1" "heading" should not exist
And "User Test" "heading" should not exist
And "Teacher 1" "heading" should not exist
And "Turtle Manatee" "heading" should not exist
@@ -0,0 +1,106 @@
@core @core_grades @gradereport_user @javascript
Feature: We can use the user report
As a user
I browse to the User report
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
Scenario: Verify we can view a user grade report with no users enrolled.
When I am on the "Course 1" "grades > User report > View" page logged in as "admin"
Then I should see "There are no students enrolled in this course."
Scenario: Teacher sees his last viewed user report when navigating back to the gradebook user report.
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| teacher2 | Teacher | 2 | teacher2@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| teacher2 | C1 | editingteacher |
| student1 | C1 | student |
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
And I should see "Search for a user to view their report" in the "region-main" "region"
And I click on "Student 1" in the "user" search widget
And I should see "Student 1" in the "region-main" "region"
When I am on the "Course 1" "grades > User report > View" page
Then I should not see "Search for a user to view their report" in the "region-main" "region"
And I should see "Student 1" in the "region-main" "region"
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher2"
And I should see "Search for a user to view their report" in the "region-main" "region"
Scenario: Teacher sees his last viewed user report if the user is a part of the the current group.
Given the following "groups" exist:
| name | course | idnumber | participation |
| Group 1 | C1 | G1 | 1 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following "group members" exist:
| user | group |
| student2 | G1 |
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
And I click on "Student 2" in the "user" search widget
And I navigate to "View > Grader report" in the course gradebook
And I click on "Group 1" in the "group" search widget
When I navigate to "View > User report" in the course gradebook
Then I should see "Student 2" in the "region-main" "region"
And I should not see "Search for a user to view their report" in the "region-main" "region"
Scenario: Teacher does not see the last viewed user if the user is not a part of the the current group.
Given the following "groups" exist:
| name | course | idnumber | participation |
| Group 1 | C1 | G1 | 1 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following "group members" exist:
| user | group |
| student2 | G1 |
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
And I click on "Student 1" in the "user" search widget
And I navigate to "View > Grader report" in the course gradebook
And I click on "Group 1" in the "group" search widget
When I navigate to "View > User report" in the course gradebook
Then I should see "Search for a user to view their report" in the "region-main" "region"
And I should not see "Student 1" in the "region-main" "region"
Scenario: Teacher does not see his last viewed user report if the user is no longer enrolled in the course.
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And I am on the "Course 1" "grades > User report > View" page logged in as "teacher1"
And I click on "Student 1" in the "user" search widget
And I should see "Student 1" in the "region-main" "region"
And I navigate to course participants
And I click on "Unenrol" "icon" in the "Student 1" "table_row"
And I click on "Unenrol" "button" in the "Unenrol" "dialogue"
And I am on "Course 1" course homepage
When I navigate to "View > User report" in the course gradebook
Then I should see "Search for a user to view their report" in the "region-main" "region"
And I should not see "Student 1" in the "region-main" "region"
@@ -0,0 +1,433 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace gradereport_user;
use core_external\external_api;
use externallib_advanced_testcase;
use gradereport_user\external\user as user_external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
/**
* User grade report functions unit tests
*
* @package gradereport_user
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class externallib_test extends externallib_advanced_testcase {
/**
* Loads some data to be used by the different tests
* @param int $s1grade Student 1 grade
* @param int $s2grade Student 2 grade
* @return array Course and users instances
*/
private function load_data(int $s1grade, int $s2grade, int $s3grade): array {
global $DB;
$course = $this->getDataGenerator()->create_course(['groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1]);
$studentrole = $DB->get_record('role', ['shortname' => 'student']);
$student1 = $this->getDataGenerator()->create_user(['idnumber' => 'testidnumber']);
$this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id);
$student2 = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id);
// Student 3 is in no groups.
$student3 = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->enrol_user($student3->id, $course->id, $studentrole->id);
$teacherrole = $DB->get_record('role', ['shortname' => 'teacher']);
$teacher = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
$context = \context_course::instance($course->id);
assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $teacherrole->id, $context);
accesslib_clear_all_caches_for_unit_testing();
$group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
$group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
groups_add_member($group1->id, $student1->id);
groups_add_member($group1->id, $teacher->id);
groups_add_member($group2->id, $student2->id);
$assignment = $this->getDataGenerator()->create_module('assign', ['name' => "Test assign & grade items", 'course' => $course->id]);
$modcontext = get_coursemodule_from_instance('assign', $assignment->id, $course->id);
$assignment->cmidnumber = $modcontext->id;
$student1grade = ['userid' => $student1->id, 'rawgrade' => $s1grade, 'idnumber' => 'testidnumber1'];
$student2grade = ['userid' => $student2->id, 'rawgrade' => $s2grade, 'idnumber' => 'testidnumber2'];
$student3grade = ['userid' => $student3->id, 'rawgrade' => $s3grade, 'idnumber' => 'testidnumber3'];
$studentgrades = [$student1->id => $student1grade, $student2->id => $student2grade, $student3->id => $student3grade];
assign_grade_item_update($assignment, $studentgrades);
return [
$course,
$teacher,
$student1,
$student2,
$student3,
$assignment
];
}
/**
* Test get_grades_table function case teacher
*/
public function test_get_grades_table_teacher(): void {
$this->resetAfterTest(true);
$s1grade = 80;
$s2grade = 60;
$s3grade = 50;
list($course, $teacher, $student1, $student2, $student3, $assignment) = $this->load_data($s1grade, $s2grade, $s3grade);
// A teacher must see all student grades (in their group only).
$this->setUser($teacher);
$studentgrades = user_external::get_grades_table($course->id);
$studentgrades = external_api::clean_returnvalue(user_external::get_grades_table_returns(), $studentgrades);
// No warnings returned.
$this->assertCount(0, $studentgrades['warnings']);
// Check that only grades for the student in the teacher group are returned.
$this->assertCount(1, $studentgrades['tables']);
// Read returned grades.
$studentreturnedgrades = [];
$studentreturnedgrades[$studentgrades['tables'][0]['userid']] =
(int) $studentgrades['tables'][0]['tabledata'][2]['grade']['content'];
$this->assertEquals($s1grade, $studentreturnedgrades[$student1->id]);
}
/**
* Test get_grades_table function case student
*/
public function test_get_grades_table_student(): void {
global $CFG, $DB;
$this->resetAfterTest(true);
$s1grade = 80;
$s2grade = 60;
$s3grade = 50;
list($course, $teacher, $student1, $student2, $student3, $assignment) = $this->load_data($s1grade, $s2grade, $s3grade);
// A user can see his own grades.
$this->setUser($student1);
$studentgrade = user_external::get_grades_table($course->id, $student1->id);
$studentgrade = external_api::clean_returnvalue(user_external::get_grades_table_returns(), $studentgrade);
// No warnings returned.
$this->assertTrue(count($studentgrade['warnings']) == 0);
$this->assertTrue(count($studentgrade['tables']) == 1);
$student1returnedgrade = (int) $studentgrade['tables'][0]['tabledata'][2]['grade']['content'];
$this->assertEquals($s1grade, $student1returnedgrade);
// A user can see his own even when in no groups.
$this->setUser($student3);
$studentgrade = user_external::get_grades_table($course->id, $student3->id);
$studentgrade = external_api::clean_returnvalue(user_external::get_grades_table_returns(), $studentgrade);
// No warnings returned.
$this->assertTrue(count($studentgrade['warnings']) == 0);
$this->assertTrue(count($studentgrade['tables']) == 1);
$student3returnedgrade = (int) $studentgrade['tables'][0]['tabledata'][2]['grade']['content'];
$this->assertEquals($s3grade, $student3returnedgrade);
// Expect exception when user is not indicated.
$this->setUser($student3);
$this->expectException(\required_capability_exception::class);
user_external::get_grades_table($course->id);
}
/**
* Test get_grades_table function case incorrect permissions
*/
public function test_get_grades_table_permissions(): void {
global $CFG, $DB;
$this->resetAfterTest(true);
$s1grade = 80;
$s2grade = 60;
$s3grade = 50;
list($course, $teacher, $student1, $student2, $student3, $assignment) = $this->load_data($s1grade, $s2grade, $s3grade);
$this->setUser($student2);
try {
$studentgrade = user_external::get_grades_table($course->id, $student1->id);
$this->fail('Exception expected due to not perissions to view other user grades.');
} catch (\moodle_exception $e) {
$this->assertEquals('notingroup', $e->errorcode);
}
}
/**
* Test view_grade_report function
*/
public function test_view_grade_report(): void {
global $USER;
$this->resetAfterTest(true);
$s1grade = 80;
$s2grade = 60;
$s3grade = 50;
list($course, $teacher, $student1, $student2, $student3, $assignment) = $this->load_data($s1grade, $s2grade, $s3grade);
// Redirect events to the sink, so we can recover them later.
$sink = $this->redirectEvents();
$this->setUser($student1);
$result = user_external::view_grade_report($course->id);
$result = external_api::clean_returnvalue(user_external::view_grade_report_returns(), $result);
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
// Check the event details are correct.
$this->assertInstanceOf('\gradereport_user\event\grade_report_viewed', $event);
$this->assertEquals(\context_course::instance($course->id), $event->get_context());
$this->assertEquals($USER->id, $event->get_data()['relateduserid']);
$this->setUser($teacher);
$result = user_external::view_grade_report($course->id, $student1->id);
$result = external_api::clean_returnvalue(user_external::view_grade_report_returns(), $result);
$events = $sink->get_events();
$event = reset($events);
$sink->close();
// Check the event details are correct.
$this->assertInstanceOf('\gradereport_user\event\grade_report_viewed', $event);
$this->assertEquals(\context_course::instance($course->id), $event->get_context());
$this->assertEquals($student1->id, $event->get_data()['relateduserid']);
$this->setUser($student2);
try {
$studentgrade = user_external::view_grade_report($course->id, $student1->id);
$this->fail('Exception expected due to not permissions to view other user grades.');
} catch (\moodle_exception $e) {
$this->assertEquals('nopermissiontoviewgrades', $e->errorcode);
}
}
/**
* Test get_grades_items function case teacher
*/
public function test_get_grade_items_teacher(): void {
$this->resetAfterTest(true);
$s1grade = 80;
$s2grade = 60;
$s3grade = 50;
list($course, $teacher, $student1, $student2, $student3, $assignment) = $this->load_data($s1grade, $s2grade, $s3grade);
// A teacher must see all student grades (in their group only).
$this->setUser($teacher);
grade_set_setting($course->id, 'report_user_showrank', 1);
grade_set_setting($course->id, 'report_user_showpercentage', 1);
grade_set_setting($course->id, 'report_user_showhiddenitems', 1);
grade_set_setting($course->id, 'report_user_showgrade', 1);
grade_set_setting($course->id, 'report_user_showfeedback', 1);
grade_set_setting($course->id, 'report_user_showweight', 1);
grade_set_setting($course->id, 'report_user_showcontributiontocoursetotal', 1);
grade_set_setting($course->id, 'report_user_showlettergrade', 1);
grade_set_setting($course->id, 'report_user_showaverage', 1);
$studentgrades = user_external::get_grade_items($course->id);
$studentgrades = external_api::clean_returnvalue(user_external::get_grade_items_returns(), $studentgrades);
// No warnings returned.
$this->assertCount(0, $studentgrades['warnings']);
// Check that only grades for the student in the teacher group are returned.
$this->assertCount(1, $studentgrades['usergrades']);
$this->assertCount(2, $studentgrades['usergrades'][0]['gradeitems']);
$this->assertEquals($course->id, $studentgrades['usergrades'][0]['courseid']);
$this->assertEquals($student1->id, $studentgrades['usergrades'][0]['userid']);
// Module grades.
$this->assertEquals($assignment->name, $studentgrades['usergrades'][0]['gradeitems'][0]['itemname']);
$this->assertEquals('mod', $studentgrades['usergrades'][0]['gradeitems'][0]['itemtype']);
$this->assertEquals('assign', $studentgrades['usergrades'][0]['gradeitems'][0]['itemmodule']);
$this->assertEquals($assignment->id, $studentgrades['usergrades'][0]['gradeitems'][0]['iteminstance']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['locked']);
$this->assertEquals($assignment->cmidnumber, $studentgrades['usergrades'][0]['gradeitems'][0]['cmid']);
$this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][0]['itemnumber']);
$this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['outcomeid']);
$this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['scaleid']);
$this->assertEquals(80, $studentgrades['usergrades'][0]['gradeitems'][0]['graderaw']);
$this->assertEquals('80.00', $studentgrades['usergrades'][0]['gradeitems'][0]['gradeformatted']);
$this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][0]['grademin']);
$this->assertEquals(100, $studentgrades['usergrades'][0]['gradeitems'][0]['grademax']);
$this->assertEquals('0&ndash;100', $studentgrades['usergrades'][0]['gradeitems'][0]['rangeformatted']);
$this->assertEquals('80.00 %', $studentgrades['usergrades'][0]['gradeitems'][0]['percentageformatted']);
$this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['feedback']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradehiddenbydate']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeneedsupdate']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeishidden']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeislocked']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeisoverridden']);
$this->assertEquals('B-', $studentgrades['usergrades'][0]['gradeitems'][0]['lettergradeformatted']);
$this->assertEquals(1, $studentgrades['usergrades'][0]['gradeitems'][0]['rank']);
$this->assertEquals(3, $studentgrades['usergrades'][0]['gradeitems'][0]['numusers']);
$this->assertEquals(
round(array_sum([$s1grade, $s2grade, $s3grade]) / 3, 2),
$studentgrades['usergrades'][0]['gradeitems'][0]['averageformatted']);
// Course grades.
$this->assertEquals('course', $studentgrades['usergrades'][0]['gradeitems'][1]['itemtype']);
$this->assertEquals(80, $studentgrades['usergrades'][0]['gradeitems'][1]['graderaw']);
$this->assertEquals('80.00', $studentgrades['usergrades'][0]['gradeitems'][1]['gradeformatted']);
$this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][1]['grademin']);
$this->assertEquals(100, $studentgrades['usergrades'][0]['gradeitems'][1]['grademax']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['locked']);
$this->assertEquals('0&ndash;100', $studentgrades['usergrades'][0]['gradeitems'][1]['rangeformatted']);
$this->assertEquals('80.00 %', $studentgrades['usergrades'][0]['gradeitems'][1]['percentageformatted']);
$this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][1]['feedback']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradehiddenbydate']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradeneedsupdate']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradeishidden']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradeislocked']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradeisoverridden']);
$this->assertEquals('B-', $studentgrades['usergrades'][0]['gradeitems'][1]['lettergradeformatted']);
$this->assertEquals(1, $studentgrades['usergrades'][0]['gradeitems'][1]['rank']);
$this->assertEquals(3, $studentgrades['usergrades'][0]['gradeitems'][1]['numusers']);
$this->assertEquals(
round(array_sum([$s1grade, $s2grade, $s3grade]) / 3, 2),
$studentgrades['usergrades'][0]['gradeitems'][1]['averageformatted']);
// Now, override and lock a grade.
$gradegrade = \grade_grade::fetch(['itemid' => $studentgrades['usergrades'][0]['gradeitems'][0]['id'],
'userid' => $studentgrades['usergrades'][0]['userid']]);
$gradegrade->set_overridden(true);
$gradegrade->set_locked(1);
$studentgrades = user_external::get_grade_items($course->id);
$studentgrades = external_api::clean_returnvalue(user_external::get_grade_items_returns(), $studentgrades);
// No warnings returned.
$this->assertCount(0, $studentgrades['warnings']);
// Module grades.
$this->assertTrue($studentgrades['usergrades'][0]['gradeitems'][0]['gradeislocked']);
$this->assertTrue($studentgrades['usergrades'][0]['gradeitems'][0]['gradeisoverridden']);
}
/**
* Test get_grades_items function case student
*/
public function test_get_grade_items_student(): void {
$this->resetAfterTest(true);
$s1grade = 80;
$s2grade = 60;
$s3grade = 50;
list($course, $teacher, $student1, $student2, $student3, $assignment) = $this->load_data($s1grade, $s2grade, $s3grade);
grade_set_setting($course->id, 'report_user_showrank', 1);
grade_set_setting($course->id, 'report_user_showpercentage', 1);
grade_set_setting($course->id, 'report_user_showgrade', 1);
grade_set_setting($course->id, 'report_user_showfeedback', 1);
grade_set_setting($course->id, 'report_user_showweight', 1);
grade_set_setting($course->id, 'report_user_showcontributiontocoursetotal', 1);
grade_set_setting($course->id, 'report_user_showlettergrade', 1);
grade_set_setting($course->id, 'report_user_showaverage', 1);
$this->setUser($student1);
$studentgrades = user_external::get_grade_items($course->id, $student1->id);
$studentgrades = external_api::clean_returnvalue(user_external::get_grade_items_returns(), $studentgrades);
// No warnings returned.
$this->assertCount(0, $studentgrades['warnings']);
// Check that only grades for the student in the teacher group are returned.
$this->assertCount(1, $studentgrades['usergrades']);
$this->assertCount(2, $studentgrades['usergrades'][0]['gradeitems']);
$this->assertEquals($course->id, $studentgrades['usergrades'][0]['courseid']);
$this->assertEquals($student1->id, $studentgrades['usergrades'][0]['userid']);
$this->assertEquals($student1->idnumber, $studentgrades['usergrades'][0]['useridnumber']);
$this->assertEquals($assignment->name, $studentgrades['usergrades'][0]['gradeitems'][0]['itemname']);
$this->assertEquals('mod', $studentgrades['usergrades'][0]['gradeitems'][0]['itemtype']);
$this->assertEquals('assign', $studentgrades['usergrades'][0]['gradeitems'][0]['itemmodule']);
$this->assertEquals($assignment->id, $studentgrades['usergrades'][0]['gradeitems'][0]['iteminstance']);
$this->assertNull($studentgrades['usergrades'][0]['gradeitems'][0]['locked']);
$this->assertEquals($assignment->cmidnumber, $studentgrades['usergrades'][0]['gradeitems'][0]['cmid']);
$this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][0]['itemnumber']);
$this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['outcomeid']);
$this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['scaleid']);
$this->assertEquals(80, $studentgrades['usergrades'][0]['gradeitems'][0]['graderaw']);
$this->assertEquals('80.00', $studentgrades['usergrades'][0]['gradeitems'][0]['gradeformatted']);
$this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][0]['grademin']);
$this->assertEquals(100, $studentgrades['usergrades'][0]['gradeitems'][0]['grademax']);
$this->assertEquals('0&ndash;100', $studentgrades['usergrades'][0]['gradeitems'][0]['rangeformatted']);
$this->assertEquals('80.00 %', $studentgrades['usergrades'][0]['gradeitems'][0]['percentageformatted']);
$this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['feedback']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradehiddenbydate']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeneedsupdate']);
$this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeishidden']);
$this->assertNull($studentgrades['usergrades'][0]['gradeitems'][0]['gradeislocked']);
$this->assertNull($studentgrades['usergrades'][0]['gradeitems'][0]['gradeisoverridden']);
$this->assertEquals('B-', $studentgrades['usergrades'][0]['gradeitems'][0]['lettergradeformatted']);
$this->assertEquals(1, $studentgrades['usergrades'][0]['gradeitems'][0]['rank']);
$this->assertEquals(3, $studentgrades['usergrades'][0]['gradeitems'][0]['numusers']);
$this->assertEquals(
round(array_sum([$s1grade, $s2grade, $s3grade]) / 3, 2),
$studentgrades['usergrades'][0]['gradeitems'][0]['averageformatted']);
// Check that the idnumber for assignment grades is equal to the cmid.
$this->assertEquals((string) $studentgrades['usergrades'][0]['gradeitems'][0]['cmid'],
$studentgrades['usergrades'][0]['gradeitems'][0]['idnumber']);
// Hide one grade for the user.
$gradegrade = new \grade_grade([
'userid' => $student1->id,
'itemid' => $studentgrades['usergrades'][0]['gradeitems'][0]['id']
], true);
$gradegrade->set_hidden(1);
$studentgrades = user_external::get_grade_items($course->id, $student1->id);
$studentgrades = external_api::clean_returnvalue(user_external::get_grade_items_returns(), $studentgrades);
// Check we get only the course final grade.
$this->assertCount(1, $studentgrades['usergrades']);
$this->assertCount(1, $studentgrades['usergrades'][0]['gradeitems']);
$this->assertEquals('course', $studentgrades['usergrades'][0]['gradeitems'][0]['itemtype']);
}
}
+88
View File
@@ -0,0 +1,88 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Tests for gradereport_user library functions.
*
* @package gradereport_user
* @copyright 2015 onwards Ankit agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
namespace gradereport_user;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/grade/report/user/lib.php');
/**
* Class gradereport_user_lib_testcase.
*
* @package gradereport_user
* @copyright 2015 onwards Ankit agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
class lib_test extends \advanced_testcase {
/**
* @var stdClass The user.
*/
private $user;
/**
* @var stdClass The course.
*/
private $course;
/**
* @var \core_user\output\myprofile\tree The navigation tree.
*/
private $tree;
public function setUp(): void {
$this->user = $this->getDataGenerator()->create_user();
$this->course = $this->getDataGenerator()->create_course();
$this->tree = new \core_user\output\myprofile\tree();
$this->resetAfterTest();
}
/**
* Tests the gradereport_user_myprofile_navigation() function.
*/
public function test_gradereport_user_myprofile_navigation(): void {
$this->setAdminUser();
$iscurrentuser = false;
gradereport_user_myprofile_navigation($this->tree, $this->user, $iscurrentuser, $this->course);
$reflector = new \ReflectionObject($this->tree);
$nodes = $reflector->getProperty('nodes');
$this->assertArrayHasKey('grade', $nodes->getValue($this->tree));
}
/**
* Tests the gradereport_user_myprofile_navigation() function for a user
* without permission to view the grade node.
*/
public function test_gradereport_user_myprofile_navigation_without_permission(): void {
$this->setUser($this->user);
$iscurrentuser = true;
gradereport_user_myprofile_navigation($this->tree, $this->user, $iscurrentuser, $this->course);
$reflector = new \ReflectionObject($this->tree);
$nodes = $reflector->getProperty('nodes');
$this->assertArrayNotHasKey('grade', $nodes->getValue($this->tree));
}
}
@@ -0,0 +1,81 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for the gradereport_user implementation of the privacy API.
*
* @package gradereport_user
* @category test
* @copyright 2018 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace gradereport_user\privacy;
defined('MOODLE_INTERNAL') || die();
use core_privacy\local\request\writer;
/**
* Unit tests for the gradereport_user implementation of the privacy API.
*
* @copyright 2018 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends \core_privacy\tests\provider_testcase {
/**
* Basic setup for these tests.
*/
public function setUp(): void {
$this->resetAfterTest(true);
}
/**
* Ensure that export_user_preferences returns no data if the user has no data.
*/
public function test_export_user_preferences_not_defined(): void {
$user = \core_user::get_user_by_username('admin');
provider::export_user_preferences($user->id);
$writer = writer::with_context(\context_system::instance());
$this->assertFalse($writer->has_any_data());
}
/**
* Ensure that export_user_preferences returns single preferences.
* These preferences can be set on each course, but the value is shared in the whole site.
*/
public function test_export_user_preferences_single(): void {
// Define a user preference.
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
set_user_preference('gradereport_user_view_user', 1, $user);
// Validate exported data.
provider::export_user_preferences($user->id);
$context = \context_user::instance($user->id);
/** @var \core_privacy\tests\request\content_writer $writer */
$writer = writer::with_context($context);
$this->assertTrue($writer->has_any_data());
$prefs = $writer->get_user_preferences('gradereport_user');
$this->assertCount(1, (array) $prefs);
$this->assertEquals(
get_string('privacy:metadata:preference:gradereport_user_view_user', 'gradereport_user'),
$prefs->gradereport_user_view_user->description
);
$this->assertEquals(get_string('yes'), $prefs->gradereport_user_view_user->value);
}
}