Proyectos de Subversion Moodle

Rev

Rev 11 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
namespace qtype_essay;
18
 
19
use question_bank;
20
use question_engine;
21
use question_state;
22
 
23
defined('MOODLE_INTERNAL') || die();
24
 
25
global $CFG;
26
require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
27
 
28
/**
29
 * Unit tests for the essay question type.
30
 *
31
 * @package   qtype_essay
32
 * @copyright 2013 The Open University
33
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34
 */
1441 ariadna 35
final class walkthrough_test extends \qbehaviour_walkthrough_test_base {
1 efrain 36
 
37
    protected function check_contains_textarea($name, $content = '', $height = 10) {
38
        $fieldname = $this->quba->get_field_prefix($this->slot) . $name;
39
 
40
        $this->assertTag(array('tag' => 'textarea',
41
                'attributes' => array('cols' => '60', 'rows' => $height,
42
                        'name' => $fieldname)),
43
                $this->currentoutput);
44
 
45
        if ($content) {
46
            $this->assertMatchesRegularExpression('/' . preg_quote(s($content), '/') . '/', $this->currentoutput);
47
        }
48
    }
49
 
50
    /**
51
     * Helper method: Store a test file with a given name and contents in a
52
     * draft file area.
53
     *
54
     * @param int $usercontextid user context id.
55
     * @param int $draftitemid draft item id.
56
     * @param string $filename filename.
57
     * @param string $contents file contents.
58
     */
59
    protected function save_file_to_draft_area($usercontextid, $draftitemid, $filename, $contents) {
60
        $fs = get_file_storage();
61
 
62
        $filerecord = new \stdClass();
63
        $filerecord->contextid = $usercontextid;
64
        $filerecord->component = 'user';
65
        $filerecord->filearea = 'draft';
66
        $filerecord->itemid = $draftitemid;
67
        $filerecord->filepath = '/';
68
        $filerecord->filename = $filename;
69
        $fs->create_file_from_string($filerecord, $contents);
70
    }
71
 
11 efrain 72
    public function test_deferred_feedback_html_editor(): void {
1 efrain 73
        global $PAGE;
74
 
75
        // The current text editor depends on the users profile setting - so it needs a valid user.
76
        $this->setAdminUser();
77
        // Required to init a text editor.
78
        $PAGE->set_url('/');
79
 
80
        // Create an essay question.
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->assertMatchesRegularExpression('/' . 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
 
11 efrain 130
    public function test_deferred_feedback_plain_text(): void {
1 efrain 131
 
132
        // Create an essay question.
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->assertMatchesRegularExpression('/' . 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
    }
181
 
11 efrain 182
    public function test_responsetemplate(): void {
1 efrain 183
        global $PAGE;
184
 
185
        // The current text editor depends on the users profile setting - so it needs a valid user.
186
        $this->setAdminUser();
187
        // Required to init a text editor.
188
        $PAGE->set_url('/');
189
 
190
        // Create an essay question.
191
        $q = \test_question_maker::make_question('essay', 'responsetemplate');
192
        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
193
 
194
        $prefix = $this->quba->get_field_prefix($this->slot);
195
        $fieldname = $prefix . 'answer';
196
 
197
        // Check the initial state.
198
        $this->check_current_state(question_state::$todo);
199
        $this->check_current_mark(null);
200
        $this->render();
201
        $this->check_contains_textarea('answer', 'Once upon a time');
202
        $this->check_current_output(
203
                $this->get_contains_question_text_expectation($q),
204
                $this->get_does_not_contain_feedback_expectation());
205
        $this->check_step_count(1);
206
 
207
        // Save.
208
        $this->quba->process_all_actions(null, array(
209
            'slots'                    => $this->slot,
210
            $fieldname                 => 'Once upon a time there was a little green frog.',
211
            $fieldname . 'format'      => FORMAT_HTML,
212
            $prefix . ':sequencecheck' => '1',
213
        ));
214
 
215
        // Verify.
216
        $this->check_current_state(question_state::$complete);
217
        $this->check_current_mark(null);
218
        $this->check_step_count(2);
219
        $this->render();
220
        $this->check_contains_textarea('answer', 'Once upon a time there was a little green frog.');
221
        $this->check_current_output(
222
                $this->get_contains_question_text_expectation($q),
223
                $this->get_does_not_contain_feedback_expectation());
224
        $this->check_step_count(2);
225
 
226
        // Finish the attempt.
227
        $this->quba->finish_all_questions();
228
 
229
        // Verify.
230
        $this->check_current_state(question_state::$needsgrading);
231
        $this->check_current_mark(null);
232
        $this->render();
233
        $this->assertMatchesRegularExpression(
234
            '/' . preg_quote(s('Once upon a time there was a little green frog.'), '/') . '/', $this->currentoutput);
235
        $this->check_current_output(
236
                $this->get_contains_question_text_expectation($q),
237
                $this->get_contains_general_feedback_expectation($q));
238
    }
239
 
11 efrain 240
    public function test_deferred_feedback_html_editor_with_files_attempt_on_last(): void {
1 efrain 241
        global $CFG, $USER, $PAGE;
242
 
243
        $this->resetAfterTest(true);
244
        $this->setAdminUser();
245
        // Required to init a text editor.
246
        $PAGE->set_url('/');
247
        $usercontextid = \context_user::instance($USER->id)->id;
248
        $fs = get_file_storage();
249
 
250
        // Create an essay question in the DB.
251
        $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
252
        $cat = $generator->create_question_category();
253
        $question = $generator->create_question('essay', 'editorfilepicker', array('category' => $cat->id));
254
 
255
        // Start attempt at the question.
256
        $q = question_bank::load_question($question->id);
257
        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
258
 
259
        $this->check_current_state(question_state::$todo);
260
        $this->check_current_mark(null);
261
        $this->check_step_count(1);
262
 
263
        // Process a response and check the expected result.
264
        // First we need to get the draft item ids.
265
        $this->render();
266
        if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
267
            throw new \coding_exception('Editor draft item id not found.');
268
        }
269
        $editordraftid = $matches[1];
270
        if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
271
            throw new \coding_exception('File manager draft item id not found.');
272
        }
273
        $attachementsdraftid = $matches[1];
274
 
275
        $this->save_file_to_draft_area($usercontextid, $editordraftid, 'smile.txt', ':-)');
276
        $this->save_file_to_draft_area($usercontextid, $attachementsdraftid, 'greeting.txt', 'Hello world!');
277
        $this->process_submission(array(
278
                'answer' => 'Here is a picture: <img src="' . $CFG->wwwroot .
279
                                "/draftfile.php/{$usercontextid}/user/draft/{$editordraftid}/smile.txt" .
280
                                '" alt="smile">.',
281
                'answerformat' => FORMAT_HTML,
282
                'answer:itemid' => $editordraftid,
283
                'attachments' => $attachementsdraftid));
284
 
285
        $this->check_current_state(question_state::$complete);
286
        $this->check_current_mark(null);
287
        $this->check_step_count(2);
288
        $this->save_quba();
289
 
290
        // Save the same response again, and verify no new step is created.
291
        $this->load_quba();
292
 
293
        $this->render();
294
        if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
295
            throw new \coding_exception('Editor draft item id not found.');
296
        }
297
        $editordraftid = $matches[1];
298
        if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
299
            throw new \coding_exception('File manager draft item id not found.');
300
        }
301
        $attachementsdraftid = $matches[1];
302
 
303
        $this->process_submission(array(
304
                'answer' => 'Here is a picture: <img src="' . $CFG->wwwroot .
305
                                "/draftfile.php/{$usercontextid}/user/draft/{$editordraftid}/smile.txt" .
306
                                '" alt="smile">.',
307
                'answerformat' => FORMAT_HTML,
308
                'answer:itemid' => $editordraftid,
309
                'attachments' => $attachementsdraftid));
310
 
311
        $this->check_current_state(question_state::$complete);
312
        $this->check_current_mark(null);
313
        $this->check_step_count(2);
314
 
315
        // Now submit all and finish.
316
        $this->finish();
317
        $this->check_current_state(question_state::$needsgrading);
318
        $this->check_current_mark(null);
319
        $this->check_step_count(3);
320
        $this->save_quba();
321
 
322
        // Now start a new attempt based on the old one.
323
        $this->load_quba();
324
        $oldqa = $this->get_question_attempt();
325
 
326
        $q = question_bank::load_question($question->id);
327
        $this->quba = question_engine::make_questions_usage_by_activity('unit_test',
328
                \context_system::instance());
329
        $this->quba->set_preferred_behaviour('deferredfeedback');
330
        $this->slot = $this->quba->add_question($q, 1);
331
        $this->quba->start_question_based_on($this->slot, $oldqa);
332
 
333
        $this->check_current_state(question_state::$complete);
334
        $this->check_current_mark(null);
335
        $this->check_step_count(1);
336
        $this->save_quba();
337
 
338
        // Now save the same response again, and ensure that a new step is not created.
339
        $this->load_quba();
340
 
341
        $this->render();
342
        if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
343
            throw new \coding_exception('Editor draft item id not found.');
344
        }
