diff --git a/question/type/multichoice/amd/build/clearchoice.min.js b/question/type/multichoice/amd/build/clearchoice.min.js index a2871af02b0..d68c68811af 100644 --- a/question/type/multichoice/amd/build/clearchoice.min.js +++ b/question/type/multichoice/amd/build/clearchoice.min.js @@ -1,2 +1,2 @@ -define ("qtype_multichoice/clearchoice",["jquery","core/custom_interaction_events"],function(a,b){var c={ANSWER_RADIOS:".answer input",CLEARRESULTS_LINK:"a[data-action=\"clearresults\"]"},d="d-none",e=function(f){var g=f.find(c.CLEARRESULTS_LINK);f.on(b.events.activate,c.CLEARRESULTS_LINK,function(b,e){f.find(c.ANSWER_RADIOS).each(function(){a(this).prop("checked",!1)});a(b.target).addClass(d);e.originalEvent.preventDefault()});f.on(b.events.activate,c.ANSWER_RADIOS,function(){g.removeClass(d)})};return{init:function init(b){b=a("#"+b);e(b)}}}); +define ("qtype_multichoice/clearchoice",["jquery","core/custom_interaction_events"],function(a,b){var c={CHOICE_ELEMENT:".answer input",CLEAR_CHOICE_ELEMENT:"div[class=\"qtype_multichoice_clearchoice\"]"},d=function(a){a.find("input[type=\"radio\"]").prop("checked",!0)},e=function(a,b){return a.find("div[id=\""+b+"\"]")},f=function(a){a.addClass("sr-only")},g=function(a){a.removeClass("sr-only")},h=function(a,h){var i=e(a,h);a.on(b.events.activate,c.CLEAR_CHOICE_ELEMENT,function(a,b){d(i);f(i);b.originalEvent.preventDefault()});a.on(b.events.activate,c.CHOICE_ELEMENT,function(){g(i)})};return{init:function init(b,c){b=a("#"+b);h(b,c)}}}); //# sourceMappingURL=clearchoice.min.js.map diff --git a/question/type/multichoice/amd/build/clearchoice.min.js.map b/question/type/multichoice/amd/build/clearchoice.min.js.map index f57d5043762..a77747785a1 100644 --- a/question/type/multichoice/amd/build/clearchoice.min.js.map +++ b/question/type/multichoice/amd/build/clearchoice.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/clearchoice.js"],"names":["define","$","CustomEvents","SELECTORS","ANSWER_RADIOS","CLEARRESULTS_LINK","CSSHIDDEN","registerEventListeners","root","clearChoiceButton","find","on","events","activate","e","data","each","prop","target","addClass","originalEvent","preventDefault","removeClass","init"],"mappings":"AAuBAA,OAAM,iCAAC,CAAC,QAAD,CAAW,gCAAX,CAAD,CAA+C,SAASC,CAAT,CAAYC,CAAZ,CAA0B,IAEvEC,CAAAA,CAAS,CAAG,CACZC,aAAa,CAAE,eADH,CAEZC,iBAAiB,CAAE,iCAFP,CAF2D,CAOvEC,CAAS,CAAG,QAP2D,CAcvEC,CAAsB,CAAG,SAASC,CAAT,CAAe,CAExC,GAAIC,CAAAA,CAAiB,CAAGD,CAAI,CAACE,IAAL,CAAUP,CAAS,CAACE,iBAApB,CAAxB,CAEAG,CAAI,CAACG,EAAL,CAAQT,CAAY,CAACU,MAAb,CAAoBC,QAA5B,CAAsCV,CAAS,CAACE,iBAAhD,CAAmE,SAASS,CAAT,CAAYC,CAAZ,CAAkB,CACjFP,CAAI,CAACE,IAAL,CAAUP,CAAS,CAACC,aAApB,EAAmCY,IAAnC,CAAwC,UAAW,CAC/Cf,CAAC,CAAC,IAAD,CAAD,CAAQgB,IAAR,CAAa,SAAb,IACH,CAFD,EAGAhB,CAAC,CAACa,CAAC,CAACI,MAAH,CAAD,CAAYC,QAAZ,CAAqBb,CAArB,EACAS,CAAI,CAACK,aAAL,CAAmBC,cAAnB,EACH,CAND,EAQAb,CAAI,CAACG,EAAL,CAAQT,CAAY,CAACU,MAAb,CAAoBC,QAA5B,CAAsCV,CAAS,CAACC,aAAhD,CAA+D,UAAW,CACtEK,CAAiB,CAACa,WAAlB,CAA8BhB,CAA9B,CACH,CAFD,CAGH,CA7B0E,CAyC3E,MAAO,CACHiB,IAAI,CANG,QAAPA,CAAAA,IAAO,CAASf,CAAT,CAAe,CACtBA,CAAI,CAAGP,CAAC,CAAC,IAAMO,CAAP,CAAR,CACAD,CAAsB,CAACC,CAAD,CACzB,CAEM,CAGV,CA5CK,CAAN","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Manages 'Clear my choice' functionality actions.\n *\n * @module qtype_multichoice/clearchoice\n * @copyright 2019 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.7\n */\ndefine(['jquery', 'core/custom_interaction_events'], function($, CustomEvents) {\n\n var SELECTORS = {\n ANSWER_RADIOS: '.answer input',\n CLEARRESULTS_LINK: 'a[data-action=\"clearresults\"]'\n };\n\n var CSSHIDDEN = 'd-none';\n\n /**\n * Register event listeners for the clear choice module.\n *\n * @param {Object} root The question outer div prefix.\n */\n var registerEventListeners = function(root) {\n\n var clearChoiceButton = root.find(SELECTORS.CLEARRESULTS_LINK);\n\n root.on(CustomEvents.events.activate, SELECTORS.CLEARRESULTS_LINK, function(e, data) {\n root.find(SELECTORS.ANSWER_RADIOS).each(function() {\n $(this).prop('checked', false);\n });\n $(e.target).addClass(CSSHIDDEN);\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.ANSWER_RADIOS, function() {\n clearChoiceButton.removeClass(CSSHIDDEN);\n });\n };\n\n /**\n * Initialise clear choice module.\n\n * @param {string} root The question outer div prefix.\n */\n var init = function(root) {\n root = $('#' + root);\n registerEventListeners(root);\n };\n\n return {\n init: init\n };\n});\n"],"file":"clearchoice.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/clearchoice.js"],"names":["define","$","CustomEvents","SELECTORS","CHOICE_ELEMENT","CLEAR_CHOICE_ELEMENT","checkClearChoiceRadio","clearChoiceContainer","find","prop","getClearChoiceElement","root","fieldPrefix","hideClearChoiceOption","addClass","showClearChoiceOption","removeClass","registerEventListeners","on","events","activate","e","data","originalEvent","preventDefault","init"],"mappings":"AAuBAA,OAAM,iCAAC,CAAC,QAAD,CAAW,gCAAX,CAAD,CAA+C,SAASC,CAAT,CAAYC,CAAZ,CAA0B,IAEvEC,CAAAA,CAAS,CAAG,CACZC,cAAc,CAAE,eADJ,CAEZC,oBAAoB,CAAE,8CAFV,CAF2D,CAYvEC,CAAqB,CAAG,SAASC,CAAT,CAA+B,CACvDA,CAAoB,CAACC,IAArB,CAA0B,uBAA1B,EAAiDC,IAAjD,CAAsD,SAAtD,IACH,CAd0E,CAuBvEC,CAAqB,CAAG,SAASC,CAAT,CAAeC,CAAf,CAA4B,CACpD,MAAOD,CAAAA,CAAI,CAACH,IAAL,CAAU,YAAaI,CAAb,CAA2B,KAArC,CACV,CAzB0E,CAgCvEC,CAAqB,CAAG,SAASN,CAAT,CAA+B,CACvDA,CAAoB,CAACO,QAArB,CAA8B,SAA9B,CACH,CAlC0E,CAyCvEC,CAAqB,CAAG,SAASR,CAAT,CAA+B,CACvDA,CAAoB,CAACS,WAArB,CAAiC,SAAjC,CACH,CA3C0E,CAmDvEC,CAAsB,CAAG,SAASN,CAAT,CAAeC,CAAf,CAA4B,CACrD,GAAIL,CAAAA,CAAoB,CAAGG,CAAqB,CAACC,CAAD,CAAOC,CAAP,CAAhD,CAEAD,CAAI,CAACO,EAAL,CAAQhB,CAAY,CAACiB,MAAb,CAAoBC,QAA5B,CAAsCjB,CAAS,CAACE,oBAAhD,CAAsE,SAASgB,CAAT,CAAYC,CAAZ,CAAkB,CAGhFhB,CAAqB,CAACC,CAAD,CAArB,CAEAM,CAAqB,CAACN,CAAD,CAArB,CAEAe,CAAI,CAACC,aAAL,CAAmBC,cAAnB,EACP,CARD,EAUAb,CAAI,CAACO,EAAL,CAAQhB,CAAY,CAACiB,MAAb,CAAoBC,QAA5B,CAAsCjB,CAAS,CAACC,cAAhD,CAAgE,UAAW,CAEvEW,CAAqB,CAACR,CAAD,CACxB,CAHD,CAIH,CApE0E,CAiF3E,MAAO,CACHkB,IAAI,CANG,QAAPA,CAAAA,IAAO,CAASd,CAAT,CAAeC,CAAf,CAA4B,CACnCD,CAAI,CAAGV,CAAC,CAAC,IAAMU,CAAP,CAAR,CACAM,CAAsB,CAACN,CAAD,CAAOC,CAAP,CACzB,CAEM,CAGV,CApFK,CAAN","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Manages 'Clear my choice' functionality actions.\n *\n * @module qtype_multichoice/clearchoice\n * @copyright 2019 Simey Lameze \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.7\n */\ndefine(['jquery', 'core/custom_interaction_events'], function($, CustomEvents) {\n\n var SELECTORS = {\n CHOICE_ELEMENT: '.answer input',\n CLEAR_CHOICE_ELEMENT: 'div[class=\"qtype_multichoice_clearchoice\"]'\n };\n\n /**\n * Mark clear choice radio as checked.\n *\n * @param {Object} clearChoiceContainer The clear choice option container.\n */\n var checkClearChoiceRadio = function(clearChoiceContainer) {\n clearChoiceContainer.find('input[type=\"radio\"]').prop('checked', true);\n };\n\n /**\n * Get the clear choice div container.\n *\n * @param {Object} root The question root element.\n * @param {string} fieldPrefix The question outer div prefix.\n * @returns {Object} The clear choice div container.\n */\n var getClearChoiceElement = function(root, fieldPrefix) {\n return root.find('div[id=\"' + fieldPrefix + '\"]');\n };\n\n /**\n * Hide clear choice option.\n *\n * @param {Object} clearChoiceContainer The clear choice option container.\n */\n var hideClearChoiceOption = function(clearChoiceContainer) {\n clearChoiceContainer.addClass('sr-only');\n };\n\n /**\n * Shows clear choice option.\n *\n * @param {Object} clearChoiceContainer The clear choice option container.\n */\n var showClearChoiceOption = function(clearChoiceContainer) {\n clearChoiceContainer.removeClass('sr-only');\n };\n\n /**\n * Register event listeners for the clear choice module.\n *\n * @param {Object} root The question outer div prefix.\n * @param {string} fieldPrefix The \"Clear choice\" div prefix.\n */\n var registerEventListeners = function(root, fieldPrefix) {\n var clearChoiceContainer = getClearChoiceElement(root, fieldPrefix);\n\n root.on(CustomEvents.events.activate, SELECTORS.CLEAR_CHOICE_ELEMENT, function(e, data) {\n\n // Mark the clear choice radio element as checked.\n checkClearChoiceRadio(clearChoiceContainer);\n // Now that the hidden radio has been checked, hide the clear choice option.\n hideClearChoiceOption(clearChoiceContainer);\n\n data.originalEvent.preventDefault();\n });\n\n root.on(CustomEvents.events.activate, SELECTORS.CHOICE_ELEMENT, function() {\n // If the event has been triggered by any other choice, show the clear choice option.\n showClearChoiceOption(clearChoiceContainer);\n });\n };\n\n /**\n * Initialise clear choice module.\n\n * @param {string} root The question outer div prefix.\n * @param {string} fieldPrefix The \"Clear choice\" div prefix.\n */\n var init = function(root, fieldPrefix) {\n root = $('#' + root);\n registerEventListeners(root, fieldPrefix);\n };\n\n return {\n init: init\n };\n});\n"],"file":"clearchoice.min.js"} \ No newline at end of file diff --git a/question/type/multichoice/amd/src/clearchoice.js b/question/type/multichoice/amd/src/clearchoice.js index e84f8d4d9fb..5ca09ce44c2 100644 --- a/question/type/multichoice/amd/src/clearchoice.js +++ b/question/type/multichoice/amd/src/clearchoice.js @@ -24,31 +24,70 @@ define(['jquery', 'core/custom_interaction_events'], function($, CustomEvents) { var SELECTORS = { - ANSWER_RADIOS: '.answer input', - CLEARRESULTS_LINK: 'a[data-action="clearresults"]' + CHOICE_ELEMENT: '.answer input', + CLEAR_CHOICE_ELEMENT: 'div[class="qtype_multichoice_clearchoice"]' }; - var CSSHIDDEN = 'd-none'; + /** + * Mark clear choice radio as checked. + * + * @param {Object} clearChoiceContainer The clear choice option container. + */ + var checkClearChoiceRadio = function(clearChoiceContainer) { + clearChoiceContainer.find('input[type="radio"]').prop('checked', true); + }; + + /** + * Get the clear choice div container. + * + * @param {Object} root The question root element. + * @param {string} fieldPrefix The question outer div prefix. + * @returns {Object} The clear choice div container. + */ + var getClearChoiceElement = function(root, fieldPrefix) { + return root.find('div[id="' + fieldPrefix + '"]'); + }; + + /** + * Hide clear choice option. + * + * @param {Object} clearChoiceContainer The clear choice option container. + */ + var hideClearChoiceOption = function(clearChoiceContainer) { + clearChoiceContainer.addClass('sr-only'); + }; + + /** + * Shows clear choice option. + * + * @param {Object} clearChoiceContainer The clear choice option container. + */ + var showClearChoiceOption = function(clearChoiceContainer) { + clearChoiceContainer.removeClass('sr-only'); + }; /** * Register event listeners for the clear choice module. * * @param {Object} root The question outer div prefix. + * @param {string} fieldPrefix The "Clear choice" div prefix. */ - var registerEventListeners = function(root) { + var registerEventListeners = function(root, fieldPrefix) { + var clearChoiceContainer = getClearChoiceElement(root, fieldPrefix); - var clearChoiceButton = root.find(SELECTORS.CLEARRESULTS_LINK); + root.on(CustomEvents.events.activate, SELECTORS.CLEAR_CHOICE_ELEMENT, function(e, data) { - root.on(CustomEvents.events.activate, SELECTORS.CLEARRESULTS_LINK, function(e, data) { - root.find(SELECTORS.ANSWER_RADIOS).each(function() { - $(this).prop('checked', false); - }); - $(e.target).addClass(CSSHIDDEN); - data.originalEvent.preventDefault(); + // Mark the clear choice radio element as checked. + checkClearChoiceRadio(clearChoiceContainer); + // Now that the hidden radio has been checked, hide the clear choice option. + hideClearChoiceOption(clearChoiceContainer); + + data.originalEvent.preventDefault(); }); - root.on(CustomEvents.events.activate, SELECTORS.ANSWER_RADIOS, function() { - clearChoiceButton.removeClass(CSSHIDDEN); + root.on(CustomEvents.events.activate, SELECTORS.CHOICE_ELEMENT, function() { + // If the event has been triggered by any other choice, show the clear choice option. + showClearChoiceOption(clearChoiceContainer); }); }; @@ -56,10 +95,11 @@ define(['jquery', 'core/custom_interaction_events'], function($, CustomEvents) { * Initialise clear choice module. * @param {string} root The question outer div prefix. + * @param {string} fieldPrefix The "Clear choice" div prefix. */ - var init = function(root) { + var init = function(root, fieldPrefix) { root = $('#' + root); - registerEventListeners(root); + registerEventListeners(root, fieldPrefix); }; return { diff --git a/question/type/multichoice/renderer.php b/question/type/multichoice/renderer.php index f43ef81b627..1213c8b5dca 100644 --- a/question/type/multichoice/renderer.php +++ b/question/type/multichoice/renderer.php @@ -274,7 +274,6 @@ class qtype_multichoice_single_renderer extends qtype_multichoice_renderer_base $question = $qa->get_question(); $response = $question->get_response($qa); - $clearchoicefieldname = $qa->get_qt_field_name('clearchoice'); $hascheckedchoice = false; foreach ($question->get_order($qa) as $value => $ansid) { if ($question->is_choice_selected($response, $value)) { @@ -283,26 +282,33 @@ class qtype_multichoice_single_renderer extends qtype_multichoice_renderer_base } } - $questiondivid = $qa->get_outer_question_div_unique_id(); + $clearchoiceid = $this->get_input_id($qa, -1); + $clearchoicefieldname = $qa->get_qt_field_name('clearchoice'); + $clearchoiceradioattrs = [ + 'type' => $this->get_input_type(), + 'name' => $qa->get_qt_field_name('answer'), + 'id' => $clearchoiceid, + 'value' => -1, + 'class' => 'sr-only' + ]; + $cssclass = 'qtype_multichoice_clearchoice'; // When no choice selected during rendering, then hide the clear choice option. - $csshidden = ''; if (!$hascheckedchoice && $response == -1) { - $csshidden = ' d-none'; + $cssclass .= ' sr-only'; + $clearchoiceradioattrs['checked'] = 'checked'; } + // Adds an hidden radio that will be checked to give the impression the choice has been cleared. + $clearchoiceradio = html_writer::empty_tag('input', $clearchoiceradioattrs); + $clearchoiceradio .= html_writer::link('', get_string('clearchoice', 'qtype_multichoice'), + ['for' => $clearchoiceid, 'role' => 'button']); - $clearchoicelink = html_writer::link('', get_string('clearchoice', 'qtype_multichoice'), [ - 'class' => $csshidden, - 'role' => 'button', - 'data-action' => 'clearresults', - 'data-target' => '#' . $questiondivid - ]); - $result = html_writer::tag('div', $clearchoicelink, ['id' => $clearchoicefieldname, - 'class' => 'qtype_multichoice_clearchoice']); + // Now wrap the radio and label inside a div. + $result = html_writer::tag('div', $clearchoiceradio, ['id' => $clearchoicefieldname, 'class' => $cssclass]); // Load required clearchoice AMD module. $this->page->requires->js_call_amd('qtype_multichoice/clearchoice', 'init', - [$questiondivid]); + [$qa->get_outer_question_div_unique_id(), $clearchoicefieldname]); return $result; } diff --git a/question/type/multichoice/tests/behat/clearanswers.feature b/question/type/multichoice/tests/behat/clearanswers.feature deleted file mode 100644 index 2facc007521..00000000000 --- a/question/type/multichoice/tests/behat/clearanswers.feature +++ /dev/null @@ -1,42 +0,0 @@ -@qtype @qtype_multichoice -Feature: Clear my answers - As a student - In order to reset Multiple choice ansers - I need to clear my choice - - Background: - Given the following "users" exist: - | username | firstname | lastname | email | - | student1 | S1 | Student1 | student1@moodle.com | - And the following "courses" exist: - | fullname | shortname | category | - | Course 1 | C1 | 0 | - And the following "course enrolments" exist: - | user | course | role | - | student1 | C1 | student | - And the following "question categories" exist: - | contextlevel | reference | name | - | Course | C1 | Test questions | - And the following "questions" exist: - | questioncategory | qtype | name | template | questiontext | - | Test questions | multichoice | Multi-choice-001 | one_of_four | Question One | - And the following "activities" exist: - | activity | name | intro | course | idnumber | preferredbehaviour | canredoquestions | - | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | immediatefeedback | 1 | - And quiz "Quiz 1" contains the following questions: - | question | page | - | Multi-choice-001 | 1 | - - @javascript - Scenario: Attempt a quiz and reset my chosen answer. - When I log in as "student1" - And I am on "Course 1" course homepage - And I follow "Quiz 1" - And I press "Attempt quiz now" - And I should see "Question One" - And I click on "Four" "radio" in the "Question One" "question" - And I should see "Clear my choice" - And I click on "Clear my choice" "button" in the "Question One" "question" - Then I should not see "Clear my choice" - And I click on "Check" "button" in the "Question One" "question" - And I should see "Please select an answer" in the "Question One" "question" diff --git a/question/type/multichoice/tests/walkthrough_test.php b/question/type/multichoice/tests/walkthrough_test.php index 9eb2be43b97..37bc62f630b 100644 --- a/question/type/multichoice/tests/walkthrough_test.php +++ b/question/type/multichoice/tests/walkthrough_test.php @@ -97,4 +97,73 @@ class qtype_multichoice_walkthrough_test extends qbehaviour_walkthrough_test_bas new question_pattern_expectation('/class="r0 correct"/'), new question_pattern_expectation('/class="r1"/')); } + + /** + * Test for clear choice option. + */ + public function test_deferredfeedback_feedback_multichoice_clearchoice() { + + // Create a multichoice, single question. + $mc = test_question_maker::make_a_multichoice_single_question(); + $mc->shuffleanswers = false; + + $clearchoice = -1; + $rightchoice = 0; + $wrongchoice = 2; + + $this->start_attempt_at_question($mc, 'deferredfeedback', 3); + + // Let's first submit the wrong choice (2). + $this->process_submission(array('answer' => $wrongchoice)); // Wrong choice (2). + + $this->check_current_mark(null); + // Clear choice radio should not be checked. + $this->check_current_output( + $this->get_contains_mc_radio_expectation($rightchoice, true, false), // Not checked. + $this->get_contains_mc_radio_expectation($rightchoice + 1, true, false), // Not checked. + $this->get_contains_mc_radio_expectation($rightchoice + 2, true, true), // Wrong choice (2) checked. + $this->get_contains_mc_radio_expectation($clearchoice, true, false), // Not checked. + $this->get_does_not_contain_correctness_expectation(), + $this->get_does_not_contain_feedback_expectation() + ); + + // Now, let's clear our previous choice. + $this->process_submission(array('answer' => $clearchoice)); // Clear choice (-1). + $this->check_current_mark(null); + + // This time, the clear choice radio should be the only one checked. + $this->check_current_output( + $this->get_contains_mc_radio_expectation($rightchoice, true, false), // Not checked. + $this->get_contains_mc_radio_expectation($rightchoice + 1, true, false), // Not checked. + $this->get_contains_mc_radio_expectation($rightchoice + 2, true, false), // Not checked. + $this->get_contains_mc_radio_expectation($clearchoice, true, true), // Clear choice radio checked. + $this->get_does_not_contain_correctness_expectation(), + $this->get_does_not_contain_feedback_expectation() + ); + + // Finally, let's submit the right choice. + $this->process_submission(array('answer' => $rightchoice)); // Right choice (0). + $this->check_current_state(question_state::$complete); + $this->check_current_mark(null); + $this->check_current_output( + $this->get_contains_mc_radio_expectation($rightchoice, true, true), + $this->get_contains_mc_radio_expectation($rightchoice + 1, true, false), + $this->get_contains_mc_radio_expectation($rightchoice + 2, true, false), + $this->get_contains_mc_radio_expectation($clearchoice, true, false), + $this->get_does_not_contain_correctness_expectation(), + $this->get_does_not_contain_feedback_expectation() + ); + + // Finish the attempt. + $this->finish(); + + // Verify. + $this->check_current_state(question_state::$gradedright); + $this->check_current_mark(3); + $this->check_current_output( + $this->get_contains_mc_radio_expectation($rightchoice, false, true), + $this->get_contains_correct_expectation(), + new question_pattern_expectation('/class="r0 correct"/'), + new question_pattern_expectation('/class="r1"/')); + } }