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,65 @@
<?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 mod_choice\backup;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . "/phpunit/classes/restore_date_testcase.php");
/**
* Restore date tests.
*
* @package mod_choice
* @copyright 2017 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class restore_date_test extends \restore_date_testcase {
public function test_restore_dates(): void {
global $DB, $USER;
$time = 100000;
$record = ['timeopen' => $time, 'timeclose' => $time + 1];
list($course, $choice) = $this->create_course_and_module('choice', $record);
$options = $DB->get_records('choice_options', ['choiceid' => $choice->id]);
$DB->set_field('choice_options', 'timemodified', $time);
$option = reset($options);
$cm = $DB->get_record('course_modules', ['id' => $choice->cmid]);
choice_user_submit_response($option->id, $choice, $USER->id, $course, $cm);
$answer = $DB->get_record('choice_answers', ['choiceid' => $choice->id]);
// Do backup and restore.
$newcourseid = $this->backup_and_restore($course);
$newchoice = $DB->get_record('choice', ['course' => $newcourseid]);
$newoptions = $DB->get_records('choice_options', ['choiceid' => $newchoice->id]);
$this->assertFieldsNotRolledForward($choice, $newchoice, ['timemodified']);
$props = ['timeopen', 'timeclose'];
$this->assertFieldsRolledForward($choice, $newchoice, $props);
// Options check.
foreach ($newoptions as $newoption) {
$this->assertEquals($time, $newoption->timemodified);
}
// Answers check.
$newanswer = $DB->get_record('choice_answers', ['choiceid' => $newchoice->id]);
$this->assertEquals($answer->timemodified, $newanswer->timemodified);
}
}
@@ -0,0 +1,55 @@
@mod @mod_choice @core_completion
Feature: Automatic completion in the choice activity
In order for me to know what to do to complete the choice activity
As a student
I need to be able to see the completion requirements of the choice activity
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "course" exists:
| fullname | Course 1 |
| shortname | C1 |
| category | 0 |
| enablecompletion | 1 |
And the following "activity" exists:
| activity | choice |
| name | What to drink? |
| intro | Friday drinks, anyone? |
| course | C1 |
| idnumber | choice1 |
| completion | 2 |
| completionview | 1 |
| completionsubmit | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
Scenario: Viewing a choice activity with automatic completion as a student
When I am on the "What to drink?" "choice activity" page logged in as student1
Then the "View" completion condition of "What to drink?" is displayed as "done"
And the "Make a choice" completion condition of "What to drink?" is displayed as "todo"
And I set the field "Beer" to "1"
And I press "Save my choice"
And the "View" completion condition of "What to drink?" is displayed as "done"
And the "Make a choice" completion condition of "What to drink?" is displayed as "done"
Scenario: Viewing a choice activity with automatic completion as a teacher
When I am on the "What to drink?" "choice activity" page logged in as teacher1
Then "What to drink?" should have the "View" completion condition
And "What to drink?" should have the "Make a choice" completion condition
@javascript
Scenario: Overriding automatic choice completion for a user
Given I am on the "Course 1" course page logged in as teacher1
And I navigate to "Reports" in current page administration
And I click on "Activity completion" "link"
And I click on "Student 1, What to drink?: Not completed" "link"
And I press "Save changes"
And I log out
When I am on the "What to drink?" "choice activity" page logged in as student1
Then the "View" completion condition of "What to drink?" overridden by "Teacher 1" is displayed as "done"
And the "Make a choice" completion condition of "What to drink?" overridden by "Teacher 1" is displayed as "done"
@@ -0,0 +1,81 @@
@mod @mod_choice @core_completion
Feature: Manual completion in the choice activity
To avoid navigating from the choice activity to the course homepage to mark the choice activity as complete
As a student
I need to be able to mark the choice activity as complete within the choice activity itself
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "course" exists:
| fullname | Course 1 |
| shortname | C1 |
| category | 0 |
| enablecompletion | 1 |
And the following "activity" exists:
| activity | choice |
| name | What to drink? |
| intro | Friday drinks, anyone? |
| course | C1 |
| idnumber | choice1 |
| completion | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
@javascript
Scenario: Toggle manual completion as a student
Given I am on the "What to drink?" "choice activity" page logged in as student1
And the manual completion button of "What to drink?" is displayed as "Mark as done"
When I toggle the manual completion state of "What to drink?"
Then the manual completion button of "What to drink?" is displayed as "Done"
But "Mark as done" "button" should not exist
# Just make sure that the change persisted.
And I reload the page
And I wait until the page is ready
And I should not see "Mark as done"
And the manual completion button of "What to drink?" is displayed as "Done"
And I toggle the manual completion state of "What to drink?"
And the manual completion button of "What to drink?" is displayed as "Mark as done"
But "Done" "button" should not exist
# Just make sure that the change persisted.
And I reload the page
And the manual completion button of "What to drink?" is displayed as "Mark as done"
But "Done" "button" should not exist
Scenario: Viewing a choice activity with manual completion as a teacher
When I am on the "What to drink?" "choice activity" page logged in as teacher1
Then the manual completion button for "What to drink?" should be disabled
@javascript
Scenario: Overriding a manual choice completion for a user to done
Given I am on the "Course 1" course page logged in as teacher1
And I navigate to "Reports" in current page administration
And I click on "Activity completion" "link"
And I click on "Student 1, What to drink?: Not completed" "link"
And I press "Save changes"
And I log out
When I am on the "What to drink?" "choice activity" page logged in as student1
Then the manual completion button of "What to drink?" overridden by "Teacher 1" is displayed as "Done"
And I toggle the manual completion state of "What to drink?"
And the manual completion button of "What to drink?" is displayed as "Mark as done"
@javascript
Scenario: Overriding a manual choice completion for a user to not done
Given I am on the "What to drink?" "choice activity" page logged in as student1
And I press "Mark as done"
And I wait until the page is ready
And I log out
And I am on the "Course 1" course page logged in as teacher1
And I navigate to "Reports" in current page administration
And I click on "Activity completion" "link"
And I click on "Student 1, What to drink?: Completed" "link"
And I press "Save changes"
And I log out
Given I am on the "What to drink?" "choice activity" page logged in as student1
Then the manual completion button of "What to drink?" overridden by "Teacher 1" is displayed as "Mark as done"
And I toggle the manual completion state of "What to drink?"
And the manual completion button of "What to drink?" is displayed as "Done"
+26
View File
@@ -0,0 +1,26 @@
@mod @mod_choice
Feature: Add choice activity
In order to ask questions as a choice of multiple responses
As a teacher
I need to add choice activities to courses
Scenario: Add a choice activity and complete the activity as a student
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | option | section |
| choice | Choice name | Choice Description | C1 | choice1 | Option 1, Option 2 | 1 |
When I log in as "student1"
And I am on "Course 1" course homepage
And I choose "Option 1" from "Choice name" choice activity
Then I should see "Your selection: Option 1"
And I should see "Your choice has been saved"
@@ -0,0 +1,51 @@
@mod @mod_choice
Feature: Allow choice preview
In order to allow students to preview options before a choice activity is opened for submission
As a teacher
I need to enable the choice preview option
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activity" exists:
| activity | choice |
| course | C1 |
| idnumber | choice1 |
| name | Choice name |
| intro | Choice Description |
| section | 1 |
| option | Option 1, Option 2 |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
Scenario: Enable the choice preview option and view the activity as a student before the opening time
And I follow "Choice name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| timeopen[enabled] | 1 |
| timeclose[enabled] | 1 |
| timeopen[day] | 30 |
| timeopen[month] | December |
| timeopen[year] | 2037 |
| timeclose[day] | 31 |
| timeclose[month] | December |
| timeclose[year] | 2037 |
| Show preview | 1 |
And I press "Save and return to course"
And I log out
When I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Choice name"
Then I should see "This is just a preview of the available options for this activity"
And the "choice_1" "radio" should be disabled
And the "choice_2" "radio" should be disabled
And "Save my choice" "button" should not exist
@@ -0,0 +1,86 @@
<?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/>.
/**
* Steps definitions for choice activity.
*
* @package mod_choice
* @category test
* @copyright 2013 David Monllaó
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
require_once(__DIR__ . '/../../../../lib/behat/behat_base.php');
/**
* Choice activity definitions.
*
* @package mod_choice
* @category test
* @copyright 2013 David Monllaó
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_mod_choice extends behat_base {
/**
* Chooses the specified option from the choice activity named as specified. You should be located in the activity's course page.
*
* @Given /^I choose "(?P<option_string>(?:[^"]|\\")*)" from "(?P<choice_activity_string>(?:[^"]|\\")*)" choice activity$/
* @param string $option
* @param string $choiceactivity
* @return array
*/
public function I_choose_option_from_activity($option, $choiceactivity) {
$this->execute('behat_navigation::i_am_on_page_instance', [$this->escape($choiceactivity), 'choice activity']);
$this->execute('behat_forms::i_set_the_field_to', array( $this->escape($option), 1));
$this->execute("behat_forms::press_button", get_string('savemychoice', 'choice'));
}
/**
* Chooses the specified option from the choice activity named as specified and save the choice.
* You should be located in the activity's course page.
*
* @Given /^I choose options (?P<option_string>"(?:[^"]|\\")*"(?:,"(?:[^"]|\\")*")*) from "(?P<choice_activity_string>(?:[^"]|\\")*)" choice activity$/
* @param string $option
* @param string $choiceactivity
* @return array
*/
public function I_choose_options_from_activity($option, $choiceactivity) {
// Get Behat general and forms contexts.
$behatgeneral = behat_context_helper::get('behat_general');
$behatforms = behat_context_helper::get('behat_forms');
// Go to choice activity.
$this->execute("behat_navigation::i_am_on_page_instance", [$this->escape($choiceactivity), 'choice activity']);
// Wait for page to be loaded.
$this->wait_for_pending_js();
// Set all options.
$options = explode('","', trim($option, '"'));
foreach ($options as $option) {
$behatforms->i_set_the_field_to($this->escape($option), '1');
}
// Save choice.
$behatforms->press_button(get_string('savemychoice', 'choice'));
}
}
@@ -0,0 +1,105 @@
@mod @mod_choice
Feature: Editing choice block
In order to customise choice page
As a teacher or admin
I need to add remove block from the choice page
# This tests that the hacky block editing is not borked by legacy forms in choice activity.
Scenario: Add a choice activity as admin and check blog menu block should contain link.
Given the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "activity" exists:
| activity | choice |
| course | C1 |
| idnumber | choice1 |
| name | Choice name 1 |
| intro | Choice Description 1 |
| section | 1 |
| option | Option 1, Option 2 |
And the following "blocks" exist:
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
| blog_menu | Activity module | choice1 | mod-choice-* | side-pre |
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
And I follow "Choice name 1"
And I should see "View all entries about this Choice"
When I configure the "Blog menu" block
And I press "Save changes"
Then I should see "View all entries about this Choice"
And I open the "Blog menu" blocks action menu
And I click on "Delete" "link" in the "Blog menu" "block"
And I press "Yes"
And I should not see "View all entries about this Choice"
And I should see "Choice Description 1"
Scenario: Add a choice activity as teacher and check blog menu block contain choice link.
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activity" exists:
| activity | choice |
| course | C1 |
| idnumber | choice1 |
| name | Choice name 1 |
| intro | Choice Description 1 |
| section | 1 |
| option | Option 1, Option 2 |
And the following "blocks" exist:
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
| blog_menu | Activity module | choice1 | mod-choice-* | side-pre |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I follow "Choice name 1"
And I should see "View all entries about this Choice"
When I configure the "Blog menu" block
And I press "Save changes"
Then I should see "View all entries about this Choice"
And I open the "Blog menu" blocks action menu
And I click on "Delete" "link" in the "Blog menu" "block"
And I press "Yes"
And I should not see "View all entries about this Choice"
And I should see "Choice Description 1"
Scenario: Add a choice activity as teacher (with dual role) and check blog menu block contain choice link.
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| teacher1 | C1 | student |
And the following "activity" exists:
| activity | choice |
| course | C1 |
| idnumber | choice1 |
| name | Choice name 1 |
| intro | Choice Description 1 |
| section | 1 |
| option | Option 1, Option 2 |
And the following "blocks" exist:
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
| blog_menu | Activity module | choice1 | mod-choice-* | side-pre |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I follow "Choice name 1"
And I should see "View all entries about this Choice"
When I configure the "Blog menu" block
And I press "Save changes"
Then I should see "View all entries about this Choice"
And I open the "Blog menu" blocks action menu
And I click on "Delete" "link" in the "Blog menu" "block"
And I press "Yes"
And I should not see "View all entries about this Choice"
And I should see "Choice Description 1"
@@ -0,0 +1,56 @@
@mod @mod_choice
Feature: Teacher can choose whether to allow students to change their choice response
In order to allow students to change their choice
As a teacher
I need to enable the option to change the choice
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
Scenario: Change a choice response as a student
Given the following "activity" exists:
| activity | choice |
| course | C1 |
| idnumber | Choice name |
| name | Choice name |
| intro | Choice Description |
| section | 1 |
| option | Option 1, Option 2 |
| allowupdate | 0 |
When I am on the "Course 1" course page logged in as student1
And I choose "Option 1" from "Choice name" choice activity
And I should see "Your selection: Option 1"
And I should see "Your choice has been saved"
Then "Save my choice" "button" should not exist
Scenario: Change a choice response as a student
Given the following "activity" exists:
| activity | choice |
| course | C1 |
| idnumber | Choice name |
| name | Choice name |
| intro | Choice Description |
| section | 1 |
| option | Option 1, Option 2 |
| allowupdate | 1 |
When I am on the "Course 1" course page logged in as student1
And I choose "Option 1" from "Choice name" choice activity
And I should see "Your selection: Option 1"
And I should see "Your choice has been saved"
Then I should see "Your selection: Option 1"
And "Save my choice" "button" should exist
And "Remove my choice" "link" should exist
And I set the field "Option 2" to "1"
And I press "Save my choice"
And I should see "Your choice has been saved"
And I should see "Your selection: Option 2"
@@ -0,0 +1,104 @@
@mod @mod_choice
Feature: Restrict availability of the choice module to a deadline
In order to limit the time a student can mace a selection
As a teacher
I need to restrict answering to within a time period
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
Scenario: Enable the choice activity with a start deadline in the future
Given the following "activities" exist:
| activity | name | intro | course | idnumber | option | section |
| choice | Choice name | Choice Description | C1 | choice1 | Option 1, Option 2 | 1 |
And I am on "Course 1" course homepage
And I follow "Choice name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| timeopen[enabled] | 1 |
| timeopen[day] | 30 |
| timeopen[month] | December |
| timeopen[year] | 2037 |
And I press "Save and return to course"
And I log out
When I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Choice name"
Then "choice_1" "radio" should not exist
And "choice_2" "radio" should not exist
And "Save my choice" "button" should not exist
Scenario: Enable the choice activity with a start deadline in the past
Given the following "activities" exist:
| activity | name | intro | course | idnumber | option | section |
| choice | Choice name | Choice Description | C1 | choice1 | Option 1, Option 2 | 1 |
And I am on "Course 1" course homepage
And I follow "Choice name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| timeopen[enabled] | 1 |
| timeopen[day] | 30 |
| timeopen[month] | December |
| timeopen[year] | 2007 |
And I press "Save and return to course"
And I log out
When I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Choice name"
And "choice_1" "radio" should exist
And "choice_2" "radio" should exist
And "Save my choice" "button" should exist
Scenario: Enable the choice activity with a end deadline in the future
Given the following "activities" exist:
| activity | name | intro | course | idnumber | option | section |
| choice | Choice name | Choice Description | C1 | choice1 | Option 1, Option 2 | 1 |
And I am on "Course 1" course homepage
And I follow "Choice name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| timeclose[enabled] | 1 |
| timeclose[day] | 30 |
| timeclose[month] | December |
| timeclose[year] | 2037 |
And I press "Save and return to course"
And I log out
When I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Choice name"
And "choice_1" "radio" should exist
And "choice_2" "radio" should exist
And "Save my choice" "button" should exist
Scenario: Enable the choice activity with a end deadline in the past
Given the following "activities" exist:
| activity | name | intro | course | idnumber | option | section |
| choice | Choice name | Choice Description | C1 | choice1 | Option 1, Option 2 | 1 |
And I am on "Course 1" course homepage
And I follow "Choice name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| timeclose[enabled] | 1 |
| timeclose[day] | 30 |
| timeclose[month] | December |
| timeclose[year] | 2007 |
And I press "Save and return to course"
And I log out
When I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Choice name"
Then "choice_1" "radio" should not exist
And "choice_2" "radio" should not exist
And "Save my choice" "button" should not exist
@@ -0,0 +1,51 @@
@mod @mod_choice
Feature: Choice with no calendar capabilites
In order to allow work effectively
As a teacher
I need to be able to create choices even when I cannot edit calendar events
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And I log in as "admin"
And I am on the "Course 1" "permissions" page
And I override the system permissions of "Teacher" role with:
| capability | permission |
| moodle/calendar:manageentries | Prohibit |
And I log out
Scenario: Editing a choice
And the following "activities" exist:
| activity | name | intro | course | idnumber | option | section |
| choice | Test choice name | Test choice description | C1 | choice1 | Option 1, Option 2 | 1 |
Given I log in as "admin"
And I am on "Course 1" course homepage
And I follow "Test choice name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| id_timeopen_enabled | 1 |
| id_timeopen_day | 1 |
| id_timeopen_month | 1 |
| id_timeopen_year | 2017 |
| id_timeclose_enabled | 1 |
| id_timeclose_day | 1 |
| id_timeclose_month | 2 |
| id_timeclose_year | 2017 |
And I press "Save and return to course"
And I log out
When I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I follow "Test choice name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| id_timeopen_year | 2018 |
| id_timeclose_year | 2018 |
And I press "Save and return to course"
Then I should see "Test choice name"
+60
View File
@@ -0,0 +1,60 @@
@mod @mod_choice
Feature: Group choice
In order to view choice responses for large courses
As a user
I need to filter the responses to a choice by group
Background:
And the following "courses" exist:
| fullname | shortname |
| Test Course 1 | C1 |
And the following "groups" exist:
| name | course | idnumber | participation |
| Group 1 | C1 | G1 | 1 |
| Group 2 | C1 | G2 | 1 |
| Group 3 | C1 | G3 | 0 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | TeacherG1 | 1 | teacher1@example.com |
| user1 | User1G1 | 1 | user1@example.com |
| user2 | User2G2 | 2 | user2@example.com |
| user3 | User3None | 3 | user3@example.com |
| user4 | User4NPgroup | 4 | user4@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| user1 | C1 | student |
| user2 | C1 | student |
| user3 | C1 | student |
| user4 | C1 | student |
And the following "group members" exist:
| user | group |
| teacher1 | G1 |
| user1 | G1 |
| user2 | G2 |
| user4 | G3 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | showresults | publish | groupmode |
| choice | Separate Choice | Choice with separate groups | C1 | choice1 | 3 | 1 | 1 |
| choice | Visible Choice | Choice with visible groups | C1 | choice2 | 3 | 1 | 2 |
Scenario Outline: Users should see their own participation groups in "separate groups" mode, and all
participation groups in "visible groups" mode.
Given I am on the "<choice>" "choice activity" page logged in as "<user>"
Then I <all> "All participants"
And I <G1> "Group 1"
And I <G2> "Group 2"
And I should not see "Group 3"
Examples:
| choice | user | all | G1 | G2 |
| choice1 | teacher1 | should see | should see | should see |
| choice1 | user1 | should not see | should see | should not see |
| choice1 | user2 | should not see | should not see | should see |
| choice1 | user3 | should see | should not see | should not see |
| choice1 | user4 | should see | should not see | should not see |
| choice2 | teacher1 | should see | should see | should see |
| choice2 | user1 | should see | should see | should see |
| choice2 | user2 | should see | should see | should see |
| choice2 | user3 | should see | should see | should see |
| choice2 | user4 | should see | should see | should see |
@@ -0,0 +1,134 @@
@mod @mod_choice
Feature: Include responses from inactive users
In order to view responses from inactive or suspended users in choice results
As a teacher
I need to enable the choice include inactive option
Background:
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 |
| student3 | Student | 3 | student3@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
Scenario: Enable the choice include inactive option and check that responses from inactive students are visible
Given the following "activity" exists:
| activity | choice |
| course | C1 |
| idnumber | choice1 |
| name | Choice name |
| intro | Choice Description |
| section | 1 |
| option | Option 1, Option 2, Option 3 |
| includeinactive | 1 |
And I log in as "student1"
And I am on "Course 1" course homepage
And I choose "Option 1" from "Choice name" choice activity
And I log out
And I log in as "student2"
And I am on "Course 1" course homepage
And I choose "Option 2" from "Choice name" choice activity
And I log out
And I log in as "student3"
And I am on "Course 1" course homepage
And I choose "Option 3" from "Choice name" choice activity
And I log out
And the following "course enrolments" exist:
| user | course | role | status |
| student1 | C1 | student | 1 |
When I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Choice name" "link" in the "region-main" "region"
And I navigate to "Responses" in current page administration
Then I should see "Student 1"
And I should see "Student 2"
And I should see "Student 3"
And I log out
And the following "course enrolments" exist:
| user | course | role | timestart |
| student2 | C1 | student | 2145830400 |
When I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Choice name" "link" in the "region-main" "region"
Then I navigate to "Responses" in current page administration
And I should see "Student 1"
And I should see "Student 2"
And I should see "Student 3"
And I log out
And the following "course enrolments" exist:
| user | course | role | timeend |
| student3 | C1 | student | 1425168000 |
When I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Choice name" "link" in the "region-main" "region"
Then I navigate to "Responses" in current page administration
And I should see "Student 1"
And I should see "Student 2"
And I should see "Student 3"
And I log out
Scenario: Disable the choice include inactive option and check that responses from inactive students are not visible
Given the following "activity" exists:
| activity | choice |
| course | C1 |
| idnumber | choice1 |
| name | Choice name |
| intro | Choice Description |
| section | 1 |
| option | Option 1, Option 2, Option 3 |
| includeinactive | 0 |
And I log in as "student1"
And I am on "Course 1" course homepage
And I choose "Option 1" from "Choice name" choice activity
And I log out
And I log in as "student2"
And I am on "Course 1" course homepage
And I choose "Option 2" from "Choice name" choice activity
And I log out
And I log in as "student3"
And I am on "Course 1" course homepage
And I choose "Option 3" from "Choice name" choice activity
And I log out
And the following "course enrolments" exist:
| user | course | role | status |
| student1 | C1 | student | 1 |
When I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Choice name" "link" in the "region-main" "region"
Then I navigate to "Responses" in current page administration
And I should not see "Student 1"
And I should see "Student 2"
And I should see "Student 3"
And I log out
And the following "course enrolments" exist:
| user | course | role | timestart |
| student2 | C1 | student | 2145830400 |
When I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Choice name" "link" in the "region-main" "region"
Then I navigate to "Responses" in current page administration
And I should not see "Student 1"
And I should not see "Student 2"
And I should see "Student 3"
And I log out
And the following "course enrolments" exist:
| user | course | role | timeend |
| student3 | C1 | student | 1425168000 |
When I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Choice name" "link" in the "region-main" "region"
Then I navigate to "Responses" in current page administration
And I should not see "Student 1"
And I should not see "Student 2"
And I should not see "Student 3"
And I log out
@@ -0,0 +1,60 @@
@mod @mod_choice
Feature: Limit choice responses
In order to restrict students from selecting a response more than a specified number of times
As a teacher
I need to limit the choice responses
Scenario: Limit the number of responses allowed for a choice activity and verify the result as students
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 |
| student3 | Student | 3 | student3@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
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 | name | intro | course | idnumber | option | showavailable | limitanswers |
| choice | Choice name | Choice description | C1 | choice1 | Option 1, Option 2 | 1 | 1 |
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I follow "Choice name"
And I navigate to "Settings" in current page administration
And I set the field "Limit 1" to "1"
And I press "Save and display"
And I log out
When I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Choice name"
And I choose "Option 1" from "Choice name" choice activity
Then I should see "Your selection: Option 1"
And I should see "Your choice has been saved"
And I log out
And I log in as "student2"
And I am on "Course 1" course homepage
And I follow "Choice name"
And I should see "Option 1 (Full)"
And I should see "Responses: 1"
And I should see "Limit: 1"
And the "choice_1" "radio" should be disabled
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I follow "Choice name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Limit the number of responses allowed | No |
And I press "Save and return to course"
And I log out
And I log in as "student3"
And I am on "Course 1" course homepage
And I follow "Choice name"
Then I should not see "Limit: 1"
And the "choice_1" "radio" should be enabled
@@ -0,0 +1,121 @@
@mod @mod_choice
Feature: Teacher can modify choices of the students
In order to have all students choices
As a teacher
I need to be able to make choice for studnets
Background:
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 |
| student3 | Student | 3 | student3@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
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 | name | intro | course | idnumber | option |
| choice | Choice name | Test choice description | C1 | choice1 | Option 1, Option 2, Option 3 |
@javascript
Scenario: Delete students choice response as a teacher
Given I am on the "Choice name" "choice activity editing" page logged in as teacher1
And I expand all fieldsets
And I set the field "Show column for unanswered" to "Yes"
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
And I choose "Option 1" from "Choice name" choice activity
Then I should see "Your selection: Option 1"
And I should see "Your choice has been saved"
And I log out
And I log in as "teacher1"
And I change window size to "large"
And I am on the "Choice name" "choice activity" page
And I navigate to "Responses" in current page administration
And I click on "Student 1 Option 1" "checkbox"
And I select "Delete" from the "With selected" singleselect
And "Student 1 Option 1" "checkbox" should not exist
And "Student 1 Not answered yet" "checkbox" should exist
@javascript
Scenario: Teacher set answers of students who did not respond or change existing answers
Given I am on the "Choice name" "choice activity editing" page logged in as teacher1
And I expand all fieldsets
And I set the field "Show column for unanswered" to "Yes"
And I press "Save and return to course"
And I log out
And I am on the "Course 1" course page logged in as student1
And I choose "Option 1" from "Choice name" choice activity
Then I should see "Your selection: Option 1"
And I should see "Your choice has been saved"
And I log out
And I change window size to "large"
And I am on the "Choice name" "choice activity" page logged in as teacher1
And I navigate to "Responses" in current page administration
And I click on "Student 1 Option 1" "checkbox"
And I click on "Student 2 Not answered yet" "checkbox"
And I click on "Student 3 Not answered yet" "checkbox"
And I select "Choose: Option 2" from the "With selected" singleselect
And "Student 1 Option 1" "checkbox" should not exist
And "Student 2 Not answered yet" "checkbox" should not exist
And "Student 3 Not answered yet" "checkbox" should not exist
And "Student 1 Option 2" "checkbox" should exist
And "Student 2 Option 2" "checkbox" should exist
And "Student 3 Option 2" "checkbox" should exist
@javascript
Scenario: Teacher can delete answers in the multiple answer choice
Given I am on the "Choice name" "choice activity editing" page logged in as teacher1
And I set the field "Allow more than one choice to be selected" to "Yes"
And I press "Save and return to course"
And I log out
And I am on the "Course 1" course page logged in as student1
And I choose options "Option 1","Option 2" from "Choice name" choice activity
And I should see "Your selection: Option 1; Option 2"
And I should see "Your choice has been saved"
And I log out
And I change window size to "large"
And I am on the "Choice name" "choice activity" page logged in as teacher1
And I navigate to "Responses" in current page administration
And I click on "Student 1 Option 2" "checkbox"
And I select "Delete" from the "With selected" singleselect
And I click on "Student 1 Option 1" "checkbox"
And I select "Choose: Option 3" from the "With selected" singleselect
And I log out
And I am on the "Choice name" "choice activity" page logged in as student1
And I should see "Your selection: Option 1; Option 3"
@javascript
Scenario: Teacher can manage answers on view page if the names are displayed
Given I am on the "Course 1" course page logged in as student1
And I choose "Option 1" from "Choice name" choice activity
Then I should see "Your selection: Option 1"
And I should see "Your choice has been saved"
And I log out
And I change window size to "large"
And I am on the "Choice name" "choice activity editing" page logged in as teacher1
And I set the following fields to these values:
| Publish results | Always show results to students |
| Privacy of results | Publish full results, showing names and their choices |
| Show column for unanswered | Yes |
And I press "Save and display"
And I click on "Student 1 Option 1" "checkbox"
And I click on "Student 2 Not answered yet" "checkbox"
And I select "Choose: Option 3" from the "With selected" singleselect
And "Student 1 Option 1" "checkbox" should not exist
And "Student 1 Option 3" "checkbox" should exist
And "Student 2 Not answered yet" "checkbox" should not exist
And "Student 2 Option 3" "checkbox" should exist
And I click on "Student 1 Option 3" "checkbox"
And I select "Delete" from the "With selected" singleselect
And "Student 1 Option 3" "checkbox" should not exist
And "Student 1 Not answered yet" "checkbox" should exist
@@ -0,0 +1,87 @@
@mod @mod_choice
Feature: Multiple option choice response
In order to ask questions as a choice of multiple responses
As a teacher
I need to add choice activities to courses with multiple options enabled
Scenario: Complete a choice with multiple options enabled
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activity" exist:
| activity | name | intro | course | idnumber | option | allowmultiple |
| choice | Choice name | Choice description | C1 | 00001 | Option 1, Option 2, Option 3 | 1 |
When I log in as "student1"
And I am on "Course 1" course homepage
And I choose options "Option 1","Option 2" from "Choice name" choice activity
Then I should see "Your selection: Option 1; Option 2"
And I should see "Your choice has been saved"
Scenario: Complete a choice with multiple options enabled and limited responses set
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 "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following "activity" exist:
| activity | name | intro | course | idnumber | option | allowmultiple | showavailable | limitanswers |
| choice | Choice name | Choice description | C1 | choice1 | Option 1, Option 2, Option 3 | 1 | 1 | 1 |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I follow "Choice name"
And I follow "Settings"
And I set the following fields to these values:
| Limit 1 | 1 |
| Limit 2 | 1 |
| Limit 3 | 1 |
And I press "Save and display"
And I log out
When I log in as "student1"
And I am on "Course 1" course homepage
And I choose options "Option 1","Option 2" from "Choice name" choice activity
Then I should see "Your selection: Option 1; Option 2"
And I should see "Your choice has been saved"
And I log out
And I log in as "student2"
And I am on "Course 1" course homepage
And I follow "Choice name"
And I should see "Option 1 (Full)"
And I should see "Option 2 (Full)"
And I should see "Option 3"
And the "#choice_1" "css_element" should be disabled
And the "#choice_2" "css_element" should be disabled
And the "#choice_3" "css_element" should be enabled
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I follow "Choice name"
And I navigate to "Responses" in current page administration
Then I should see "Option 1 (Full)"
And I should see "Limit: 1"
And I am on "Course 1" course homepage with editing mode on
And I follow "Choice name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Limit the number of responses allowed | No |
And I press "Save and return to course"
And I am on "Course 1" course homepage
And I follow "Choice name"
And I navigate to "Responses" in current page administration
Then I should not see "Limit: 1"
And I log out
+54
View File
@@ -0,0 +1,54 @@
@mod @mod_choice
Feature: Test the display of the choice module on my home
In order to know my status in a choice activity
As a user
I need to see it in My dashboard.
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | option | section |
| choice | Test choice name | Test choice description | C1 | choice1 | Option 1, Option 2 | 1 |
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I follow "Test choice name"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| timeopen[enabled] | 1 |
| timeclose[enabled] | 1 |
| timeclose[day] | 1 |
| timeclose[month] | January |
| timeclose[year] | 2030 |
| timeclose[hour] | 08 |
| timeclose[minute] | 00 |
| Allow choice to be updated | No |
And I press "Save and return to course"
And I log out
Scenario: View my home as a student after answering the choice
Given I log in as "student1"
And I am on "Course 1" course homepage
And I choose "Option 1" from "Test choice name" choice activity
And I should see "Your selection: Option 1"
And I should see "Your choice has been saved"
And "Save my choice" "button" should not exist
And I log out
Scenario: View my home as a teacher
Given I log in as "student1"
And I am on "Course 1" course homepage
And I choose "Option 1" from "Test choice name" choice activity
And I should see "Your selection: Option 1"
And I should see "Your choice has been saved"
And "Save my choice" "button" should not exist
And I log out
+117
View File
@@ -0,0 +1,117 @@
@mod @mod_choice
Feature: A student can see how the results of the choice activity will be published
In order to put my mind at ease when it comes to answering a choice
As a student
I need to learn how my choice will be handled and published to the other course participants.
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And I log in as "teacher1"
Scenario: Results will not be published to the students
Given the following "activities" exist:
| activity | name | intro | course | idnumber | option |
| choice | Choice 1 | Choice description | C1 | choice1 | Option 1, Option 2 |
And I am on "Course 1" course homepage
And I follow "Choice 1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Publish results | Do not publish results to students |
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
When I follow "Choice 1"
Then I should see "The results of this activity will not be published after you answer."
Scenario: Full results will be shown to the students after they answer
Given the following "activities" exist:
| activity | name | intro | course | idnumber | option |
| choice | Choice 1 | Choice description | C1 | choice1 | Option 1, Option 2 |
And I am on "Course 1" course homepage
When I follow "Choice 1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Publish results | Show results to students after they answer |
| Privacy of results | Publish full results, showing names and their choices |
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
When I follow "Choice 1"
Then I should see "Full results, showing everyone's choices, will be published after you answer."
Scenario: Anonymous results will be shown to students after they answer
Given the following "activities" exist:
| activity | name | intro | course | idnumber | option |
| choice | Choice 1 | Choice description | C1 | choice1 | Option 1, Option 2 |
And I am on "Course 1" course homepage
When I follow "Choice 1"
And I navigate to "Settings" in current page administration
And I set the field "Publish results" to "Show results to students after they answer"
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
When I follow "Choice 1"
Then I should see "Anonymous results will be published after you answer."
Scenario: Full results will be shown to students only after the choice is closed
Given the following "activities" exist:
| activity | name | intro | course | idnumber | option |
| choice | Choice 1 | Choice description | C1 | choice1 | Option 1, Option 2 |
And I am on "Course 1" course homepage
When I follow "Choice 1"
And I navigate to "Settings" in current page administration
And I set the field "Publish results" to "Show results to students only after the choice is closed"
And I set the field "Privacy of results" to "Publish full results, showing names and their choices"
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
When I follow "Choice 1"
Then I should see "Full results, showing everyone's choices, will be published after the activity is closed."
Scenario: Anonymous results will be shown to students only after the choice is closed
Given the following "activities" exist:
| activity | name | intro | course | idnumber | option |
| choice | Choice 1 | Choice description | C1 | choice1 | Option 1, Option 2 |
And I am on "Course 1" course homepage
When I follow "Choice 1"
And I navigate to "Settings" in current page administration
And I set the field "Publish results" to "Show results to students only after the choice is closed"
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
When I follow "Choice 1"
Then I should see "Anonymous results will be published after the activity is closed."
Scenario: Results will always be shown to students
And the following "activities" exist:
| activity | name | intro | course | idnumber | option |
| choice | Choice 1 | Choice description | C1 | choice1 | Option 1, Option 2 |
And I am on "Course 1" course homepage
When I follow "Choice 1"
And I navigate to "Settings" in current page administration
And I set the field "Publish results" to "Always show results to students"
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
When I follow "Choice 1"
Then I should not see "Full results, showing everyone's choices, will be published after you answer."
And I should not see "Full results, showing everyone's choices, will be published after the activity is closed."
And I should not see "Anonymous results will be published after you answer."
And I should not see "Anonymous results will be published after the activity is closed."
And I should not see "The results of this activity will not be published after you answer."
@@ -0,0 +1,132 @@
@mod @mod_choice
Feature: A teacher can choose one of 4 options for publishing choice results
In order to display choice activities outcomes
As a teacher
I need to publish the choice activity results in different ways
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
Scenario: Do not publish results to students
Given the following "activity" exists:
| activity | choice |
| course | C1 |
| idnumber | choice1 |
| name | Choice 1 |
| intro | Choice Description |
| section | 1 |
| option | Option 1, Option 2 |
And I am on "Course 1" course homepage
And I follow "Choice 1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Publish results | Do not publish results to students |
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
When I choose "Option 1" from "Choice 1" choice activity
Then I should see "Your selection: Option 1"
And I should not see "Responses"
And I should not see "Graph display"
Scenario: Show results to students after they answer
Given the following "activity" exists:
| activity | choice |
| course | C1 |
| idnumber | choice1 |
| name | Choice 1 |
| intro | Choice Description |
| section | 1 |
| option | Option 1, Option 2 |
And I am on "Course 1" course homepage
And I follow "Choice 1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Publish results | Show results to students after they answer |
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
When I follow "Choice 1"
Then I should not see "Responses"
And I am on "Course 1" course homepage
And I choose "Option 1" from "Choice 1" choice activity
And I should see "Your selection: Option 1"
And I should see "Responses"
Scenario: Show results to students only after the choice is closed
Given the following "activity" exists:
| activity | choice |
| course | C1 |
| idnumber | choice1 |
| name | Choice 1 |
| intro | Choice Description |
| section | 1 |
| option | Option 1, Option 2 |
And I am on "Course 1" course homepage
And I follow "Choice 1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Publish results | Show results to students only after the choice is closed |
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
When I follow "Choice 1"
Then I should not see "Responses"
And I choose "Option 1" from "Choice 1" choice activity
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I follow "Choice 1"
And I follow "Settings"
And I expand all fieldsets
And I set the following fields to these values:
| timeopen[enabled] | 1 |
| timeopen[day] | 1 |
| timeopen[month] | January |
| timeopen[year] | 2010 |
| timeclose[enabled] | 1 |
| timeclose[day] | 2 |
| timeclose[month] | January |
| timeclose[year] | 2010 |
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Choice 1"
And I should see "Responses"
Scenario: Always show results to students
Given the following "activity" exists:
| activity | choice |
| course | C1 |
| idnumber | choice1 |
| name | Choice 1 |
| intro | Choice Description |
| section | 1 |
| option | Option 1, Option 2 |
And I am on "Course 1" course homepage
And I follow "Choice 1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Publish results | Always show results to students |
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
When I follow "Choice 1"
And I should see "Responses"
@@ -0,0 +1,65 @@
@mod @mod_choice
Feature: A teacher can choose whether to publish choice activity results anonymously or showing names
In order to keep students privacy or to give more info to students
As a teacher
I need to select whether I want other students to know who selected what option
Background:
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 "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And I log in as "teacher1"
Scenario: Publish anonymous results
Given the following "activities" exist:
| activity | name | intro | course | idnumber | option | section |
| choice | Choice 1 | Choice Description | C1 | choice1 | Option 1, Option 2 | 1 |
And I am on "Course 1" course homepage
And I follow "Choice 1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Publish results | Always show results to students |
| Privacy of results | Publish anonymous results, do not show student names |
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
And I choose "Option 1" from "Choice 1" choice activity
And I log out
When I log in as "student2"
And I am on "Course 1" course homepage
And I follow "Choice 1"
Then I should not see "Student 1"
And I should not see "Users who chose this option"
Scenario: Publish full results
Given the following "activities" exist:
| activity | name | intro | course | idnumber | option | section |
| choice | Choice 1 | Choice Description | C1 | choice1 | Option 1, Option 2 | 1 |
And I am on "Course 1" course homepage
And I follow "Choice 1"
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Publish results | Always show results to students |
| Privacy of results | Publish full results, showing names and their choices |
And I press "Save and return to course"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
And I choose "Option 1" from "Choice 1" choice activity
And I log out
When I log in as "student2"
And I am on "Course 1" course homepage
And I follow "Choice 1"
Then I should see "Student 1"
And I should see "Users who chose this option"
@@ -0,0 +1,43 @@
@mod @mod_choice
Feature: Update a choice activity removing options
In order to remove incorrect or unwanted options
As a teacher
I need to update the choice activity
Scenario: Update a choice activity that has student responses.
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 "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | option | section |
| choice | Choice name | Choice Description | C1 | choice1 | Option 1, Option 2, Option 3 | 1 |
And I log in as "student1"
And I am on "Course 1" course homepage
And I choose "Option 3" from "Choice name" choice activity
And I should see "Your selection: Option 3"
And I should see "Your choice has been saved"
And I log out
And I log in as "student2"
And I am on "Course 1" course homepage
And I choose "Option 2" from "Choice name" choice activity
And I should see "Your selection: Option 2"
And I should see "Your choice has been saved"
And I log out
When I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Choice name" "link" in the "region-main" "region"
And I navigate to "Settings" in current page administration
And I set the field "option[2]" to ""
And I press "Save and display"
Then I navigate to "Responses" in current page administration
And I should see "1" in the "Number of responses" "table_row"
+209
View File
@@ -0,0 +1,209 @@
<?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/>.
declare(strict_types = 1);
namespace mod_choice;
use advanced_testcase;
use cm_info;
use coding_exception;
use mod_choice\completion\custom_completion;
use moodle_exception;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . '/completionlib.php');
/**
* Class for unit testing mod_choice/custom_completion.
*
* @package mod_choice
* @copyright 2021 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class custom_completion_test extends advanced_testcase {
/**
* Data provider for get_state().
*
* @return array[]
*/
public function get_state_provider(): array {
return [
'Undefined rule' => [
'somenonexistentrule', COMPLETION_DISABLED, false, null, coding_exception::class
],
'Rule not available' => [
'completionsubmit', COMPLETION_DISABLED, false, null, moodle_exception::class
],
'Rule available, user has not submitted' => [
'completionsubmit', COMPLETION_ENABLED, false, COMPLETION_INCOMPLETE, null
],
'Rule available, user has submitted' => [
'completionsubmit', COMPLETION_ENABLED, true, COMPLETION_COMPLETE, null
],
];
}
/**
* Test for get_state().
*
* @dataProvider get_state_provider
* @param string $rule The custom completion rule.
* @param int $available Whether this rule is available.
* @param bool $submitted Whether the user has made a choice.
* @param int|null $status Expected status.
* @param string|null $exception Expected exception.
*/
public function test_get_state(string $rule, int $available, ?bool $submitted, ?int $status, ?string $exception): void {
global $DB;
if (!is_null($exception)) {
$this->expectException($exception);
}
// Custom completion rule data for cm_info::customdata.
$customdataval = [
'customcompletionrules' => [
$rule => $available
]
];
// Build a mock cm_info instance.
$mockcminfo = $this->getMockBuilder(cm_info::class)
->disableOriginalConstructor()
->onlyMethods(['__get'])
->getMock();
// Mock the return of the magic getter method when fetching the cm_info object's customdata and instance values.
$mockcminfo->expects($this->any())
->method('__get')
->will($this->returnValueMap([
['customdata', $customdataval],
['instance', 1],
]));
// Mock the DB calls.
$DB = $this->createMock(get_class($DB));
$DB->expects($this->atMost(1))
->method('record_exists')
->willReturn($submitted);
$customcompletion = new custom_completion($mockcminfo, 2);
$this->assertEquals($status, $customcompletion->get_state($rule));
}
/**
* Test for get_defined_custom_rules().
*/
public function test_get_defined_custom_rules(): void {
$rules = custom_completion::get_defined_custom_rules();
$this->assertCount(1, $rules);
$this->assertEquals('completionsubmit', reset($rules));
}
/**
* Test for get_defined_custom_rule_descriptions().
*/
public function test_get_custom_rule_descriptions(): void {
// Get defined custom rules.
$rules = custom_completion::get_defined_custom_rules();
// Build a mock cm_info instance.
$mockcminfo = $this->getMockBuilder(cm_info::class)
->disableOriginalConstructor()
->onlyMethods(['__get'])
->getMock();
// Instantiate a custom_completion object using the mocked cm_info.
$customcompletion = new custom_completion($mockcminfo, 1);
// Get custom rule descriptions.
$ruledescriptions = $customcompletion->get_custom_rule_descriptions();
// Confirm that defined rules and rule descriptions are consistent with each other.
$this->assertEquals(count($rules), count($ruledescriptions));
foreach ($rules as $rule) {
$this->assertArrayHasKey($rule, $ruledescriptions);
}
}
/**
* Test for is_defined().
*/
public function test_is_defined(): void {
// Build a mock cm_info instance.
$mockcminfo = $this->getMockBuilder(cm_info::class)
->disableOriginalConstructor()
->getMock();
$customcompletion = new custom_completion($mockcminfo, 1);
// Rule is defined.
$this->assertTrue($customcompletion->is_defined('completionsubmit'));
// Undefined rule.
$this->assertFalse($customcompletion->is_defined('somerandomrule'));
}
/**
* Data provider for test_get_available_custom_rules().
*
* @return array[]
*/
public function get_available_custom_rules_provider(): array {
return [
'Completion submit available' => [
COMPLETION_ENABLED, ['completionsubmit']
],
'Completion submit not available' => [
COMPLETION_DISABLED, []
],
];
}
/**
* Test for get_available_custom_rules().
*
* @dataProvider get_available_custom_rules_provider
* @param int $status
* @param array $expected
*/
public function test_get_available_custom_rules(int $status, array $expected): void {
$customdataval = [
'customcompletionrules' => [
'completionsubmit' => $status
]
];
// Build a mock cm_info instance.
$mockcminfo = $this->getMockBuilder(cm_info::class)
->disableOriginalConstructor()
->onlyMethods(['__get'])
->getMock();
// Mock the return of magic getter for the customdata attribute.
$mockcminfo->expects($this->any())
->method('__get')
->with('customdata')
->willReturn($customdataval);
$customcompletion = new custom_completion($mockcminfo, 1);
$this->assertEquals($expected, $customcompletion->get_available_custom_rules());
}
}
+122
View File
@@ -0,0 +1,122 @@
<?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/>.
/**
* Contains unit tests for mod_choice\dates.
*
* @package mod_choice
* @category test
* @copyright Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
declare(strict_types=1);
namespace mod_choice;
use advanced_testcase;
use cm_info;
use core\activity_dates;
/**
* Class for unit testing mod_choice\dates.
*
* @copyright Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class dates_test extends advanced_testcase {
/**
* Data provider for get_dates_for_module().
* @return array[]
*/
public function get_dates_for_module_provider(): array {
$now = time();
$before = $now - DAYSECS;
$earlier = $before - DAYSECS;
$after = $now + DAYSECS;
$later = $after + DAYSECS;
return [
'without any dates' => [
null, null, []
],
'only with opening time' => [
$after, null, [
['label' => 'Opens:', 'timestamp' => $after, 'dataid' => 'timeopen'],
]
],
'only with closing time' => [
null, $after, [
['label' => 'Closes:', 'timestamp' => $after, 'dataid' => 'timeclose'],
]
],
'with both times' => [
$after, $later, [
['label' => 'Opens:', 'timestamp' => $after, 'dataid' => 'timeopen'],
['label' => 'Closes:', 'timestamp' => $later, 'dataid' => 'timeclose'],
]
],
'between the dates' => [
$before, $after, [
['label' => 'Opened:', 'timestamp' => $before, 'dataid' => 'timeopen'],
['label' => 'Closes:', 'timestamp' => $after, 'dataid' => 'timeclose'],
]
],
'dates are past' => [
$earlier, $before, [
['label' => 'Opened:', 'timestamp' => $earlier, 'dataid' => 'timeopen'],
['label' => 'Closed:', 'timestamp' => $before, 'dataid' => 'timeclose'],
]
],
];
}
/**
* Test for get_dates_for_module().
*
* @dataProvider get_dates_for_module_provider
* @param int|null $timeopen Time of opening the choice
* @param int|null $timeclose Time of closing the choice
* @param array $expected The expected value of calling get_dates_for_module()
*/
public function test_get_dates_for_module(?int $timeopen, ?int $timeclose, array $expected): void {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$user = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->enrol_user($user->id, $course->id);
$data = ['course' => $course->id];
if ($timeopen) {
$data['timeopen'] = $timeopen;
}
if ($timeclose) {
$data['timeclose'] = $timeclose;
}
$choice = $this->getDataGenerator()->create_module('choice', $data);
$this->setUser($user);
$cm = get_coursemodule_from_instance('choice', $choice->id);
// Make sure we're using a cm_info object.
$cm = cm_info::create($cm);
$dates = activity_dates::get_dates_for_module($cm, (int)$user->id);
$this->assertEquals($expected, $dates);
}
}
+393
View File
@@ -0,0 +1,393 @@
<?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/>.
/**
* Events tests.
*
* @package mod_choice
* @copyright 2013 Adrian Greeve <adrian@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_choice\event;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/choice/lib.php');
/**
* Events tests class.
*
* @package mod_choice
* @copyright 2013 Adrian Greeve <adrian@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class events_test extends \advanced_testcase {
/** @var choice_object */
protected $choice;
/** @var course_object */
protected $course;
/** @var cm_object Course module object. */
protected $cm;
/** @var context_object */
protected $context;
/**
* Setup often used objects for the following tests.
*/
protected function setUp(): void {
global $DB;
$this->resetAfterTest();
$this->course = $this->getDataGenerator()->create_course();
$this->choice = $this->getDataGenerator()->create_module('choice', array('course' => $this->course->id));
$this->cm = $DB->get_record('course_modules', array('id' => $this->choice->cmid));
$this->context = \context_module::instance($this->choice->cmid);
}
/**
* Test to ensure that event data is being stored correctly.
*/
public function test_answer_created(): void {
global $DB;
// Generate user data.
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$optionids = array_keys($DB->get_records('choice_options', array('choiceid' => $this->choice->id)));
// Redirect event.
$sink = $this->redirectEvents();
choice_user_submit_response($optionids[3], $this->choice, $user->id, $this->course, $this->cm);
$events = $sink->get_events();
$answer = $DB->get_record('choice_answers', ['userid' => $user->id, 'choiceid' => $this->choice->id]);
// Data checking.
$this->assertCount(1, $events);
$this->assertInstanceOf('\mod_choice\event\answer_created', $events[0]);
$this->assertEquals($user->id, $events[0]->userid);
$this->assertEquals($user->id, $events[0]->relateduserid);
$this->assertEquals(\context_module::instance($this->choice->cmid), $events[0]->get_context());
$this->assertEquals($answer->id, $events[0]->objectid);
$this->assertEquals($this->choice->id, $events[0]->other['choiceid']);
$this->assertEquals($optionids[3], $events[0]->other['optionid']);
$this->assertEventContextNotUsed($events[0]);
$sink->close();
}
/**
* Test to ensure that event data is being stored correctly.
*/
public function test_answer_submitted_by_another_user(): void {
global $DB, $USER;
// Generate user data.
$user = $this->getDataGenerator()->create_user();
$optionids = array_keys($DB->get_records('choice_options', array('choiceid' => $this->choice->id)));
// Redirect event.
$sink = $this->redirectEvents();
choice_user_submit_response($optionids[3], $this->choice, $user->id, $this->course, $this->cm);
$events = $sink->get_events();
$answer = $DB->get_record('choice_answers', ['userid' => $user->id, 'choiceid' => $this->choice->id]);
// Data checking.
$this->assertCount(1, $events);
$this->assertInstanceOf('\mod_choice\event\answer_created', $events[0]);
$this->assertEquals($USER->id, $events[0]->userid);
$this->assertEquals($user->id, $events[0]->relateduserid);
$this->assertEquals(\context_module::instance($this->choice->cmid), $events[0]->get_context());
$this->assertEquals($answer->id, $events[0]->objectid);
$this->assertEquals($this->choice->id, $events[0]->other['choiceid']);
$this->assertEquals($optionids[3], $events[0]->other['optionid']);
$this->assertEventContextNotUsed($events[0]);
$sink->close();
}
/**
* Test to ensure that multiple choice data is being stored correctly.
*/
public function test_answer_created_multiple(): void {
global $DB;
// Generate user data.
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
// Create multiple choice.
$choice = $this->getDataGenerator()->create_module('choice', array('course' => $this->course->id,
'allowmultiple' => 1));
$cm = $DB->get_record('course_modules', array('id' => $choice->cmid));
$context = \context_module::instance($choice->cmid);
$optionids = array_keys($DB->get_records('choice_options', array('choiceid' => $choice->id)));
$submittedoptionids = array($optionids[1], $optionids[3]);
// Redirect event.
$sink = $this->redirectEvents();
choice_user_submit_response($submittedoptionids, $choice, $user->id, $this->course, $cm);
$events = $sink->get_events();
$answers = $DB->get_records('choice_answers', ['userid' => $user->id, 'choiceid' => $choice->id], 'id');
$answers = array_values($answers);
// Data checking.
$this->assertCount(2, $events);
$this->assertInstanceOf('\mod_choice\event\answer_created', $events[0]);
$this->assertEquals($user->id, $events[0]->userid);
$this->assertEquals($user->id, $events[0]->relateduserid);
$this->assertEquals(\context_module::instance($choice->cmid), $events[0]->get_context());
$this->assertEquals($answers[0]->id, $events[0]->objectid);
$this->assertEquals($choice->id, $events[0]->other['choiceid']);
$this->assertEquals($optionids[1], $events[0]->other['optionid']);
$this->assertEventContextNotUsed($events[0]);
$this->assertInstanceOf('\mod_choice\event\answer_created', $events[1]);
$this->assertEquals($user->id, $events[1]->userid);
$this->assertEquals($user->id, $events[1]->relateduserid);
$this->assertEquals(\context_module::instance($choice->cmid), $events[1]->get_context());
$this->assertEquals($answers[1]->id, $events[1]->objectid);
$this->assertEquals($choice->id, $events[1]->other['choiceid']);
$this->assertEquals($optionids[3], $events[1]->other['optionid']);
$this->assertEventContextNotUsed($events[1]);
$sink->close();
}
/**
* Test custom validations.
*/
public function test_answer_created_other_exception(): void {
// Generate user data.
$user = $this->getDataGenerator()->create_user();
$eventdata = array();
$eventdata['context'] = $this->context;
$eventdata['objectid'] = 2;
$eventdata['userid'] = $user->id;
$eventdata['courseid'] = $this->course->id;
$eventdata['other'] = array();
// Make sure content identifier is always set.
$this->expectException(\coding_exception::class);
$event = \mod_choice\event\answer_created::create($eventdata);
$event->trigger();
$this->assertEventContextNotUsed($event);
}
/**
* Test to ensure that event data is being stored correctly.
*/
public function test_answer_updated(): void {
global $DB;
// Generate user data.
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$optionids = array_keys($DB->get_records('choice_options', array('choiceid' => $this->choice->id)));
// Create the first answer.
choice_user_submit_response($optionids[2], $this->choice, $user->id, $this->course, $this->cm);
$oldanswer = $DB->get_record('choice_answers', ['userid' => $user->id, 'choiceid' => $this->choice->id]);
// Redirect event.
$sink = $this->redirectEvents();
// Now choose a different answer.
choice_user_submit_response($optionids[3], $this->choice, $user->id, $this->course, $this->cm);
$newanswer = $DB->get_record('choice_answers', ['userid' => $user->id, 'choiceid' => $this->choice->id]);
$events = $sink->get_events();
// Data checking.
$this->assertCount(2, $events);
$this->assertInstanceOf('\mod_choice\event\answer_deleted', $events[0]);
$this->assertEquals($user->id, $events[0]->userid);
$this->assertEquals(\context_module::instance($this->choice->cmid), $events[0]->get_context());
$this->assertEquals($oldanswer->id, $events[0]->objectid);
$this->assertEquals($this->choice->id, $events[0]->other['choiceid']);
$this->assertEquals($optionids[2], $events[0]->other['optionid']);
$this->assertEventContextNotUsed($events[0]);
$this->assertInstanceOf('\mod_choice\event\answer_created', $events[1]);
$this->assertEquals($user->id, $events[1]->userid);
$this->assertEquals(\context_module::instance($this->choice->cmid), $events[1]->get_context());
$this->assertEquals($newanswer->id, $events[1]->objectid);
$this->assertEquals($this->choice->id, $events[1]->other['choiceid']);
$this->assertEquals($optionids[3], $events[1]->other['optionid']);
$this->assertEventContextNotUsed($events[1]);
$sink->close();
}
/**
* Test to ensure that event data is being stored correctly.
*/
public function test_answer_deleted(): void {
global $DB, $USER;
// Generate user data.
$user = $this->getDataGenerator()->create_user();
$optionids = array_keys($DB->get_records('choice_options', array('choiceid' => $this->choice->id)));
// Create the first answer.
choice_user_submit_response($optionids[2], $this->choice, $user->id, $this->course, $this->cm);
// Get the users response.
$answer = $DB->get_record('choice_answers', array('userid' => $user->id, 'choiceid' => $this->choice->id),
'*', $strictness = IGNORE_MULTIPLE);
// Redirect event.
$sink = $this->redirectEvents();
// Now delete the answer.
choice_delete_responses(array($answer->id), $this->choice, $this->cm, $this->course);
// Get our event event.
$events = $sink->get_events();
$event = reset($events);
// Data checking.
$this->assertInstanceOf('\mod_choice\event\answer_deleted', $event);
$this->assertEquals($USER->id, $event->userid);
$this->assertEquals($user->id, $event->relateduserid);
$this->assertEquals(\context_module::instance($this->choice->cmid), $event->get_context());
$this->assertEquals($this->choice->id, $event->other['choiceid']);
$this->assertEquals($answer->optionid, $event->other['optionid']);
$this->assertEventContextNotUsed($event);
$sink->close();
}
/**
* Test to ensure that event data is being stored correctly.
*/
public function test_report_viewed(): void {
global $USER;
$this->resetAfterTest();
// Generate user data.
$this->setAdminUser();
$eventdata = array();
$eventdata['objectid'] = $this->choice->id;
$eventdata['context'] = $this->context;
$eventdata['courseid'] = $this->course->id;
$eventdata['other']['content'] = 'choicereportcontentviewed';
// This is fired in a page view so we can't run this through a function.
$event = \mod_choice\event\report_viewed::create($eventdata);
// Redirect event.
$sink = $this->redirectEvents();
$event->trigger();
$event = $sink->get_events();
// Data checking.
$this->assertCount(1, $event);
$this->assertInstanceOf('\mod_choice\event\report_viewed', $event[0]);
$this->assertEquals($USER->id, $event[0]->userid);
$this->assertEquals(\context_module::instance($this->choice->cmid), $event[0]->get_context());
$sink->close();
}
/**
* Test to ensure that event data is being stored correctly.
*/
public function test_report_downloaded(): void {
global $USER;
$this->resetAfterTest();
// Generate user data.
$this->setAdminUser();
$eventdata = array();
$eventdata['context'] = $this->context;
$eventdata['courseid'] = $this->course->id;
$eventdata['other']['content'] = 'choicereportcontentviewed';
$eventdata['other']['format'] = 'csv';
$eventdata['other']['choiceid'] = $this->choice->id;
// This is fired in a page view so we can't run this through a function.
$event = \mod_choice\event\report_downloaded::create($eventdata);
// Redirect event.
$sink = $this->redirectEvents();
$event->trigger();
$event = $sink->get_events();
// Data checking.
$this->assertCount(1, $event);
$this->assertInstanceOf('\mod_choice\event\report_downloaded', $event[0]);
$this->assertEquals($USER->id, $event[0]->userid);
$this->assertEquals(\context_module::instance($this->choice->cmid), $event[0]->get_context());
$this->assertEquals('csv', $event[0]->other['format']);
$this->assertEquals($this->choice->id, $event[0]->other['choiceid']);
$this->assertEventContextNotUsed($event[0]);
$sink->close();
}
/**
* Test to ensure that event data is being stored correctly.
*/
public function test_course_module_viewed(): void {
global $USER;
// Generate user data.
$this->setAdminUser();
$eventdata = array();
$eventdata['objectid'] = $this->choice->id;
$eventdata['context'] = $this->context;
$eventdata['courseid'] = $this->course->id;
$eventdata['other']['content'] = 'pageresourceview';
// This is fired in a page view so we can't run this through a function.
$event = \mod_choice\event\course_module_viewed::create($eventdata);
// Redirect event.
$sink = $this->redirectEvents();
$event->trigger();
$event = $sink->get_events();
// Data checking.
$this->assertCount(1, $event);
$this->assertInstanceOf('\mod_choice\event\course_module_viewed', $event[0]);
$this->assertEquals($USER->id, $event[0]->userid);
$this->assertEquals(\context_module::instance($this->choice->cmid), $event[0]->get_context());
$sink->close();
}
/**
* Test to ensure that event data is being stored correctly.
*/
public function test_course_module_instance_list_viewed_viewed(): void {
global $USER;
// Not much can be tested here as the event is only triggered on a page load,
// let's just check that the event contains the expected basic information.
$this->setAdminUser();
$params = array('context' => \context_course::instance($this->course->id));
$event = \mod_choice\event\course_module_instance_list_viewed::create($params);
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$event = reset($events);
$this->assertInstanceOf('\mod_choice\event\course_module_instance_list_viewed', $event);
$this->assertEquals($USER->id, $event->userid);
$this->assertEquals(\context_course::instance($this->course->id), $event->get_context());
}
}
+580
View File
@@ -0,0 +1,580 @@
<?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 mod_choice;
use core_external\external_api;
use externallib_advanced_testcase;
use mod_choice_external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
require_once($CFG->dirroot . '/mod/choice/lib.php');
/**
* External choice functions unit tests
*
* @package mod_choice
* @category external
* @copyright 2015 Costantino Cito <ccito@cvaconsulting.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class externallib_test extends externallib_advanced_testcase {
/**
* Test get_choice_results
*/
public function test_get_choice_results(): void {
global $DB;
$this->resetAfterTest(true);
$course = self::getDataGenerator()->create_course();
$params = new \stdClass();
$params->course = $course->id;
$params->option = array('fried rice', 'spring rolls', 'sweet and sour pork', 'satay beef', 'gyouza');
$params->name = 'First Choice Activity';
$params->showresults = CHOICE_SHOWRESULTS_AFTER_ANSWER;
$params->publish = 1;
$params->allowmultiple = 1;
$params->showunanswered = 1;
$choice = self::getDataGenerator()->create_module('choice', $params);
$cm = get_coursemodule_from_id('choice', $choice->cmid);
$choiceinstance = choice_get_choice($cm->instance);
$options = array_keys($choiceinstance->option);
$student1 = $this->getDataGenerator()->create_user();
$student2 = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
// Enroll Students in Course1.
self::getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id);
self::getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id);
$this->setUser($student1);
$myanswer = $options[2];
choice_user_submit_response($myanswer, $choice, $student1->id, $course, $cm);
$results = mod_choice_external::get_choice_results($choice->id);
// We need to execute the return values cleaning process to simulate the web service server.
$results = external_api::clean_returnvalue(mod_choice_external::get_choice_results_returns(), $results);
// Create an array with optionID as Key.
$resultsarr = array();
foreach ($results['options'] as $option) {
$resultsarr[$option['id']] = $option['userresponses'];
}
// The stundent1 is the userid who choosed the myanswer(option 3).
$this->assertEquals($resultsarr[$myanswer][0]['userid'], $student1->id);
// The stundent2 is the userid who didn't answered yet.
$this->assertEquals($resultsarr[0][0]['userid'], $student2->id);
// As Stundent2 we cannot see results (until we answered).
$this->setUser($student2);
$results = mod_choice_external::get_choice_results($choice->id);
// We need to execute the return values cleaning process to simulate the web service server.
$results = external_api::clean_returnvalue(mod_choice_external::get_choice_results_returns(), $results);
// We do not retrieve any response!
foreach ($results['options'] as $option) {
$this->assertCount(0, $option['userresponses']);
}
$timenow = time();
// We can see results only after activity close (even if we didn't answered).
$choice->showresults = CHOICE_SHOWRESULTS_AFTER_CLOSE;
// Set timeopen and timeclose in the past.
$choice->timeopen = $timenow - (60 * 60 * 24 * 3);
$choice->timeclose = $timenow + (60 * 60 * 24 * 2);
$DB->update_record('choice', $choice);
$results = mod_choice_external::get_choice_results($choice->id);
// We need to execute the return values cleaning process to simulate the web service server.
$results = external_api::clean_returnvalue(mod_choice_external::get_choice_results_returns(), $results);
// We do not retrieve any response (activity is still open).
foreach ($results['options'] as $option) {
$this->assertCount(0, $option['userresponses']);
}
// We close the activity (setting timeclose in the past).
$choice->timeclose = $timenow - (60 * 60 * 24 * 2);
$DB->update_record('choice', $choice);
// Now as Stundent2 we will see results!
$results = mod_choice_external::get_choice_results($choice->id);
// We need to execute the return values cleaning process to simulate the web service server.
$results = external_api::clean_returnvalue(mod_choice_external::get_choice_results_returns(), $results);
// Create an array with optionID as Key.
$resultsarr = array();
foreach ($results['options'] as $option) {
$resultsarr[$option['id']] = $option['userresponses'];
}
// The stundent1 is the userid who choosed the myanswer(option 3).
$this->assertEquals($resultsarr[$myanswer][0]['userid'], $student1->id);
// The stundent2 is the userid who didn't answered yet.
$this->assertEquals($resultsarr[0][0]['userid'], $student2->id);
// Do not publish user names!
$choice->publish = 0;
$DB->update_record('choice', $choice);
$results = mod_choice_external::get_choice_results($choice->id);
// We need to execute the return values cleaning process to simulate the web service server.
$results = external_api::clean_returnvalue(mod_choice_external::get_choice_results_returns(), $results);
// Create an array with optionID as Key.
$resultsarr = array();
// Does not show any user response!
foreach ($results['options'] as $option) {
$this->assertCount(0, $option['userresponses']);
$resultsarr[$option['id']] = $option;
}
// But we can see totals and percentages.
$this->assertEquals(1, $resultsarr[$myanswer]['numberofuser']);
}
/**
* Test get_choice_options
*/
public function test_get_choice_options(): void {
global $DB;
// Warningcodes.
$notopenyet = 1;
$previewonly = 2;
$expired = 3;
$this->resetAfterTest(true);
$timenow = time();
$timeopen = $timenow + (60 * 60 * 24 * 2);
$timeclose = $timenow + (60 * 60 * 24 * 7);
$course = self::getDataGenerator()->create_course();
$possibleoptions = array('fried rice', 'spring rolls', 'sweet and sour pork', 'satay beef', 'gyouza');
$params = array();
$params['course'] = $course->id;
$params['option'] = $possibleoptions;
$params['name'] = 'First Choice Activity';
$params['showpreview'] = 0;
$generator = $this->getDataGenerator()->get_plugin_generator('mod_choice');
$choice = $generator->create_instance($params);
$student1 = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
// Enroll Students in Course.
self::getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id);
$this->setUser($student1);
$results = mod_choice_external::get_choice_options($choice->id);
// We need to execute the return values cleaning process to simulate the web service server.
$results = external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
// We should retrieve all options.
$this->assertCount(count($possibleoptions), $results['options']);
// Here we force timeopen/close in the future.
$choice->timeopen = $timeopen;
$choice->timeclose = $timeclose;
$DB->update_record('choice', $choice);
$results = mod_choice_external::get_choice_options($choice->id);
// We need to execute the return values cleaning process to simulate the web service server.
$results = external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
// We should retrieve no options.
$this->assertCount(0, $results['options']);
$this->assertEquals($notopenyet, $results['warnings'][0]['warningcode']);
// Here we see the options because of preview!
$choice->showpreview = 1;
$DB->update_record('choice', $choice);
$results = mod_choice_external::get_choice_options($choice->id);
// We need to execute the return values cleaning process to simulate the web service server.
$results = external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
// We should retrieve all options.
$this->assertCount(count($possibleoptions), $results['options']);
foreach ($results['options'] as $option) {
// Each option is disabled as this is only the preview!
$this->assertEquals(1, $option['disabled']);
}
$warnings = array();
foreach ($results['warnings'] as $warning) {
$warnings[$warning['warningcode']] = $warning['message'];
}
$this->assertTrue(isset($warnings[$previewonly]));
$this->assertTrue(isset($warnings[$notopenyet]));
// Simulate activity as opened!
$choice->timeopen = $timenow - (60 * 60 * 24 * 3);
$choice->timeclose = $timenow + (60 * 60 * 24 * 2);
$DB->update_record('choice', $choice);
$cm = get_coursemodule_from_id('choice', $choice->cmid);
$choiceinstance = choice_get_choice($cm->instance);
$optionsids = array_keys($choiceinstance->option);
$myanswerid = $optionsids[2];
choice_user_submit_response($myanswerid, $choice, $student1->id, $course, $cm);
$results = mod_choice_external::get_choice_options($choice->id);
// We need to execute the return values cleaning process to simulate the web service server.
$results = external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
// We should retrieve all options.
$this->assertCount(count($possibleoptions), $results['options']);
foreach ($results['options'] as $option) {
// When we answered and we cannot update our choice.
if ($option['id'] == $myanswerid and !$choice->allowupdate) {
$this->assertEquals(1, $option['disabled']);
$this->assertEquals(1, $option['checked']);
} else {
$this->assertEquals(0, $option['disabled']);
}
}
// Set timeopen and timeclose as older than today!
// We simulate what happens when the activity is closed.
$choice->timeopen = $timenow - (60 * 60 * 24 * 3);
$choice->timeclose = $timenow - (60 * 60 * 24 * 2);
$DB->update_record('choice', $choice);
$results = mod_choice_external::get_choice_options($choice->id);
// We need to execute the return values cleaning process to simulate the web service server.
$results = external_api::clean_returnvalue(mod_choice_external::get_choice_options_returns(), $results);
// We should retrieve no options.
$this->assertCount(0, $results['options']);
$this->assertEquals($expired, $results['warnings'][0]['warningcode']);
}
/**
* Test submit_choice_response
*/
public function test_submit_choice_response(): void {
global $DB;
$this->resetAfterTest(true);
$course = self::getDataGenerator()->create_course();
$params = new \stdClass();
$params->course = $course->id;
$params->option = array('fried rice', 'spring rolls', 'sweet and sour pork', 'satay beef', 'gyouza');
$params->name = 'First Choice Activity';
$params->showresults = CHOICE_SHOWRESULTS_ALWAYS;
$params->allowmultiple = 1;
$params->showunanswered = 1;
$choice = self::getDataGenerator()->create_module('choice', $params);
$cm = get_coursemodule_from_id('choice', $choice->cmid);
$choiceinstance = choice_get_choice($cm->instance);
$options = array_keys($choiceinstance->option);
$student1 = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
// Enroll Students in Course1.
self::getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id);
$this->setUser($student1);
$myresponse = $options[2];
$results = mod_choice_external::submit_choice_response($choice->id, array($myresponse));
// We need to execute the return values cleaning process to simulate the web service server.
$results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
$myanswers = $DB->get_records('choice_answers', array('choiceid' => $choice->id, 'userid' => $student1->id));
$myanswer = reset($myanswers);
$this->assertEquals($results['answers'][0]['id'], $myanswer->id);
$this->assertEquals($results['answers'][0]['choiceid'], $myanswer->choiceid);
$this->assertEquals($results['answers'][0]['userid'], $myanswer->userid);
$this->assertEquals($results['answers'][0]['timemodified'], $myanswer->timemodified);
}
/**
* Test view_choice
*/
public function test_view_choice(): void {
global $DB;
$this->resetAfterTest(true);
// Setup test data.
$course = $this->getDataGenerator()->create_course();
$choice = $this->getDataGenerator()->create_module('choice', array('course' => $course->id));
$context = \context_module::instance($choice->cmid);
$cm = get_coursemodule_from_instance('choice', $choice->id);
// Test invalid instance id.
try {
mod_choice_external::view_choice(0);
$this->fail('Exception expected due to invalid mod_choice instance id.');
} catch (\moodle_exception $e) {
$this->assertEquals('invalidcoursemodule', $e->errorcode);
}
// Test not-enrolled user.
$user = self::getDataGenerator()->create_user();
$this->setUser($user);
try {
mod_choice_external::view_choice($choice->id);
$this->fail('Exception expected due to not enrolled user.');
} catch (\moodle_exception $e) {
$this->assertEquals('requireloginerror', $e->errorcode);
}
// Test user with full capabilities.
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
// Trigger and capture the event.
$sink = $this->redirectEvents();
$result = mod_choice_external::view_choice($choice->id);
$result = external_api::clean_returnvalue(mod_choice_external::view_choice_returns(), $result);
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = array_shift($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_choice\event\course_module_viewed', $event);
$this->assertEquals($context, $event->get_context());
$moodlechoice = new \moodle_url('/mod/choice/view.php', array('id' => $cm->id));
$this->assertEquals($moodlechoice, $event->get_url());
$this->assertEventContextNotUsed($event);
$this->assertNotEmpty($event->get_name());
}
/**
* Test get_choices_by_courses
*/
public function test_get_choices_by_courses(): void {
global $DB;
$this->resetAfterTest(true);
// As admin.
$this->setAdminUser();
$course1 = self::getDataGenerator()->create_course();
$choiceoptions1 = array(
'course' => $course1->id,
'name' => 'First IMSCP'
);
$choice1 = self::getDataGenerator()->create_module('choice', $choiceoptions1);
$course2 = self::getDataGenerator()->create_course();
$choiceoptions2 = array(
'course' => $course2->id,
'name' => 'Second IMSCP'
);
$choice2 = self::getDataGenerator()->create_module('choice', $choiceoptions2);
$student1 = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
// Enroll Student1 in Course1.
self::getDataGenerator()->enrol_user($student1->id, $course1->id, $studentrole->id);
$this->setUser($student1);
$choices = mod_choice_external::get_choices_by_courses(array());
$choices = external_api::clean_returnvalue(mod_choice_external::get_choices_by_courses_returns(), $choices);
$this->assertCount(1, $choices['choices']);
$this->assertEquals('First IMSCP', $choices['choices'][0]['name']);
// As Student you cannot see some IMSCP properties like 'section'.
$this->assertFalse(isset($choices['choices'][0]['section']));
// Student1 is not enrolled in this Course.
// The webservice will give a warning!
$choices = mod_choice_external::get_choices_by_courses(array($course2->id));
$choices = external_api::clean_returnvalue(mod_choice_external::get_choices_by_courses_returns(), $choices);
$this->assertCount(0, $choices['choices']);
$this->assertEquals(1, $choices['warnings'][0]['warningcode']);
// Now as admin.
$this->setAdminUser();
// As Admin we can see this IMSCP.
$choices = mod_choice_external::get_choices_by_courses(array($course2->id));
$choices = external_api::clean_returnvalue(mod_choice_external::get_choices_by_courses_returns(), $choices);
$this->assertCount(1, $choices['choices']);
$this->assertEquals('Second IMSCP', $choices['choices'][0]['name']);
// As an Admin you can see some IMSCP properties like 'section'.
$this->assertEquals(0, $choices['choices'][0]['section']);
// Now, prohibit capabilities.
$this->setUser($student1);
$contextcourse1 = \context_course::instance($course1->id);
// Prohibit capability = mod:choice:choose on Course1 for students.
assign_capability('mod/choice:choose', CAP_PROHIBIT, $studentrole->id, $contextcourse1->id);
accesslib_clear_all_caches_for_unit_testing();
$choices = mod_choice_external::get_choices_by_courses(array($course1->id));
$choices = external_api::clean_returnvalue(mod_choice_external::get_choices_by_courses_returns(), $choices);
$this->assertFalse(isset($choices['choices'][0]['timeopen']));
}
/**
* Test delete_choice_responses
*/
public function test_delete_choice_responses(): void {
global $DB;
$this->resetAfterTest(true);
$course = self::getDataGenerator()->create_course();
$params = new \stdClass();
$params->course = $course->id;
$params->option = array('fried rice', 'spring rolls', 'sweet and sour pork', 'satay beef', 'gyouza');
$params->name = 'First Choice Activity';
$params->showresults = CHOICE_SHOWRESULTS_ALWAYS;
$params->allowmultiple = 1;
$params->showunanswered = 1;
$choice = self::getDataGenerator()->create_module('choice', $params);
$cm = get_coursemodule_from_id('choice', $choice->cmid);
$choiceinstance = choice_get_choice($cm->instance);
$options = array_keys($choiceinstance->option);
$student = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
// Enroll student in Course1.
self::getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id);
$this->setUser($student);
$results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
$results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
$myresponses = array_keys(choice_get_my_response($choice));
// Try to delete responses when allow update is false.
try {
mod_choice_external::delete_choice_responses($choice->id, array($myresponses[0], $myresponses[0]));
$this->fail('Exception expected due to missing permissions.');
} catch (\required_capability_exception $e) {
$this->assertEquals('nopermissions', $e->errorcode);
}
// Set allow update to true, and a passed time close.
$DB->set_field('choice', 'allowupdate', 1, array('id' => $choice->id));
$DB->set_field('choice', 'timeclose', time() - DAYSECS, array('id' => $choice->id));
try {
mod_choice_external::delete_choice_responses($choice->id, array($myresponses[0], $myresponses[1]));
$this->fail('Exception expected due to expired choice.');
} catch (\moodle_exception $e) {
$this->assertEquals('expired', $e->errorcode);
}
// Reset time close. We should be able now to delete all the responses.
$DB->set_field('choice', 'timeclose', 0, array('id' => $choice->id));
$results = mod_choice_external::delete_choice_responses($choice->id, array($myresponses[0], $myresponses[1]));
$results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
$this->assertTrue($results['status']);
$this->assertCount(0, $results['warnings']);
// Now, in the DB 0 responses.
$this->assertCount(0, choice_get_my_response($choice));
// Submit again the responses.
$results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
$results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
$myresponses = array_keys(choice_get_my_response($choice));
// Delete only one response.
$results = mod_choice_external::delete_choice_responses($choice->id, array($myresponses[0]));
$results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
$this->assertTrue($results['status']);
$this->assertCount(0, $results['warnings']);
// Now, in the DB 1 response still.
$this->assertCount(1, choice_get_my_response($choice));
// Delete the remaining response, passing 2 invalid responses ids.
$results = mod_choice_external::delete_choice_responses($choice->id, array($myresponses[1], $myresponses[0] + 2,
$myresponses[0] + 3));
$results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
$this->assertTrue($results['status']);
// 2 warnings, 2 invalid responses.
$this->assertCount(2, $results['warnings']);
// Now, in the DB 0 responses.
$this->assertCount(0, choice_get_my_response($choice));
// Now, as an admin we must be able to delete all the responses under any condition.
$this->setUser($student);
// Submit again the responses.
$results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
$results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
$studentresponses = array_keys(choice_get_my_response($choice));
$this->setAdminUser();
$DB->set_field('choice', 'allowupdate', 0, array('id' => $choice->id));
$DB->set_field('choice', 'timeclose', time() - DAYSECS, array('id' => $choice->id));
$results = mod_choice_external::delete_choice_responses($choice->id, array($studentresponses[0], $studentresponses[1]));
$results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
$this->assertTrue($results['status']);
$this->assertCount(0, $results['warnings']);
// Submit again the responses.
$this->setUser($student);
$DB->set_field('choice', 'timeclose', 0, array('id' => $choice->id));
$results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
$results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
// Test admin try to delete his own responses (he didn't respond so nothing should be deleted).
$this->setAdminUser();
$results = mod_choice_external::delete_choice_responses($choice->id);
$results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
$this->assertFalse($results['status']);
$this->assertCount(0, $results['warnings']);
$allresponses = choice_get_all_responses($choice);
$this->assertCount(2, $allresponses); // No responses deleted (admin didn't submit any).
// Now admin submit a couple of responses more.
$results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
$results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
$allresponses = choice_get_all_responses($choice);
$this->assertCount(4, $allresponses);
// Admin responses are deleted when passing an empty array.
$results = mod_choice_external::delete_choice_responses($choice->id);
$results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
$this->assertTrue($results['status']);
$this->assertCount(0, $results['warnings']);
$allresponses = choice_get_all_responses($choice);
$this->assertCount(2, $allresponses);
// Now admin will delete all the other users responses.
$results = mod_choice_external::delete_choice_responses($choice->id, array_keys($allresponses));
$results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
$this->assertTrue($results['status']);
$this->assertCount(0, $results['warnings']);
$allresponses = choice_get_all_responses($choice);
$this->assertCount(0, $allresponses); // Now all the responses were deleted.
// Admin try do delete an invalid response.
$results = mod_choice_external::delete_choice_responses($choice->id, array(-1));
$results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
$this->assertFalse($results['status']);
$this->assertCount(1, $results['warnings']);
// Now, in the DB 0 responses.
$this->setUser($student);
// Submit again respones.
$DB->set_field('choice', 'allowupdate', 1, array('id' => $choice->id));
$DB->set_field('choice', 'timeclose', 0, array('id' => $choice->id));
$results = mod_choice_external::submit_choice_response($choice->id, array($options[1], $options[2]));
$results = external_api::clean_returnvalue(mod_choice_external::submit_choice_response_returns(), $results);
// Delete all responses.
$results = mod_choice_external::delete_choice_responses($choice->id);
$results = external_api::clean_returnvalue(mod_choice_external::delete_choice_responses_returns(), $results);
$this->assertTrue($results['status']);
$this->assertCount(0, $results['warnings']);
$this->assertCount(0, choice_get_my_response($choice));
}
}
+55
View File
@@ -0,0 +1,55 @@
<?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/>.
/**
* mod_choice data generator.
*
* @package mod_choice
* @category test
* @copyright 2013 Adrian Greeve <adrian@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* mod_choice data generator class.
*
* @package mod_choice
* @category test
* @copyright 2013 Adrian Greeve <adrian@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_choice_generator extends testing_module_generator {
public function create_instance($record = null, array $options = null) {
$record = (object)(array)$record;
if (!isset($record->timemodified)) {
$record->timemodified = time();
}
if (!isset($record->option)) {
$record->option = array();
$record->option[] = 'Soft Drink';
$record->option[] = 'Beer';
$record->option[] = 'Wine';
$record->option[] = 'Spirits';
} else if (!is_array($record->option)) {
$record->option = preg_split('/\s*,\s*/', trim($record->option), -1, PREG_SPLIT_NO_EMPTY);
}
return parent::create_instance($record, (array)$options);
}
}
+52
View File
@@ -0,0 +1,52 @@
<?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 mod_choice;
/**
* Generator tests class.
*
* @package mod_choice
* @copyright 2013 Adrian Greeve <adrian@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class generator_test extends \advanced_testcase {
public function test_create_instance(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$this->assertFalse($DB->record_exists('choice', array('course' => $course->id)));
$choice = $this->getDataGenerator()->create_module('choice', array('course' => $course->id));
$this->assertEquals(1, $DB->count_records('choice', array('course' => $course->id)));
$this->assertTrue($DB->record_exists('choice', array('course' => $course->id)));
$this->assertTrue($DB->record_exists('choice', array('id' => $choice->id)));
$params = array('course' => $course->id, 'name' => 'One more choice');
$choice = $this->getDataGenerator()->create_module('choice', $params);
$this->assertEquals(2, $DB->count_records('choice', array('course' => $course->id)));
$this->assertEquals('One more choice', $DB->get_field_select('choice', 'name', 'id = :id', array('id' => $choice->id)));
$params = new \stdClass();
$params->course = $course->id;
$params->option = array('fried rice', 'spring rolls', 'sweet and sour pork', 'satay beef', 'gyouza');
$choice = $this->getDataGenerator()->create_module('choice', $params);
$this->assertEquals(5, $DB->count_records('choice_options', array('choiceid' => $choice->id)));
}
}
File diff suppressed because it is too large Load Diff
+316
View File
@@ -0,0 +1,316 @@
<?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/>.
/**
* Privacy provider tests.
*
* @package mod_choice
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_choice\privacy;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\deletion_criteria;
use mod_choice\privacy\provider;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy provider tests class.
*
* @package mod_choice
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends \core_privacy\tests\provider_testcase {
/** @var stdClass The student object. */
protected $student;
/** @var stdClass The choice object. */
protected $choice;
/** @var stdClass The course object. */
protected $course;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
$this->resetAfterTest();
global $DB;
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$options = ['fried rice', 'spring rolls', 'sweet and sour pork', 'satay beef', 'gyouza'];
$params = [
'course' => $course->id,
'option' => $options,
'name' => 'First Choice Activity',
'showpreview' => 0
];
$plugingenerator = $generator->get_plugin_generator('mod_choice');
// The choice activity the user will answer.
$choice = $plugingenerator->create_instance($params);
// Create another choice activity.
$plugingenerator->create_instance($params);
$cm = get_coursemodule_from_instance('choice', $choice->id);
// Create a student which will make a choice.
$student = $generator->create_user();
$studentrole = $DB->get_record('role', ['shortname' => 'student']);
$generator->enrol_user($student->id, $course->id, $studentrole->id);
$choicewithoptions = choice_get_choice($choice->id);
$optionids = array_keys($choicewithoptions->option);
choice_user_submit_response($optionids[2], $choice, $student->id, $course, $cm);
$this->student = $student;
$this->choice = $choice;
$this->course = $course;
}
/**
* Test for provider::get_metadata().
*/
public function test_get_metadata(): void {
$collection = new collection('mod_choice');
$newcollection = provider::get_metadata($collection);
$itemcollection = $newcollection->get_collection();
$this->assertCount(1, $itemcollection);
$table = reset($itemcollection);
$this->assertEquals('choice_answers', $table->get_name());
$privacyfields = $table->get_privacy_fields();
$this->assertArrayHasKey('choiceid', $privacyfields);
$this->assertArrayHasKey('optionid', $privacyfields);
$this->assertArrayHasKey('userid', $privacyfields);
$this->assertArrayHasKey('timemodified', $privacyfields);
$this->assertEquals('privacy:metadata:choice_answers', $table->get_summary());
}
/**
* Test for provider::get_contexts_for_userid().
*/
public function test_get_contexts_for_userid(): void {
$cm = get_coursemodule_from_instance('choice', $this->choice->id);
$contextlist = provider::get_contexts_for_userid($this->student->id);
$this->assertCount(1, $contextlist);
$contextforuser = $contextlist->current();
$cmcontext = \context_module::instance($cm->id);
$this->assertEquals($cmcontext->id, $contextforuser->id);
}
/**
* Test for provider::export_user_data().
*/
public function test_export_for_context(): void {
$cm = get_coursemodule_from_instance('choice', $this->choice->id);
$cmcontext = \context_module::instance($cm->id);
// Export all of the data for the context.
$this->export_context_data_for_user($this->student->id, $cmcontext, 'mod_choice');
$writer = \core_privacy\local\request\writer::with_context($cmcontext);
$this->assertTrue($writer->has_any_data());
}
/**
* Test for provider::delete_data_for_all_users_in_context().
*/
public function test_delete_data_for_all_users_in_context(): void {
global $DB;
$choice = $this->choice;
$generator = $this->getDataGenerator();
$cm = get_coursemodule_from_instance('choice', $this->choice->id);
// Create another student who will answer the choice activity.
$student = $generator->create_user();
$studentrole = $DB->get_record('role', ['shortname' => 'student']);
$generator->enrol_user($student->id, $this->course->id, $studentrole->id);
$choicewithoptions = choice_get_choice($choice->id);
$optionids = array_keys($choicewithoptions->option);
choice_user_submit_response($optionids[1], $choice, $student->id, $this->course, $cm);
// Before deletion, we should have 2 responses.
$count = $DB->count_records('choice_answers', ['choiceid' => $choice->id]);
$this->assertEquals(2, $count);
// Delete data based on context.
$cmcontext = \context_module::instance($cm->id);
provider::delete_data_for_all_users_in_context($cmcontext);
// After deletion, the choice answers for that choice activity should have been deleted.
$count = $DB->count_records('choice_answers', ['choiceid' => $choice->id]);
$this->assertEquals(0, $count);
}
/**
* Test for provider::delete_data_for_user().
*/
public function test_delete_data_for_user_(): void {
global $DB;
$choice = $this->choice;
$generator = $this->getDataGenerator();
$cm1 = get_coursemodule_from_instance('choice', $this->choice->id);
// Create a second choice activity.
$options = ['Boracay', 'Camiguin', 'Bohol', 'Cebu', 'Coron'];
$params = [
'course' => $this->course->id,
'option' => $options,
'name' => 'Which do you think is the best island in the Philippines?',
'showpreview' => 0
];
$plugingenerator = $generator->get_plugin_generator('mod_choice');
$choice2 = $plugingenerator->create_instance($params);
$plugingenerator->create_instance($params);
$cm2 = get_coursemodule_from_instance('choice', $choice2->id);
// Make a selection for the first student for the 2nd choice activity.
$choicewithoptions = choice_get_choice($choice2->id);
$optionids = array_keys($choicewithoptions->option);
choice_user_submit_response($optionids[2], $choice2, $this->student->id, $this->course, $cm2);
// Create another student who will answer the first choice activity.
$otherstudent = $generator->create_user();
$studentrole = $DB->get_record('role', ['shortname' => 'student']);
$generator->enrol_user($otherstudent->id, $this->course->id, $studentrole->id);
$choicewithoptions = choice_get_choice($choice->id);
$optionids = array_keys($choicewithoptions->option);
choice_user_submit_response($optionids[1], $choice, $otherstudent->id, $this->course, $cm1);
// Before deletion, we should have 2 responses.
$count = $DB->count_records('choice_answers', ['choiceid' => $choice->id]);
$this->assertEquals(2, $count);
$context1 = \context_module::instance($cm1->id);
$context2 = \context_module::instance($cm2->id);
$contextlist = new \core_privacy\local\request\approved_contextlist($this->student, 'choice',
[\context_system::instance()->id, $context1->id, $context2->id]);
provider::delete_data_for_user($contextlist);
// After deletion, the choice answers for the first student should have been deleted.
$count = $DB->count_records('choice_answers', ['choiceid' => $choice->id, 'userid' => $this->student->id]);
$this->assertEquals(0, $count);
// Confirm that we only have one choice answer available.
$choiceanswers = $DB->get_records('choice_answers');
$this->assertCount(1, $choiceanswers);
$lastresponse = reset($choiceanswers);
// And that it's the other student's response.
$this->assertEquals($otherstudent->id, $lastresponse->userid);
}
/**
* Test for provider::get_users_in_context().
*/
public function test_get_users_in_context(): void {
$cm = get_coursemodule_from_instance('choice', $this->choice->id);
$cmcontext = \context_module::instance($cm->id);
$userlist = new \core_privacy\local\request\userlist($cmcontext, 'mod_choice');
\mod_choice\privacy\provider::get_users_in_context($userlist);
$this->assertEquals(
[$this->student->id],
$userlist->get_userids()
);
}
/**
* Test for provider::get_users_in_context() with invalid context type.
*/
public function test_get_users_in_context_invalid_context_type(): void {
$systemcontext = \context_system::instance();
$userlist = new \core_privacy\local\request\userlist($systemcontext, 'mod_choice');
\mod_choice\privacy\provider::get_users_in_context($userlist);
$this->assertCount(0, $userlist->get_userids());
}
/**
* Test for provider::delete_data_for_users().
*/
public function test_delete_data_for_users(): void {
global $DB;
$choice = $this->choice;
$generator = $this->getDataGenerator();
$cm1 = get_coursemodule_from_instance('choice', $this->choice->id);
// Create a second choice activity.
$options = ['Boracay', 'Camiguin', 'Bohol', 'Cebu', 'Coron'];
$params = [
'course' => $this->course->id,
'option' => $options,
'name' => 'Which do you think is the best island in the Philippines?',
'showpreview' => 0
];
$plugingenerator = $generator->get_plugin_generator('mod_choice');
$choice2 = $plugingenerator->create_instance($params);
$plugingenerator->create_instance($params);
$cm2 = get_coursemodule_from_instance('choice', $choice2->id);
// Make a selection for the first student for the 2nd choice activity.
$choicewithoptions = choice_get_choice($choice2->id);
$optionids = array_keys($choicewithoptions->option);
choice_user_submit_response($optionids[2], $choice2, $this->student->id, $this->course, $cm2);
// Create 2 other students who will answer the first choice activity.
$otherstudent = $generator->create_and_enrol($this->course, 'student');
$anotherstudent = $generator->create_and_enrol($this->course, 'student');
$choicewithoptions = choice_get_choice($choice->id);
$optionids = array_keys($choicewithoptions->option);
choice_user_submit_response($optionids[1], $choice, $otherstudent->id, $this->course, $cm1);
choice_user_submit_response($optionids[1], $choice, $anotherstudent->id, $this->course, $cm1);
// Before deletion, we should have 3 responses in the first choice activity.
$count = $DB->count_records('choice_answers', ['choiceid' => $choice->id]);
$this->assertEquals(3, $count);
$context1 = \context_module::instance($cm1->id);
$approveduserlist = new \core_privacy\local\request\approved_userlist($context1, 'choice',
[$this->student->id, $otherstudent->id]);
provider::delete_data_for_users($approveduserlist);
// After deletion, the choice answers of the 2 students provided above should have been deleted
// from the first choice activity. So there should only remain 1 answer which is for $anotherstudent.
$choiceanswers = $DB->get_records('choice_answers', ['choiceid' => $choice->id]);
$this->assertCount(1, $choiceanswers);
$lastresponse = reset($choiceanswers);
$this->assertEquals($anotherstudent->id, $lastresponse->userid);
// Confirm that the answer that was submitted in the other choice activity is intact.
$choiceanswers = $DB->get_records_select('choice_answers', 'choiceid <> ?', [$choice->id]);
$this->assertCount(1, $choiceanswers);
$lastresponse = reset($choiceanswers);
// And that it's for the choice2 activity.
$this->assertEquals($choice2->id, $lastresponse->choiceid);
}
}