345
        $editordraftid = $matches[1];
346
        if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
347
            throw new \coding_exception('File manager draft item id not found.');
348
        }
349
        $attachementsdraftid = $matches[1];
350
 
351
        $this->process_submission(array(
352
                'answer' => 'Here is a picture: <img src="' . $CFG->wwwroot .
353
                                "/draftfile.php/{$usercontextid}/user/draft/{$editordraftid}/smile.txt" .
354
                                '" alt="smile">.',
355
                'answerformat' => FORMAT_HTML,
356
                'answer:itemid' => $editordraftid,
357
                'attachments' => $attachementsdraftid));
358
 
359
        $this->check_current_state(question_state::$complete);
360
        $this->check_current_mark(null);
361
        $this->check_step_count(1);
362
    }
363
 
11 efrain 364
    public function test_deferred_feedback_html_editor_with_files_attempt_on_last_no_files_uploaded(): void {
1 efrain 365
        global $CFG, $USER, $PAGE;
366
 
367
        $this->resetAfterTest(true);
368
        $this->setAdminUser();
369
        // Required to init a text editor.
370
        $PAGE->set_url('/');
371
        $usercontextid = \context_user::instance($USER->id)->id;
372
        $fs = get_file_storage();
373
 
374
        // Create an essay question in the DB.
375
        $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
376
        $cat = $generator->create_question_category();
377
        $question = $generator->create_question('essay', 'editorfilepicker', array('category' => $cat->id));
378
 
379
        // Start attempt at the question.
380
        $q = question_bank::load_question($question->id);
381
        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
382
 
383
        $this->check_current_state(question_state::$todo);
384
        $this->check_current_mark(null);
385
        $this->check_step_count(1);
386
 
387
        // Process a response and check the expected result.
388
        // First we need to get the draft item ids.
389
        $this->render();
390
        if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
391
            throw new \coding_exception('Editor draft item id not found.');
392
        }
