feat add olx solution support (#225)
This adds support for the tag in OLX and maps it to the description in the settings options on the ShowAnswer card. https://2u-internal.atlassian.net/browse/TNL-10397
This commit is contained in:
@@ -8,24 +8,24 @@ import { ProblemTypeKeys } from '../../../data/constants/problem';
|
||||
export const indexToLetterMap = [...Array(26)].map((val, i) => String.fromCharCode(i + 65));
|
||||
|
||||
export const nonQuestionKeys = [
|
||||
'responseparam',
|
||||
'formulaequationinput',
|
||||
'correcthint',
|
||||
'@_answer',
|
||||
'optioninput',
|
||||
'@_type',
|
||||
'additional_answer',
|
||||
'checkboxgroup',
|
||||
'choicegroup',
|
||||
'additional_answer',
|
||||
'stringequalhint',
|
||||
'textline',
|
||||
'@_type',
|
||||
'formulaequationinput',
|
||||
'numericalresponse',
|
||||
'stringresponse',
|
||||
'multiplechoiceresponse',
|
||||
'choiceresponse',
|
||||
'optionresponse',
|
||||
'correcthint',
|
||||
'demandhint',
|
||||
'formulaequationinput',
|
||||
'multiplechoiceresponse',
|
||||
'numericalresponse',
|
||||
'optioninput',
|
||||
'optionresponse',
|
||||
'responseparam',
|
||||
'solution',
|
||||
'stringequalhint',
|
||||
'stringresponse',
|
||||
'textline',
|
||||
];
|
||||
|
||||
export class OLXParser {
|
||||
@@ -327,6 +327,38 @@ export class OLXParser {
|
||||
return hintsObject;
|
||||
}
|
||||
|
||||
#extractTextAndChildren(node) {
|
||||
const children = [];
|
||||
let text = null;
|
||||
|
||||
if (_.isArray(node)) {
|
||||
children.push(...node);
|
||||
} else if (_.isPlainObject(node)) {
|
||||
text = _.get(node, '#text');
|
||||
const nodeWithoutText = _.omit(node, '#text');
|
||||
children.push(...Object.values(nodeWithoutText));
|
||||
}
|
||||
|
||||
return { text, children };
|
||||
}
|
||||
|
||||
getSolutionExplanation() {
|
||||
if (!_.has(this.problem, 'solution')) { return null; }
|
||||
|
||||
const stack = [this.problem.solution];
|
||||
const texts = [];
|
||||
let currentNode;
|
||||
|
||||
while (stack.length) {
|
||||
currentNode = stack.pop();
|
||||
const { text, children } = this.#extractTextAndChildren(currentNode);
|
||||
if (text) { texts.push(text); }
|
||||
stack.push(...children);
|
||||
}
|
||||
|
||||
return texts.reverse().join('\n ');
|
||||
}
|
||||
|
||||
getFeedback(xmlElement) {
|
||||
return _.has(xmlElement, 'correcthint') ? _.get(xmlElement, 'correcthint.#text') : '';
|
||||
}
|
||||
@@ -365,6 +397,8 @@ export class OLXParser {
|
||||
const problemType = this.getProblemType();
|
||||
const hints = this.getHints();
|
||||
const question = this.parseQuestions(problemType);
|
||||
const solutionExplanation = this.getSolutionExplanation();
|
||||
|
||||
switch (problemType) {
|
||||
case ProblemTypeKeys.DROPDOWN:
|
||||
answersObject = this.parseMultipleChoiceAnswers(ProblemTypeKeys.DROPDOWN, 'optioninput', 'option');
|
||||
@@ -400,6 +434,8 @@ export class OLXParser {
|
||||
}
|
||||
const { answers } = answersObject;
|
||||
const settings = { hints };
|
||||
if (solutionExplanation) { settings.solutionExplanation = solutionExplanation; }
|
||||
|
||||
return {
|
||||
question,
|
||||
settings,
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { OLXParser } from './OLXParser';
|
||||
import {
|
||||
checkboxesOLXWithFeedbackAndHintsOLX,
|
||||
getCheckboxesOLXWithFeedbackAndHintsOLX,
|
||||
dropdownOLXWithFeedbackAndHintsOLX,
|
||||
numericInputWithFeedbackAndHintsOLX,
|
||||
numericInputWithFeedbackAndHintsOLXException,
|
||||
textInputWithFeedbackAndHintsOLX,
|
||||
mutlipleChoiceWithFeedbackAndHintsOLX,
|
||||
multipleChoiceWithFeedbackAndHintsOLX,
|
||||
textInputWithFeedbackAndHintsOLXWithMultipleAnswers,
|
||||
advancedProblemOlX,
|
||||
multipleProblemOlX,
|
||||
@@ -31,7 +32,7 @@ describe('Check OLXParser problem type', () => {
|
||||
expect(problemType).toBe(ProblemTypeKeys.DROPDOWN);
|
||||
});
|
||||
test('Test multiple choice with feedback and hints problem type', () => {
|
||||
const olxparser = new OLXParser(mutlipleChoiceWithFeedbackAndHintsOLX.rawOLX);
|
||||
const olxparser = new OLXParser(multipleChoiceWithFeedbackAndHintsOLX.rawOLX);
|
||||
const problemType = olxparser.getProblemType();
|
||||
expect(problemType).toBe(ProblemTypeKeys.SINGLESELECT);
|
||||
});
|
||||
@@ -74,9 +75,9 @@ describe('Check OLXParser hints', () => {
|
||||
expect(hints).toEqual(dropdownOLXWithFeedbackAndHintsOLX.hints);
|
||||
});
|
||||
test('Test multiple choice with feedback and hints problem type', () => {
|
||||
const olxparser = new OLXParser(mutlipleChoiceWithFeedbackAndHintsOLX.rawOLX);
|
||||
const olxparser = new OLXParser(multipleChoiceWithFeedbackAndHintsOLX.rawOLX);
|
||||
const hints = olxparser.getHints();
|
||||
expect(hints).toEqual(mutlipleChoiceWithFeedbackAndHintsOLX.hints);
|
||||
expect(hints).toEqual(multipleChoiceWithFeedbackAndHintsOLX.hints);
|
||||
});
|
||||
test('Test textual problem type', () => {
|
||||
const olxparser = new OLXParser(textInputWithFeedbackAndHintsOLX.rawOLX);
|
||||
@@ -97,9 +98,9 @@ describe('Check OLXParser for answer parsing', () => {
|
||||
expect(answer).toEqual(dropdownOLXWithFeedbackAndHintsOLX.data);
|
||||
});
|
||||
test('Test multiple choice single select', () => {
|
||||
const olxparser = new OLXParser(mutlipleChoiceWithFeedbackAndHintsOLX.rawOLX);
|
||||
const olxparser = new OLXParser(multipleChoiceWithFeedbackAndHintsOLX.rawOLX);
|
||||
const answer = olxparser.parseMultipleChoiceAnswers('multiplechoiceresponse', 'choicegroup', 'choice');
|
||||
expect(answer).toEqual(mutlipleChoiceWithFeedbackAndHintsOLX.data);
|
||||
expect(answer).toEqual(multipleChoiceWithFeedbackAndHintsOLX.data);
|
||||
});
|
||||
test('Test string response answers', () => {
|
||||
const olxparser = new OLXParser(textInputWithFeedbackAndHintsOLX.rawOLX);
|
||||
@@ -135,9 +136,9 @@ describe('Check OLXParser for question parsing', () => {
|
||||
expect(question).toEqual(dropdownOLXWithFeedbackAndHintsOLX.question);
|
||||
});
|
||||
test('Test multiple choice single select question', () => {
|
||||
const olxparser = new OLXParser(mutlipleChoiceWithFeedbackAndHintsOLX.rawOLX);
|
||||
const olxparser = new OLXParser(multipleChoiceWithFeedbackAndHintsOLX.rawOLX);
|
||||
const question = olxparser.parseQuestions('multiplechoiceresponse');
|
||||
expect(question).toEqual(mutlipleChoiceWithFeedbackAndHintsOLX.question);
|
||||
expect(question).toEqual(multipleChoiceWithFeedbackAndHintsOLX.question);
|
||||
});
|
||||
test('Test string response question', () => {
|
||||
const olxparser = new OLXParser(textInputWithFeedbackAndHintsOLX.rawOLX);
|
||||
@@ -161,3 +162,20 @@ describe('Check OLXParser for question parsing', () => {
|
||||
expect(question).toBe(blankQuestionOLX.question);
|
||||
});
|
||||
});
|
||||
|
||||
describe('OLXParser for problem with solution tag', () => {
|
||||
describe('for checkbox questions', () => {
|
||||
test('should parse simple text', () => {
|
||||
const olxparser = new OLXParser(checkboxesOLXWithFeedbackAndHintsOLX.rawOLX);
|
||||
const explanation = olxparser.getSolutionExplanation();
|
||||
expect(explanation).toEqual(checkboxesOLXWithFeedbackAndHintsOLX.solutionExplanation);
|
||||
});
|
||||
test('should parse text in p tags', () => {
|
||||
const { rawOLX } = getCheckboxesOLXWithFeedbackAndHintsOLX({ solution: 'html' });
|
||||
const olxparser = new OLXParser(rawOLX);
|
||||
const explanation = olxparser.getSolutionExplanation();
|
||||
const expected = getCheckboxesOLXWithFeedbackAndHintsOLX({ solution: 'html' }).solutionExplanation;
|
||||
expect(explanation.replace(/\s/g, '')).toBe(expected.replace(/\s/g, ''));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -36,6 +36,18 @@ class ReactStateOLXParser {
|
||||
return demandhint;
|
||||
}
|
||||
|
||||
addSolution() {
|
||||
if (!_.has(this.problemState, 'settings.solutionExplanation')) { return {}; }
|
||||
|
||||
const solutionText = _.get(this.problemState, 'settings.solutionExplanation');
|
||||
const solutionObject = {
|
||||
solution: {
|
||||
'#text': solutionText,
|
||||
},
|
||||
};
|
||||
return solutionObject;
|
||||
}
|
||||
|
||||
addMultiSelectAnswers(option) {
|
||||
const choice = [];
|
||||
let compoundhint = [];
|
||||
@@ -106,6 +118,8 @@ class ReactStateOLXParser {
|
||||
const question = this.addQuestion();
|
||||
const widgetObject = this.addMultiSelectAnswers(option);
|
||||
const demandhint = this.addHints();
|
||||
const solution = this.addSolution();
|
||||
|
||||
const problemObject = {
|
||||
problem: {
|
||||
[problemType]: {
|
||||
@@ -113,6 +127,7 @@ class ReactStateOLXParser {
|
||||
[widget]: widgetObject,
|
||||
},
|
||||
...demandhint,
|
||||
...solution,
|
||||
},
|
||||
};
|
||||
return this.builder.build(problemObject);
|
||||
@@ -122,6 +137,8 @@ class ReactStateOLXParser {
|
||||
const question = this.addQuestion();
|
||||
const demandhint = this.addHints();
|
||||
const answerObject = this.buildTextInputAnswersFeedback();
|
||||
const solution = this.addSolution();
|
||||
|
||||
const problemObject = {
|
||||
problem: {
|
||||
[ProblemTypeKeys.TEXTINPUT]: {
|
||||
@@ -129,6 +146,7 @@ class ReactStateOLXParser {
|
||||
...answerObject,
|
||||
},
|
||||
...demandhint,
|
||||
...solution,
|
||||
},
|
||||
};
|
||||
return this.builder.build(problemObject);
|
||||
@@ -178,11 +196,14 @@ class ReactStateOLXParser {
|
||||
const question = this.addQuestion();
|
||||
const demandhint = this.addHints();
|
||||
const answerObject = this.buildNumericalResponse();
|
||||
const solution = this.addSolution();
|
||||
|
||||
const problemObject = {
|
||||
problem: {
|
||||
...question,
|
||||
[ProblemTypeKeys.NUMERIC]: answerObject,
|
||||
...demandhint,
|
||||
...solution,
|
||||
},
|
||||
};
|
||||
return this.builder.build(problemObject);
|
||||
@@ -255,6 +276,7 @@ class ReactStateOLXParser {
|
||||
buildOLX() {
|
||||
const { problemType } = this.problemState;
|
||||
let problemString = '';
|
||||
|
||||
switch (problemType) {
|
||||
case ProblemTypeKeys.MULTISELECT:
|
||||
problemString = this.buildMultiSelectProblem(ProblemTypeKeys.MULTISELECT, 'checkboxgroup', 'choice');
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
numericInputWithFeedbackAndHintsOLX,
|
||||
numericInputWithFeedbackAndHintsOLXException,
|
||||
textInputWithFeedbackAndHintsOLX,
|
||||
mutlipleChoiceWithFeedbackAndHintsOLX,
|
||||
multipleChoiceWithFeedbackAndHintsOLX,
|
||||
textInputWithFeedbackAndHintsOLXWithMultipleAnswers,
|
||||
} from './mockData/olxTestData';
|
||||
import ReactStateOLXParser from './ReactStateOLXParser';
|
||||
@@ -33,11 +33,11 @@ describe('Check React Sate OLXParser problem', () => {
|
||||
expect(buildOLX).toEqual(textInputWithFeedbackAndHintsOLX.buildOLX);
|
||||
});
|
||||
test('Test multiple choice with feedback and hints problem type', () => {
|
||||
const olxparser = new OLXParser(mutlipleChoiceWithFeedbackAndHintsOLX.rawOLX);
|
||||
const olxparser = new OLXParser(multipleChoiceWithFeedbackAndHintsOLX.rawOLX);
|
||||
const problem = olxparser.getParsedOLXData();
|
||||
const stateParser = new ReactStateOLXParser({ problem });
|
||||
const buildOLX = stateParser.buildOLX();
|
||||
expect(buildOLX).toEqual(mutlipleChoiceWithFeedbackAndHintsOLX.buildOLX);
|
||||
expect(buildOLX).toEqual(multipleChoiceWithFeedbackAndHintsOLX.buildOLX);
|
||||
});
|
||||
test('Test numerical response with feedback and hints problem type', () => {
|
||||
const olxparser = new OLXParser(numericInputWithFeedbackAndHintsOLX.rawOLX);
|
||||
|
||||
@@ -1,38 +1,55 @@
|
||||
export const checkboxesOLXWithFeedbackAndHintsOLX = {
|
||||
export const getCheckboxesOLXWithFeedbackAndHintsOLX = ({ solution = 'simple' }) => ({
|
||||
rawOLX: `<problem>
|
||||
<choiceresponse>
|
||||
<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for checkboxes with hints and feedback problems. Edit this component to replace this template with your own assessment.</p>
|
||||
<label>Add the question text, or prompt, here. This text is required.</label>
|
||||
<description>You can add an optional tip or note related to the prompt like this.</description>
|
||||
<checkboxgroup>
|
||||
<choice correct="true">a correct answer
|
||||
<choicehint selected="true">You can specify optional feedback that appears after the learner selects and submits this answer.</choicehint>
|
||||
<choicehint selected="false">You can specify optional feedback that appears after the learner clears and submits this answer.</choicehint>
|
||||
</choice>
|
||||
<choice correct="false">an incorrect answer</choice>
|
||||
<choice correct="false">an incorrect answer
|
||||
<choicehint selected="true">You can specify optional feedback for none, all, or a subset of the answers.</choicehint>
|
||||
<choicehint selected="false">You can specify optional feedback for selected answers, cleared answers, or both.</choicehint>
|
||||
</choice>
|
||||
<choice correct="true">a correct answer</choice>
|
||||
<compoundhint value="A B D">You can specify optional feedback for a combination of answers which appears after the specified set of answers is submitted.</compoundhint>
|
||||
<compoundhint value="A B C D">You can specify optional feedback for one, several, or all answer combinations.</compoundhint>
|
||||
</checkboxgroup>
|
||||
</choiceresponse>
|
||||
<demandhint>
|
||||
<hint>You can add an optional hint like this. Problems that have a hint include a hint button, and this text appears the first time learners select the button.</hint>
|
||||
<hint>If you add more than one hint, a different hint appears each time learners select the hint button.</hint>
|
||||
</demandhint>
|
||||
</problem>`,
|
||||
hints: [{
|
||||
id: 0,
|
||||
value: 'You can add an optional hint like this. Problems that have a hint include a hint button, and this text appears the first time learners select the button.',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
value: 'If you add more than one hint, a different hint appears each time learners select the hint button.',
|
||||
},
|
||||
<choiceresponse>
|
||||
<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for checkboxes with hints and feedback problems. Edit this component to replace this template with your own assessment.</p>
|
||||
<label>Add the question text, or prompt, here. This text is required.</label>
|
||||
<description>You can add an optional tip or note related to the prompt like this.</description>
|
||||
<checkboxgroup>
|
||||
<choice correct="true">a correct answer
|
||||
<choicehint selected="true">You can specify optional feedback that appears after the learner selects and submits this answer.</choicehint>
|
||||
<choicehint selected="false">You can specify optional feedback that appears after the learner clears and submits this answer.</choicehint>
|
||||
</choice>
|
||||
<choice correct="false">an incorrect answer</choice>
|
||||
<choice correct="false">an incorrect answer
|
||||
<choicehint selected="true">You can specify optional feedback for none, all, or a subset of the answers.</choicehint>
|
||||
<choicehint selected="false">You can specify optional feedback for selected answers, cleared answers, or both.</choicehint>
|
||||
</choice>
|
||||
<choice correct="true">a correct answer</choice>
|
||||
<compoundhint value="A B D">You can specify optional feedback for a combination of answers which appears after the specified set of answers is submitted.</compoundhint>
|
||||
<compoundhint value="A B C D">You can specify optional feedback for one, several, or all answer combinations.</compoundhint>
|
||||
</checkboxgroup>
|
||||
</choiceresponse>
|
||||
<demandhint>
|
||||
<hint>You can add an optional hint like this. Problems that have a hint include a hint button, and this text appears the first time learners select the button.</hint>
|
||||
<hint>If you add more than one hint, a different hint appears each time learners select the hint button.</hint>
|
||||
</demandhint>
|
||||
${solution === 'simple' ? '<solution>This is a detailed explanation of the solution.</solution>' : (
|
||||
`<solution>
|
||||
<div class="detailed-solution">
|
||||
<p>Explanation</p>
|
||||
<p>
|
||||
You can form a voltage divider that evenly divides the input
|
||||
voltage with two identically valued resistors, with the sampled
|
||||
voltage taken in between the two.
|
||||
</p>
|
||||
<p><img src="/static/images/voltage_divider.png" alt=""/></p>
|
||||
</div>
|
||||
</solution>`
|
||||
)}
|
||||
</problem>`,
|
||||
hints: [
|
||||
{
|
||||
id: 0,
|
||||
value: 'You can add an optional hint like this. Problems that have a hint include a hint button, and this text appears the first time learners select the button.',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
value: 'If you add more than one hint, a different hint appears each time learners select the hint button.',
|
||||
},
|
||||
],
|
||||
solutionExplanation: solution === 'simple' ? 'This is a detailed explanation of the solution.' : (
|
||||
'Explanation\n You can form a voltage divider that evenly divides the input voltage with two identically valued resistors, with the sampled voltage taken in between the two.'
|
||||
),
|
||||
data: {
|
||||
answers: [
|
||||
{
|
||||
@@ -107,9 +124,19 @@ an incorrect answer <choicehint selected="true">You can specify optional
|
||||
<hint>You can add an optional hint like this. Problems that have a hint include a hint button, and this text appears the first time learners select the button.</hint>
|
||||
<hint>If you add more than one hint, a different hint appears each time learners select the hint button.</hint>
|
||||
</demandhint>
|
||||
${solution === 'simple' ? '<solution>This is a detailed explanation of the solution.</solution>' : (
|
||||
`<solution>
|
||||
Explanation\n
|
||||
You can form a voltage divider that evenly divides the input
|
||||
voltage with two identically valued resistors, with the sampled
|
||||
voltage taken in between the two.
|
||||
</solution>`
|
||||
)}
|
||||
</problem>
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
export const checkboxesOLXWithFeedbackAndHintsOLX = getCheckboxesOLXWithFeedbackAndHintsOLX({});
|
||||
|
||||
export const dropdownOLXWithFeedbackAndHintsOLX = {
|
||||
rawOLX: `<problem>
|
||||
@@ -184,7 +211,7 @@ an incorrect answer <optionhint>You can specify optional feedback for non
|
||||
`,
|
||||
};
|
||||
|
||||
export const mutlipleChoiceWithFeedbackAndHintsOLX = {
|
||||
export const multipleChoiceWithFeedbackAndHintsOLX = {
|
||||
rawOLX: `<problem>
|
||||
<multiplechoiceresponse>
|
||||
<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for multiple choice with hints and feedback problems. Edit this component to replace this template with your own assessment.</p>
|
||||
|
||||
Reference in New Issue
Block a user