Merge branch 'MDL-40493-master-fix1' of git://github.com/damyon/moodle
[moodle.git] / question / type / essay / tests / walkthrough_test.php
CommitLineData
c0d12fc1
TH
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/>.
16
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 */
24
25
26defined('MOODLE_INTERNAL') || die();
27
28global $CFG;
29require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
30
31
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 */
afb1b3d0 38class qtype_essay_walkthrough_testcase extends qbehaviour_walkthrough_test_base {
c0d12fc1
TH
39
40 protected function check_contains_textarea($name, $content = '', $height = 10) {
41 $fieldname = $this->quba->get_field_prefix($this->slot) . $name;
42
43 $this->assertTag(array('tag' => 'textarea',
44 'attributes' => array('cols' => '60', 'rows' => $height,
45 'name' => $fieldname)),
46 $this->currentoutput);
47
48 if ($content) {
49 $this->assertRegExp('/' . preg_quote(s($content), '/') . '/', $this->currentoutput);
50 }
51 }
52
afb1b3d0
TH
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();
64
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 }
74
c0d12fc1
TH
75 public function test_deferred_feedback_html_editor() {
76
6e4dcb9a 77 // The current text editor depends on the users profile setting - so it needs a valid user.
c9697538
PS
78 $this->setAdminUser();
79
60527d0c 80 // Create an essay question.
c0d12fc1
TH
81 $q = test_question_maker::make_question('essay', 'editor');
82 $this->start_attempt_at_question($q, 'deferredfeedback', 1);
83
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>';
87
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);
97
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 ));
105
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);
116
117 // Finish the attempt.
118 $this->quba->finish_all_questions();
119
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 }
129
130 public function test_deferred_feedback_plain_text() {
131
60527d0c 132 // Create an essay question.
c0d12fc1
TH
133 $q = test_question_maker::make_question('essay', 'plain');
134 $this->start_attempt_at_question($q, 'deferredfeedback', 1);
135
136 $prefix = $this->quba->get_field_prefix($this->slot);
137 $fieldname = $prefix . 'answer';
138 $response = "x < 1\nx > 0\nFrog & Toad were friends.";
139
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);
149
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 ));
157
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);
168
169 // Finish the attempt.
170 $this->quba->finish_all_questions();
171
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 }
60527d0c
JMV
181
182 public function test_responsetemplate() {
183
6e4dcb9a 184 // The current text editor depends on the users profile setting - so it needs a valid user.
c9697538
PS
185 $this->setAdminUser();
186
60527d0c
JMV
187 // Create an essay question.
188 $q = test_question_maker::make_question('essay', 'responsetemplate');
189 $this->start_attempt_at_question($q, 'deferredfeedback', 1);
190
191 $prefix = $this->quba->get_field_prefix($this->slot);
192 $fieldname = $prefix . 'answer';
193
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);
203
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 ));
211
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);
222
223 // Finish the attempt.
224 $this->quba->finish_all_questions();
225
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 }
afb1b3d0
TH
235
236 public function test_deferred_feedback_html_editor_with_files_attempt_on_last() {
237 global $CFG, $USER;
238
239 $this->resetAfterTest(true);
240 $this->setAdminUser();
241 $usercontextid = context_user::instance($USER->id)->id;
242 $fs = get_file_storage();
243
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));
248
249 // Start attempt at the question.
250 $q = question_bank::load_question($question->id);
251 $this->start_attempt_at_question($q, 'deferredfeedback', 1);
252
253 $this->check_current_state(question_state::$todo);
254 $this->check_current_mark(null);
255 $this->check_step_count(1);
256
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];
268
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));
278
279 $this->check_current_state(question_state::$complete);
280 $this->check_current_mark(null);
281 $this->check_step_count(2);
282 $this->save_quba();
283
284 // Save the same response again, and verify no new step is created.
285 $this->load_quba();
286
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];
296
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));
304
305 $this->check_current_state(question_state::$complete);
306 $this->check_current_mark(null);
307 $this->check_step_count(2);
308
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();
315
316 // Now start a new attempt based on the old one.
317 $this->load_quba();
318 $oldqa = $this->get_question_attempt();
319
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);
326
327 $this->check_current_state(question_state::$complete);
328 $this->check_current_mark(null);
329 $this->check_step_count(1);
330 $this->save_quba();
331
332 // Now save the same response again, and ensure that a new step is not created.
333 $this->load_quba();
334
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];
344
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));
352
353 $this->check_current_state(question_state::$complete);
354 $this->check_current_mark(null);
355 $this->check_step_count(1);
356 }
d629327a
TH
357
358 public function test_deferred_feedback_html_editor_with_files_attempt_on_last_no_files_uploaded() {
359 global $CFG, $USER;
360
361 $this->resetAfterTest(true);
362 $this->setAdminUser();
363 $usercontextid = context_user::instance($USER->id)->id;
364 $fs = get_file_storage();
365
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));
370
371 // Start attempt at the question.
372 $q = question_bank::load_question($question->id);
373 $this->start_attempt_at_question($q, 'deferredfeedback', 1);
374
375 $this->check_current_state(question_state::$todo);
376 $this->check_current_mark(null);
377 $this->check_step_count(1);
378
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];
390
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));
396
397 $this->check_current_state(question_state::$complete);
398 $this->check_current_mark(null);
399 $this->check_step_count(2);
400 $this->save_quba();
401
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();
408
409 // Now start a new attempt based on the old one.
410 $this->load_quba();
411 $oldqa = $this->get_question_attempt();
412
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);
419
420 $this->check_current_state(question_state::$complete);
421 $this->check_current_mark(null);
422 $this->check_step_count(1);
423 $this->save_quba();
424
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 }
c0d12fc1 430}