393
        $editordraftid = $matches[1];
394
        if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
395
            throw new \coding_exception('File manager draft item id not found.');
396
        }
397
        $attachementsdraftid = $matches[1];
398
 
399
        $this->process_submission(array(
400
                'answer' => 'I refuse to draw you a picture, so there!',
401
                'answerformat' => FORMAT_HTML,
402
                'answer:itemid' => $editordraftid,
403
                'attachments' => $attachementsdraftid));
404
 
405
        $this->check_current_state(question_state::$complete);
406
        $this->check_current_mark(null);
407
        $this->check_step_count(2);
408
        $this->save_quba();
409
 
410
        // Now submit all and finish.
411
        $this->finish();
412
        $this->check_current_state(question_state::$needsgrading);
413
        $this->check_current_mark(null);
414
        $this->check_step_count(3);
415
        $this->save_quba();
416
 
417
        // Now start a new attempt based on the old one.
418
        $this->load_quba();
419
        $oldqa = $this->get_question_attempt();
420
 
421
        $q = question_bank::load_question($question->id);
422
        $this->quba = question_engine::make_questions_usage_by_activity('unit_test',
423
                \context_system::instance());
424
        $this->quba->set_preferred_behaviour('deferredfeedback');
425
        $this->slot = $this->quba->add_question($q, 1);
426
        $this->quba->start_question_based_on($this->slot, $oldqa);
427
 
428
        $this->check_current_state(question_state::$complete);
