MDL-40493 Question: Explain why setAdminUser is needed for tests
[moodle.git] / question / type / essay / tests / walkthrough_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * This file contains tests that walks essay questions through some attempts.
19  *
20  * @package   qtype_essay
21  * @copyright 2013 The Open University
22  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
32 /**
33  * Unit tests for the essay question type.
34  *
35  * @copyright 2013 The Open University
36  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37  */
38 class qtype_essay_walkthrough_testcase extends qbehaviour_walkthrough_test_base {
40     protected function check_contains_textarea($name, $content = '', $height = 10) {
41         $fieldname = $this->quba->get_field_prefix($this->slot) . $name;
43         $this->assertTag(array('tag' => 'textarea',
44                 'attributes' => array('cols' => '60', 'rows' => $height,
45                         'name' => $fieldname)),
46                 $this->currentoutput);
48         if ($content) {
49             $this->assertRegExp('/' . preg_quote(s($content), '/') . '/', $this->currentoutput);
50         }
51     }
53     /**
54      * Helper method: Store a test file with a given name and contents in a
55      * draft file area.
56      *
57      * @param int $usercontextid user context id.
58      * @param int $draftitemid draft item id.
59      * @param string $filename filename.
60      * @param string $contents file contents.
61      */
62     protected function save_file_to_draft_area($usercontextid, $draftitemid, $filename, $contents) {
63         $fs = get_file_storage();
65         $filerecord = new stdClass();
66         $filerecord->contextid = $usercontextid;
67         $filerecord->component = 'user';
68         $filerecord->filearea = 'draft';
69         $filerecord->itemid = $draftitemid;
70         $filerecord->filepath = '/';
71         $filerecord->filename = $filename;
72         $fs->create_file_from_string($filerecord, $contents);
73     }
75     public function test_deferred_feedback_html_editor() {
77         // The current text editor depends on the users profile setting - so it needs a valid user.
78         $this->setAdminUser();
80         // Create an essay question.
81         $q = test_question_maker::make_question('essay', 'editor');
82         $this->start_attempt_at_question($q, 'deferredfeedback', 1);
84         $prefix = $this->quba->get_field_prefix($this->slot);
85         $fieldname = $prefix . 'answer';
86         $response = '<p>The <b>cat</b> sat on the mat. Then it ate a <b>frog</b>.</p>';
88         // Check the initial state.
89         $this->check_current_state(question_state::$todo);
90         $this->check_current_mark(null);
91         $this->render();
92         $this->check_contains_textarea('answer', '');
93         $this->check_current_output(
94                 $this->get_contains_question_text_expectation($q),
95                 $this->get_does_not_contain_feedback_expectation());
96         $this->check_step_count(1);
98         // Save a response.
99         $this->quba->process_all_actions(null, array(
100             'slots'                    => $this->slot,
101             $fieldname                 => $response,
102             $fieldname . 'format'      => FORMAT_HTML,
103             $prefix . ':sequencecheck' => '1',
104         ));
106         // Verify.
107         $this->check_current_state(question_state::$complete);
108         $this->check_current_mark(null);
109         $this->check_step_count(2);
110         $this->render();
111         $this->check_contains_textarea('answer', $response);
112         $this->check_current_output(
113                 $this->get_contains_question_text_expectation($q),
114                 $this->get_does_not_contain_feedback_expectation());
115         $this->check_step_count(2);
117         // Finish the attempt.
118         $this->quba->finish_all_questions();
120         // Verify.
121         $this->check_current_state(question_state::$needsgrading);
122         $this->check_current_mark(null);
123         $this->render();
124         $this->assertRegExp('/' . preg_quote($response, '/') . '/', $this->currentoutput);
125         $this->check_current_output(
126                 $this->get_contains_question_text_expectation($q),
127                 $this->get_contains_general_feedback_expectation($q));
128     }
130     public function test_deferred_feedback_plain_text() {
132         // Create an essay question.
133         $q = test_question_maker::make_question('essay', 'plain');
134         $this->start_attempt_at_question($q, 'deferredfeedback', 1);
136         $prefix = $this->quba->get_field_prefix($this->slot);
137         $fieldname = $prefix . 'answer';
138         $response = "x < 1\nx > 0\nFrog & Toad were friends.";
140         // Check the initial state.
141         $this->check_current_state(question_state::$todo);
142         $this->check_current_mark(null);
143         $this->render();
144         $this->check_contains_textarea('answer', '');
145         $this->check_current_output(
146                 $this->get_contains_question_text_expectation($q),
147                 $this->get_does_not_contain_feedback_expectation());
148         $this->check_step_count(1);
150         // Save a response.
151         $this->quba->process_all_actions(null, array(
152             'slots'                    => $this->slot,
153             $fieldname                 => $response,
154             $fieldname . 'format'      => FORMAT_HTML,
155             $prefix . ':sequencecheck' => '1',
156         ));
158         // Verify.
159         $this->check_current_state(question_state::$complete);
160         $this->check_current_mark(null);
161         $this->check_step_count(2);
162         $this->render();
163         $this->check_contains_textarea('answer', $response);
164         $this->check_current_output(
165                 $this->get_contains_question_text_expectation($q),
166                 $this->get_does_not_contain_feedback_expectation());
167         $this->check_step_count(2);
169         // Finish the attempt.
170         $this->quba->finish_all_questions();
172         // Verify.
173         $this->check_current_state(question_state::$needsgrading);
174         $this->check_current_mark(null);
175         $this->render();
176         $this->assertRegExp('/' . preg_quote(s($response), '/') . '/', $this->currentoutput);
177         $this->check_current_output(
178                 $this->get_contains_question_text_expectation($q),
179                 $this->get_contains_general_feedback_expectation($q));
180     }
182     public function test_responsetemplate() {
184         // The current text editor depends on the users profile setting - so it needs a valid user.
185         $this->setAdminUser();
187         // Create an essay question.
188         $q = test_question_maker::make_question('essay', 'responsetemplate');
189         $this->start_attempt_at_question($q, 'deferredfeedback', 1);
191         $prefix = $this->quba->get_field_prefix($this->slot);
192         $fieldname = $prefix . 'answer';
194         // Check the initial state.
195         $this->check_current_state(question_state::$todo);
196         $this->check_current_mark(null);
197         $this->render();
198         $this->check_contains_textarea('answer', 'Once upon a time');
199         $this->check_current_output(
200                 $this->get_contains_question_text_expectation($q),
201                 $this->get_does_not_contain_feedback_expectation());
202         $this->check_step_count(1);
204         // Save.
205         $this->quba->process_all_actions(null, array(
206             'slots'                    => $this->slot,
207             $fieldname                 => 'Once upon a time there was a little green frog.',
208             $fieldname . 'format'      => FORMAT_HTML,
209             $prefix . ':sequencecheck' => '1',
210         ));
212         // Verify.
213         $this->check_current_state(question_state::$complete);
214         $this->check_current_mark(null);
215         $this->check_step_count(2);
216         $this->render();
217         $this->check_contains_textarea('answer', 'Once upon a time there was a little green frog.');
218         $this->check_current_output(
219                 $this->get_contains_question_text_expectation($q),
220                 $this->get_does_not_contain_feedback_expectation());
221         $this->check_step_count(2);
223         // Finish the attempt.
224         $this->quba->finish_all_questions();
226         // Verify.
227         $this->check_current_state(question_state::$needsgrading);
228         $this->check_current_mark(null);
229         $this->render();
230         $this->assertRegExp('/' . preg_quote(s('Once upon a time there was a little green frog.'), '/') . '/', $this->currentoutput);
231         $this->check_current_output(
232                 $this->get_contains_question_text_expectation($q),
233                 $this->get_contains_general_feedback_expectation($q));
234     }
236     public function test_deferred_feedback_html_editor_with_files_attempt_on_last() {
237         global $CFG, $USER;
239         $this->resetAfterTest(true);
240         $this->setAdminUser();
241         $usercontextid = context_user::instance($USER->id)->id;
242         $fs = get_file_storage();
244         // Create an essay question in the DB.
245         $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
246         $cat = $generator->create_question_category();
247         $question = $generator->create_question('essay', 'editorfilepicker', array('category' => $cat->id));
249         // Start attempt at the question.
250         $q = question_bank::load_question($question->id);
251         $this->start_attempt_at_question($q, 'deferredfeedback', 1);
253         $this->check_current_state(question_state::$todo);
254         $this->check_current_mark(null);
255         $this->check_step_count(1);
257         // Process a response and check the expected result.
258         // First we need to get the draft item ids.
259         $this->render();
260         if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
261             throw new coding_exception('Editor draft item id not found.');
262         }
263         $editordraftid = $matches[1];
264         if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
265             throw new coding_exception('File manager draft item id not found.');
266         }
267         $attachementsdraftid = $matches[1];
269         $this->save_file_to_draft_area($usercontextid, $editordraftid, 'smile.txt', ':-)');
270         $this->save_file_to_draft_area($usercontextid, $attachementsdraftid, 'greeting.txt', 'Hello world!');
271         $this->process_submission(array(
272                 'answer' => 'Here is a picture: <img src="' . $CFG->wwwroot .
273                                 "/draftfile.php/{$usercontextid}/user/draft/{$editordraftid}/smile.txt" .
274                                 '" alt="smile">.',
275                 'answerformat' => FORMAT_HTML,
276                 'answer:itemid' => $editordraftid,
277                 'attachments' => $attachementsdraftid));
279         $this->check_current_state(question_state::$complete);
280         $this->check_current_mark(null);
281         $this->check_step_count(2);
282         $this->save_quba();
284         // Save the same response again, and verify no new step is created.
285         $this->load_quba();
287         $this->render();
288         if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
289             throw new coding_exception('Editor draft item id not found.');
290         }
291         $editordraftid = $matches[1];
292         if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
293             throw new coding_exception('File manager draft item id not found.');
294         }
295         $attachementsdraftid = $matches[1];
297         $this->process_submission(array(
298                 'answer' => 'Here is a picture: <img src="' . $CFG->wwwroot .
299                                 "/draftfile.php/{$usercontextid}/user/draft/{$editordraftid}/smile.txt" .
300                                 '" alt="smile">.',
301                 'answerformat' => FORMAT_HTML,
302                 'answer:itemid' => $editordraftid,
303                 'attachments' => $attachementsdraftid));
305         $this->check_current_state(question_state::$complete);
306         $this->check_current_mark(null);
307         $this->check_step_count(2);
309         // Now submit all and finish.
310         $this->finish();
311         $this->check_current_state(question_state::$needsgrading);
312         $this->check_current_mark(null);
313         $this->check_step_count(3);
314         $this->save_quba();
316         // Now start a new attempt based on the old one.
317         $this->load_quba();
318         $oldqa = $this->get_question_attempt();
320         $q = question_bank::load_question($question->id);
321         $this->quba = question_engine::make_questions_usage_by_activity('unit_test',
322                 context_system::instance());
323         $this->quba->set_preferred_behaviour('deferredfeedback');
324         $this->slot = $this->quba->add_question($q, 1);
325         $this->quba->start_question_based_on($this->slot, $oldqa);
327         $this->check_current_state(question_state::$complete);
328         $this->check_current_mark(null);
329         $this->check_step_count(1);
330         $this->save_quba();
332         // Now save the same response again, and ensure that a new step is not created.
333         $this->load_quba();
335         $this->render();
336         if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
337             throw new coding_exception('Editor draft item id not found.');
338         }
339         $editordraftid = $matches[1];
340         if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
341             throw new coding_exception('File manager draft item id not found.');
342         }
343         $attachementsdraftid = $matches[1];
345         $this->process_submission(array(
346                 'answer' => 'Here is a picture: <img src="' . $CFG->wwwroot .
347                                 "/draftfile.php/{$usercontextid}/user/draft/{$editordraftid}/smile.txt" .
348                                 '" alt="smile">.',
349                 'answerformat' => FORMAT_HTML,
350                 'answer:itemid' => $editordraftid,
351                 'attachments' => $attachementsdraftid));
353         $this->check_current_state(question_state::$complete);
354         $this->check_current_mark(null);
355         $this->check_step_count(1);
356     }
358     public function test_deferred_feedback_html_editor_with_files_attempt_on_last_no_files_uploaded() {
359         global $CFG, $USER;
361         $this->resetAfterTest(true);
362         $this->setAdminUser();
363         $usercontextid = context_user::instance($USER->id)->id;
364         $fs = get_file_storage();
366         // Create an essay question in the DB.
367         $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
368         $cat = $generator->create_question_category();
369         $question = $generator->create_question('essay', 'editorfilepicker', array('category' => $cat->id));
371         // Start attempt at the question.
372         $q = question_bank::load_question($question->id);
373         $this->start_attempt_at_question($q, 'deferredfeedback', 1);
375         $this->check_current_state(question_state::$todo);
376         $this->check_current_mark(null);
377         $this->check_step_count(1);
379         // Process a response and check the expected result.
380         // First we need to get the draft item ids.
381         $this->render();
382         if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
383             throw new coding_exception('Editor draft item id not found.');
384         }
385         $editordraftid = $matches[1];
386         if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
387             throw new coding_exception('File manager draft item id not found.');
388         }
389         $attachementsdraftid = $matches[1];
391         $this->process_submission(array(
392                 'answer' => 'I refuse to draw you a picture, so there!',
393                 'answerformat' => FORMAT_HTML,
394                 'answer:itemid' => $editordraftid,
395                 'attachments' => $attachementsdraftid));
397         $this->check_current_state(question_state::$complete);
398         $this->check_current_mark(null);
399         $this->check_step_count(2);
400         $this->save_quba();
402         // Now submit all and finish.
403         $this->finish();
404         $this->check_current_state(question_state::$needsgrading);
405         $this->check_current_mark(null);
406         $this->check_step_count(3);
407         $this->save_quba();
409         // Now start a new attempt based on the old one.
410         $this->load_quba();
411         $oldqa = $this->get_question_attempt();
413         $q = question_bank::load_question($question->id);
414         $this->quba = question_engine::make_questions_usage_by_activity('unit_test',
415                 context_system::instance());
416         $this->quba->set_preferred_behaviour('deferredfeedback');
417         $this->slot = $this->quba->add_question($q, 1);
418         $this->quba->start_question_based_on($this->slot, $oldqa);
420         $this->check_current_state(question_state::$complete);
421         $this->check_current_mark(null);
422         $this->check_step_count(1);
423         $this->save_quba();
425         // Check the display.
426         $this->load_quba();
427         $this->render();
428         $this->assertRegExp('/I refuse to draw you a picture, so there!/', $this->currentoutput);
429     }