You are here

QuizResultTest.php in Quiz 8.5

File

tests/src/Functional/QuizResultTest.php
View source
<?php

namespace Drupal\Tests\quiz\Functional;

use Drupal\paragraphs\Entity\Paragraph;
use Drupal\quiz\Entity\Quiz;
use Drupal\quiz\Entity\QuizQuestion;
use Drupal\quiz\Entity\QuizQuestionRelationship;
use Drupal\quiz\Entity\QuizResult;
use Drupal\quiz\Entity\QuizResultAnswer;
use function node_load;

/**
 * Test quiz results behavior.
 *
 * @group Quiz
 */
class QuizResultTest extends QuizTestBase {
  public static $modules = array(
    'quiz_truefalse',
    'quiz_multichoice',
  );

  /**
   * Test the various result summaries and pass rate.
   */
  public function testPassRateSummary() {

    // Set up some alternatives.
    $a = Paragraph::create([
      'type' => 'quiz_result_feedback',
      'quiz_feedback' => 'You got 90 or more on the quiz',
      'quiz_feedback_range' => [
        'from' => 90,
        'to' => 100,
      ],
    ]);
    $a
      ->save();
    $b = Paragraph::create([
      'type' => 'quiz_result_feedback',
      'quiz_feedback' => 'You got between 50 and 89',
      'quiz_feedback_range' => [
        'from' => 50,
        'to' => 89,
      ],
    ]);
    $b
      ->save();
    $c = Paragraph::create([
      'type' => 'quiz_result_feedback',
      'quiz_feedback' => 'You failed bro',
      'quiz_feedback_range' => [
        'from' => 0,
        'to' => 49,
      ],
    ]);
    $c
      ->save();

    // By default, the feedback is after the quiz.
    $quiz = $this
      ->createQuiz(array(
      'pass_rate' => 75,
      'summary_pass' => 'This is the summary if passed',
      'summary_default' => 'This is the default summary text',
    ));
    $quiz
      ->get('result_options')
      ->appendItem($a);
    $quiz
      ->get('result_options')
      ->appendItem($b);
    $quiz
      ->get('result_options')
      ->appendItem($c);
    $quiz
      ->save();

    // 3 questions.
    $question1 = $this
      ->createQuestion(array(
      'type' => 'truefalse',
      'truefalse_correct' => 1,
      'feedback' => 'Q1Feedback',
    ));
    $this
      ->linkQuestionToQuiz($question1, $quiz);
    $question2 = $this
      ->createQuestion(array(
      'type' => 'truefalse',
      'truefalse_correct' => 1,
      'feedback' => 'Q2Feedback',
    ));
    $this
      ->linkQuestionToQuiz($question2, $quiz);
    $question3 = $this
      ->createQuestion(array(
      'type' => 'truefalse',
      'truefalse_correct' => 1,
      'feedback' => 'Q3Feedback',
    ));
    $this
      ->linkQuestionToQuiz($question3, $quiz);

    // Test 100%.
    $this
      ->drupalLogin($this->user);
    $this
      ->drupalGet("quiz/{$quiz->id()}/take");
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question1->id()}][answer]" => 1,
    ), t('Next'));
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question2->id()}][answer]" => 1,
    ), t('Next'));
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question3->id()}][answer]" => 1,
    ), t('Finish'));
    $this
      ->assertText('You got 90 or more on the quiz');
    $this
      ->assertText('This is the summary if passed');
    $this
      ->assertNoText('This is the default summary text');

    // Test 66%.
    $this
      ->drupalGet("quiz/{$quiz->id()}/take");
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question1->id()}][answer]" => 1,
    ), t('Next'));
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question2->id()}][answer]" => 1,
    ), t('Next'));
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question3->id()}][answer]" => 0,
    ), t('Finish'));
    $this
      ->assertText('You got between 50 and 89');
    $this
      ->assertNoText('This is the summary if passed');
    $this
      ->assertText('This is the default summary text');

    // Test 33%.
    $this
      ->drupalGet("quiz/{$quiz->id()}/take");
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question1->id()}][answer]" => 1,
    ), t('Next'));
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question2->id()}][answer]" => 0,
    ), t('Next'));
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question3->id()}][answer]" => 0,
    ), t('Finish'));
    $this
      ->assertText('You failed bro');
    $this
      ->assertNoText('This is the summary if passed');
    $this
      ->assertText('This is the default summary text');
  }

  /**
   * Test result CRUD operations.
   *
   * We have (at least) 3 different tables to clean up from on a Quiz result
   * deletion - the quiz_result, the result answers, and the question type's
   * answer storage. Let's ensure at least that happens.
   *
   * @todo rework for D8, at least we don't have to clean up question storage
   * because it's attached to QuizResultAnswer.
   */
  public function testQuizResultCrud() {
    $this
      ->drupalLogin($this->admin);
    $question1 = $this
      ->createQuestion(array(
      'type' => 'truefalse',
      'truefalse_correct' => 1,
    ));
    $quiz = $this
      ->linkQuestionToQuiz($question1);

    // Submit an answer.
    $this
      ->drupalLogin($this->user);
    $this
      ->drupalGet("quiz/{$quiz->id()}/take");
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question1->id()}][answer]" => 1,
    ), t('Finish'));
    $q = Quiz::load(1);
    $qq = QuizQuestion::load(1);
    $qqr = QuizQuestionRelationship::load(1);
    $qr = QuizResult::load(1);
    $qra = QuizResultAnswer::load(1);
    $this
      ->assertEquals($qq
      ->id(), $qqr
      ->getQuiz()
      ->id(), 'Question belongs to the relationship.');
    $this
      ->assertEquals($qqr
      ->getQuiz()
      ->id(), $q
      ->id(), 'Relationship belongs to the quiz.');
    $this
      ->assertEquals($qr
      ->id(), $qra
      ->getQuizResult()
      ->id(), 'Answer belongs to the result.');

    // Delete the quiz.
    $q
      ->delete();
    $q = Quiz::load(1);
    $qq = QuizQuestion::load(1);
    $qqr = QuizQuestionRelationship::load(1);
    $qr = QuizResult::load(1);
    $qra = QuizResultAnswer::load(1);

    // Check that only the question remains.
    $this
      ->assertEquals($q, NULL);
    $this
      ->assertEquals($qqr, NULL);
    $this
      ->assertNotEquals($qq, NULL);
    $this
      ->assertEquals($qr, NULL);
    $this
      ->assertEquals($qra, NULL);
  }

  /**
   * Test access to results.
   */
  public function testQuizResultAccess() {
    $this
      ->drupalLogin($this->admin);
    $question1 = $this
      ->createQuestion(array(
      'type' => 'truefalse',
      'truefalse_correct' => 1,
    ));
    $quiz_node = $this
      ->linkQuestionToQuiz($question1);

    // Submit an answer.
    $this
      ->drupalLogin($this->user);
    $this
      ->drupalGet("quiz/{$quiz_node->id()}/take");
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question1->id()}][answer]" => 1,
    ), t('Finish'));
    $resultsUrl = $this
      ->getUrl();
    $this
      ->drupalGet($resultsUrl);
    $this
      ->assertResponse(200, t('User can view own result'));
    $this
      ->drupalLogout();
    $this
      ->drupalGet($resultsUrl);
    $this
      ->assertSession()
      ->statusCodeEquals(403);
  }

  /**
   * Test our wildcard answer exporter.
   */
  public function testQuizResultAnswerExport() {
    $settings = array(
      'title' => 'MCQ 1 Title',
      'type' => 'multichoice',
      'choice_multi' => 0,
      'choice_random' => 0,
      'choice_boolean' => 0,
      'body' => 'MCQ 1 body text',
    );
    $settings['alternatives'][0]['answer']['value'] = 'This is the A answer';
    $settings['alternatives'][0]['answer']['format'] = 'filtered_html';
    $settings['alternatives'][0]['score_if_chosen'] = 1;
    $settings['alternatives'][0]['feedback_if_chosen']['format'] = 'filtered_html';
    $settings['alternatives'][0]['feedback_if_not_chosen']['format'] = 'filtered_html';
    $settings['alternatives'][1]['answer']['value'] = 'This is the B answer';
    $settings['alternatives'][1]['answer']['format'] = 'filtered_html';
    $settings['alternatives'][1]['score_if_chosen'] = 0;
    $settings['alternatives'][1]['feedback_if_chosen']['format'] = 'filtered_html';
    $settings['alternatives'][1]['feedback_if_not_chosen']['format'] = 'filtered_html';
    $question_node = $this
      ->createQuestion($settings);

    // Reload to get the answer IDs.
    $question_node = node_load($question_node->nid);
    $quiz_node = $this
      ->linkQuestionToQuiz($question_node);
    $this
      ->drupalLogin($this->admin);
    $this
      ->drupalGet("quiz/{$quiz_node->id()}/take");
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question_node->nid}][answer][user_answer]" => $question_node->alternatives[0]['id'],
    ), t('Finish'));

    // Make a modification to the default view.
    $view = views_get_view('quiz_results');
    $view
      ->set_arguments(array(
      $quiz_node->nid,
    ));
    $view
      ->set_display('page_1');
    $fields = $view->display_handler
      ->get_option('fields');
    $newfield = array();
    $newfield['id'] = 'answers';
    $newfield['table'] = 'quiz_node_results';
    $newfield['field'] = 'answers';
    $fields['answers'] = $newfield;
    $view->display_handler
      ->set_option('fields', $fields);
    $view
      ->save();

    // Verify the user's answer appears on our modified report.
    $this
      ->drupalGet("quiz/{$quiz_node->id()}/quiz/results");
    $this
      ->assertText('1. MCQ 1 Title');
    $this
      ->assertText('This is the A answer');
    $this
      ->assertNoText('This is the B answer');
  }

  /**
   * Test that deleting a question from a Quiz doesn't result in a fatal error.
   */
  public function testBrokenResults() {
    $this
      ->drupalLogin($this->admin);
    $question1 = $this
      ->createQuestion(array(
      'type' => 'truefalse',
      'truefalse_correct' => 1,
    ));
    $quiz_node = $this
      ->linkQuestionToQuiz($question1);

    // Submit an answer.
    $this
      ->drupalLogin($this->user);
    $this
      ->drupalGet("quiz/{$quiz_node->id()}/take");
    $this
      ->drupalPostForm(NULL, array(
      "question[{$question1->id()}][answer]" => 1,
    ), t('Finish'));

    // Delete the question.
    $question1
      ->delete();

    // And there should not be a fatal error.
    $this
      ->drupalGet("quiz/{$quiz_node->id()}/result/1");
    $this
      ->assertResponse(200, 'Saw the results page.');
  }

}

Classes

Namesort descending Description
QuizResultTest Test quiz results behavior.