429
        $this->check_current_mark(null);
430
        $this->check_step_count(1);
431
        $this->save_quba();
432
 
433
        // Check the display.
434
        $this->load_quba();
435
        $this->render();
436
        $this->assertMatchesRegularExpression('/I refuse to draw you a picture, so there!/', $this->currentoutput);
437
    }
438
 
11 efrain 439
    public function test_deferred_feedback_plain_attempt_on_last(): void {
1 efrain 440
        global $CFG, $USER;
441
 
442
        $this->resetAfterTest(true);
443
        $this->setAdminUser();
444
        $usercontextid = \context_user::instance($USER->id)->id;
445
 
446
        // Create an essay question in the DB.
447
        $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
448
        $cat = $generator->create_question_category();
449
        $question = $generator->create_question('essay', 'plain', array('category' => $cat->id));
450
 
451
        // Start attempt at the question.
452
        $q = question_bank::load_question($question->id);
453
        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
454
 
455
        $this->check_current_state(question_state::$todo);
456
        $this->check_current_mark(null);
457
        $this->check_step_count(1);
458
 
459
        // Process a response and check the expected result.
460
 
461
        $this->process_submission(array(
462
            'answer' => 'Once upon a time there was a frog called Freddy. He lived happily ever after.',
463
            'answerformat' => FORMAT_PLAIN,
464
        ));
465
 
466
        $this->check_current_state(question_state::$complete);
467
        $this->check_current_mark(null);
468
        $this->check_step_count(2);
469
        $this->save_quba();
470
 
471
        // Now submit all and finish.
472
        $this->finish();
473
        $this->check_current_state(question_state::$needsgrading);
474
        $this->check_current_mark(null);
475
        $this->check_step_count(3);
476
        $this->save_quba();
477
 
478
        // Now start a new attempt based on the old one.
479
        $this->load_quba();
480
        $oldqa = $this->get_question_attempt();
481
 
482
        $q = question_bank::load_question($question->id);
483
        $this->quba = question_engine::make_questions_usage_by_activity('unit_test',
484
                \context_system::instance());
485
        $this->quba->set_preferred_behaviour('deferredfeedback');
486
        $this->slot = $this->quba->add_question($q, 1);
487
        $this->quba->start_question_based_on($this->slot, $oldqa);
488
 
489
        $this->check_current_state(question_state::$complete);
490
        $this->check_current_mark(null);
491
        $this->check_step_count(1);
492
        $this->save_quba();
493
 
494
        // Check the display.
495
        $this->load_quba();
496
        $this->render();
497
        // Test taht no HTML comment has been added to the response.
498
        $this->assertMatchesRegularExpression(
499
            '/Once upon a time there was a frog called Freddy. He lived happily ever after.(?!&lt;!--)/', $this->currentoutput);
500
        // Test for the hash of an empty file area.
501
        $this->assertStringNotContainsString('d41d8cd98f00b204e9800998ecf8427e', $this->currentoutput);
502
    }
503
 
11 efrain 504
    public function test_deferred_feedback_html_editor_with_files_attempt_wrong_filetypes(): void {
1 efrain 505
        global $CFG, $USER, $PAGE;
506
 
507
        $this->resetAfterTest(true);
508
        $this->setAdminUser();
509
        // Required to init a text editor.
510
        $PAGE->set_url('/');
511
        $usercontextid = \context_user::instance($USER->id)->id;
512
        $fs = get_file_storage();
513
 
514
        // Create an essay question in the DB.
515
        $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
516
        $cat = $generator->create_question_category();
517
        $question = $generator->create_question('essay', 'editorfilepicker', array('category' => $cat->id));
518
 
519
        // Start attempt at the question.
520
        $q = question_bank::load_question($question->id);
521
        $q->filetypeslist = '.pdf,.docx';
522
        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
523
 
524
        $this->check_current_state(question_state::$todo);
525
        $this->check_current_mark(null);
526
        $this->check_step_count(1);
527
 
528
        // Process a response and check the expected result.
529
        // First we need to get the draft item ids.
530
        $this->render();
531
        if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
532
            throw new \coding_exception('Editor draft item id not found.');
533
        }
534
        $editordraftid = $matches[1];
