See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401]
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 */ 35 class walkthrough_test extends \qbehaviour_walkthrough_test_base { 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 72 public function test_deferred_feedback_html_editor() { 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 130 public function test_deferred_feedback_plain_text() { 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 182 public function test_responsetemplate() { 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 240 public function test_deferred_feedback_html_editor_with_files_attempt_on_last() { 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&.*?itemid=(\d+)&/', $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&action=browse&.*?itemid=(\d+)&/', $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&.*?itemid=(\d+)&/', $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&action=browse&.*?itemid=(\d+)&/', $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&.*?itemid=(\d+)&/', $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&action=browse&.*?itemid=(\d+)&/', $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 364 public function test_deferred_feedback_html_editor_with_files_attempt_on_last_no_files_uploaded() { 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&.*?itemid=(\d+)&/', $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&action=browse&.*?itemid=(\d+)&/', $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 439 public function test_deferred_feedback_plain_attempt_on_last() { 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.(?!<!--)/', $this->currentoutput); 500 // Test for the hash of an empty file area. 501 $this->assertStringNotContainsString('d41d8cd98f00b204e9800998ecf8427e', $this->currentoutput); 502 } 503 504 public function test_deferred_feedback_html_editor_with_files_attempt_wrong_filetypes() { 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&.*?itemid=(\d+)&/', $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&action=browse&.*?itemid=(\d+)&/', $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 563 public function test_deferred_feedback_html_editor_with_files_attempt_correct_filetypes() { 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&.*?itemid=(\d+)&/', $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&action=browse&.*?itemid=(\d+)&/', $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 622 public function test_deferred_feedback_word_limits() { 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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body