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,91 @@
<?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_feedback\backup;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . "/phpunit/classes/restore_date_testcase.php");
/**
* Restore date tests.
*
* @package mod_feedback
* @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 = 10000;
list($course, $feedback) = $this->create_course_and_module('feedback', ['timeopen' => $time, 'timeclose' => $time]);
// Create response.
$response = new \stdClass();
$response->feedback = $feedback->id;
$response->userid = $USER->id;
$response->anonymous_response = FEEDBACK_ANONYMOUS_NO;
$response->timemodified = $time;
$completedid = $DB->insert_record('feedback_completed', $response);
$response = $DB->get_record('feedback_completed', array('id' => $completedid), '*', MUST_EXIST);
// Do backup and restore.
$newcourseid = $this->backup_and_restore($course);
$newfeedback = $DB->get_record('feedback', ['course' => $newcourseid]);
$newresponse = $DB->get_record('feedback_completed', ['feedback' => $newfeedback->id]);
$this->assertFieldsNotRolledForward($feedback, $newfeedback, ['timemodified']);
$props = ['timeopen', 'timeclose'];
$this->assertFieldsRolledForward($feedback, $newfeedback, $props);
$this->assertEquals($response->timemodified, $newresponse->timemodified);
}
/**
* Test that dependency for items is restored correctly.
*/
public function test_restore_item_dependency(): void {
global $DB;
// Create a course and a feedback activity.
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course));
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
// Create a couple of items which depend on each other.
$item1 = $feedbackgenerator->create_item_numeric($feedback);
$item2 = $feedbackgenerator->create_item_numeric($feedback, array('dependitem' => $item1->id));
$DB->set_field('feedback_item', 'dependitem', $item2->id, ['id' => $item1->id]);
// Create one more item with fake/broken dependitem.
$item3 = $feedbackgenerator->create_item_numeric($feedback, array('dependitem' => 123456));
// Backup and restore the course.
$restoredcourseid = $this->backup_and_restore($course);
$restoredfeedback = $DB->get_record('feedback', ['course' => $restoredcourseid]);
// Restored item1 and item2 are expected to be dependent the same way as the original ones.
$restoreditem1 = $DB->get_record('feedback_item', ['feedback' => $restoredfeedback->id, 'name' => $item1->name]);
$restoreditem2 = $DB->get_record('feedback_item', ['feedback' => $restoredfeedback->id, 'name' => $item2->name]);
$this->assertEquals($restoreditem2->id, $restoreditem1->dependitem);
$this->assertEquals($restoreditem1->id, $restoreditem2->dependitem);
// Restored item3 is expected to have an empty dependitem.
$restoreditem3 = $DB->get_record('feedback_item', ['feedback' => $restoredfeedback->id, 'name' => $item3->name]);
$this->assertEquals(0, $restoreditem3->dependitem);
}
}
+258
View File
@@ -0,0 +1,258 @@
@mod @mod_feedback
Feature: Anonymous feedback
In order to collect feedbacks
As an admin
I need to be able to allow anonymous feedbacks
Background:
Given the following "users" exist:
| username | firstname | lastname |
| user1 | Username | 1 |
| user2 | Username | 2 |
| teacher | Teacher | 3 |
| manager | Manager | 4 |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| user1 | C1 | student |
| user2 | C1 | student |
| teacher | C1 | editingteacher |
And the following "system role assigns" exist:
| user | course | role |
| manager | Acceptance test site | manager |
And the following "activities" exist:
| activity | name | course | idnumber | anonymous | publish_stats | section |
| feedback | Site feedback | Acceptance test site | feedback0 | 1 | 1 | 1 |
| feedback | Course feedback | C1 | feedback1 | 1 | 1 | 0 |
When I log in as "manager"
And I am on site homepage
And I follow "Site feedback"
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Multiple choice" question to the feedback with:
| Question | Do you like our site? |
| Label | multichoice2 |
| Multiple choice type | Multiple choice - single answer |
| Hide the "Not selected" option | Yes |
| Multiple choice values | Yes\nNo\nI don't know |
And I log out
Scenario: Guests can see anonymous feedback on front page but can not complete
When I follow "Site feedback"
Then I should not see "Answer the questions"
And I should not see "Preview questions"
Scenario: Complete anonymous feedback on the front page as an authenticated user
And I log in as "user1"
And I am on site homepage
When I follow "Site feedback"
And I should not see "Preview questions"
And I follow "Answer the questions"
And I should see "Do you like our site?"
And I set the following fields to these values:
| Yes | 1 |
And I press "Submit your answers"
And I should not see "Analysis"
And I press "Continue"
@javascript
Scenario: Complete anonymous feedback and view analysis on the front page as an authenticated user
Given the following "role capability" exists:
| role | frontpage |
| mod/feedback:viewanalysepage | allow |
And I log in as "user1"
And I am on site homepage
When I follow "Site feedback"
And I should not see "Preview questions"
And I follow "Answer the questions"
And I should see "Do you like our site?"
And I set the following fields to these values:
| Yes | 1 |
And I press "Submit your answers"
And I log out
And I log in as "user2"
And I am on site homepage
And I follow "Site feedback"
And I should not see "Preview questions"
And I follow "Answer the questions"
And I set the following fields to these values:
| No | 1 |
And I press "Submit your answers"
And I follow "Analysis"
And I should see "Submitted answers: 2"
And I should see "Questions: 1"
# And I should not see "multichoice2" # TODO MDL-29303 do not show labels to users who can not edit feedback
And I show chart data for the "multichoice2" feedback
And I should see "Do you like our site?"
And I should see "1 (50.00 %)" in the "Yes" "table_row"
And I should see "1 (50.00 %)" in the "No" "table_row"
And I log out
And I log in as "manager"
And I am on site homepage
And I follow "Site feedback"
And I navigate to "Responses" in current page administration
And I should not see "Username"
And I should see "Anonymous entries (2)"
And I follow "Response number: 1"
And I should not see "Username"
And I should see "Response number: 1 (Anonymous)"
And I log out
Scenario: Complete fully anonymous feedback on the front page as a guest
Given the following config values are set as admin:
| feedback_allowfullanonymous | 1 |
When I follow "Site feedback"
And I should not see "Preview questions"
And I follow "Answer the questions"
And I should see "Do you like our site?"
And I set the following fields to these values:
| Yes | 1 |
And I press "Submit your answers"
And I should not see "Analysis"
And I press "Continue"
@javascript
Scenario: Complete fully anonymous feedback and view analyze on the front page as a guest
Given the following config values are set as admin:
| feedback_allowfullanonymous | 1 |
And the following "role capability" exists:
| role | guest |
| mod/feedback:viewanalysepage | allow |
When I follow "Site feedback"
And I should not see "Preview questions"
And I follow "Answer the questions"
And I should see "Do you like our site?"
And I set the following fields to these values:
| Yes | 1 |
And I press "Submit your answers"
And I press "Continue"
# Starting new feedback
When I follow "Site feedback"
And I should not see "Preview questions"
And I follow "Answer the questions"
And I should see "Do you like our site?"
And I set the following fields to these values:
| No | 1 |
And I press "Submit your answers"
And I follow "Analysis"
And I should see "Submitted answers: 2"
And I should see "Questions: 1"
# And I should not see "multichoice2" # TODO MDL-29303
And I show chart data for the "multichoice2" feedback
And I should see "Do you like our site?"
And I should see "1 (50.00 %)" in the "Yes" "table_row"
And I should see "1 (50.00 %)" in the "No" "table_row"
And I log in as "manager"
And I am on site homepage
And I follow "Site feedback"
And I navigate to "Responses" in current page administration
And I should see "Anonymous entries (2)"
And I follow "Response number: 1"
And I should see "Response number: 1 (Anonymous)"
And I log out
@javascript
Scenario: Anonymous feedback in a course
# Teacher can not
When I am on the "Course feedback" "feedback activity" page logged in as teacher
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Multiple choice" question to the feedback with:
| Question | Do you like this course? |
| Label | multichoice1 |
| Multiple choice type | Multiple choice - single answer |
| Hide the "Not selected" option | Yes |
| Multiple choice values | Yes\nNo\nI don't know |
And I log out
And I am on the "Course feedback" "feedback activity" page logged in as user1
And I should not see "Preview questions"
And I follow "Answer the questions"
And I should see "Do you like this course?"
And I set the following fields to these values:
| Yes | 1 |
And I press "Submit your answers"
And I log out
And I am on the "Course feedback" "feedback activity" page logged in as user2
And I should not see "Preview questions"
And I follow "Answer the questions"
And I should see "Do you like this course?"
And I set the following fields to these values:
| No | 1 |
And I press "Submit your answers"
And I follow "Analysis"
And I should see "Submitted answers: 2"
And I should see "Questions: 1"
# And I should not see "multichoice2" # TODO MDL-29303
And I show chart data for the "multichoice1" feedback
And I should see "Do you like this course?"
And I should see "1 (50.00 %)" in the "Yes" "table_row"
And I should see "1 (50.00 %)" in the "No" "table_row"
And I log out
And I am on the "Course feedback" "feedback activity" page logged in as teacher
And I follow "Preview"
And I should see "Do you like this course?"
And I press "Continue"
And I should not see "Answer the questions"
And I navigate to "Responses" in current page administration
And I should not see "Username"
And I should see "Anonymous entries (2)"
And I follow "Response number: 1"
And I should not see "Username"
And I should see "Response number: 1 (Anonymous)"
And I should not see "Prev"
And I follow "Next"
And I should see "Response number: 2 (Anonymous)"
And I should see "Prev"
And I should not see "Next"
And I click on "Back" "link" in the "[role=main]" "css_element"
# Delete anonymous response
And I click on "Delete entry" "link" in the "Response number: 1" "table_row"
And I press "Yes"
And I should see "Anonymous entries (1)"
And I should not see "Response number: 1"
And I should see "Response number: 2"
Scenario: Collecting new non-anonymous feedback from a previously anonymous feedback activity
When I am on the "Course feedback" "feedback activity" page logged in as teacher
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Allow multiple submissions | Yes |
And I press "Save and display"
And I follow "Edit questions"
And I add a "Short text answer" question to the feedback with:
| Question | this is a short text answer |
| Label | shorttext |
| Maximum characters accepted | 200 |
And I log out
When I am on the "Course feedback" "feedback activity" page logged in as user1
And I follow "Answer the questions"
And I set the following fields to these values:
| this is a short text answer | anontext |
And I press "Submit your answers"
And I log out
# Switch to non-anon responses.
And I am on the "Course feedback" "feedback activity editing" page logged in as teacher
And I set the following fields to these values:
| Record user names | User's name will be logged and shown with answers |
And I press "Save and display"
And I log out
# Now leave a non-anon feedback as user1
And I am on the "Course feedback" "feedback activity" page logged in as user1
And I follow "Answer the questions"
And I set the following fields to these values:
| this is a short text answer | usertext |
And I press "Submit your answers"
And I log out
# Now check the responses are correct.
And I am on the "Course feedback" "feedback activity" page logged in as teacher
And I follow "Responses"
And I should see "Anonymous entries (1)"
And I should see "Non anonymous entries (1)"
And I click on "," "link" in the "Username 1" "table_row"
And I should see "(Username 1)"
Then the field "this is a short text answer" matches value "usertext"
And I navigate to "Responses" in current page administration
And I follow "Response number: 1"
And I should see "Response number: 1 (Anonymous)"
And the field "this is a short text answer" matches value "anontext"
@@ -0,0 +1,229 @@
<?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 related to mod_feedback.
*
* @package mod_feedback
* @category test
* @copyright 2016 Marina Glancy
* @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');
use Behat\Gherkin\Node\TableNode as TableNode,
Behat\Mink\Exception\ExpectationException as ExpectationException;
/**
* Steps definitions related to mod_feedback.
*
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_mod_feedback extends behat_base {
/**
* Adds a question to the existing feedback with filling the form.
*
* The form for creating a question should be on one page.
*
* @When /^I add a "(?P<question_type_string>(?:[^"]|\\")*)" question to the feedback with:$/
* @param string $questiontype
* @param TableNode $questiondata with data for filling the add question form
*/
public function i_add_question_to_the_feedback_with($questiontype, TableNode $questiondata) {
$questiontype = $this->escape($questiontype);
$this->execute('behat_forms::i_select_from_the_singleselect', array($questiontype, 'typ'));
// Wait again, for page to reloaded.
$this->execute('behat_general::i_wait_to_be_redirected');
$rows = $questiondata->getRows();
$modifiedrows = array();
foreach ($rows as $row) {
foreach ($row as $key => $value) {
$row[$key] = preg_replace('|\\\\n|', "\n", $value);
}
$modifiedrows[] = $row;
}
$newdata = new TableNode($modifiedrows);
$this->execute("behat_forms::i_set_the_following_fields_to_these_values", $newdata);
$saveitem = $this->escape(get_string('save'));
$this->execute("behat_forms::press_button", $saveitem);
}
/**
* Adds a question to the existing feedback with filling the form.
*
* The form for creating a question should be on one page.
*
* @When /^I add a page break to the feedback$/
*/
public function i_add_a_page_break_to_the_feedback() {
$questiontype = $this->escape(get_string('add_pagebreak', 'feedback'));
$this->execute('behat_forms::i_select_from_the_singleselect', array($questiontype, 'typ'));
// Wait again, for page to reloaded.
$this->execute('behat_general::i_wait_to_be_redirected');
}
/**
* Quick way to generate answers to a one-page feedback.
*
* @When /^I log in as "(?P<user_name_string>(?:[^"]|\\")*)" and complete feedback "(?P<feedback_name_string>(?:[^"]|\\")*)" in course "(?P<course_name_string>(?:[^"]|\\")*)" with:$/
* @param string $questiontype
* @param TableNode $questiondata with data for filling the add question form
*/
public function i_log_in_as_and_complete_feedback_in_course($username, $feedbackname, $coursename, TableNode $answers) {
$username = $this->escape($username);
$coursename = $this->escape($coursename);
$feedbackname = $this->escape($feedbackname);
$completeform = $this->escape(get_string('complete_the_form', 'feedback'));
// Log in as user.
$this->execute('behat_auth::i_log_in_as', $username);
// Navigate to feedback complete form.
$this->execute('behat_navigation::i_am_on_page_instance', [$feedbackname, 'feedback activity']);
$this->execute('behat_general::click_link', $completeform);
// Fill form and submit.
$this->execute("behat_forms::i_set_the_following_fields_to_these_values", $answers);
$this->execute("behat_forms::press_button", 'Submit your answers');
// Log out.
$this->execute('behat_auth::i_log_out');
}
/**
* Exports feedback and makes sure the export file is the same as in the fixture
*
* @Then /^following "(?P<link_string>(?:[^"]|\\")*)" should export feedback identical to "(?P<filename_string>(?:[^"]|\\")*)"$/
* @param string $link
* @param string $filename
*/
public function following_should_export_feedback_identical_to($link, $filename) {
global $CFG;
$exception = new ExpectationException('Error while downloading data from ' . $link, $this->getSession());
// It will stop spinning once file is downloaded or time out.
$behatgeneralcontext = behat_context_helper::get('behat_general');
$result = $this->spin(
function($context, $args) use ($behatgeneralcontext) {
$link = $args['link'];
return $behatgeneralcontext->download_file_from_link($link);
},
array('link' => $link),
behat_base::get_extended_timeout(),
$exception
);
$this->compare_exports(file_get_contents($CFG->dirroot . '/' . $filename), $result);
}
/**
* Clicks on Show chart data to display chart data if not visible.
*
* @Then /^I show chart data for the "(?P<feedback_name_string>(?:[^"]|\\")*)" feedback$/
* @param string $feedbackname name of the feedback for which chart data needs to be shown.
*/
public function i_show_chart_data_for_the_feedback($feedbackname) {
$feedbackxpath = "//th[contains(normalize-space(string(.)), \"" . $feedbackname . "\")]/ancestor::table//" .
"div[contains(concat(' ', normalize-space(@class), ' '), ' chart-table ')]" .
"//p[contains(concat(' ', normalize-space(@class), ' '), ' chart-table-expand ') and ".
"//a[contains(normalize-space(string(.)), '".get_string('showchartdata')."')]]";
$charttabledataxpath = $feedbackxpath .
"/following-sibling::div[contains(concat(' ', normalize-space(@class), ' '), ' chart-table-data ')][1]";
// If chart data is not visible then expand.
$node = $this->get_selected_node("xpath_element", $charttabledataxpath);
if ($node) {
if ($node->getAttribute('aria-expanded') === 'false') {
$this->execute('behat_general::i_click_on_in_the', array(
get_string('showchartdata'),
'link',
$feedbackxpath,
'xpath_element'
));
}
}
}
/**
* Ensures two feedback export files are identical
*
* Maps the itemids and converts DEPENDITEM if necessary
*
* Throws ExpectationException if exports are different
*
* @param string $expected
* @param string $actual
* @throws ExpectationException
*/
protected function compare_exports($expected, $actual) {
$dataexpected = xmlize($expected, 1, 'UTF-8');
$dataexpected = $dataexpected['FEEDBACK']['#']['ITEMS'][0]['#']['ITEM'];
$dataactual = xmlize($actual, 1, 'UTF-8');
$dataactual = $dataactual['FEEDBACK']['#']['ITEMS'][0]['#']['ITEM'];
if (count($dataexpected) != count($dataactual)) {
throw new ExpectationException('Expected ' . count($dataexpected) .
' items in the export file, found ' . count($dataactual), $this->getSession());
}
$itemmapping = array();
$itemactual = reset($dataactual);
foreach ($dataexpected as $idx => $itemexpected) {
// Map ITEMID and DEPENDITEM.
$itemmapping[intval($itemactual['#']['ITEMID'][0]['#'])] = intval($itemexpected['#']['ITEMID'][0]['#']);
$itemactual['#']['ITEMID'][0]['#'] = $itemexpected['#']['ITEMID'][0]['#'];
$expecteddependitem = $actualdependitem = 0;
if (isset($itemexpected['#']['DEPENDITEM'][0]['#'])) {
$expecteddependitem = intval($itemexpected['#']['DEPENDITEM'][0]['#']);
}
if (isset($itemactual['#']['DEPENDITEM'][0]['#'])) {
$actualdependitem = intval($itemactual['#']['DEPENDITEM'][0]['#']);
}
if ($expecteddependitem && !$actualdependitem) {
throw new ExpectationException('Expected DEPENDITEM in ' . ($idx + 1) . 'th item', $this->getSession());
}
if (!$expecteddependitem && $actualdependitem) {
throw new ExpectationException('Unexpected DEPENDITEM in ' . ($idx + 1) . 'th item', $this->getSession());
}
if ($expecteddependitem && $actualdependitem) {
if (!isset($itemmapping[$actualdependitem]) || $itemmapping[$actualdependitem] != $expecteddependitem) {
throw new ExpectationException('Unknown DEPENDITEM in ' . ($idx + 1) . 'th item', $this->getSession());
}
$itemactual['#']['DEPENDITEM'][0]['#'] = $itemexpected['#']['DEPENDITEM'][0]['#'];
}
// Now, after mapping, $itemexpected should be exactly the same as $itemactual.
if (json_encode($itemexpected) !== json_encode($itemactual)) {
throw new ExpectationException('Actual ' . ($idx + 1) . 'th item does not match expected', $this->getSession());
}
// Get the next itemactual.
$itemactual = next($dataactual);
}
}
}
@@ -0,0 +1,236 @@
@mod @mod_feedback
Feature: Mapping courses in a feedback
In order to collect the same feedback about multiple courses
As a manager
I need to be able to map site feedback to courses
Background:
Given the following "users" exist:
| username | firstname | lastname |
| user1 | Username | 1 |
| user2 | Username | 2 |
| user3 | Username | 3 |
| teacher | Teacher | 4 |
| manager | Manager | 5 |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
| Course 2 | C2 |
| Course 3 | C3 |
And the following "course enrolments" exist:
| user | course | role |
| user1 | C1 | student |
| user1 | C2 | student |
| user2 | C1 | student |
| user2 | C2 | student |
| user3 | C3 | student |
| teacher | C1 | editingteacher |
| teacher | C2 | editingteacher |
| teacher | C3 | editingteacher |
And the following "system role assigns" exist:
| user | course | role |
| manager | Acceptance test site | manager |
And the following "activities" exist:
| activity | name | course | idnumber | anonymous | publish_stats | section |
| feedback | Course feedback | Acceptance test site | feedback0 | 1 | 1 | 1 |
| feedback | Another feedback | C1 | feedback1 | 1 | 1 | 0 |
And I enable "feedback" "block" plugin
And the following "blocks" exist:
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
| feedback | Course | C1 | course-view-* | side-pre |
| feedback | Course | C2 | course-view-* | side-pre |
| feedback | Course | C3 | course-view-* | side-pre |
When I log in as "manager"
And I am on site homepage
And I follow "Course feedback"
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Information" question to the feedback with:
| Question | this is an information question |
| Label | info |
| Information type | Course |
And I add a "Multiple choice (rated)" question to the feedback with:
| Question | this is a multiple choice rated |
| Label | multichoicerated |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | 0/option a\n1/option b\n5/option c |
And I add a "Multiple choice" question to the feedback with:
| Question | this is a simple multiple choice |
| Label | multichoicesimple |
| Multiple choice type | Multiple choice - single answer allowed (drop-down menu) |
| Multiple choice values | option d\noption e\noption f |
And I log out
Scenario: Course feedback can not be mapped
And I log in as "manager"
And I am on "Course 1" course homepage
And I follow "Another feedback"
And I should not see "Mapped courses"
@javascript
Scenario: Site feedback is not mapped to any course
And I log in as "user1"
And I am on site homepage
And I follow "Course feedback"
And I follow "Answer the questions"
And I should see "Acceptance test site" in the ".feedback_form" "css_element"
And I set the following fields to these values:
| option a | 1 |
| this is a simple multiple choice | option d |
And I press "Submit your answers"
And I press "Continue"
And I am on "Course 1" course homepage
And I click on "Course feedback" "link" in the "Feedback" "block"
And I follow "Answer the questions"
And I should not see "Acceptance test site" in the ".feedback_form" "css_element"
And I should see "C1" in the ".feedback_form" "css_element"
And I set the following fields to these values:
| option b | 1 |
| this is a simple multiple choice | option e |
And I press "Submit your answers"
And I press "Continue"
And I click on "Course feedback" "link" in the "Feedback" "block"
And I should not see "Answer the questions"
And I log out
And I log in as "user2"
And I am on "Course 1" course homepage
And I click on "Course feedback" "link" in the "Feedback" "block"
And I follow "Answer the questions"
And I should not see "Acceptance test site" in the ".feedback_form" "css_element"
And I should see "C1" in the ".feedback_form" "css_element"
And I set the following fields to these values:
| option c | 1 |
| this is a simple multiple choice | option e |
And I press "Submit your answers"
And I press "Continue"
And I log out
And I log in as "manager"
And I am on site homepage
And I follow "Course feedback"
And I navigate to "Analysis" in current page administration
And I should see "All courses" in the "#feedback_course_filter [data-fieldtype=autocomplete] .form-autocomplete-selection [role=option]" "css_element"
And I show chart data for the "multichoicerated" feedback
And I should see "1 (33.33 %)" in the "option a" "table_row"
And I should see "1 (33.33 %)" in the "option b" "table_row"
And I should see "1 (33.33 %)" in the "option c" "table_row"
And I should see "Average: 2.00"
And I follow "Sort by course"
And I should see "2.50" in the "C1" "table_row"
And I should see "1.00" in the "Acceptance test site" "table_row"
And I click on "Back" "link" in the "region-main" "region"
And I set the field "Filter by course" to "Course 1"
And I press "Filter"
And I should see "Course 1" in the "#feedback_course_filter [data-fieldtype=autocomplete] .form-autocomplete-selection [role=option]" "css_element"
And I show chart data for the "multichoicerated" feedback
And I should see "0" in the "option a" "table_row"
And I should see "1 (50.00 %)" in the "option b" "table_row"
And I should see "1 (50.00 %)" in the "option c" "table_row"
And I log out
@javascript
Scenario: Site feedback is mapped to courses
And I log in as "manager"
And I am on site homepage
And I follow "Course feedback"
And I follow "Mapped courses"
And I set the field "Courses" to "Course 2, Course 3"
And I press "Save changes"
And I should see "Course mapping has been changed"
And I log out
And I log in as "user1"
And I am on site homepage
And I follow "Course feedback"
And I should see "You can only access this feedback from a course"
And I should not see "Answer the questions"
And I am on "Course 1" course homepage
And "Feedback" "block" should not exist
And I should not see "Course feedback"
And I am on "Course 2" course homepage
And I click on "Course feedback" "link" in the "Feedback" "block"
And I follow "Answer the questions"
And I should not see "Acceptance test site" in the ".feedback_form" "css_element"
And I should see "C2" in the ".feedback_form" "css_element"
And I set the following fields to these values:
| option b | 1 |
| this is a simple multiple choice | option e |
And I press "Submit your answers"
And I press "Continue"
And I click on "Course feedback" "link" in the "Feedback" "block"
And I should not see "Answer the questions"
And I log out
And I log in as "user2"
And I am on "Course 2" course homepage
And I click on "Course feedback" "link" in the "Feedback" "block"
And I follow "Answer the questions"
And I should not see "Acceptance test site" in the ".feedback_form" "css_element"
And I should see "C2" in the ".feedback_form" "css_element"
And I set the following fields to these values:
| option c | 1 |
| this is a simple multiple choice | option e |
And I press "Submit your answers"
And I press "Continue"
And I log out
And I log in as "user3"
And I am on "Course 3" course homepage
And I click on "Course feedback" "link" in the "Feedback" "block"
And I follow "Answer the questions"
And I should not see "Acceptance test site" in the ".feedback_form" "css_element"
And I should see "C3" in the ".feedback_form" "css_element"
And I set the following fields to these values:
| option c | 1 |
| this is a simple multiple choice | option d |
And I press "Submit your answers"
And I press "Continue"
And I log out
And I log in as "manager"
And I am on site homepage
And I follow "Course feedback"
And I navigate to "Analysis" in current page administration
And I should see "All courses" in the "#feedback_course_filter [data-fieldtype=autocomplete] .form-autocomplete-selection [role=option]" "css_element"
And I show chart data for the "multichoicerated" feedback
And I should see "0" in the "option a" "table_row"
And I should see "1 (33.33 %)" in the "option b" "table_row"
And I should see "2 (66.67 %)" in the "option c" "table_row"
And I should see "Average: 3.67"
And I click on "Sort by course" "link"
And I should see "3.00" in the "C3" "table_row"
And I should see "2.50" in the "C2" "table_row"
And I click on "Back" "link" in the "region-main" "region"
And I set the field "Filter by course" to "Course 2"
And I press "Filter"
And I show chart data for the "multichoicerated" feedback
And I should see "0" in the "option a" "table_row"
And I should see "1 (50.00 %)" in the "option b" "table_row"
And I should see "1 (50.00 %)" in the "option c" "table_row"
And I show chart data for the "multichoicesimple" feedback
And I should see "2 (100.00 %)" in the "option e" "table_row"
And I set the field "Filter by course" to "Course 3"
And I press "Filter"
And I show chart data for the "multichoicerated" feedback
And I should see "0" in the "option a" "table_row"
And I should see "0" in the "option b" "table_row"
And I should see "1 (100.00 %)" in the "option c" "table_row"
And I show chart data for the "multichoicesimple" feedback
And I should see "1 (100.00 %)" in the "option d" "table_row"
And I follow "Show all"
And I show chart data for the "multichoicesimple" feedback
And I should see "1 (33.33 %)" in the "option d" "table_row"
And I should see "2 (66.67 %)" in the "option e" "table_row"
And I should see "0" in the "option f" "table_row"
Scenario: Site feedback deletion hides feedback block completely
When I log in as "manager"
And I am on site homepage
And I turn editing mode on
And I add the "Feedback" block
And I add the "Main menu" block
And I click on "Delete" "link" in the "Course feedback" activity
And I press "Yes"
And I turn editing mode off
And I am on site homepage
Then "Feedback" "block" should not exist
And I am on "Course 1" course homepage
And "Feedback" "block" should not exist
@@ -0,0 +1,119 @@
@mod @mod_feedback
Feature: Exporting and importing feedbacks
In order to quickly copy feedbacks across courses and sites
As a teacher
I need to be able to export and import feedbacks
Background:
Given the following "users" exist:
| username | firstname | lastname |
| teacher | Teacher | 1 |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
| Course 2 | C2 |
And the following "course enrolments" exist:
| user | course | role |
| teacher | C1 | editingteacher |
| teacher | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| feedback | Learning experience | C1 | feedback0 |
And I change window size to "large"
Scenario: Export sample feedback and compare with the fixture
When I am on the "Learning experience" "feedback activity" page logged in as teacher
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And "Export questions" "link" should not exist in the ".tertiary-navigation" "css_element"
And I add a "Information" question to the feedback with:
| Question | this is an information question |
| Label | info |
| Information type | Course |
And I add a "Text and media area" question to the feedback with:
| Contents | label text |
And I add a "Longer text answer" question to the feedback with:
| Question | this is a longer text answer |
| Label | longertext |
| Required | 1 |
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 1 |
| Label | multichoice1 |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | option a\noption b\noption c |
And I select "Add a page break" from the "typ" singleselect
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 2 |
| Label | multichoice2 |
| Multiple choice type | Multiple choice - multiple answers |
| Hide the "Not selected" option | Yes |
| Multiple choice values | option d\noption e\noption f |
| Dependence item | multichoice1 |
| Dependence value | option a |
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 3 |
| Label | multichoice3 |
| Multiple choice type | Multiple choice - single answer allowed (drop-down menu) |
| Multiple choice values | option g\noption h\noption i |
And I add a "Multiple choice (rated)" question to the feedback with:
| Question | this is a multiple choice rated |
| Label | multichoice4 |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | 0/option k\n1/option l\n5/option m |
And I add a "Numeric answer" question to the feedback with:
| Question | this is a numeric answer |
| Label | numeric |
| Range to | 100 |
And I add a "Short text answer" question to the feedback with:
| Question | this is a short text answer |
| Label | shorttext |
| Maximum characters accepted | 200 |
Then following "Export questions" should export feedback identical to "mod/feedback/tests/fixtures/testexport.xml"
And I log out
@javascript @_file_upload
Scenario: Import feedback deleting old items
When I am on the "Learning experience" "feedback activity" page logged in as teacher
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Numeric answer" question to the feedback with:
| Question | Existing question |
| Label | numeric |
| Range to | 100 |
And I select "Import questions" from the "jump" singleselect
And I upload "mod/feedback/tests/fixtures/testexport.xml" file to "File" filemanager
And I press "Save"
And I select "Add question" from the "jump" singleselect
Then I should not see "Existing question"
And I should see "this is an information question"
And I should see "label text"
And I should see "this is a longer text answer"
And I should see "this is a multiple choice 1"
And I should see "this is a multiple choice 2"
And I should see "this is a multiple choice 3"
And I should see "this is a multiple choice rated"
And I should see "this is a numeric answer"
And I should see "this is a short text answer"
@javascript @_file_upload
Scenario: Import feedback appending new items
When I am on the "Learning experience" "feedback activity" page logged in as teacher
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Numeric answer" question to the feedback with:
| Question | Existing question |
| Label | numeric |
| Range to | 100 |
And I select "Import questions" from the "jump" singleselect
And I set the field "Append new items" to "1"
And I upload "mod/feedback/tests/fixtures/testexport.xml" file to "File" filemanager
And I press "Save"
And I select "Add question" from the "jump" singleselect
Then I should see "Existing question"
And "Existing question" "text" should appear before "this is an information question" "text"
And I should see "this is an information question"
And I should see "label text"
And I should see "this is a longer text answer"
And I should see "this is a multiple choice 1"
And I should see "this is a multiple choice 2"
And I should see "this is a multiple choice 3"
And I should see "this is a multiple choice rated"
And I should see "this is a numeric answer"
And I should see "this is a short text answer"
@@ -0,0 +1,67 @@
@mod @mod_feedback @core_completion
Feature: View activity completion in the feedback activity
In order to have visibility of feedback completion requirements
As a student
I need to be able to view my feedback completion progress
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Vinnie | Student1 | student1@example.com |
| teacher1 | Darrell | Teacher1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | enablecompletion | showcompletionconditions |
| Course 1 | C1 | 1 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
And the following "activity" exists:
| activity | feedback |
| course | C1 |
| idnumber | mh1 |
| name | Music history |
| section | 1 |
| completion | 2 |
| completionview | 1 |
| completionsubmit | 1 |
And I am on the "Music history" "feedback activity" page logged in as teacher1
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Multiple choice" question to the feedback with:
| Question | What is your favourite instrument |
| Label | instrument1 |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | drums\guitar\hurdygurdy |
And I log out
Scenario: View automatic completion items as a teacher
When I am on the "Music history" "feedback activity" page logged in as teacher1
Then "Music history" should have the "View" completion condition
And "Music history" should have the "Submit feedback" completion condition
Scenario: View automatic completion items as a student
Given I am on the "Music history" "feedback activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "todo"
And the "Submit feedback" completion condition of "Music history" is displayed as "todo"
When I follow "Answer the questions"
And I set the field "drums" to "1"
And I press "Submit your answers"
And I press "Continue"
And I am on the "Music history" "feedback activity" page
Then the "View" completion condition of "Music history" is displayed as "done"
And the "Submit feedback" completion condition of "Music history" is displayed as "done"
@javascript
Scenario: Use manual completion
Given I am on the "Music history" "feedback activity editing" page logged in as teacher1
And I expand all fieldsets
And I set the field "Students must manually mark the activity as done" to "1"
And I press "Save and display"
# Teacher view.
And the manual completion button for "Music history" should be disabled
And I log out
# Student view.
When I am on the "Music history" "feedback activity" page logged in as student1
Then the manual completion button of "Music history" is displayed as "Mark as done"
And I toggle the manual completion state of "Music history"
And the manual completion button of "Music history" is displayed as "Done"
@@ -0,0 +1,51 @@
@mod @mod_feedback
Feature: Feedback with no calendar capabilites
In order to allow work effectively
As a teacher
I need to be able to create feedbacks 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 feedback
Given the following "activities" exist:
| activity | name | intro | course | idnumber |
| feedback | Test feedback name | Test feedback description | C1 | feedback1 |
And I log in as "admin"
And I am on "Course 1" course homepage
And I follow "Test feedback 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 feedback 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 feedback name"
+267
View File
@@ -0,0 +1,267 @@
@mod @mod_feedback
Feature: Feedbacks in courses with groups
In order to collect feedbacks per group
As an teacher
I need to be able to filter feedback replies by groups
Background:
Given the following "users" exist:
| username | firstname | lastname |
| user1 | Username | 1 |
| user2 | Username | 2 |
| user3 | Username | 3 |
| user4 | Username | 4 |
| user5 | Username | 5 |
| user6 | Username | 6 |
| user7 | Username | 7 |
| user8 | Username | 8 |
| teacher | Teacher | T |
| manager | Manager | M |
And the following "courses" exist:
| fullname | shortname | groupmode |
| Course 1 | C1 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| user1 | C1 | student |
| user2 | C1 | student |
| user3 | C1 | student |
| user4 | C1 | student |
| user5 | C1 | student |
| user6 | C1 | student |
| user7 | C1 | student |
| user8 | C1 | student |
| teacher | C1 | editingteacher |
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 "group members" exist:
| user | group |
| user1 | G1 |
| user2 | G1 |
| user2 | G2 |
| user3 | G2 |
| user4 | G1 |
| user5 | G1 |
| user6 | G2 |
| user8 | G3 |
And the following "system role assigns" exist:
| user | course | role |
| manager | Acceptance test site | manager |
And the following "activities" exist:
| activity | name | course | idnumber | anonymous | publish_stats | groupmode | section |
| feedback | Site feedback | Acceptance test site | feedback0 | 2 | 1 | 1 | 1 |
| feedback | Course feedback | C1 | feedback1 | 2 | 1 | 1 | 0 |
| feedback | Course anon feedback | C1 | feedback2 | 1 | 1 | 1 | 0 |
@javascript
Scenario: Non anonymous feedback with groups in a course
Given the following "mod_feedback > question" exists:
| activity | feedback1 |
| name | Do you like this course? |
| questiontype | multichoice |
| label | multichoice1 |
| subtype | r |
| hidenoselect | 1 |
| values | Yes of course\nNot at all\nI don't know |
And the following "mod_feedback > responses" exist:
| activity | user | Do you like this course? |
| feedback1 | user1 | Not at all |
| feedback1 | user2 | I don't know |
| feedback1 | user3 | Not at all |
| feedback1 | user4 | Yes of course |
| feedback1 | user5 | Yes of course |
| feedback1 | user6 | Not at all |
| feedback1 | user7 | I don't know |
| feedback1 | user8 | Yes of course |
# View analysis, user1 should only see one group - group 1
When I am on the "Course feedback" "feedback activity" page logged in as user1
And I follow "Analysis"
And I should see "Separate groups: Group 1"
And I show chart data for the "multichoice1" feedback
And I should see "2 (50.00 %)" in the "Yes of course" "table_row"
And I should see "1 (25.00 %)" in the "Not at all" "table_row"
And I log out
# View analysis, user3 should only see one group - group 2
And I am on the "Course feedback" "feedback activity" page logged in as user3
And I follow "Analysis"
And I should see "Separate groups: Group 2"
And I show chart data for the "multichoice1" feedback
And I should see "0" in the "Yes of course" "table_row"
And I should see "2 (66.67 %)" in the "Not at all" "table_row"
And I log out
# View analysis, user2 should see a group selector and be able to change the group but not view all.
And I am on the "Course feedback" "feedback activity" page logged in as user2
And I follow "Analysis"
And the field "Separate groups" matches value "Group 1"
And I should not see "Group 3" in the "Separate groups" "select"
And I show chart data for the "multichoice1" feedback
And I should see "2 (50.00 %)" in the "Yes of course" "table_row"
And I should see "1 (25.00 %)" in the "Not at all" "table_row"
And I select "Group 2" from the "Separate groups" singleselect
And I show chart data for the "multichoice1" feedback
And I should see "0" in the "Yes of course" "table_row"
And I should see "2 (66.67 %)" in the "Not at all" "table_row"
And the "Separate groups" select box should not contain "All participants"
And I log out
# User without group can see all participants only
And I am on the "Course feedback" "feedback activity" page logged in as user7
And I follow "Analysis"
And I should see "Separate groups: All participants"
And I show chart data for the "multichoice1" feedback
And I should see "3 (37.50 %)" in the "Yes of course" "table_row"
And I should see "3 (37.50 %)" in the "Not at all" "table_row"
And I should see "2 (25.00 %)" in the "I don't know" "table_row"
And I log out
# User in non-participation group sees the same as no groups
And I am on the "Course feedback" "feedback activity" page logged in as user8
And I follow "Analysis"
And I should see "Separate groups: All participants"
And I show chart data for the "multichoice1" feedback
And I should see "3 (37.50 %)" in the "Yes of course" "table_row"
And I should see "3 (37.50 %)" in the "Not at all" "table_row"
And I should see "2 (25.00 %)" in the "I don't know" "table_row"
And I log out
# Teacher can browse everybody
And I am on the "Course feedback" "feedback activity" page logged in as teacher
And I navigate to "Analysis" in current page administration
And the field "Separate groups" matches value "All participants"
And I should not see "Group 3" in the "Separate groups" "select"
And I show chart data for the "multichoice1" feedback
And I should see "3 (37.50 %)" in the "Yes of course" "table_row"
And I should see "3 (37.50 %)" in the "Not at all" "table_row"
And I should see "2 (25.00 %)" in the "I don't know" "table_row"
And I select "Group 1" from the "Separate groups" singleselect
And I show chart data for the "multichoice1" feedback
And I should see "2 (50.00 %)" in the "Yes of course" "table_row"
And I should see "1 (25.00 %)" in the "Not at all" "table_row"
And I select "Group 2" from the "Separate groups" singleselect
And I show chart data for the "multichoice1" feedback
And I should see "0" in the "Yes of course" "table_row"
And I should see "2 (66.67 %)" in the "Not at all" "table_row"
And I am on the "Course feedback" "feedback activity" page
And I navigate to "Responses" in current page administration
And the field "Separate groups" matches value "Group 2"
And I should not see "Username 1"
And I should see "Username 3"
And I select "Group 1" from the "Separate groups" singleselect
And I should see "Username 1"
And I should not see "Username 3"
And I select "All participants" from the "Separate groups" singleselect
And I should see "Username 1"
And I should see "Username 3"
@javascript
Scenario: Anonymous feedback with groups in a course - insufficient responses
Given the following "mod_feedback > question" exists:
| activity | feedback2 |
| name | Do you like this course? |
| questiontype | multichoice |
| label | multichoice1 |
| subtype | r |
| hidenoselect | 1 |
| values | Yes of course\nNot at all\nI don't know |
And the following "mod_feedback > responses" exist:
| activity | user | Do you like this course? |
| feedback2 | user1 | Not at all |
When I am on the "Course anon feedback" "feedback activity" page logged in as user1
And I follow "Analysis"
Then I should not see "Yes of course"
And I should see "There are insufficient responses for this group"
@javascript
Scenario: Anonymous feedback with groups in a course
Given the following "mod_feedback > question" exists:
| activity | feedback2 |
| name | Do you like this course? |
| questiontype | multichoice |
| label | multichoice1 |
| subtype | r |
| hidenoselect | 1 |
| values | Yes of course\nNot at all\nI don't know |
And the following "mod_feedback > responses" exist:
| activity | user | Do you like this course? |
| feedback2 | user1 | Not at all |
| feedback2 | user2 | I don't know |
| feedback2 | user3 | Not at all |
| feedback2 | user4 | Yes of course |
| feedback2 | user5 | Yes of course |
| feedback2 | user6 | Not at all |
| feedback2 | user7 | I don't know |
| feedback2 | user8 | Yes of course |
# View analysis, user1 should only see one group - group 1
When I am on the "Course anon feedback" "feedback activity" page logged in as user1
And I follow "Analysis"
And I should see "Separate groups: Group 1"
And I show chart data for the "multichoice1" feedback
And I should see "2 (50.00 %)" in the "Yes of course" "table_row"
And I should see "1 (25.00 %)" in the "Not at all" "table_row"
And I log out
# View analysis, user3 should only see one group - group 2
And I am on the "Course anon feedback" "feedback activity" page logged in as user3
And I follow "Analysis"
And I should see "Separate groups: Group 2"
And I show chart data for the "multichoice1" feedback
And I should see "0" in the "Yes of course" "table_row"
And I should see "2 (66.67 %)" in the "Not at all" "table_row"
And I log out
# View analysis, user2 should see a group selector and be able to change the group but not view all.
And I am on the "Course anon feedback" "feedback activity" page logged in as user2
And I follow "Analysis"
And the field "Separate groups" matches value "Group 1"
And I show chart data for the "multichoice1" feedback
And I should see "2 (50.00 %)" in the "Yes of course" "table_row"
And I should see "1 (25.00 %)" in the "Not at all" "table_row"
And I select "Group 2" from the "Separate groups" singleselect
And I show chart data for the "multichoice1" feedback
And I should see "0" in the "Yes of course" "table_row"
And I should see "2 (66.67 %)" in the "Not at all" "table_row"
And the "Separate groups" select box should not contain "All participants"
And I log out
# User without group can see all participants only
And I am on the "Course anon feedback" "feedback activity" page logged in as user7
And I follow "Analysis"
And I should see "Separate groups: All participants"
And I show chart data for the "multichoice1" feedback
And I should see "3 (37.50 %)" in the "Yes of course" "table_row"
And I should see "3 (37.50 %)" in the "Not at all" "table_row"
And I should see "2 (25.00 %)" in the "I don't know" "table_row"
And I log out
# User in non-participation group is the same as no groups.
And I am on the "Course anon feedback" "feedback activity" page logged in as user8
And I follow "Analysis"
And I should see "Separate groups: All participants"
And I show chart data for the "multichoice1" feedback
And I should see "3 (37.50 %)" in the "Yes of course" "table_row"
And I should see "3 (37.50 %)" in the "Not at all" "table_row"
And I should see "2 (25.00 %)" in the "I don't know" "table_row"
And I log out
# Teacher can browse everybody
And I am on the "Course anon feedback" "feedback activity" page logged in as teacher
And I navigate to "Analysis" in current page administration
And the field "Separate groups" matches value "All participants"
And I show chart data for the "multichoice1" feedback
And I should see "3 (37.50 %)" in the "Yes of course" "table_row"
And I should see "3 (37.50 %)" in the "Not at all" "table_row"
And I should see "2 (25.00 %)" in the "I don't know" "table_row"
And I select "Group 1" from the "Separate groups" singleselect
And I show chart data for the "multichoice1" feedback
And I should see "2 (50.00 %)" in the "Yes of course" "table_row"
And I should see "1 (25.00 %)" in the "Not at all" "table_row"
And I select "Group 2" from the "Separate groups" singleselect
And I show chart data for the "multichoice1" feedback
And I should see "0" in the "Yes of course" "table_row"
And I should see "2 (66.67 %)" in the "Not at all" "table_row"
And I am on the "Course anon feedback" "feedback activity" page
And I navigate to "Responses" in current page administration
# The response numbers were randomly allocated, we only can assert the number of visible responses here:
And the field "Separate groups" matches value "Group 2"
And "//tr[contains(@id,'_r2') and contains(.,'Response number')]" "xpath_element" should exist
And "//tr[contains(@id,'_r3') and contains(@class,'emptyrow')]" "xpath_element" should exist
And I select "Group 1" from the "Separate groups" singleselect
And "//tr[contains(@id,'_r3') and contains(.,'Response number')]" "xpath_element" should exist
And "//tr[contains(@id,'_r4') and contains(@class,'emptyrow')]" "xpath_element" should exist
And I select "All participants" from the "Separate groups" singleselect
And "//tr[contains(@id,'_r7') and contains(.,'Response number')]" "xpath_element" should exist
And "//tr[contains(@id,'_r8') and contains(@class,'emptyrow')]" "xpath_element" should exist
@@ -0,0 +1,422 @@
@mod @mod_feedback
Feature: Testing multichoice questions in feedback
In order to create feedbacks
As a teacher
I need to be able to create different types of multichoice questions
Background:
Given the following "users" exist:
| username | firstname | lastname |
| teacher1 | Teacher | 1 |
| student1 | Student | 1 |
| student2 | Student | 2 |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
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 | course | idnumber |
| feedback | Learning experience | C1 | feedback0 |
And I am on the "Learning experience" "feedback activity" page logged in as teacher1
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
@javascript
Scenario: Non-rated single-answer multiple choice questions in feedback
When I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 1 |
| Label | multichoice1 |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | option a\noption b\noption c |
And I add a "Text and media area" question to the feedback with:
| Contents | this is the first page of the feedback |
And I select "Add a page break" from the "typ" singleselect
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 2 |
| Label | multichoice2 |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | option d\noption e\noption f |
| Required | 1 |
And I add a "Text and media area" question to the feedback with:
| Contents | this is the second page of the feedback |
And I select "Add a page break" from the "typ" singleselect
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 3 |
| Label | multichoice3 |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | option g\noption h\noption i |
| Hide the "Not selected" option | Yes |
| Dependence item | multichoice2 |
| Dependence value | option d |
And I add a "Text and media area" question to the feedback with:
| Contents | this is the third page of the feedback |
And I log out
And I am on the "Learning experience" "feedback activity" page logged in as student1
And I follow "Answer the questions"
# Examine the first page, select nothing, go to the next page
Then the following fields match these values:
| Not selected | 1 |
| option a | 0 |
| option b | 0 |
| option c | 0 |
And "Previous page" "button" should not exist
And "Submit your answers" "button" should not exist
And I should see "this is the first page of the feedback"
And I should not see "this is the second page of the feedback"
And I should not see "this is the third page of the feedback"
And I press "Next page"
# Examine the second page, select nothing, try to go to the next page
And I should see "Not selected"
And the following fields match these values:
| Not selected | 1 |
| option d | 0 |
| option e | 0 |
| option f | 0 |
And "Previous page" "button" should exist
And "Submit your answers" "button" should not exist
And I should not see "this is the first page of the feedback"
And I should see "this is the second page of the feedback"
And I should not see "this is the third page of the feedback"
And I press "Next page"
# We are still on the second page because the field is required
And I should see "Required" in the "form" "css_element"
And I should see "this is the second page of the feedback"
And I set the field "option e" to "1"
And the following fields match these values:
| Not selected | 0 |
| option d | 0 |
| option e | 1 |
| option f | 0 |
And I press "Next page"
# Now we are on the third page, element is not shown because of wrong dependency.
And I should see "this is the third page of the feedback"
And I should not see "this is a multiple choice 3"
# Go back, check that values are preserved and change the option to enable dependency.
And I press "Previous page"
And the following fields match these values:
| Not selected | 0 |
| option d | 0 |
| option e | 1 |
| option f | 0 |
And I set the field "option d" to "1"
And I press "Next page"
# Now third page contains all items.
And I should see "this is a multiple choice 3"
And I should see "this is the third page of the feedback"
And I should not see "Not selected"
And the following fields match these values:
| option g | 0 |
| option h | 0 |
| option i | 0 |
And "Previous page" "button" should exist
And "Next page" "button" should not exist
And "Submit your answers" "button" should exist
And I set the field "option i" to "1"
And I press "Submit your answers"
And I log out
# Student 2 tries to trick - he answers the third question and then
# goes back and changes dependency question. Analysis should not show this answer!
And I am on the "Learning experience" "feedback activity" page logged in as student2
And I follow "Answer the questions"
And I set the field "option a" to "1"
And I press "Next page"
And I set the field "option d" to "1"
And I press "Next page"
And I set the field "option g" to "1"
And I press "Previous page"
And I set the field "option f" to "1"
And I press "Next page"
And I press "Submit your answers"
And I log out
# Login as teacher and check analysis
And I am on the "Learning experience" "feedback activity" page logged in as teacher1
And I navigate to "Analysis" in current page administration
And I should see "Submitted answers: 2"
And I should see "Questions: 3"
And I show chart data for the "multichoice1" feedback
And I should see "1 (50.00 %)" in the "option a" "table_row"
And I should not see "%" in the "option b" "table_row"
And I should not see "%" in the "option c" "table_row"
And I show chart data for the "multichoice2" feedback
And I should see "1 (50.00 %)" in the "option d" "table_row"
And I should not see "%" in the "option e" "table_row"
And I should see "1 (50.00 %)" in the "option f" "table_row"
And I show chart data for the "multichoice3" feedback
And I should not see "%" in the "option g" "table_row"
And I should not see "%" in the "option h" "table_row"
And I should see "1 (100.00 %)" in the "option i" "table_row"
# Change the settings so we don't analyse empty submits
And I am on the "Learning experience" "feedback activity" page
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I open the action menu in "//div[contains(@class, 'feedback_itemlist') and contains(.,'multichoice1')]" "xpath_element"
And I choose "Edit question" in the open action menu
And I set the field "Omit empty submits in analysis" to "Yes"
And I press "Save changes to question"
And I am on the "Learning experience" "feedback activity" page
And I navigate to "Analysis" in current page administration
And I show chart data for the "multichoice1" feedback
And I should see "1 (100.00 %)" in the "option a" "table_row"
And I should not see "%" in the "option b" "table_row"
And I should not see "%" in the "option c" "table_row"
And I log out
@javascript
Scenario: Non-rated multiple-answers multiple choice questions in feedback
# Create a feedback with three pages, required and dependent questions.
When I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 1 |
| Label | multichoice1 |
| Multiple choice type | Multiple choice - multiple answers |
| Multiple choice values | option a\noption b\noption c |
And I add a "Text and media area" question to the feedback with:
| Contents | this is the first page of the feedback |
And I select "Add a page break" from the "typ" singleselect
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 2 |
| Label | multichoice2 |
| Multiple choice type | Multiple choice - multiple answers |
| Multiple choice values | option d\noption e\noption f |
| Required | 1 |
And I add a "Text and media area" question to the feedback with:
| Contents | this is the second page of the feedback |
And I select "Add a page break" from the "typ" singleselect
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 3 |
| Label | multichoice3 |
| Multiple choice type | Multiple choice - multiple answers |
| Multiple choice values | option g\noption h\noption i |
| Dependence item | multichoice2 |
| Dependence value | option d |
And I add a "Text and media area" question to the feedback with:
| Contents | this is the third page of the feedback |
And I log out
# Login as the first student.
And I am on the "Learning experience" "feedback activity" page logged in as student1
And I follow "Answer the questions"
# Examine the first page, select nothing, go to the next page
And I should not see "Not selected"
And the following fields match these values:
| option a | 0 |
| option b | 0 |
| option c | 0 |
And "Previous page" "button" should not exist
And "Submit your answers" "button" should not exist
And I should see "this is the first page of the feedback"
And I should not see "this is the second page of the feedback"
And I should not see "this is the third page of the feedback"
And I press "Next page"
# Examine the second page, select nothing, try to go to the next page
Then I should not see "Not selected"
And the following fields match these values:
| option d | 0 |
| option e | 0 |
| option f | 0 |
And "Previous page" "button" should exist
And "Submit your answers" "button" should not exist
And I should not see "this is the first page of the feedback"
And I should see "this is the second page of the feedback"
And I should not see "this is the third page of the feedback"
And I press "Next page"
# We are still on the second page because the field is required
And I should see "Required" in the "form" "css_element"
And I should see "this is the second page of the feedback"
And I set the field "option e" to "1"
And I set the field "option f" to "1"
And the following fields match these values:
| option d | 0 |
| option e | 1 |
| option f | 1 |
And I press "Next page"
# Now we are on the third page, element is not shown because of wrong dependency.
And I should see "this is the third page of the feedback"
And I should not see "this is a multiple choice 3"
# Go back, check that values are preserved and change the option to enable dependency.
And I press "Previous page"
And the following fields match these values:
| option d | 0 |
| option e | 1 |
| option f | 1 |
And I set the field "option d" to "1"
And I set the field "option e" to "0"
And I press "Next page"
# Now third page contains all items.
And I should see "this is a multiple choice 3"
And I should see "this is the third page of the feedback"
And the following fields match these values:
| option g | 0 |
| option h | 0 |
| option i | 0 |
And "Previous page" "button" should exist
And "Next page" "button" should not exist
And "Submit your answers" "button" should exist
And I set the field "option i" to "1"
And I press "Submit your answers"
And I log out
# Student 2 tries to trick - he answers the third question and then
# goes back and changes dependency question. Analysis should not show this answer!
And I am on the "Learning experience" "feedback activity" page logged in as student2
And I follow "Answer the questions"
And I set the field "option a" to "1"
And I set the field "option b" to "1"
And I press "Next page"
And I set the field "option d" to "1"
And I press "Next page"
And I set the field "option g" to "1"
And I press "Previous page"
And I set the field "option d" to "0"
And I set the field "option f" to "1"
And I press "Next page"
And I press "Submit your answers"
And I log out
# Login as teacher and check analysis
And I am on the "Learning experience" "feedback activity" page logged in as teacher1
And I navigate to "Analysis" in current page administration
And I should see "Submitted answers: 2"
And I should see "Questions: 3"
And I show chart data for the "multichoice1" feedback
And I should see "1 (50.00 %)" in the "option a" "table_row"
And I should see "1 (50.00 %)" in the "option b" "table_row"
And I should not see "%" in the "option c" "table_row"
And I show chart data for the "multichoice2" feedback
And I should see "1 (50.00 %)" in the "option d" "table_row"
And I should not see "%" in the "option e" "table_row"
And I should see "2 (100.00 %)" in the "option f" "table_row"
And I show chart data for the "multichoice3" feedback
And I should not see "%" in the "option g" "table_row"
And I should not see "%" in the "option h" "table_row"
And I should see "1 (100.00 %)" in the "option i" "table_row"
# Change the settings so we don't analyse empty submits
And I am on the "Learning experience" "feedback activity" page
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I open the action menu in "//div[contains(@class, 'feedback_itemlist') and contains(.,'multichoice1')]" "xpath_element"
And I choose "Edit question" in the open action menu
And I set the field "Omit empty submits in analysis" to "Yes"
And I press "Save changes to question"
And I am on the "Learning experience" "feedback activity" page
And I navigate to "Analysis" in current page administration
And I show chart data for the "multichoice1" feedback
And I should see "1 (100.00 %)" in the "option a" "table_row"
And I should see "1 (100.00 %)" in the "option b" "table_row"
And I should not see "%" in the "option c" "table_row"
And I log out
@javascript
Scenario: Non-rated single-answer dropdown multiple choice questions in feedback
When I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 1 |
| Label | multichoice1 |
| Multiple choice type | Multiple choice - single answer allowed (drop-down menu) |
| Multiple choice values | option a\noption b\noption c |
And I add a "Text and media area" question to the feedback with:
| Contents | this is the first page of the feedback |
And I select "Add a page break" from the "typ" singleselect
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 2 |
| Label | multichoice2 |
| Multiple choice type | Multiple choice - single answer allowed (drop-down menu) |
| Multiple choice values | option d\noption e\noption f |
| Required | 1 |
And I add a "Text and media area" question to the feedback with:
| Contents | this is the second page of the feedback |
And I select "Add a page break" from the "typ" singleselect
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 3 |
| Label | multichoice3 |
| Multiple choice type | Multiple choice - single answer allowed (drop-down menu) |
| Multiple choice values | option g\noption h\noption i |
| Dependence item | multichoice2 |
| Dependence value | option d |
And I add a "Text and media area" question to the feedback with:
| Contents | this is the third page of the feedback |
And I log out
And I am on the "Learning experience" "feedback activity" page logged in as student1
And I follow "Answer the questions"
# Examine the first page, select nothing, go to the next page
Then the following fields match these values:
| this is a multiple choice 1 | 0 |
And "Previous page" "button" should not exist
And "Submit your answers" "button" should not exist
And I should see "this is the first page of the feedback"
And I should not see "this is the second page of the feedback"
And I should not see "this is the third page of the feedback"
And I press "Next page"
# Examine the second page, select nothing, try to go to the next page
And the following fields match these values:
| this is a multiple choice 2 | 0 |
And "Previous page" "button" should exist
And "Submit your answers" "button" should not exist
And I should not see "this is the first page of the feedback"
And I should see "this is the second page of the feedback"
And I should not see "this is the third page of the feedback"
And I press "Next page"
# We are still on the second page because the field is required
And I should see "Required" in the "form" "css_element"
And I should see "this is the second page of the feedback"
And I set the field "this is a multiple choice 2" to "option e"
And I press "Next page"
# Now we are on the third page, element is not shown because of wrong dependency.
And I should see "this is the third page of the feedback"
And I should not see "this is a multiple choice 3"
# Go back, check that values are preserved and change the option to enable dependency.
And I press "Previous page"
And the following fields match these values:
| this is a multiple choice 2 | option e |
And I set the field "this is a multiple choice 2" to "option d"
And I press "Next page"
# Now third page contains all items.
And I should see "this is the third page of the feedback"
And the following fields match these values:
| this is a multiple choice 3 | 0 |
And "Previous page" "button" should exist
And "Next page" "button" should not exist
And "Submit your answers" "button" should exist
And I set the field "this is a multiple choice 3" to "option i"
And I press "Submit your answers"
And I log out
# Student 2 tries to trick - he answers the third question and then
# goes back and changes dependency question. Analysis should not show this answer!
And I am on the "Learning experience" "feedback activity" page logged in as student2
And I follow "Answer the questions"
And I set the field "this is a multiple choice 1" to "option a"
And I press "Next page"
And I set the field "this is a multiple choice 2" to "option d"
And I press "Next page"
And I set the field "this is a multiple choice 3" to "option g"
And I press "Previous page"
And I set the field "this is a multiple choice 2" to "option f"
And I press "Next page"
And I press "Submit your answers"
And I log out
# Login as teacher and check analysis
And I am on the "Learning experience" "feedback activity" page logged in as teacher1
And I navigate to "Analysis" in current page administration
And I should see "Submitted answers: 2"
And I should see "Questions: 3"
And I show chart data for the "multichoice1" feedback
And I should see "1 (50.00 %)" in the "option a" "table_row"
And I should not see "%" in the "option b" "table_row"
And I should not see "%" in the "option c" "table_row"
And I show chart data for the "multichoice2" feedback
And I should see "1 (50.00 %)" in the "option d" "table_row"
And I should not see "%" in the "option e" "table_row"
And I should see "1 (50.00 %)" in the "option f" "table_row"
And I show chart data for the "multichoice3" feedback
And I should not see "%" in the "option g" "table_row"
And I should not see "%" in the "option h" "table_row"
And I should see "1 (100.00 %)" in the "option i" "table_row"
# Change the settings so we don't analyse empty submits
And I am on the "Learning experience" "feedback activity" page
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I open the action menu in "//div[contains(@class, 'feedback_itemlist') and contains(.,'multichoice1')]" "xpath_element"
And I choose "Edit question" in the open action menu
And I set the field "Omit empty submits in analysis" to "Yes"
And I press "Save changes to question"
And I am on the "Learning experience" "feedback activity" page
And I navigate to "Analysis" in current page administration
And I show chart data for the "multichoice1" feedback
And I should see "1 (100.00 %)" in the "option a" "table_row"
And I should not see "%" in the "option b" "table_row"
And I should not see "%" in the "option c" "table_row"
@@ -0,0 +1,61 @@
@mod @mod_feedback
Feature: Non anonymous feedback with multiple submissions
In order to modify feedback response
As a student
I need to be able to see previous response when I re-submit feedback
Background:
Given the following "users" exist:
| username | firstname | lastname |
| user1 | Username | 1 |
| user2 | Username | 2 |
| teacher | Teacher | 3 |
| manager | Manager | 4 |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| user1 | C1 | student |
| user2 | C1 | student |
| teacher | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber | anonymous | publish_stats | multiple_submit | section |
| feedback | Course feedback | C1 | feedback1 | 2 | 1 | 1 | 0 |
Scenario: Completing a feedback second time
When I log in as "teacher"
And I am on "Course 1" course homepage
And I follow "Course feedback"
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Short text answer" question to the feedback with:
| Question | first |
| Label | shorttext1 |
| Maximum characters accepted | 200 |
And I add a page break to the feedback
And I add a "Short text answer" question to the feedback with:
| Question | second |
| Label | shorttext2 |
| Maximum characters accepted | 200 |
And I log out
And I log in as "user1"
And I am on "Course 1" course homepage
And I follow "Course feedback"
And I follow "Answer the questions"
And I set the following fields to these values:
| first | 111 |
And I press "Next"
And I set the following fields to these values:
| second | 222 |
And I press "Submit your answers"
And I log out
And I log in as "user1"
And I am on "Course 1" course homepage
And I follow "Course feedback"
And I follow "Answer the questions"
Then the field "first" matches value "111"
And I press "Next"
And the field "second" matches value "222"
And I set the following fields to these values:
| second | 333 |
And I press "Submit your answers"
@@ -0,0 +1,152 @@
@mod @mod_feedback
Feature: Non anonymous feedback
In order to collect feedbacks
As an teacher
I need to be able to create and collect feedbacks
Background:
Given the following "users" exist:
| username | firstname | lastname |
| user1 | Username | 1 |
| user2 | Username | 2 |
| teacher | Teacher | 3 |
| manager | Manager | 4 |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| user1 | C1 | student |
| user2 | C1 | student |
| teacher | C1 | editingteacher |
And the following "system role assigns" exist:
| user | course | role |
| manager | Acceptance test site | manager |
And the following "activities" exist:
| activity | name | course | idnumber | anonymous | publish_stats | section |
| feedback | Site feedback | Acceptance test site | feedback0 | 2 | 1 | 1 |
| feedback | Course feedback | C1 | feedback1 | 2 | 1 | 0 |
When I am on the "Site feedback" "feedback activity" page logged in as manager
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Multiple choice" question to the feedback with:
| Question | Do you like our site? |
| Label | multichoice2 |
| Multiple choice type | Multiple choice - single answer |
| Hide the "Not selected" option | Yes |
| Multiple choice values | Yes of course\nNot at all\nI don't know |
And I log out
Scenario: Guests can see non anonymous feedback on front page but can not complete
When I am on the "Site feedback" "feedback activity" page
Then I should not see "Answer the questions"
And I should not see "Preview questions"
Scenario: Complete non anonymous feedback on the front page as an authenticated user
When I am on the "Site feedback" "feedback activity" page logged in as user1
And I should not see "Preview questions"
And I follow "Answer the questions"
And I should see "Do you like our site?"
And I set the following fields to these values:
| Yes of course | 1 |
And I press "Submit your answers"
And I should not see "Analysis"
And I press "Continue"
@javascript
Scenario: Complete non anonymous feedback and view analysis on the front page as an authenticated user
Given the following "role capability" exists:
| role | frontpage |
| mod/feedback:viewanalysepage | allow |
When I am on the "Site feedback" "feedback activity" page logged in as user1
And I follow "Answer the questions"
And I should see "Do you like our site?"
And I set the following fields to these values:
| Yes of course | 1 |
And I press "Submit your answers"
And I log out
And I am on the "Site feedback" "feedback activity" page logged in as user2
And I follow "Answer the questions"
And I set the following fields to these values:
| Not at all | 1 |
And I press "Submit your answers"
And I follow "Analysis"
And I should see "Submitted answers: 2"
And I should see "Questions: 1"
# And I should not see "multichoice2" # TODO MDL-29303 do not show labels to users who can not edit feedback
And I show chart data for the "multichoice2" feedback
And I should see "Do you like our site?"
And I should see "1 (50.00 %)" in the "Yes of course" "table_row"
And I should see "1 (50.00 %)" in the "Not at all" "table_row"
And I log out
And I am on the "Site feedback" "feedback activity" page logged in as manager
And I navigate to "Responses" in current page administration
And I should see "Username"
And I should see "Non anonymous entries (2)"
And I should not see "Anonymous entries"
And I click on "," "link" in the "Username 1" "table_row"
And I should see "(Username 1)"
And I should see "Yes of course"
And I log out
@javascript
Scenario: Non anonymous feedback in a course
When I am on the "Course feedback" "feedback activity" page logged in as teacher
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Multiple choice" question to the feedback with:
| Question | Do you like this course? |
| Label | multichoice1 |
| Multiple choice type | Multiple choice - single answer |
| Hide the "Not selected" option | Yes |
| Multiple choice values | Yes of course\nNot at all\nI don't know |
And I log out
When I am on the "Course feedback" "feedback activity" page logged in as user1
And I follow "Answer the questions"
And I should see "Do you like this course?"
And I set the following fields to these values:
| Yes of course | 1 |
And I press "Submit your answers"
And I log out
When I am on the "Course feedback" "feedback activity" page logged in as user2
And I follow "Answer the questions"
And I should see "Do you like this course?"
And I set the following fields to these values:
| Not at all | 1 |
And I press "Submit your answers"
And I follow "Analysis"
And I should see "Submitted answers: 2"
And I should see "Questions: 1"
# And I should not see "multichoice2" # TODO MDL-29303
And I show chart data for the "multichoice1" feedback
And I should see "Do you like this course?"
And I should see "1 (50.00 %)" in the "Yes of course" "table_row"
And I should see "1 (50.00 %)" in the "Not at all" "table_row"
And I log out
When I am on the "Course feedback" "feedback activity" page logged in as teacher
And I follow "Preview"
And I should see "Do you like this course?"
And I press "Continue"
And I should not see "Answer the questions"
And I navigate to "Responses" in current page administration
And I should see "Non anonymous entries (2)"
And I should not see "Anonymous"
And I click on "," "link" in the "Username 1" "table_row"
And I should see "(Username 1)"
And I should see "Yes of course"
And I should not see "Prev"
And I follow "Next"
And I should see "(Username 2)"
And I should not see "Next"
And I should see "Prev"
And I click on "Back" "link" in the "region-main" "region"
# Sort the feedback responses.
And I click on "Do you like this course?" "link" in the "generaltable" "table"
And "Username 1" "table_row" should appear before "Username 2" "table_row"
# Now sort descending.
And I click on "Do you like this course?" "link" in the "generaltable" "table"
And "Username 2" "table_row" should appear before "Username 1" "table_row"
# Delete non anonymous response
And I click on "Delete entry" "link" in the "Username 1" "table_row"
And I press "Yes"
And I should see "Non anonymous entries (1)"
And I should not see "Username 1"
And I should see "Username 2"
@@ -0,0 +1,47 @@
@mod @mod_feedback
Feature: Preview feedback questions
In order to view the feedback questions
As a teacher
I need to be able to preview them
Background:
Given the following "users" exist:
| username | firstname | lastname |
| student | Student | User |
| editingteacher | Editing | Teacher |
| teacher | NonEditing | Teacher |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| student | C1 | student |
| editingteacher | C1 | editingteacher |
| teacher | C1 | teacher |
And the following "activities" exist:
| activity | name | course | idnumber |
| feedback | Music history | C1 | feedback0 |
And I am on the "Music history" "feedback activity" page logged in as editingteacher
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Multiple choice" question to the feedback with:
| Question | What is your favourite instrument |
| Label | instrument1 |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | drums\guitar\hurdygurdy |
And I log out
Scenario: Students cannot see the Preview questions button
When I am on the "Music history" "feedback activity" page logged in as student
Then I should not see "Preview questions"
Scenario: Non-editing teachers can see the Preview questions button
When I am on the "Music history" "feedback activity" page logged in as teacher
Then I should see "Preview questions"
And I follow "Preview questions"
And I should see "What is your favourite instrument"
Scenario: Editing teachers can see the Preview questions button
When I am on the "Music history" "feedback activity" page logged in as editingteacher
Then I should see "Preview questions"
And I follow "Preview questions"
And I should see "What is your favourite instrument"
@@ -0,0 +1,124 @@
@mod @mod_feedback
Feature: Test creating different types of feedback questions for anonymous feedback
In order to create feedbacks
As a teacher
I need to be able to add different question types
@javascript
Scenario: Create different types of questions in anonymous feedback with javascript enabled
Given the following "users" exist:
| username | firstname | lastname |
| teacher1 | Teacher | 1 |
| student1 | Student | 1 |
| student2 | Student | 2 |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
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 | course | idnumber |
| feedback | Learning experience | C1 | feedback0 |
When I am on the "Learning experience" "feedback activity" page logged in as teacher1
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Information" question to the feedback with:
| Question | this is an information question |
| Label | info |
| Information type | Course |
And I add a "Text and media area" question to the feedback with:
| Contents | label text |
And I add a "Longer text answer" question to the feedback with:
| Question | this is a longer text answer |
| Label | longertext |
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 1 |
| Label | multichoice1 |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | option a\noption b\noption c |
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 2 |
| Label | multichoice2 |
| Multiple choice type | Multiple choice - multiple answers |
| Multiple choice values | option d\noption e\noption f |
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 3 |
| Label | multichoice3 |
| Multiple choice type | Multiple choice - single answer allowed (drop-down menu) |
| Multiple choice values | option g\noption h\noption i |
And I add a "Multiple choice (rated)" question to the feedback with:
| Question | this is a multiple choice rated |
| Label | multichoice4 |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | 0/option k\n1/option l\n5/option m |
And I add a "Numeric answer" question to the feedback with:
| Question | this is a numeric answer |
| Label | numeric |
| Range from | 0 |
| Range to | 100 |
And I add a "Short text answer" question to the feedback with:
| Question | this is a short text answer |
| Label | shorttext |
| Maximum characters accepted | 200 |
And I log out
And I am on the "Learning experience" "feedback activity" page logged in as student1
And I follow "Answer the questions"
And I set the following fields to these values:
| this is a longer text answer | my long answer |
| option b | 1 |
| option d | 1 |
| option f | 1 |
| this is a multiple choice 3 | option h |
| option l | 1 |
| this is a numeric answer (0 - 100) | 35 |
| this is a short text answer | hello |
And I press "Submit your answers"
And I log out
And I am on the "Learning experience" "feedback activity" page logged in as student2
And I follow "Answer the questions"
And I set the following fields to these values:
| this is a longer text answer | lots of feedbacks |
| option a | 1 |
| option d | 1 |
| option e | 1 |
| this is a multiple choice 3 | option i |
| option m | 1 |
| this is a numeric answer (0 - 100) | 71 |
| this is a short text answer | no way |
And I press "Submit your answers"
And I log out
When I am on the "Learning experience" "feedback activity" page logged in as teacher1
And I navigate to "Analysis" in current page administration
And I should see "Submitted answers: 2"
And I should see "Questions: 8"
And I am on the "Learning experience" "feedback activity" page
And I navigate to "Analysis" in current page administration
And I should see "C1" in the "(info)" "table"
And I should see "my long answer" in the "(longertext)" "table"
And I should see "lots of feedbacks" in the "(longertext)" "table"
And I show chart data for the "multichoice2" feedback
And I should see "2 (100.00 %)" in the "option d" "table_row"
And I should see "1 (50.00 %)" in the "option e" "table_row"
And I should see "1 (50.00 %)" in the "option f" "table_row"
And I show chart data for the "multichoice3" feedback
And I should see "0" in the "option g" "table_row"
And I should not see "%" in the "option g" "table_row"
And I should see "1 (50.00 %)" in the "option h" "table_row"
And I should see "1 (50.00 %)" in the "option i" "table_row"
And I show chart data for the "multichoice4" feedback
And I should see "0" in the "option k" "table_row"
And I should not see "%" in the "(0) option k" "table_row"
And I should see "1 (50.00 %)" in the "(1) option l" "table_row"
And I should see "1 (50.00 %)" in the "(5) option m" "table_row"
And I should see "Average: 3.00"
And I should see "35" in the "(numeric)" "table"
And I should see "71" in the "(numeric)" "table"
And I should see "Average: 53.00" in the "(numeric)" "table"
And I should see "no way" in the "(shorttext)" "table"
And I should see "hello" in the "(shorttext)" "table"
And I show chart data for the "multichoice1" feedback
And I should see "1 (50.00 %)" in the "option a" "table_row"
And I should see "1 (50.00 %)" in the "option b" "table_row"
And I log out
@@ -0,0 +1,129 @@
@mod @mod_feedback
Feature: Test creating different types of feedback questions for non-anonymous feedback
In order to create feedbacks
As a teacher
I need to be able to add different question types
@javascript
Scenario: Create different types of questions in non-anonymous feedback with javascript enabled
Given the following "users" exist:
| username | firstname | lastname |
| teacher1 | Teacher | 1 |
| student1 | Student | 1 |
| student2 | Student | 2 |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
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 | course | idnumber | anonymous |
| feedback | Learning experience | C1 | feedback0 | 2 |
When I am on the "Learning experience" "feedback activity" page logged in as teacher1
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Information" question to the feedback with:
| Question | this is an information question |
| Label | info |
| Information type | Course |
And I add a "Information" question to the feedback with:
| Question | this is a response time question |
| Label | curtime |
| Information type | Responses time |
And I add a "Text and media area" question to the feedback with:
| Contents | label text |
And I add a "Longer text answer" question to the feedback with:
| Question | this is a longer text answer |
| Label | longertext |
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 1 |
| Label | multichoice1 |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | option a\noption b\noption c |
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 2 |
| Label | multichoice2 |
| Multiple choice type | Multiple choice - multiple answers |
| Multiple choice values | option d\noption e\noption f |
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 3 |
| Label | multichoice3 |
| Multiple choice type | Multiple choice - single answer allowed (drop-down menu) |
| Multiple choice values | option g\noption h\noption i |
And I add a "Multiple choice (rated)" question to the feedback with:
| Question | this is a multiple choice rated |
| Label | multichoice4 |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | 0/option k\n1/option l\n5/option m |
And I add a "Numeric answer" question to the feedback with:
| Question | this is a numeric answer |
| Label | numeric |
| Range from | 0 |
| Range to | 100 |
And I add a "Short text answer" question to the feedback with:
| Question | this is a short text answer |
| Label | shorttext |
| Maximum characters accepted | 200 |
And I log out
When I am on the "Learning experience" "feedback activity" page logged in as student1
And I follow "Answer the questions"
And I set the following fields to these values:
| this is a longer text answer | my long answer |
| option b | 1 |
| option d | 1 |
| option f | 1 |
| this is a multiple choice 3 | option h |
| option l | 1 |
| this is a numeric answer (0 - 100) | 35 |
| this is a short text answer | hello |
And I press "Submit your answers"
And I log out
When I am on the "Learning experience" "feedback activity" page logged in as student2
And I follow "Answer the questions"
And I set the following fields to these values:
| this is a longer text answer | lots of feedbacks |
| option a | 1 |
| option d | 1 |
| option e | 1 |
| this is a multiple choice 3 | option i |
| option m | 1 |
| this is a numeric answer (0 - 100) | 71 |
| this is a short text answer | no way |
And I press "Submit your answers"
And I log out
When I am on the "Learning experience" "feedback activity" page logged in as teacher1
And I navigate to "Analysis" in current page administration
And I should see "Submitted answers: 2"
And I should see "Questions: 9"
And I log out
And I am on the "Learning experience" "feedback activity" page logged in as teacher1
And I navigate to "Analysis" in current page administration
And I should see "C1" in the "(info)" "table"
And I should see "my long answer" in the "(longertext)" "table"
And I should see "lots of feedbacks" in the "(longertext)" "table"
And I show chart data for the "multichoice2" feedback
And I should see "2 (100.00 %)" in the "option d" "table_row"
And I should see "1 (50.00 %)" in the "option e" "table_row"
And I should see "1 (50.00 %)" in the "option f" "table_row"
And I show chart data for the "multichoice3" feedback
And I should see "0" in the "option g" "table_row"
And I should not see "%" in the "option g" "table_row"
And I should see "1 (50.00 %)" in the "option h" "table_row"
And I should see "1 (50.00 %)" in the "option i" "table_row"
And I show chart data for the "multichoice4" feedback
And I should see "0" in the "(0) option k" "table_row"
And I should not see "%" in the "(0) option k" "table_row"
And I should see "1 (50.00 %)" in the "(1) option l" "table_row"
And I should see "1 (50.00 %)" in the "(5) option m" "table_row"
And I should see "Average: 3.00"
And I should see "35" in the "(numeric)" "table"
And I should see "71" in the "(numeric)" "table"
And I should see "Average: 53.00" in the "(numeric)" "table"
And I should see "no way" in the "(shorttext)" "table"
And I should see "hello" in the "(shorttext)" "table"
And I show chart data for the "multichoice1" feedback
And I should see "1 (50.00 %)" in the "option a" "table_row"
And I should see "1 (50.00 %)" in the "option b" "table_row"
And I log out
@@ -0,0 +1,65 @@
@mod @mod_feedback
Feature: Show users who have not responded to the feedback survey
In order to harass students about completing the feedback
As a teacher
I need to see which students haven't responded
Background:
Given the following "users" exist:
| username | firstname | lastname |
| teacher1 | Teacher | 1 |
| student1 | Student | 1 |
| student2 | Student | 2 |
| student3 | Student | 3 |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
And the following "groups" exist:
| course | name | idnumber |
| C1 | G1 | GI1 |
And the following "group members" exist:
| user | group |
| student1 | GI1 |
| student2 | GI1 |
And the following "groupings" exist:
| name | course | idnumber |
| GX1 | C1 | GXI1 |
And the following "grouping groups" exist:
| grouping | group |
| GXI1 | GI1 |
Scenario: See users who have not responded
# Set up a feedback.
When I log in as "teacher1"
And I add a feedback activity to course "Course 1" section "1" and I fill the form with:
| Name | Frogs |
| Description | x |
| Record user names | User's name will be logged and shown with answers |
| Access restrictions | Grouping: GX1 |
And I am on the Frogs "feedback activity" page
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Short text answer" question to the feedback with:
| Question | Y/N? |
And I log out
# Go in as student 1 and do the feedback.
And I am on the Frogs "feedback activity" page logged in as student1
And I follow "Answer the questions"
And I set the field "Y/N?" to "Y"
And I press "Submit your answers"
And I log out
# Go in as teacher and check the users who haven't completed it.
And I am on the Frogs "feedback activity" page logged in as teacher1
And I navigate to "Responses" in current page administration
And I select "Show non-respondents" from the "jump" singleselect
# Should only show student 2; not student 1 (they did it) or 3 (not in grouping).
Then I should see "Student 2"
And I should not see "Student 1"
And I should not see "Student 3"
+189
View File
@@ -0,0 +1,189 @@
@mod @mod_feedback
Feature: Saving, using and deleting feedback templates
In order to quickly create feedbacks
As a manager
I need to be able to create feedback templates
Background:
Given the following "users" exist:
| username | firstname | lastname |
| teacher | Teacher | 1 |
| manager | Manager | 1 |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
| Course 2 | C2 |
And the following "course enrolments" exist:
| user | course | role |
| teacher | C1 | editingteacher |
| teacher | C2 | editingteacher |
And the following "system role assigns" exist:
| user | course | role |
| manager | Acceptance test site | manager |
And the following "activities" exist:
| activity | name | course | idnumber |
| feedback | Learning experience course 1 | C1 | feedback1 |
| feedback | Another feedback in course 1 | C1 | feedback2 |
| feedback | Learning experience course 2 | C2 | feedback3 |
And I am on the "Learning experience course 1" "feedback activity" page logged in as teacher
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Multiple choice" question to the feedback with:
| Question | this is a multiple choice 1 |
| Label | multichoice1 |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | option a\noption b\noption c |
And I log out
@javascript
Scenario: Teacher can save template and re-use it in the same course only
# Go to feedback templates and make sure none exist yet
When I am on the "Learning experience course 1" "feedback activity" page logged in as teacher
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I select "Use a template" from the "jump" singleselect
Then I should see "No templates available yet"
And "Use a template" "field" should not exist
And "Public" "field" should not exist
And I select "Add question" from the "jump" singleselect
# Save as a course template
And I press "Save as new template"
And I should see "Save as new template" in the ".modal-title" "css_element"
And I should see "Name" in the ".modal-body" "css_element"
And I set the field "Name" to "My first template"
And I click on "Save" "button" in the ".modal-dialog" "css_element"
And I should see "Template saved"
And I select "Use a template" from the "jump" singleselect
And I should see "My first template"
# Create a feedback from this template in the same course
And I am on the "Another feedback in course 1" "feedback activity" page
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I select "Use a template" from the "jump" singleselect
And I follow "My first template"
And I should see "this is a multiple choice 1"
And I press "Use this template"
And I click on "Save" "button" in the ".modal-dialog" "css_element"
And I should see "this is a multiple choice 1"
# Make sure this template is not available in another course
And I am on the "Learning experience course 2" "feedback activity" page
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I select "Use a template" from the "jump" singleselect
And I should see "No templates available yet"
And I log out
@javascript
Scenario: Teacher can append template to existing questions or remove them
# Save feedback as a course template
When I am on the "Learning experience course 1" "feedback activity" page logged in as teacher
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I press "Save as new template"
And I should see "Save as new template" in the ".modal-title" "css_element"
And I should see "Name" in the ".modal-body" "css_element"
And I set the field "Name" to "My first template"
And I click on "Save" "button" in the ".modal-dialog" "css_element"
And I press "Save as new template"
# Add questions to another feedback
And I am on the "Another feedback in course 1" "feedback activity" page
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I add a "Multiple choice" question to the feedback with:
| Question | What is your favourite subject |
| Label | subjectchoice |
| Multiple choice type | Multiple choice - single answer |
| Multiple choice values | Maths\bScience\nEnglish\nOther |
# Import template appending items
And I select "Use a template" from the "jump" singleselect
And I follow "My first template"
And I press "Use this template"
And I set the field "Append new items" to "1"
And I click on "Save" "button" in the ".modal-dialog" "css_element"
Then "What is your favourite subject" "text" should appear before "this is a multiple choice 1" "text"
# Import template replacing items
And I select "Use a template" from the "jump" singleselect
And I follow "My first template"
And I press "Use this template"
And I set the field "Delete old items" to "1"
And I click on "Save" "button" in the ".modal-dialog" "css_element"
And I should see "this is a multiple choice 1"
And I should not see "What is your favourite subject"
And I should see "this is a multiple choice 1"
@javascript
Scenario: Manager can save template as public and it will be available in any course
When I am on the "Learning experience course 1" "feedback activity" page logged in as manager
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I press "Save as new template"
And I set the field "Name" to "My first template"
And I set the field "Public" to "1"
And I click on "Save" "button" in the ".modal-dialog" "css_element"
And I log out
And I am on the "Learning experience course 2" "feedback activity" page logged in as teacher
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I select "Use a template" from the "jump" singleselect
And I follow "My first template"
And I should see "this is a multiple choice 1"
And I press "Use this template"
And I set the field "Delete old items" to "1"
And I click on "Save" "button" in the ".modal-dialog" "css_element"
Then I should see "this is a multiple choice 1"
And I log out
@javascript
Scenario: Teacher can delete course templates but can not delete public templates
# Save feedback as both public and course template
When I am on the "Learning experience course 1" "feedback activity" page logged in as manager
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I press "Save as new template"
And I set the field "Name" to "My public template"
And I set the field "Public" to "1"
And I click on "Save" "button" in the ".modal-dialog" "css_element"
And I press "Save as new template"
And I set the field "Name" to "My course template"
And I click on "Save" "button" in the ".modal-dialog" "css_element"
And I log out
# Login as teacher and try to delete templates
And I am on the "Another feedback in course 1" "feedback activity" page logged in as teacher
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I select "Use a template" from the "jump" singleselect
And I follow "My public template"
Then I should not see "Delete"
And I click on "Back" "link" in the ".tertiary-navigation" "css_element"
And "My course template" "text" should exist in the ".coursetemplates" "css_element"
And I follow "My course template"
And I click on "Delete" "link"
And I click on "Yes" "button"
And I should see "Template deleted"
And "My course template" "text" should not exist in the ".coursetemplates" "css_element"
And "No templates available yet" "text" should exist in the ".coursetemplates" "css_element"
And I log out
@javascript
Scenario: Manager can delete both course and public templates
# Save feedback as both public and course template
When I am on the "Learning experience course 1" "feedback activity" page logged in as manager
And I click on "Edit questions" "link" in the "[role=main]" "css_element"
And I press "Save as new template"
And I set the field "Name" to "My public template"
And I set the field "Public" to "1"
And I click on "Save" "button" in the ".modal-dialog" "css_element"
And I press "Save as new template"
And I set the field "Name" to "My course template"
And I click on "Save" "button" in the ".modal-dialog" "css_element"
# Delete course template
And I select "Use a template" from the "jump" singleselect
Then "My public template" "text" should exist in the ".publictemplates" "css_element"
And "My course template" "text" should exist in the ".coursetemplates" "css_element"
And I follow "My course template"
And I click on "Delete" "link"
And I should see "Are you sure you want to delete this template?"
And I press "Yes"
And I should see "Template deleted"
And "My course template" "text" should not exist in the ".coursetemplates" "css_element"
And "No templates available yet" "text" should exist in the ".coursetemplates" "css_element"
And "My public template" "text" should exist in the ".publictemplates" "css_element"
And I follow "My public template"
And I click on "Delete" "link"
And I should see "Are you sure you want to delete this template?"
And I press "Yes"
And I should see "Template deleted"
And "My public template" "text" should not exist in the ".publictemplates" "css_element"
And "No templates available yet" "text" should exist in the ".publictemplates" "css_element"
And I should see "No templates available yet"
And I log out
+124
View File
@@ -0,0 +1,124 @@
<?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_feedback;
use mod_feedback_completion;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/feedback/classes/completion.php');
/**
* Unit tests for (some of) mod/feedback/classes/completion.php.
*
* @package mod_feedback
* @copyright 2019 Tobias Reischmann
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class completion_test extends \advanced_testcase {
/**
* Returns the number of pages with visible elements for the current state of the feedback completion.
* @param mod_feedback_completion $completion
* @return int number of pages with at least one visible item.
*/
private function get_number_of_visible_pages(mod_feedback_completion $completion) {
$pages = $completion->get_pages();
$result = 0;
foreach ($pages as $items) {
if (count($items) > 0) {
$result++;
}
}
return $result;
}
/**
* Tests get_pages for transitive dependencies.
* @throws coding_exception
*/
public function test_get_pages(): void {
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback',
array('course' => $course->id));
$cm = get_coursemodule_from_instance('feedback', $feedback->id);
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
$itemscreated = [];
// Create at least one page.
$itemscreated[] = $feedbackgenerator->create_item_multichoice($feedback,
$record = ['values' => "y\nn"]);
$itemscreated[] = $feedbackgenerator->create_item_pagebreak($feedback);
$itemscreated[] = $feedbackgenerator->create_item_multichoice($feedback,
$record = ['values' => "y\nn", 'dependitem' => $itemscreated[0]->id, 'dependvalue' => 'n']);
$itemscreated[] = $feedbackgenerator->create_item_pagebreak($feedback);
$itemscreated[] = $feedbackgenerator->create_item_multichoice($feedback,
$record = ['values' => "y\nn", 'dependitem' => $itemscreated[0]->id, 'dependvalue' => 'y']);
$itemscreated[] = $feedbackgenerator->create_item_pagebreak($feedback);
$itemscreated[] = $feedbackgenerator->create_item_multichoice($feedback,
$record = ['values' => "y\nn", 'dependitem' => $itemscreated[2]->id, 'dependvalue' => 'y']);
// Test hiding item since transitive dependency is not met.
// Answering the first multichoice with 'y', should hide the second and therefor also the fourth.
$user1 = $this->getDataGenerator()->create_and_enrol($course);
$completion = new mod_feedback_completion($feedback, $cm, $course,
false, null, $user1->id);
// Initially, all pages should be visible.
$this->assertEquals(4, $this->get_number_of_visible_pages($completion));
// Answer the first multichoice with 'y', which should exclude the second and the fourth.
$answers = ['multichoice_' . $itemscreated[0]->id => [1]];
$completion->save_response_tmp((object) $answers);
$this->assertEquals(2, $this->get_number_of_visible_pages($completion));
// Answer the third multichoice with 'n', which should exclude the last one.
$answers = ['multichoice_' . $itemscreated[4]->id => [2]];
$completion->save_response_tmp((object) $answers);
$this->assertEquals(2, $this->get_number_of_visible_pages($completion));
$completion->save_response();
// Test showing item since transitive dependency is met.
// Answering the first multichoice with 'n' should hide the third multichoice.
$user2 = $this->getDataGenerator()->create_and_enrol($course);
$completion2 = new mod_feedback_completion($feedback, $cm, $course,
false, null, $user2->id);
// Initially, all pages should be visible.
$this->assertEquals(4, $this->get_number_of_visible_pages($completion2));
// Answer the first multichoice with 'n' should hide the third multichoice.
$answers = ['multichoice_' . $itemscreated[0]->id => [2]];
$completion2->save_response_tmp((object) $answers);
$this->assertEquals(3, $this->get_number_of_visible_pages($completion2));
// Answering the second multichoice with 'n' should hide the fourth one.
$answers = ['multichoice_' . $itemscreated[2]->id => [2]];
$completion2->save_response_tmp((object) $answers);
$this->assertEquals(2, $this->get_number_of_visible_pages($completion2));
}
}
@@ -0,0 +1,217 @@
<?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 core_completion/activity_custom_completion.
*
* @package mod_feedback
* @copyright Simey Lameze <simey@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
declare(strict_types=1);
namespace mod_feedback;
use advanced_testcase;
use cm_info;
use coding_exception;
use mod_feedback\completion\custom_completion;
use moodle_exception;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . '/completionlib.php');
/**
* Class for unit testing mod_feedback/activity_custom_completion.
*
* @package mod_feedback
* @copyright Simey Lameze <simey@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
* @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_feedback\dates.
*
* @package mod_feedback
* @category test
* @copyright 2021 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
declare(strict_types=1);
namespace mod_feedback;
use advanced_testcase;
use cm_info;
use core\activity_dates;
/**
* Class for unit testing mod_feedback\dates.
*
* @copyright 2021 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 The "allow answers from" time in the feedback activity.
* @param int|null $timeclose The "allow answers to" time in the feedback activity.
* @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;
}
$feedback = $this->getDataGenerator()->create_module('feedback', $data);
$this->setUser($user);
$cm = get_coursemodule_from_instance('feedback', $feedback->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);
}
}
+331
View File
@@ -0,0 +1,331 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Tests for feedback events.
*
* @package mod_feedback
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
namespace mod_feedback\event;
/**
* Class mod_feedback_events_testcase
*
* Class for tests related to feedback events.
*
* @package mod_feedback
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
class events_test extends \advanced_testcase {
/** @var stdClass A user who likes to interact with feedback activity. */
private $eventuser;
/** @var stdClass A course used to hold feedback activities for testing. */
private $eventcourse;
/** @var stdClass A feedback activity used for feedback event testing. */
private $eventfeedback;
/** @var stdClass course module object . */
private $eventcm;
/** @var stdClass A feedback item. */
private $eventfeedbackitem;
/** @var stdClass A feedback activity response submitted by user. */
private $eventfeedbackcompleted;
/** @var stdClass value associated with $eventfeedbackitem . */
private $eventfeedbackvalue;
public function setUp(): void {
global $DB;
$this->setAdminUser();
$gen = $this->getDataGenerator();
$this->eventuser = $gen->create_user(); // Create a user.
$course = $gen->create_course(); // Create a course.
// Assign manager role, so user can see reports.
role_assign(1, $this->eventuser->id, \context_course::instance($course->id));
// Add a feedback activity to the created course.
$record = new \stdClass();
$record->course = $course->id;
$feedback = $gen->create_module('feedback', $record);
$this->eventfeedback = $DB->get_record('feedback', array('id' => $feedback->id), '*', MUST_EXIST); // Get exact copy.
$this->eventcm = get_coursemodule_from_instance('feedback', $this->eventfeedback->id, false, MUST_EXIST);
// Create a feedback item.
$item = new \stdClass();
$item->feedback = $this->eventfeedback->id;
$item->type = 'numeric';
$item->presentation = '0|0';
$itemid = $DB->insert_record('feedback_item', $item);
$this->eventfeedbackitem = $DB->get_record('feedback_item', array('id' => $itemid), '*', MUST_EXIST);
// Create a response from a user.
$response = new \stdClass();
$response->feedback = $this->eventfeedback->id;
$response->userid = $this->eventuser->id;
$response->anonymous_response = FEEDBACK_ANONYMOUS_YES;
$completedid = $DB->insert_record('feedback_completed', $response);
$this->eventfeedbackcompleted = $DB->get_record('feedback_completed', array('id' => $completedid), '*', MUST_EXIST);
$value = new \stdClass();
$value->course_id = $course->id;
$value->item = $this->eventfeedbackitem->id;
$value->completed = $this->eventfeedbackcompleted->id;
$value->value = 25; // User response value.
$valueid = $DB->insert_record('feedback_value', $value);
$this->eventfeedbackvalue = $DB->get_record('feedback_value', array('id' => $valueid), '*', MUST_EXIST);
// Do this in the end to get correct sortorder and cacherev values.
$this->eventcourse = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST);
}
/**
* Tests for event response_deleted.
*/
public function test_response_deleted_event(): void {
global $USER, $DB;
$this->resetAfterTest();
// Create and delete a module.
$sink = $this->redirectEvents();
feedback_delete_completed($this->eventfeedbackcompleted->id);
$events = $sink->get_events();
$event = array_pop($events); // Delete feedback event.
$sink->close();
// Validate event data.
$this->assertInstanceOf('\mod_feedback\event\response_deleted', $event);
$this->assertEquals($this->eventfeedbackcompleted->id, $event->objectid);
$this->assertEquals($USER->id, $event->userid);
$this->assertEquals($this->eventuser->id, $event->relateduserid);
$this->assertEquals('feedback_completed', $event->objecttable);
$this->assertEquals(null, $event->get_url());
$this->assertEquals($this->eventfeedbackcompleted, $event->get_record_snapshot('feedback_completed', $event->objectid));
$this->assertEquals($this->eventcourse, $event->get_record_snapshot('course', $event->courseid));
$this->assertEquals($this->eventfeedback, $event->get_record_snapshot('feedback', $event->other['instanceid']));
// Test can_view() .
$this->setUser($this->eventuser);
$this->assertFalse($event->can_view());
$this->assertDebuggingCalled();
$this->setAdminUser();
$this->assertTrue($event->can_view());
$this->assertDebuggingCalled();
// Create a response, with anonymous set to no and test can_view().
$response = new \stdClass();
$response->feedback = $this->eventcm->instance;
$response->userid = $this->eventuser->id;
$response->anonymous_response = FEEDBACK_ANONYMOUS_NO;
$completedid = $DB->insert_record('feedback_completed', $response);
$DB->get_record('feedback_completed', array('id' => $completedid), '*', MUST_EXIST);
$value = new \stdClass();
$value->course_id = $this->eventcourse->id;
$value->item = $this->eventfeedbackitem->id;
$value->completed = $completedid;
$value->value = 25; // User response value.
$DB->insert_record('feedback_valuetmp', $value);
// Save the feedback.
$sink = $this->redirectEvents();
feedback_delete_completed($completedid);
$events = $sink->get_events();
$event = array_pop($events); // Response submitted feedback event.
$sink->close();
// Test can_view() .
$this->setUser($this->eventuser);
$this->assertTrue($event->can_view());
$this->assertDebuggingCalled();
$this->setAdminUser();
$this->assertTrue($event->can_view());
$this->assertDebuggingCalled();
$this->assertEventContextNotUsed($event);
}
/**
* Tests for event validations related to feedback response deletion.
*/
public function test_response_deleted_event_exceptions(): void {
$this->resetAfterTest();
$context = \context_module::instance($this->eventcm->id);
// Test not setting other['anonymous'].
try {
\mod_feedback\event\response_submitted::create(array(
'context' => $context,
'objectid' => $this->eventfeedbackcompleted->id,
'relateduserid' => 2,
));
$this->fail("Event validation should not allow \\mod_feedback\\event\\response_deleted to be triggered without
other['anonymous']");
} catch (\coding_exception $e) {
$this->assertStringContainsString("The 'anonymous' value must be set in other.", $e->getMessage());
}
}
/**
* Tests for event response_submitted.
*/
public function test_response_submitted_event(): void {
global $USER, $DB;
$this->resetAfterTest();
$this->setUser($this->eventuser);
// Create a temporary response, with anonymous set to yes.
$response = new \stdClass();
$response->feedback = $this->eventcm->instance;
$response->userid = $this->eventuser->id;
$response->anonymous_response = FEEDBACK_ANONYMOUS_YES;
$completedid = $DB->insert_record('feedback_completedtmp', $response);
$completed = $DB->get_record('feedback_completedtmp', array('id' => $completedid), '*', MUST_EXIST);
$value = new \stdClass();
$value->course_id = $this->eventcourse->id;
$value->item = $this->eventfeedbackitem->id;
$value->completed = $completedid;
$value->value = 25; // User response value.
$DB->insert_record('feedback_valuetmp', $value);
// Save the feedback.
$sink = $this->redirectEvents();
$id = feedback_save_tmp_values($completed);
$events = $sink->get_events();
$event = array_pop($events); // Response submitted feedback event.
$sink->close();
// Validate event data. Feedback is anonymous.
$this->assertInstanceOf('\mod_feedback\event\response_submitted', $event);
$this->assertEquals($id, $event->objectid);
$this->assertEquals($USER->id, $event->userid);
$this->assertEquals($USER->id, $event->relateduserid);
$this->assertEquals('feedback_completed', $event->objecttable);
$this->assertEquals(1, $event->anonymous);
$this->assertEquals(FEEDBACK_ANONYMOUS_YES, $event->other['anonymous']);
$this->setUser($this->eventuser);
$this->assertFalse($event->can_view());
$this->assertDebuggingCalled();
$this->setAdminUser();
$this->assertTrue($event->can_view());
$this->assertDebuggingCalled();
// Create a temporary response, with anonymous set to no.
$response = new \stdClass();
$response->feedback = $this->eventcm->instance;
$response->userid = $this->eventuser->id;
$response->anonymous_response = FEEDBACK_ANONYMOUS_NO;
$completedid = $DB->insert_record('feedback_completedtmp', $response);
$completed = $DB->get_record('feedback_completedtmp', array('id' => $completedid), '*', MUST_EXIST);
$value = new \stdClass();
$value->course_id = $this->eventcourse->id;
$value->item = $this->eventfeedbackitem->id;
$value->completed = $completedid;
$value->value = 25; // User response value.
$DB->insert_record('feedback_valuetmp', $value);
// Save the feedback.
$sink = $this->redirectEvents();
feedback_save_tmp_values($completed);
$events = $sink->get_events();
$event = array_pop($events); // Response submitted feedback event.
$sink->close();
// Test can_view().
$this->assertTrue($event->can_view());
$this->assertDebuggingCalled();
$this->setAdminUser();
$this->assertTrue($event->can_view());
$this->assertDebuggingCalled();
$this->assertEventContextNotUsed($event);
}
/**
* Tests for event validations related to feedback response submission.
*/
public function test_response_submitted_event_exceptions(): void {
$this->resetAfterTest();
$context = \context_module::instance($this->eventcm->id);
// Test not setting instanceid.
try {
\mod_feedback\event\response_submitted::create(array(
'context' => $context,
'objectid' => $this->eventfeedbackcompleted->id,
'relateduserid' => 2,
'anonymous' => 0,
'other' => array('cmid' => $this->eventcm->id, 'anonymous' => 2)
));
$this->fail("Event validation should not allow \\mod_feedback\\event\\response_deleted to be triggered without
other['instanceid']");
} catch (\coding_exception $e) {
$this->assertStringContainsString("The 'instanceid' value must be set in other.", $e->getMessage());
}
// Test not setting cmid.
try {
\mod_feedback\event\response_submitted::create(array(
'context' => $context,
'objectid' => $this->eventfeedbackcompleted->id,
'relateduserid' => 2,
'anonymous' => 0,
'other' => array('instanceid' => $this->eventfeedback->id, 'anonymous' => 2)
));
$this->fail("Event validation should not allow \\mod_feedback\\event\\response_deleted to be triggered without
other['cmid']");
} catch (\coding_exception $e) {
$this->assertStringContainsString("The 'cmid' value must be set in other.", $e->getMessage());
}
// Test not setting anonymous.
try {
\mod_feedback\event\response_submitted::create(array(
'context' => $context,
'objectid' => $this->eventfeedbackcompleted->id,
'relateduserid' => 2,
'other' => array('cmid' => $this->eventcm->id, 'instanceid' => $this->eventfeedback->id)
));
$this->fail("Event validation should not allow \\mod_feedback\\event\\response_deleted to be triggered without
other['anonymous']");
} catch (\coding_exception $e) {
$this->assertStringContainsString("The 'anonymous' value must be set in other.", $e->getMessage());
}
}
/**
* Test that event observer is executed on course deletion and the templates are removed.
*/
public function test_delete_course(): void {
global $DB;
$this->resetAfterTest();
feedback_save_as_template($this->eventfeedback, 'my template', 0);
$courseid = $this->eventcourse->id;
$this->assertNotEmpty($DB->get_records('feedback_template', array('course' => $courseid)));
delete_course($this->eventcourse, false);
$this->assertEmpty($DB->get_records('feedback_template', array('course' => $courseid)));
}
}
File diff suppressed because it is too large Load Diff
+235
View File
@@ -0,0 +1,235 @@
<?xml version="1.0" encoding="UTF-8" ?>
<FEEDBACK VERSION="200701" COMMENT="XML-Importfile for mod/feedback">
<ITEMS>
<ITEM TYPE="info" REQUIRED="0">
<ITEMID>
<![CDATA[1000]]>
</ITEMID>
<ITEMTEXT>
<![CDATA[this is an information question]]>
</ITEMTEXT>
<ITEMLABEL>
<![CDATA[info]]>
</ITEMLABEL>
<PRESENTATION>
<![CDATA[2]]>
</PRESENTATION>
<OPTIONS>
<![CDATA[]]>
</OPTIONS>
<DEPENDITEM>
<![CDATA[0]]>
</DEPENDITEM>
<DEPENDVALUE>
<![CDATA[]]>
</DEPENDVALUE>
</ITEM>
<ITEM TYPE="label" REQUIRED="0">
<ITEMID>
<![CDATA[1001]]>
</ITEMID>
<ITEMTEXT>
<![CDATA[label]]>
</ITEMTEXT>
<ITEMLABEL>
<![CDATA[]]>
</ITEMLABEL>
<PRESENTATION>
<![CDATA[label text]]>
</PRESENTATION>
<OPTIONS>
<![CDATA[]]>
</OPTIONS>
<DEPENDITEM>
<![CDATA[0]]>
</DEPENDITEM>
<DEPENDVALUE>
<![CDATA[]]>
</DEPENDVALUE>
</ITEM>
<ITEM TYPE="textarea" REQUIRED="1">
<ITEMID>
<![CDATA[1002]]>
</ITEMID>
<ITEMTEXT>
<![CDATA[this is a longer text answer]]>
</ITEMTEXT>
<ITEMLABEL>
<![CDATA[longertext]]>
</ITEMLABEL>
<PRESENTATION>
<![CDATA[30|5]]>
</PRESENTATION>
<OPTIONS>
<![CDATA[]]>
</OPTIONS>
<DEPENDITEM>
<![CDATA[0]]>
</DEPENDITEM>
<DEPENDVALUE>
<![CDATA[]]>
</DEPENDVALUE>
</ITEM>
<ITEM TYPE="multichoice" REQUIRED="0">
<ITEMID>
<![CDATA[1003]]>
</ITEMID>
<ITEMTEXT>
<![CDATA[this is a multiple choice 1]]>
</ITEMTEXT>
<ITEMLABEL>
<![CDATA[multichoice1]]>
</ITEMLABEL>
<PRESENTATION>
<![CDATA[r>>>>>option a|option b|option c]]>
</PRESENTATION>
<OPTIONS>
<![CDATA[]]>
</OPTIONS>
<DEPENDITEM>
<![CDATA[0]]>
</DEPENDITEM>
<DEPENDVALUE>
<![CDATA[]]>
</DEPENDVALUE>
</ITEM>
<ITEM TYPE="pagebreak" REQUIRED="0">
<ITEMID>
<![CDATA[1004]]>
</ITEMID>
<ITEMTEXT>
<![CDATA[]]>
</ITEMTEXT>
<ITEMLABEL>
<![CDATA[]]>
</ITEMLABEL>
<PRESENTATION>
<![CDATA[]]>
</PRESENTATION>
<OPTIONS>
<![CDATA[]]>
</OPTIONS>
<DEPENDITEM>
<![CDATA[0]]>
</DEPENDITEM>
<DEPENDVALUE>
<![CDATA[]]>
</DEPENDVALUE>
</ITEM>
<ITEM TYPE="multichoice" REQUIRED="0">
<ITEMID>
<![CDATA[1005]]>
</ITEMID>
<ITEMTEXT>
<![CDATA[this is a multiple choice 2]]>
</ITEMTEXT>
<ITEMLABEL>
<![CDATA[multichoice2]]>
</ITEMLABEL>
<PRESENTATION>
<![CDATA[c>>>>>option d|option e|option f]]>
</PRESENTATION>
<OPTIONS>
<![CDATA[h]]>
</OPTIONS>
<DEPENDITEM>
<![CDATA[1003]]>
</DEPENDITEM>
<DEPENDVALUE>
<![CDATA[option a]]>
</DEPENDVALUE>
</ITEM>
<ITEM TYPE="multichoice" REQUIRED="0">
<ITEMID>
<![CDATA[1006]]>
</ITEMID>
<ITEMTEXT>
<![CDATA[this is a multiple choice 3]]>
</ITEMTEXT>
<ITEMLABEL>
<![CDATA[multichoice3]]>
</ITEMLABEL>
<PRESENTATION>
<![CDATA[d>>>>>option g|option h|option i]]>
</PRESENTATION>
<OPTIONS>
<![CDATA[]]>
</OPTIONS>
<DEPENDITEM>
<![CDATA[0]]>
</DEPENDITEM>
<DEPENDVALUE>
<![CDATA[]]>
</DEPENDVALUE>
</ITEM>
<ITEM TYPE="multichoicerated" REQUIRED="0">
<ITEMID>
<![CDATA[1007]]>
</ITEMID>
<ITEMTEXT>
<![CDATA[this is a multiple choice rated]]>
</ITEMTEXT>
<ITEMLABEL>
<![CDATA[multichoice4]]>
</ITEMLABEL>
<PRESENTATION>
<![CDATA[r>>>>>0####option k|1####option l|5####option m]]>
</PRESENTATION>
<OPTIONS>
<![CDATA[]]>
</OPTIONS>
<DEPENDITEM>
<![CDATA[0]]>
</DEPENDITEM>
<DEPENDVALUE>
<![CDATA[]]>
</DEPENDVALUE>
</ITEM>
<ITEM TYPE="numeric" REQUIRED="0">
<ITEMID>
<![CDATA[1008]]>
</ITEMID>
<ITEMTEXT>
<![CDATA[this is a numeric answer]]>
</ITEMTEXT>
<ITEMLABEL>
<![CDATA[numeric]]>
</ITEMLABEL>
<PRESENTATION>
<![CDATA[-|100]]>
</PRESENTATION>
<OPTIONS>
<![CDATA[]]>
</OPTIONS>
<DEPENDITEM>
<![CDATA[0]]>
</DEPENDITEM>
<DEPENDVALUE>
<![CDATA[]]>
</DEPENDVALUE>
</ITEM>
<ITEM TYPE="textfield" REQUIRED="0">
<ITEMID>
<![CDATA[1009]]>
</ITEMID>
<ITEMTEXT>
<![CDATA[this is a short text answer]]>
</ITEMTEXT>
<ITEMLABEL>
<![CDATA[shorttext]]>
</ITEMLABEL>
<PRESENTATION>
<![CDATA[30|200]]>
</PRESENTATION>
<OPTIONS>
<![CDATA[]]>
</OPTIONS>
<DEPENDITEM>
<![CDATA[0]]>
</DEPENDITEM>
<DEPENDVALUE>
<![CDATA[]]>
</DEPENDVALUE>
</ITEM>
</ITEMS>
</FEEDBACK>
@@ -0,0 +1,211 @@
<?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_feedback\form;
/**
* Tests the confirm use template form
*
* @author Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
class create_template_form_test extends \advanced_testcase {
/**
* Run the basic setup for the test
*/
public function setup_instance(): array {
global $DB, $PAGE;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
$cm = get_coursemodule_from_instance('feedback', $feedback->id, $course->id);
$user = $this->getDataGenerator()->create_user();
$teacher = $this->getDataGenerator()->create_user();
$manager = $this->getDataGenerator()->create_user();
// Enrol a student and teacher.
$this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
$this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
// Setup the site wide manager role.
$managerrole = $DB->get_record('role', ['shortname' => 'manager']);
role_assign($managerrole->id, $manager->id, SYSCONTEXTID);
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
// Create at least one page.
$feedbackgenerator->create_item_multichoice($feedback, ['values' => "y\nn"]);
$feedbackgenerator->create_item_multichoice($feedback, ['values' => "0\n1"]);
$feedbackparams = [
'id' => $cm->id,
];
$PAGE->set_cm($cm);
$PAGE->set_activity_record($feedback);
return [$manager, $teacher, $user, $managerrole, $feedbackparams];
}
/**
* Test the create template for when capabilities have been modified
*
* @param array $unassignedroles
* @param bool $accessallowed
* @param bool $public
* @param bool $expectedispublicvalue
* @dataProvider createtemplate_form_with_modified_capabilities_provider
*/
public function test_createtemplate_form_with_modified_capabilities(array $unassignedroles, bool $accessallowed,
bool $public = false, bool $expectedispublicvalue = false): void {
global $DB;
[$manager, $teacher, $user, $managerrole, $feedback] = $this->setup_instance();
$this->setAdminUser();
foreach ($unassignedroles as $role) {
unassign_capability($role, $managerrole->id);
}
$data = [
'id' => $feedback['id'],
'templatename' => 'mytemplate',
'ispublic' => $public
];
$this->setUser($manager);
$submitdata = create_template_form::mock_ajax_submit($data);
if (!$accessallowed) {
$this->expectException(\moodle_exception::class);
}
$form = new create_template_form(null, null, 'post', '', null, true,
$submitdata, true);
$form->set_data_for_dynamic_submission();
$this->assertTrue($form->is_validated());
$form->process_dynamic_submission();
$records = array_values($DB->get_records('feedback_template', null, 'id ASC'));
$this->assertEquals($expectedispublicvalue, (bool) $records[0]->ispublic);
}
/**
* Provider for the test_createtemplate_form_with_modified_capabilities
*
* @return array
*/
public function createtemplate_form_with_modified_capabilities_provider(): array {
return [
"Manager without edititems permission cannot create any templates" => [
['mod/feedback:edititems'], false
],
"Manager without createprivatetemplate permission creating public template" => [
['mod/feedback:createprivatetemplate'], true, true, true
],
"Manager without createprivatetemplate permission creating private template" => [
['mod/feedback:createprivatetemplate'], true
],
"Manager without createpublictemplate permission creating private template" => [
['mod/feedback:createpublictemplate'], true
],
"Manager without createpublictemplate permission creating public template" => [
['mod/feedback:createpublictemplate'], true, true
],
"Manager without createprivatetemplate,createpublictemplate permission cannot create templates" => [
['mod/feedback:createpublictemplate', 'mod/feedback:createprivatetemplate'], false
]
];
}
/**
* Test the form
*
* @param string $loginas
* @param bool $public
* @param bool $accessallowed
* @dataProvider createtemplate_form_provider
*/
public function test_createtemplate_form(string $loginas, bool $public,
bool $accessallowed = true): void {
global $DB;
[$manager, $teacher, $user, $managerrole, $feedback] = $this->setup_instance();
switch($loginas) {
case 'admin':
$this->setAdminUser();
break;
case 'student':
$this->setUser($user);
break;
case 'teacher':
$this->setUser($teacher);
break;
case 'manager':
$this->setUser($manager);
break;
}
$data = [
'id' => $feedback['id'],
'templatename' => 'mytemplate',
'ispublic' => $public
];
$submitdata = create_template_form::mock_ajax_submit($data);
if (!$accessallowed) {
$this->expectException(\moodle_exception::class);
}
$form = new create_template_form(null, null, 'post', '', null, true,
$submitdata, true);
$form->set_data_for_dynamic_submission();
$this->assertTrue($form->is_validated());
$form->process_dynamic_submission();
// A teacher can access the form but cannot create public templates.
if ($loginas == 'teacher' && $public) {
$records = array_values($DB->get_records('feedback_template', null, 'id ASC'));
$this->assertFalse((bool) $records[0]->ispublic);
}
}
/**
* Provider for the test_createtemplate_form
*
* @return array
*/
public function createtemplate_form_provider(): array {
return [
'Create a private template as an admin' => [
'admin', false
],
'Create a public template as an admin' => [
'admin', true
],
'Create a private template as a manager' => [
'manager', false
],
'Create a public template as a manager' => [
'manager', true
],
'Create a private template as a teacher' => [
'teacher', false
],
'Create a public template as a teacher' => [
'teacher', true
],
'Create a public template as a student' => [
'student', true, false
],
'Create a private template as a student' => [
'student', false, false
],
];
}
}
@@ -0,0 +1,119 @@
<?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_feedback\form;
/**
* Tests the confirm use template form
*
* @author Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
class use_template_form_test extends \advanced_testcase {
/**
* Run the basic setup for the test
*/
public function setup_instance(): array {
global $DB, $PAGE;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
$cm = get_coursemodule_from_instance('feedback', $feedback->id, $course->id);
$user = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
// Create at least one page.
$feedbackgenerator->create_item_multichoice($feedback, ['values' => "y\nn"]);
feedback_save_as_template($feedback, 'my template', 0);
$feedbackgenerator->create_item_multichoice($feedback, ['values' => "0\n1"]);
feedback_save_as_template($feedback, 'mytemplate2', 1);
$records = array_keys($DB->get_records('feedback_template', null, 'id ASC'));
$feedbackparams = [
'id' => $cm->id,
'privatetemplate' => $records[0],
'publictemplate' => $records[1],
];
$PAGE->set_cm($cm);
$PAGE->set_activity_record($feedback);
return [$user, $feedbackparams];
}
/**
* Test the form
*
* @param string $loginas Which user to log in as
* @param bool $private Whether we are creating a private template
* @param bool $expected Whether or not the form should be validated
* @dataProvider usetemplate_form_provider
*/
public function test_usetemplate_form(string $loginas, bool $private, bool $expected): void {
[$user, $feedback] = $this->setup_instance();
switch($loginas) {
case 'admin':
$this->setAdminUser();
break;
case 'student':
$this->setUser($user);
break;
}
$data = [
'id' => $feedback['id'],
'templateid' => $private ? $feedback['privatetemplate'] : $feedback['publictemplate'],
];
$submitdata = use_template_form::mock_ajax_submit($data);
if (!$expected) {
$this->expectException(\moodle_exception::class);
}
$form = new use_template_form(null, null, 'post', '', null, true,
$submitdata, true);
$form->set_data_for_dynamic_submission();
if ($expected) {
$this->assertTrue($form->is_validated());
}
$form->process_dynamic_submission();
}
/**
* Provider for the test_usetemplate_form test
*
* @return array
*/
public function usetemplate_form_provider() {
return [
'Test submission with a private template as an admin' => [
'admin', true, true
],
'Test submission with a public template as an admin' => [
'admin', false, true
],
'Test submission with a public template as a student' => [
'student', false, false
],
'Test submission with a private template as a student' => [
'student', true, false
],
];
}
}
@@ -0,0 +1,49 @@
<?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/>.
/**
* Behat data generator for mod_feedback.
*
* @package mod_feedback
* @category test
* @copyright 2022 Noel De Martin
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_mod_feedback_generator extends behat_generator_base {
/**
* Get a list of the entities that Behat can create using the generator step.
*
* @return array
*/
protected function get_creatable_entities(): array {
return [
'questions' => [
'singular' => 'question',
'datagenerator' => 'question',
'required' => ['activity'],
'switchids' => ['activity' => 'cmid'],
],
'responses' => [
'singular' => 'response',
'datagenerator' => 'response',
'required' => ['activity', 'user'],
'switchids' => ['activity' => 'cmid', 'user' => 'userid'],
],
];
}
}
+553
View File
@@ -0,0 +1,553 @@
<?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_feedback data generator.
*
* @package mod_feedback
* @category test
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* mod_feedback data generator class.
*
* @package mod_feedback
* @category test
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_feedback_generator extends testing_module_generator {
public function create_instance($record = null, array $options = null) {
global $CFG;
require_once($CFG->dirroot.'/mod/feedback/lib.php');
$record = (object)(array)$record;
if (!isset($record->anonymous)) {
$record->anonymous = FEEDBACK_ANONYMOUS_YES;
}
if (!isset($record->email_notification)) {
$record->email_notification = 0;
}
if (!isset($record->multiple_submit)) {
$record->multiple_submit = 0;
}
if (!isset($record->autonumbering)) {
$record->autonumbering = 0;
}
if (!isset($record->site_after_submit)) {
$record->site_after_submit = '';
}
if (!isset($record->page_after_submit)) {
$record->page_after_submit = 'This is page after submit';
}
if (!isset($record->page_after_submitformat)) {
$record->page_after_submitformat = FORMAT_MOODLE;
}
if (!isset($record->publish_stats)) {
$record->publish_stats = 0;
}
if (!isset($record->timeopen)) {
$record->timeopen = 0;
}
if (!isset($record->timeclose)) {
$record->timeclose = 0;
}
if (!isset($record->timemodified)) {
$record->timemodified = time();
}
if (!isset($record->completionsubmit)) {
$record->completionsubmit = 0;
}
// Hack to bypass draft processing of feedback_add_instance.
$record->page_after_submit_editor['itemid'] = false;
return parent::create_instance($record, (array)$options);
}
/**
* Create question.
*
* @param array $data Question data
* @return mixed Question instance
*/
public function create_question(array $data) {
global $DB;
$questiontype = $data['questiontype'] ?? 'textfield';
$cm = get_coursemodule_from_id('feedback', $data['cmid']);
$feedback = $DB->get_record('feedback', ['id' => $cm->instance]);
unset($data['questiontype']);
unset($data['cmid']);
if (isset($data['values'])) {
$data['values'] = $this->format_item_values($questiontype, $data['values']);
}
return call_user_func([$this, "create_item_{$questiontype}"], $feedback, $data);
}
/**
* Create response.
*
* @param array $data Response data.
* @return stdClass feedback_completed response instance.
*/
public function create_response(array $data): stdClass {
global $DB;
$userid = $data['userid'];
$responsenumber = null;
$cm = get_coursemodule_from_id('feedback', $data['cmid']);
$feedback = $DB->get_record('feedback', ['id' => $cm->instance]);
$answers = [];
if (isset($data['responsenumber']) && trim($data['responsenumber']) !== '') {
$responsenumber = $data['responsenumber'];
}
if (isset($data['anonymous']) && trim($data['anonymous']) !== '') {
$anonymous = filter_var(trim($data['anonymous']), FILTER_VALIDATE_BOOLEAN);
$feedback->anonymous = $anonymous ? FEEDBACK_ANONYMOUS_YES : FEEDBACK_ANONYMOUS_NO;
}
unset($data['cmid']);
unset($data['userid']);
unset($data['anonymous']);
unset($data['responsenumber']);
foreach ($data as $question => $response) {
$item = $DB->get_record('feedback_item', ['name' => trim($question)], '*', MUST_EXIST);
$answers["{$item->typ}_{$item->id}"] = $this->get_item_response_value($item, $response);
}
$feedbackcompletion = new mod_feedback_completion(
$feedback,
$cm,
$cm->course,
false,
null,
$feedback->anonymous === FEEDBACK_ANONYMOUS_YES ? null : $userid,
$userid
);
if (!$feedbackcompletion->can_complete()) {
throw new coding_exception("User {$userid} cannot complete this feedback activity.");
}
if (!$feedbackcompletion->is_open()) {
throw new coding_exception("This activity is not open.");
}
$feedbackcompletion->set_module_viewed();
$feedbackcompletion->save_response_tmp((object) $answers);
$feedbackcompletion->save_response();
$completed = $feedbackcompletion->get_completed();
if (!is_null($responsenumber)) {
$DB->update_record('feedback_completed', [
'id' => $completed->id,
'random_response' => $responsenumber,
]);
}
return $completed;
}
/**
* Create info question item.
*
* @param object $feedback feedback record
* @param array $record (optional) to override default values
* @return stdClass
*/
public function create_item_info($feedback, $record = array()) {
global $DB, $CFG;
require_once($CFG->dirroot.'/mod/feedback/lib.php');
$itemobj = feedback_get_item_class('info');
$position = $DB->count_records('feedback_item', array('feedback' => $feedback->id)) + 1;
$record = (array)$record + array(
'id' => 0,
'feedback' => $feedback->id,
'template' => 0,
'name' => 'Feedback question item ' . $position,
'label' => 'Feedback label ' . $position,
'presentation' => \feedback_item_info::MODE_COURSE,
'typ' => 'info',
'hasvalue' => 0,
'position' => $position,
'required' => 0,
'dependitem' => 0,
'dependvalue' => '',
'options' => '',
);
$itemobj->set_data((object) $record);
return $itemobj->save_item();
}
/**
* Create label question item.
*
* @param object $feedback feedback record
* @param array $record (optional) to override default values
* @return stdClass
*/
public function create_item_label($feedback, $record = array()) {
global $DB, $CFG;
require_once($CFG->dirroot.'/mod/feedback/lib.php');
$itemobj = feedback_get_item_class('label');
$position = $DB->count_records('feedback_item', array('feedback' => $feedback->id)) + 1;
$record = (array)$record + array(
'id' => 0,
'feedback' => $feedback->id,
'template' => 0,
'name' => 'label',
'label' => '',
'presentation' => '',
'typ' => 'label',
'hasvalue' => 0,
'position' => $position,
'required' => 0,
'dependitem' => 0,
'dependvalue' => '',
'options' => '',
);
if (!isset($record['presentation_editor'])) {
$record['presentation_editor'] = array(
'text' => "The label $position text goes here",
'format' => FORMAT_HTML,
'itemid' => 0
);
}
$itemobj->set_data((object) $record);
return $itemobj->save_item();
}
/**
* Create multichoice question item.
*
* @param object $feedback feedback record
* @param array $record (optional) to override default values
* @return stdClass
*/
public function create_item_multichoice($feedback, $record = array()) {
global $DB, $CFG;
require_once($CFG->dirroot.'/mod/feedback/lib.php');
$itemobj = feedback_get_item_class('multichoice');
$position = $DB->count_records('feedback_item', array('feedback' => $feedback->id)) + 1;
$record = (array)$record + array(
'id' => 0,
'feedback' => $feedback->id,
'template' => 0,
'name' => 'Feedback question item ' . $position,
'label' => 'Feedback label ' . $position,
'presentation' => '',
'typ' => 'multichoice',
'hasvalue' => 0,
'position' => $position,
'required' => 0,
'dependitem' => 0,
'dependvalue' => '',
'options' => '',
'subtype' => 'r',
'horizontal' => 0,
'hidenoselect' => 1,
'ignoreempty' => 0,
'values' => "a\nb\nc\nd\ne"
);
$presentation = str_replace("\n", FEEDBACK_MULTICHOICE_LINE_SEP, trim($record['values']));
if ($record['horizontal'] == 1 AND $record['subtype'] != 'd') {
$presentation .= FEEDBACK_MULTICHOICE_ADJUST_SEP.'1';
}
$record['presentation'] = $record['subtype'].FEEDBACK_MULTICHOICE_TYPE_SEP.$presentation;
$itemobj->set_data((object) $record);
return $itemobj->save_item();
}
/**
* Create multichoicerated question item.
*
* @param object $feedback feedback record
* @param array $record (optional) to override default values
* @return stdClass
*/
public function create_item_multichoicerated($feedback, $record = array()) {
global $DB, $CFG;
require_once($CFG->dirroot.'/mod/feedback/lib.php');
$itemobj = feedback_get_item_class('multichoicerated');
$position = $DB->count_records('feedback_item', array('feedback' => $feedback->id)) + 1;
$record = (array)$record + array(
'id' => 0,
'feedback' => $feedback->id,
'template' => 0,
'name' => 'Feedback question item ' . $position,
'label' => 'Feedback label ' . $position,
'presentation' => '',
'typ' => 'multichoicerated',
'hasvalue' => 0,
'position' => $position,
'required' => 0,
'dependitem' => 0,
'dependvalue' => '',
'options' => '',
'subtype' => 'r',
'horizontal' => 0,
'hidenoselect' => 1,
'ignoreempty' => 0,
'values' => "0/a\n1/b\n2/c\n3/d\n4/e"
);
$itemobj = new feedback_item_multichoicerated();
$presentation = $itemobj->prepare_presentation_values_save(trim($record['values']),
FEEDBACK_MULTICHOICERATED_VALUE_SEP2, FEEDBACK_MULTICHOICERATED_VALUE_SEP);
if ($record['horizontal'] == 1 AND $record['subtype'] != 'd') {
$presentation .= FEEDBACK_MULTICHOICERATED_ADJUST_SEP.'1';
}
$record['presentation'] = $record['subtype'].FEEDBACK_MULTICHOICERATED_TYPE_SEP.$presentation;
$itemobj->set_data((object) $record);
return $itemobj->save_item();
}
/**
* Create numeric question item.
*
* @param object $feedback feedback record
* @param array $record (optional) to override default values
* @return stdClass
*/
public function create_item_numeric($feedback, $record = array()) {
global $DB, $CFG;
require_once($CFG->dirroot.'/mod/feedback/lib.php');
$itemobj = feedback_get_item_class('numeric');
$position = $DB->count_records('feedback_item', array('feedback' => $feedback->id)) + 1;
$record = (array)$record + array(
'id' => 0,
'feedback' => $feedback->id,
'template' => 0,
'name' => 'Feedback question item ' . $position,
'label' => 'Feedback label ' . $position,
'presentation' => '',
'typ' => 'numeric',
'hasvalue' => 0,
'position' => $position,
'required' => 0,
'dependitem' => 0,
'dependvalue' => '',
'options' => '',
'rangefrom' => '-',
'rangeto' => '-',
);
if ($record['rangefrom'] === '-' OR $record['rangeto'] === '-') {
$record['presentation'] = $record['rangefrom'] . '|'. $record['rangeto'];
} else if ($record['rangefrom'] > $record['rangeto']) {
$record['presentation'] = $record['rangeto'] . '|'. $record['rangefrom'];
} else {
$record['presentation'] = $record['rangefrom'] . '|'. $record['rangeto'];
}
$itemobj->set_data((object) $record);
return $itemobj->save_item();
}
/**
* Create textarea question item.
*
* @param object $feedback feedback record
* @param array $record (optional) to override default values
* @return stdClass
*/
public function create_item_textarea($feedback, $record = array()) {
global $DB, $CFG;
require_once($CFG->dirroot.'/mod/feedback/lib.php');
$itemobj = feedback_get_item_class('textarea');
$position = $DB->count_records('feedback_item', array('feedback' => $feedback->id)) + 1;
$record = (array)$record + array(
'id' => 0,
'feedback' => $feedback->id,
'template' => 0,
'name' => 'Feedback question item ' . $position,
'label' => 'Feedback label ' . $position,
'presentation' => '',
'typ' => 'textarea',
'hasvalue' => 0,
'position' => $position,
'required' => 0,
'dependitem' => 0,
'dependvalue' => '',
'options' => '',
'itemwidth' => '40',
'itemheight' => '20',
);
$record['presentation'] = $record['itemwidth'] . '|'. $record['itemheight'];
$itemobj->set_data((object) $record);
return $itemobj->save_item();
}
/**
* Create textfield question item.
*
* @param object $feedback feedback record
* @param array $record (optional) to override default values
* @return stdClass
*/
public function create_item_textfield($feedback, $record = array()) {
global $DB, $CFG;
require_once($CFG->dirroot.'/mod/feedback/lib.php');
$itemobj = feedback_get_item_class('textfield');
$position = $DB->count_records('feedback_item', array('feedback' => $feedback->id)) + 1;
$record = (array)$record + array(
'id' => 0,
'feedback' => $feedback->id,
'template' => 0,
'name' => 'Feedback question item ' . $position,
'label' => 'Feedback label ' . $position,
'presentation' => '',
'typ' => 'textfield',
'hasvalue' => 0,
'position' => $position,
'required' => 0,
'dependitem' => 0,
'dependvalue' => '',
'options' => '',
'itemsize' => '20',
'itemmaxlength' => '30',
);
$record['presentation'] = $record['itemsize'] . '|'. $record['itemmaxlength'];
$itemobj->set_data((object) $record);
return $itemobj->save_item();
}
/**
* Create pagebreak.
*
* @param object $feedback feedback record
* @return int|false false if there already is a pagebreak on last position or the id of the pagebreak-item
*/
public function create_item_pagebreak($feedback) {
global $CFG;
require_once($CFG->dirroot.'/mod/feedback/lib.php');
return feedback_create_pagebreak($feedback->id);
}
/**
* Format feedback item values.
*
* This method will replace newline characters with the proper line separator for each question type.
*
* @param string $questiontype Question types
* @param string $values Values
* @return string Formatted values
*/
protected function format_item_values(string $questiontype, string $values): string {
global $CFG;
if (!file_exists($CFG->dirroot.'/mod/feedback/item/'.$questiontype.'/lib.php')) {
throw new coding_exception("Question type '$questiontype' not found");
}
require_once($CFG->dirroot.'/mod/feedback/item/'.$questiontype.'/lib.php');
$questiontype = strtoupper($questiontype);
if (defined("FEEDBACK_{$questiontype}_LINE_SEP")) {
return implode(constant("FEEDBACK_{$questiontype}_LINE_SEP"), explode('\n', $values));
}
return $values;
}
/**
* Given a response to a feedback item, return its corresponding value.
*
* @param mixed $record Item record
* @param string $response Response name
* @return int|string Response value
*/
protected function get_item_response_value($record, string $response) {
if (strpos($record->typ, 'multichoice') === 0) {
$item = feedback_get_item_class($record->typ);
return $this->get_choice_item_response_value($item, $record, $response);
}
return $response;
}
/**
* Given a response to a feedback choice item, return its corresponding value.
*
* @param feedback_item_base $item Feedback item
* @param mixed $record Item record
* @param string $response Response
* @param int $offset Choice to start looking from
* @return int Response choice index
*/
protected function get_choice_item_response_value(feedback_item_base $item, $record, string $response, int $offset = 1): int {
$printval = $item->get_printval($record, (object) ['value' => $offset]);
if (empty($printval)) {
throw new coding_exception("Value '$offset' not found");
}
if ($printval === $response) {
return $offset;
}
return $this->get_choice_item_response_value($item, $record, $response, $offset + 1);
}
}
+221
View File
@@ -0,0 +1,221 @@
<?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_feedback;
/**
* Generator tests class.
*
* @package mod_feedback
* @copyright 2013 Ankit Agarwal
* @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('feedback', array('course' => $course->id)));
$feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course->id));
$this->assertEquals(1, $DB->count_records('feedback', array('course' => $course->id)));
$this->assertTrue($DB->record_exists('feedback', array('course' => $course->id)));
$this->assertTrue($DB->record_exists('feedback', array('id' => $feedback->id)));
$params = array('course' => $course->id, 'name' => 'One more feedback');
$feedback = $this->getDataGenerator()->create_module('feedback', $params);
$this->assertEquals(2, $DB->count_records('feedback', array('course' => $course->id)));
$this->assertEquals('One more feedback', $DB->get_field_select('feedback', 'name', 'id = :id',
array('id' => $feedback->id)));
}
public function test_create_item_info(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course));
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
$item1 = $feedbackgenerator->create_item_info($feedback);
$item2 = $feedbackgenerator->create_item_info($feedback, array('name' => 'Custom name'));
$records = $DB->get_records('feedback_item', array('feedback' => $feedback->id), 'id');
$this->assertCount(2, $records);
$this->assertEquals($item1->id, $records[$item1->id]->id);
$this->assertEquals($item2->id, $records[$item2->id]->id);
$this->assertEquals('Custom name', $records[$item2->id]->name);
$this->assertEquals('info', $records[$item1->id]->typ);
}
public function test_create_item_label(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course));
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
$item1 = $feedbackgenerator->create_item_label($feedback);
$editor = array(
'text' => "Custom editor",
'format' => FORMAT_HTML,
'itemid' => 0
);
$item2 = $feedbackgenerator->create_item_label($feedback, array('presentation_editor' => $editor));
$records = $DB->get_records('feedback_item', array('feedback' => $feedback->id), 'id');
$this->assertCount(2, $records);
$this->assertEquals($item1->id, $records[$item1->id]->id);
$this->assertEquals($item2->id, $records[$item2->id]->id);
$this->assertEquals($editor['text'], $records[$item2->id]->presentation);
$this->assertEquals('label', $records[$item1->id]->typ);
}
public function test_create_item_multichoice(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course));
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
$item1 = $feedbackgenerator->create_item_multichoice($feedback);
$item2 = $feedbackgenerator->create_item_multichoice($feedback, array('values' => "1\n2\n3\n4\n5", 'horizontal' => 1));
$records = $DB->get_records('feedback_item', array('feedback' => $feedback->id), 'id');
$this->assertCount(2, $records);
$this->assertEquals($item1->id, $records[$item1->id]->id);
$this->assertEquals($item2->id, $records[$item2->id]->id);
$this->assertEquals('r>>>>>a|b|c|d|e', $records[$item1->id]->presentation);
$this->assertEquals('r>>>>>1|2|3|4|5<<<<<1', $records[$item2->id]->presentation);
$this->assertEquals('multichoice', $records[$item1->id]->typ);
}
public function test_create_item_multichoicerated(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course));
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
$item1 = $feedbackgenerator->create_item_multichoicerated($feedback);
$item2 = $feedbackgenerator->create_item_multichoicerated($feedback, array(
'values' => "0/1\n1/2\n2/3\n3/4\n4/5", 'horizontal' => 1));
$records = $DB->get_records('feedback_item', array('feedback' => $feedback->id), 'id');
$this->assertCount(2, $records);
$this->assertEquals($item1->id, $records[$item1->id]->id);
$this->assertEquals($item2->id, $records[$item2->id]->id);
$this->assertEquals('r>>>>>0####a|1####b|2####c|3####d|4####e', $records[$item1->id]->presentation);
$this->assertEquals('r>>>>>0####1|1####2|2####3|3####4|4####5<<<<<1', $records[$item2->id]->presentation);
$this->assertEquals('multichoicerated', $records[$item1->id]->typ);
}
public function test_create_item_numeric(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course));
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
$item1 = $feedbackgenerator->create_item_numeric($feedback);
$item2 = $feedbackgenerator->create_item_numeric($feedback, array('rangefrom' => '0', 'rangeto' => '10'));
$records = $DB->get_records('feedback_item', array('feedback' => $feedback->id), 'id');
$this->assertCount(2, $records);
$this->assertEquals($item1->id, $records[$item1->id]->id);
$this->assertEquals($item2->id, $records[$item2->id]->id);
$this->assertEquals('-|-', $records[$item1->id]->presentation);
$this->assertEquals('0|10', $records[$item2->id]->presentation);
$this->assertEquals('numeric', $records[$item1->id]->typ);
}
public function test_create_item_textarea(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course));
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
$item1 = $feedbackgenerator->create_item_textarea($feedback);
$item2 = $feedbackgenerator->create_item_textarea($feedback, array('itemwidth' => '20', 'itemheight' => '10'));
$records = $DB->get_records('feedback_item', array('feedback' => $feedback->id), 'id');
$this->assertCount(2, $records);
$this->assertEquals($item1->id, $records[$item1->id]->id);
$this->assertEquals($item2->id, $records[$item2->id]->id);
$this->assertEquals('40|20', $records[$item1->id]->presentation);
$this->assertEquals('20|10', $records[$item2->id]->presentation);
$this->assertEquals('textarea', $records[$item1->id]->typ);
}
public function test_create_item_textfield(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course));
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
$item1 = $feedbackgenerator->create_item_textfield($feedback);
$item2 = $feedbackgenerator->create_item_textfield($feedback, array('itemsize' => '20', 'itemmaxlength' => '10'));
$records = $DB->get_records('feedback_item', array('feedback' => $feedback->id), 'id');
$this->assertCount(2, $records);
$this->assertEquals($item1->id, $records[$item1->id]->id);
$this->assertEquals($item2->id, $records[$item2->id]->id);
$this->assertEquals('20|30', $records[$item1->id]->presentation);
$this->assertEquals('20|10', $records[$item2->id]->presentation);
$this->assertEquals('textfield', $records[$item1->id]->typ);
}
public function test_create_item_pagebreak(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course));
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
// Try to create a page break in an empty feedback (no items).
$feedbackgenerator->create_item_pagebreak($feedback);
$records = $DB->get_records('feedback_item', array('feedback' => $feedback->id), 'id');
$this->assertCount(0, $records);
// Create at least one item before the pagebreak.
$feedbackgenerator->create_item_textfield($feedback);
// Now, create one pagebreak.
$item1 = $feedbackgenerator->create_item_pagebreak($feedback);
$records = $DB->get_records('feedback_item', array('feedback' => $feedback->id), 'id');
$this->assertCount(2, $records);
// This pagebreak won't be created (there is already one in the last position).
$item2 = $feedbackgenerator->create_item_pagebreak($feedback);
$this->assertFalse($item2);
$records = $DB->get_records('feedback_item', array('feedback' => $feedback->id), 'id');
$this->assertCount(2, $records);
}
}
+70
View File
@@ -0,0 +1,70 @@
<?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_feedback;
use advanced_testcase;
use ReflectionClass;
/**
* This file contains unit tests for the mod_feedback items.
*
* @package mod_feedback
* @copyright 2020 Mikhail Golenkov <mikhailgolenkov@catalyst-au.net>
* @author 2023 David Woloszyn <david.woloszyn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class item_test extends advanced_testcase {
/**
* Test that get_analysed() for textarea item returns correctly formatted data for exporting to Excel.
*
* @covers ::get_analysed
*/
public function test_get_analysed_textarea_for_excel_export(): void {
global $DB;
$this->resetAfterTest();
// Create a course, a feedback activity and an item.
$course = $this->getDataGenerator()->create_course();
$feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course]);
$feedbackgenerator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
$item = $feedbackgenerator->create_item_textfield($feedback);
// Expected text.
$valuetext = "First line\nSecond line";
// Create a temporary response.
$completedid = $DB->insert_record('feedback_completedtmp', (object)['feedback' => $feedback->id]);
$completed = $DB->get_record('feedback_completedtmp', ['id' => $completedid], '*', MUST_EXIST);
$value = (object)['course_id' => $course->id, 'item' => $item->id, 'completed' => $completedid, 'value' => $valuetext];
$DB->insert_record('feedback_valuetmp', $value);
feedback_save_tmp_values($completed);
// Set get_analysed() method accessibility.
$itemclass = feedback_get_item_class('textarea');
$reflection = new ReflectionClass($itemclass);
$method = $reflection->getMethod('get_analysed');
// Call the method and indicate it is being used for Excel.
$actual = $method->invoke(new $itemclass(), $item, false, $course->id, true);
// Check returned data maintains the line break.
$this->assertCount(1, $actual->data);
$datum = reset($actual->data);
$this->assertEquals($valuetext, $datum);
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,563 @@
<?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/>.
/**
* Data provider tests.
*
* @package mod_feedback
* @category test
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\privacy;
defined('MOODLE_INTERNAL') || die();
global $CFG;
use core_privacy\tests\provider_testcase;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
use mod_feedback\privacy\provider;
require_once($CFG->dirroot . '/mod/feedback/lib.php');
/**
* Data provider testcase class.
*
* @package mod_feedback
* @category test
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends provider_testcase {
public function setUp(): void {
$this->resetAfterTest();
}
/**
* Test getting the contexts for a user.
*/
public function test_get_contexts_for_userid(): void {
global $DB;
$dg = $this->getDataGenerator();
$fg = $dg->get_plugin_generator('mod_feedback');
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$cm0a = $dg->create_module('feedback', ['course' => SITEID]);
$cm1a = $dg->create_module('feedback', ['course' => $c1, 'anonymous' => FEEDBACK_ANONYMOUS_NO]);
$cm1b = $dg->create_module('feedback', ['course' => $c1]);
$cm2a = $dg->create_module('feedback', ['course' => $c2]);
$cm2b = $dg->create_module('feedback', ['course' => $c2]);
$cm2c = $dg->create_module('feedback', ['course' => $c2]);
$u1 = $dg->create_user();
$u2 = $dg->create_user();
foreach ([$cm0a, $cm1a, $cm1b, $cm2a] as $feedback) {
$i1 = $fg->create_item_numeric($feedback);
$i2 = $fg->create_item_multichoice($feedback);
$answers = ['numeric_' . $i1->id => '1', 'multichoice_' . $i2->id => [1]];
if ($feedback == $cm1b) {
$this->create_submission_with_answers($feedback, $u2, $answers);
} else {
$this->create_submission_with_answers($feedback, $u1, $answers);
}
}
// Unsaved submission for u1 in cm2b.
$feedback = $cm2b;
$i1 = $fg->create_item_numeric($feedback);
$i2 = $fg->create_item_multichoice($feedback);
$answers = ['numeric_' . $i1->id => '1', 'multichoice_' . $i2->id => [1]];
$this->create_tmp_submission_with_answers($feedback, $u1, $answers);
// Unsaved submission for u2 in cm2c.
$feedback = $cm2c;
$i1 = $fg->create_item_numeric($feedback);
$i2 = $fg->create_item_multichoice($feedback);
$answers = ['numeric_' . $i1->id => '1', 'multichoice_' . $i2->id => [1]];
$this->create_tmp_submission_with_answers($feedback, $u2, $answers);
$contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
$this->assertCount(4, $contextids);
$this->assertTrue(in_array(\context_module::instance($cm0a->cmid)->id, $contextids));
$this->assertTrue(in_array(\context_module::instance($cm1a->cmid)->id, $contextids));
$this->assertTrue(in_array(\context_module::instance($cm2a->cmid)->id, $contextids));
$this->assertFalse(in_array(\context_module::instance($cm1b->cmid)->id, $contextids));
$this->assertTrue(in_array(\context_module::instance($cm2b->cmid)->id, $contextids));
$this->assertFalse(in_array(\context_module::instance($cm2c->cmid)->id, $contextids));
$contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
$this->assertCount(2, $contextids);
$this->assertFalse(in_array(\context_module::instance($cm0a->cmid)->id, $contextids));
$this->assertFalse(in_array(\context_module::instance($cm1a->cmid)->id, $contextids));
$this->assertFalse(in_array(\context_module::instance($cm2a->cmid)->id, $contextids));
$this->assertTrue(in_array(\context_module::instance($cm1b->cmid)->id, $contextids));
$this->assertFalse(in_array(\context_module::instance($cm2b->cmid)->id, $contextids));
$this->assertTrue(in_array(\context_module::instance($cm2c->cmid)->id, $contextids));
}
/**
* Test getting the users in a context.
*/
public function test_get_users_in_context(): void {
global $DB;
$dg = $this->getDataGenerator();
$fg = $dg->get_plugin_generator('mod_feedback');
$component = 'mod_feedback';
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$cm0 = $dg->create_module('feedback', ['course' => SITEID]);
$cm1a = $dg->create_module('feedback', ['course' => $c1, 'anonymous' => FEEDBACK_ANONYMOUS_NO]);
$cm1b = $dg->create_module('feedback', ['course' => $c1]);
$cm2 = $dg->create_module('feedback', ['course' => $c2]);
$u1 = $dg->create_user();
$u2 = $dg->create_user();
foreach ([$cm0, $cm1a, $cm1b, $cm2] as $feedback) {
$i1 = $fg->create_item_numeric($feedback);
$i2 = $fg->create_item_multichoice($feedback);
$answers = ['numeric_' . $i1->id => '1', 'multichoice_' . $i2->id => [1]];
if ($feedback == $cm1b) {
$this->create_submission_with_answers($feedback, $u2, $answers);
} else {
$this->create_submission_with_answers($feedback, $u1, $answers);
}
}
// Unsaved submission for u2 in cm1a.
$feedback = $cm1a;
$i1 = $fg->create_item_numeric($feedback);
$i2 = $fg->create_item_multichoice($feedback);
$answers = ['numeric_' . $i1->id => '1', 'multichoice_' . $i2->id => [1]];
$this->create_tmp_submission_with_answers($feedback, $u2, $answers);
// Only u1 in cm0.
$context = \context_module::instance($cm0->cmid);
$userlist = new \core_privacy\local\request\userlist($context, $component);
provider::get_users_in_context($userlist);
$this->assertCount(1, $userlist);
$this->assertEquals([$u1->id], $userlist->get_userids());
$context = \context_module::instance($cm1a->cmid);
$userlist = new \core_privacy\local\request\userlist($context, $component);
provider::get_users_in_context($userlist);
// Two submissions in cm1a: saved for u1, unsaved for u2.
$this->assertCount(2, $userlist);
$expected = [$u1->id, $u2->id];
$actual = $userlist->get_userids();
sort($expected);
sort($actual);
$this->assertEquals($expected, $actual);
// Only u2 in cm1b.
$context = \context_module::instance($cm1b->cmid);
$userlist = new \core_privacy\local\request\userlist($context, $component);
provider::get_users_in_context($userlist);
$this->assertCount(1, $userlist);
$this->assertEquals([$u2->id], $userlist->get_userids());
// Only u1 in cm2.
$context = \context_module::instance($cm2->cmid);
$userlist = new \core_privacy\local\request\userlist($context, $component);
provider::get_users_in_context($userlist);
$this->assertCount(1, $userlist);
$this->assertEquals([$u1->id], $userlist->get_userids());
}
/**
* Test deleting user data.
*/
public function test_delete_data_for_user(): void {
global $DB;
$dg = $this->getDataGenerator();
$fg = $dg->get_plugin_generator('mod_feedback');
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$cm0a = $dg->create_module('feedback', ['course' => SITEID]);
$cm1a = $dg->create_module('feedback', ['course' => $c1, 'anonymous' => FEEDBACK_ANONYMOUS_NO]);
$cm2a = $dg->create_module('feedback', ['course' => $c2]);
$u1 = $dg->create_user();
$u2 = $dg->create_user();
// Create a bunch of data.
foreach ([$cm1a, $cm0a, $cm2a] as $feedback) {
$i1 = $fg->create_item_numeric($feedback);
$i2 = $fg->create_item_multichoice($feedback);
$answers = ['numeric_' . $i1->id => '1', 'multichoice_' . $i2->id => [1]];
// Create u2 user data for this module.
if ($feedback == $cm1a) {
$this->create_submission_with_answers($feedback, $u2, $answers);
$this->create_tmp_submission_with_answers($feedback, $u2, $answers);
}
$this->create_submission_with_answers($feedback, $u1, $answers);
$this->create_tmp_submission_with_answers($feedback, $u1, $answers);
}
$appctx = new approved_contextlist($u1, 'mod_feedback', [
\context_module::instance($cm0a->cmid)->id,
\context_module::instance($cm1a->cmid)->id
]);
provider::delete_data_for_user($appctx);
// Confirm all data is gone in those, except for u2.
foreach ([$cm0a, $cm1a] as $feedback) {
$this->assert_no_feedback_data_for_user($feedback, $u1);
if ($feedback == $cm1a) {
$this->assert_feedback_data_for_user($feedback, $u2);
$this->assert_feedback_tmp_data_for_user($feedback, $u2);
}
}
// Confirm cm2a wasn't affected.
$this->assert_feedback_data_for_user($cm2a, $u1);
$this->assert_feedback_tmp_data_for_user($cm2a, $u1);
}
/**
* Test deleting data within a context for an approved userlist.
*/
public function test_delete_data_for_users(): void {
global $DB;
$dg = $this->getDataGenerator();
$fg = $dg->get_plugin_generator('mod_feedback');
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$cm0 = $dg->create_module('feedback', ['course' => SITEID]);
$cm1 = $dg->create_module('feedback', ['course' => $c1, 'anonymous' => FEEDBACK_ANONYMOUS_NO]);
$cm2 = $dg->create_module('feedback', ['course' => $c2]);
$context0 = \context_module::instance($cm0->cmid);
$context1 = \context_module::instance($cm1->cmid);
$u1 = $dg->create_user();
$u2 = $dg->create_user();
// Create a bunch of data.
foreach ([$cm0, $cm1, $cm2] as $feedback) {
$i1 = $fg->create_item_numeric($feedback);
$i2 = $fg->create_item_multichoice($feedback);
$answers = ['numeric_' . $i1->id => '1', 'multichoice_' . $i2->id => [1]];
$this->create_submission_with_answers($feedback, $u1, $answers);
$this->create_tmp_submission_with_answers($feedback, $u1, $answers);
$this->create_submission_with_answers($feedback, $u2, $answers);
$this->create_tmp_submission_with_answers($feedback, $u2, $answers);
}
// Delete u1 from cm0, ensure u2 data is retained.
$approveduserlist = new approved_userlist($context0, 'mod_feedback', [$u1->id]);
provider::delete_data_for_users($approveduserlist);
$this->assert_no_feedback_data_for_user($cm0, $u1);
$this->assert_feedback_data_for_user($cm0, $u2);
$this->assert_feedback_tmp_data_for_user($cm0, $u2);
// Ensure cm1 unaffected by cm1 deletes.
$this->assert_feedback_data_for_user($cm1, $u1);
$this->assert_feedback_tmp_data_for_user($cm1, $u1);
$this->assert_feedback_data_for_user($cm1, $u2);
$this->assert_feedback_tmp_data_for_user($cm1, $u2);
// Delete u1 and u2 from cm1, ensure no data is retained.
$approveduserlist = new approved_userlist($context1, 'mod_feedback', [$u1->id, $u2->id]);
provider::delete_data_for_users($approveduserlist);
$this->assert_no_feedback_data_for_user($cm1, $u1);
$this->assert_no_feedback_data_for_user($cm1, $u2);
// Ensure cm2 is unaffected by any of the deletes.
$this->assert_feedback_data_for_user($cm2, $u1);
$this->assert_feedback_tmp_data_for_user($cm2, $u1);
$this->assert_feedback_data_for_user($cm2, $u2);
$this->assert_feedback_tmp_data_for_user($cm2, $u2);
}
/**
* Test deleting a whole context.
*/
public function test_delete_data_for_all_users_in_context(): void {
global $DB;
$dg = $this->getDataGenerator();
$fg = $dg->get_plugin_generator('mod_feedback');
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$cm0a = $dg->create_module('feedback', ['course' => SITEID]);
$cm1a = $dg->create_module('feedback', ['course' => $c1, 'anonymous' => FEEDBACK_ANONYMOUS_NO]);
$u1 = $dg->create_user();
$u2 = $dg->create_user();
// Create a bunch of data.
foreach ([$cm1a, $cm0a] as $feedback) {
$i1 = $fg->create_item_numeric($feedback);
$i2 = $fg->create_item_multichoice($feedback);
$answers = ['numeric_' . $i1->id => '1', 'multichoice_' . $i2->id => [1]];
$this->create_submission_with_answers($feedback, $u1, $answers);
$this->create_tmp_submission_with_answers($feedback, $u1, $answers);
$this->create_submission_with_answers($feedback, $u2, $answers);
$this->create_tmp_submission_with_answers($feedback, $u2, $answers);
}
provider::delete_data_for_all_users_in_context(\context_module::instance($cm1a->cmid));
$this->assert_no_feedback_data_for_user($cm1a, $u1);
$this->assert_no_feedback_data_for_user($cm1a, $u2);
$this->assert_feedback_data_for_user($cm0a, $u1);
$this->assert_feedback_data_for_user($cm0a, $u2);
$this->assert_feedback_tmp_data_for_user($cm0a, $u1);
$this->assert_feedback_tmp_data_for_user($cm0a, $u2);
}
/**
* Test exporting data.
*/
public function test_export_user_data(): void {
global $DB;
$dg = $this->getDataGenerator();
$fg = $dg->get_plugin_generator('mod_feedback');
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$cm0a = $dg->create_module('feedback', ['course' => SITEID]);
$cm1a = $dg->create_module('feedback', ['course' => $c1, 'anonymous' => FEEDBACK_ANONYMOUS_NO]);
$cm2a = $dg->create_module('feedback', ['course' => $c2, 'anonymous' => FEEDBACK_ANONYMOUS_YES, 'multiple_submit' => 1]);
$cm2b = $dg->create_module('feedback', ['course' => $c2]);
$cm2c = $dg->create_module('feedback', ['course' => $c2]);
$u1 = $dg->create_user();
$u2 = $dg->create_user();
// Create a bunch of data.
foreach ([$cm0a, $cm1a, $cm2a, $cm2b] as $feedback) {
$i1 = $fg->create_item_numeric($feedback, ['name' => 'Q1', 'label' => 'L1']);
$i2 = $fg->create_item_multichoice($feedback, ['name' => 'Q2', 'label' => 'L2']);
$answersu1 = ['numeric_' . $i1->id => '1', 'multichoice_' . $i2->id => [1]];
$answersu2 = ['numeric_' . $i1->id => '2', 'multichoice_' . $i2->id => [2]];
if ($cm0a == $feedback) {
$this->create_submission_with_answers($feedback, $u1, $answersu1);
$this->create_tmp_submission_with_answers($feedback, $u1, $answersu1);
} else if ($cm1a == $feedback) {
$this->create_tmp_submission_with_answers($feedback, $u1, $answersu1);
} else if ($cm2a == $feedback) {
$this->create_submission_with_answers($feedback, $u1, $answersu1);
$this->create_submission_with_answers($feedback, $u1, ['numeric_' . $i1->id => '1337'], 2);
} else if ($cm2c == $feedback) {
$this->create_submission_with_answers($feedback, $u1, $answersu1);
$this->create_tmp_submission_with_answers($feedback, $u1, $answersu1);
}
$this->create_submission_with_answers($feedback, $u2, $answersu2);
$this->create_tmp_submission_with_answers($feedback, $u2, $answersu2);
}
$appctx = new approved_contextlist($u1, 'mod_feedback', [
\context_module::instance($cm0a->cmid)->id,
\context_module::instance($cm1a->cmid)->id,
\context_module::instance($cm2a->cmid)->id,
\context_module::instance($cm2b->cmid)->id,
]);
provider::export_user_data($appctx);
// CM0A.
$data = writer::with_context(\context_module::instance($cm0a->cmid))->get_data();
$this->assertCount(2, $data->submissions);
$submission = $data->submissions[0];
$this->assertEquals(transform::yesno(false), $submission['inprogress']);
$this->assertEquals(transform::yesno(true), $submission['anonymousresponse']);
$this->assertCount(2, $submission['answers']);
$this->assertEquals('Q1', $submission['answers'][0]['question']);
$this->assertEquals('1', $submission['answers'][0]['answer']);
$this->assertEquals('Q2', $submission['answers'][1]['question']);
$this->assertEquals('a', $submission['answers'][1]['answer']);
$submission = $data->submissions[1];
$this->assertEquals(transform::yesno(true), $submission['inprogress']);
$this->assertEquals(transform::yesno(true), $submission['anonymousresponse']);
$this->assertCount(2, $submission['answers']);
$this->assertEquals('Q1', $submission['answers'][0]['question']);
$this->assertEquals('1', $submission['answers'][0]['answer']);
$this->assertEquals('Q2', $submission['answers'][1]['question']);
$this->assertEquals('a', $submission['answers'][1]['answer']);
// CM1A.
$data = writer::with_context(\context_module::instance($cm1a->cmid))->get_data();
$this->assertCount(1, $data->submissions);
$submission = $data->submissions[0];
$this->assertEquals(transform::yesno(true), $submission['inprogress']);
$this->assertEquals(transform::yesno(false), $submission['anonymousresponse']);
$this->assertCount(2, $submission['answers']);
$this->assertEquals('Q1', $submission['answers'][0]['question']);
$this->assertEquals('1', $submission['answers'][0]['answer']);
$this->assertEquals('Q2', $submission['answers'][1]['question']);
$this->assertEquals('a', $submission['answers'][1]['answer']);
// CM2A.
$data = writer::with_context(\context_module::instance($cm2a->cmid))->get_data();
$this->assertCount(2, $data->submissions);
$submission = $data->submissions[0];
$this->assertEquals(transform::yesno(false), $submission['inprogress']);
$this->assertEquals(transform::yesno(true), $submission['anonymousresponse']);
$this->assertCount(2, $submission['answers']);
$this->assertEquals('Q1', $submission['answers'][0]['question']);
$this->assertEquals('1', $submission['answers'][0]['answer']);
$this->assertEquals('Q2', $submission['answers'][1]['question']);
$this->assertEquals('a', $submission['answers'][1]['answer']);
$submission = $data->submissions[1];
$this->assertEquals(transform::yesno(false), $submission['inprogress']);
$this->assertEquals(transform::yesno(true), $submission['anonymousresponse']);
$this->assertCount(1, $submission['answers']);
$this->assertEquals('Q1', $submission['answers'][0]['question']);
$this->assertEquals('1337', $submission['answers'][0]['answer']);
// CM2B (no data).
$data = writer::with_context(\context_module::instance($cm2b->cmid))->get_data();
$this->assertEmpty($data);
// CM2C (not exported).
$data = writer::with_context(\context_module::instance($cm2b->cmid))->get_data();
$this->assertEmpty($data);
}
/**
* Assert there is no feedback data for a user.
*
* @param object $feedback The feedback.
* @param object $user The user.
* @return void
*/
protected function assert_no_feedback_data_for_user($feedback, $user) {
global $DB;
$this->assertFalse($DB->record_exists('feedback_completed', ['feedback' => $feedback->id, 'userid' => $user->id]));
$this->assertFalse($DB->record_exists('feedback_completedtmp', ['feedback' => $feedback->id, 'userid' => $user->id]));
// Check that there aren't orphan values because we can't check by userid.
$sql = "
SELECT fv.id
FROM {%s} fv
LEFT JOIN {%s} fc
ON fc.id = fv.completed
WHERE fc.id IS NULL";
$this->assertFalse($DB->record_exists_sql(sprintf($sql, 'feedback_value', 'feedback_completed'), []));
$this->assertFalse($DB->record_exists_sql(sprintf($sql, 'feedback_valuetmp', 'feedback_completedtmp'), []));
}
/**
* Assert there are submissions and answers for user.
*
* @param object $feedback The feedback.
* @param object $user The user.
* @param int $submissioncount The number of submissions.
* @param int $valuecount The number of values per submission.
* @return void
*/
protected function assert_feedback_data_for_user($feedback, $user, $submissioncount = 1, $valuecount = 2) {
global $DB;
$completeds = $DB->get_records('feedback_completed', ['feedback' => $feedback->id, 'userid' => $user->id]);
$this->assertCount($submissioncount, $completeds);
foreach ($completeds as $record) {
$this->assertEquals($valuecount, $DB->count_records('feedback_value', ['completed' => $record->id]));
}
}
/**
* Assert there are temporary submissions and answers for user.
*
* @param object $feedback The feedback.
* @param object $user The user.
* @param int $submissioncount The number of submissions.
* @param int $valuecount The number of values per submission.
* @return void
*/
protected function assert_feedback_tmp_data_for_user($feedback, $user, $submissioncount = 1, $valuecount = 2) {
global $DB;
$completedtmps = $DB->get_records('feedback_completedtmp', ['feedback' => $feedback->id, 'userid' => $user->id]);
$this->assertCount($submissioncount, $completedtmps);
foreach ($completedtmps as $record) {
$this->assertEquals($valuecount, $DB->count_records('feedback_valuetmp', ['completed' => $record->id]));
}
}
/**
* Create an submission with answers.
*
* @param object $feedback The feedback.
* @param object $user The user.
* @param array $answers Answers.
* @param int $submissioncount The number of submissions expected after this entry.
* @return void
*/
protected function create_submission_with_answers($feedback, $user, $answers, $submissioncount = 1) {
global $DB;
$modinfo = get_fast_modinfo($feedback->course);
$cm = $modinfo->get_cm($feedback->cmid);
$feedbackcompletion = new \mod_feedback_completion($feedback, $cm, $feedback->course, false, null, null, $user->id);
$feedbackcompletion->save_response_tmp((object) $answers);
$feedbackcompletion->save_response();
$this->assertEquals($submissioncount, $DB->count_records('feedback_completed', ['feedback' => $feedback->id,
'userid' => $user->id]));
$this->assertEquals(count($answers), $DB->count_records('feedback_value', [
'completed' => $feedbackcompletion->get_completed()->id]));
}
/**
* Create a temporary submission with answers.
*
* @param object $feedback The feedback.
* @param object $user The user.
* @param array $answers Answers.
* @return void
*/
protected function create_tmp_submission_with_answers($feedback, $user, $answers) {
global $DB;
$modinfo = get_fast_modinfo($feedback->course);
$cm = $modinfo->get_cm($feedback->cmid);
$feedbackcompletion = new \mod_feedback_completion($feedback, $cm, $feedback->course, false, null, null, $user->id);
$feedbackcompletion->save_response_tmp((object) $answers);
$this->assertEquals(1, $DB->count_records('feedback_completedtmp', ['feedback' => $feedback->id, 'userid' => $user->id]));
$this->assertEquals(2, $DB->count_records('feedback_valuetmp', [
'completed' => $feedbackcompletion->get_current_completed_tmp()->id]));
}
}