535
        if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
536
            throw new \coding_exception('File manager draft item id not found.');
537
        }
538
        $attachementsdraftid = $matches[1];
539
 
540
        $this->save_file_to_draft_area($usercontextid, $editordraftid, 'smile.txt', ':-)');
541
        $this->save_file_to_draft_area($usercontextid, $attachementsdraftid, 'greeting.txt', 'Hello world!');
542
        $this->process_submission(array(
543
            'answer' => 'Here is a picture: <img src="' . $CFG->wwwroot .
544
                "/draftfile.php/{$usercontextid}/user/draft/{$editordraftid}/smile.txt" .
545
                '" alt="smile">.',
546
            'answerformat' => FORMAT_HTML,
547
            'answer:itemid' => $editordraftid,
548
            'attachments' => $attachementsdraftid));
549
 
550
        $this->check_current_state(question_state::$invalid);
551
        $this->check_current_mark(null);
552
        $this->check_step_count(2);
553
        $this->save_quba();
554
 
555
        // Now submit all and finish.
556
        $this->finish();
557
        $this->check_current_state(question_state::$needsgrading);
558
        $this->check_current_mark(null);
559
        $this->check_step_count(3);
560
        $this->save_quba();
561
    }
562
 
11 efrain 563
    public function test_deferred_feedback_html_editor_with_files_attempt_correct_filetypes(): void {
1 efrain 564
        global $CFG, $USER, $PAGE;
565
 
566
        $this->resetAfterTest(true);
567
        $this->setAdminUser();
568
        // Required to init a text editor.
569
        $PAGE->set_url('/');
570
        $usercontextid = \context_user::instance($USER->id)->id;
571
        $fs = get_file_storage();
572
 
573
        // Create an essay question in the DB.
574
        $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
575
        $cat = $generator->create_question_category();
576
        $question = $generator->create_question('essay', 'editorfilepicker', array('category' => $cat->id));
577
 
578
        // Start attempt at the question.
579
        $q = question_bank::load_question($question->id);
580
        $q->filetypeslist = '.txt,.docx';
581
        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
582
 
583
        $this->check_current_state(question_state::$todo);
584
        $this->check_current_mark(null);
585
        $this->check_step_count(1);
586
 
587
        // Process a response and check the expected result.
588
        // First we need to get the draft item ids.
589
        $this->render();
590
        if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
591
            throw new \coding_exception('Editor draft item id not found.');
592
        }
593
        $editordraftid = $matches[1];
594
        if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
595
            throw new \coding_exception('File manager draft item id not found.');
596
        }
597
        $attachementsdraftid = $matches[1];
598
 
599
        $this->save_file_to_draft_area($usercontextid, $editordraftid, 'smile.txt', ':-)');
600
        $this->save_file_to_draft_area($usercontextid, $attachementsdraftid, 'greeting.txt', 'Hello world!');
601
        $this->process_submission(array(
602
            'answer' => 'Here is a picture: <img src="' . $CFG->wwwroot .
603
                "/draftfile.php/{$usercontextid}/user/draft/{$editordraftid}/smile.txt" .
604
                '" alt="smile">.',
605
            'answerformat' => FORMAT_HTML,
606
            'answer:itemid' => $editordraftid,
607
            'attachments' => $attachementsdraftid));
608
 
609
        $this->check_current_state(question_state::$complete);
610
        $this->check_current_mark(null);
611
        $this->check_step_count(2);
612
        $this->save_quba();
613
 
614
        // Now submit all and finish.
615
        $this->finish();
616
        $this->check_current_state(question_state::$needsgrading);
617
        $this->check_current_mark(null);
618
        $this->check_step_count(3);
619
        $this->save_quba();
620
    }
621
 
11 efrain 622
    public function test_deferred_feedback_word_limits(): void {
1 efrain 623
        global $PAGE;
624
 
625
        // The current text editor depends on the users profile setting - so it needs a valid user.
626
        $this->setAdminUser();
627
        // Required to init a text editor.
628
        $PAGE->set_url('/');
629
 
630
        // Create an essay question.
631
        /** @var qtype_essay_question $q */
632
        $q = \test_question_maker::make_question('essay', 'editor');
633
        $q->minwordlimit = 3;
634
        $q->maxwordlimit = 7;
635
        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
636
 
637
        // Check the initial state.
638
        $this->check_current_state(question_state::$todo);
639
        $this->check_current_mark(null);
640
        $this->render();
641
        $this->check_contains_textarea('answer', '');
642
        $this->check_current_output(
643
                $this->get_contains_question_text_expectation($q),
644
                $this->get_does_not_contain_validation_error_expectation(),
645
                $this->get_does_not_contain_feedback_expectation());
646
 
647
        // Save a response that is too short (and give the word-count code a tricky case).
648
        $response = '<div class="card">
649
                        <div class="card-body">
650
                            <h3 class="card-title">One</h3>
651
                            <div class="card-text">
652
                                <ul>
653
                                    <li>Two</li>
654
                                </ul>
655
                            </div>
656
                        </div>
657
                    </div>';
658
        $this->process_submission(['answer' => $response, 'answerformat' => FORMAT_HTML]);
659
 
660
        // Verify.
661
        $this->check_current_state(question_state::$invalid);
662
        $this->check_current_mark(null);
663
        $this->render();
664
        $this->check_contains_textarea('answer', $response);
665
        $this->check_current_output(
666
                $this->get_contains_question_text_expectation($q),
667
                $this->get_contains_validation_error_expectation(),
668
                $this->get_does_not_contain_feedback_expectation());
669
        $this->assertStringContainsString('This question requires a response of at least 3 words and you are ' .
670
                'attempting to submit 2 words. Please expand your response and try again.',
671
                $this->currentoutput);
672
 
673
        // Save a response that is just long enough.
674
        $this->process_submission(['answer' => '<p>One two three.</p>', 'answerformat' => FORMAT_HTML]);
675
 
676
        // Verify.
677
        $this->check_current_state(question_state::$complete);
678
        $this->check_current_mark(null);
679
        $this->render();
680
        $this->check_contains_textarea('answer', '<p>One two three.</p>');
681
        $this->check_current_output(
682
                $this->get_contains_question_text_expectation($q),
683
                $this->get_does_not_contain_validation_error_expectation(),
684
                $this->get_does_not_contain_feedback_expectation());
685
 
686
        // Save a response that is as long as possible short.
687
        $this->process_submission(['answer' => '<p>One two three four five six seven.</p>',
688
                'answerformat' => FORMAT_HTML]);
689
 
690
        // Verify.
691
        $this->check_current_state(question_state::$complete);
692
        $this->check_current_mark(null);
693
        $this->render();
694
        $this->check_contains_textarea('answer', '<p>One two three four five six seven.</p>');
695
        $this->check_current_output(
696
                $this->get_contains_question_text_expectation($q),
697
                $this->get_does_not_contain_validation_error_expectation(),
698
                $this->get_does_not_contain_feedback_expectation());
699
 
700
        // Save a response that is just too long.
701
        $this->process_submission(['answer' => '<p>One two three four five six seven eight.</p>',
702
                'answerformat' => FORMAT_HTML]);
703
 
704
        // Verify.
705
        $this->check_current_state(question_state::$invalid);
706
        $this->check_current_mark(null);
707
        $this->render();
708
        $this->check_contains_textarea('answer', '<p>One two three four five six seven eight.</p>');
709
        $this->check_current_output(
710
                $this->get_contains_question_text_expectation($q),
711
                $this->get_contains_validation_error_expectation(),
712
                $this->get_does_not_contain_feedback_expectation());
713
        $this->assertStringContainsString('The word limit for this question is 7 words and you are ' .
714
                'attempting to submit 8 words. Please shorten your response and try again.',
715
                $this->currentoutput);
716
 
717
        // Now submit all and finish.
718
        $this->finish();
719
 
720
        // Verify.
721
        $this->check_current_state(question_state::$needsgrading);
722
        $this->check_current_mark(null);
723
        $this->render();
724
        $this->check_current_output(
725
                $this->get_contains_question_text_expectation($q),
726
                $this->get_contains_general_feedback_expectation($q));
727
        $this->assertStringContainsString('Word count: 8, more than the limit of 7 words.',
728
                $this->currentoutput);
729
    }
730
}