feat(challenge-parser): add feedback to mc questions (#51942)

This commit is contained in:
Tom
2023-11-02 01:28:53 -05:00
committed by GitHub
parent 7e1f7e060a
commit bce1b9915b
28 changed files with 346 additions and 42 deletions

View File

@@ -4,10 +4,19 @@ exports[`add-video-question plugin should match the video snapshot 1`] = `
{
"question": {
"answers": [
"<p>Some inline <code>code</code></p>",
"<p>Some <em>italics</em></p>
{
"answer": "<p>Some inline <code>code</code></p>",
"feedback": "<p>That is not correct.</p>",
},
{
"answer": "<p>Some <em>italics</em></p>
<p>A second answer paragraph.</p>",
"<p><code> code in </code> code tags</p>",
"feedback": null,
},
{
"answer": "<p><code> code in </code> code tags</p>",
"feedback": null,
},
],
"solution": 3,
"text": "<p>Question line 1</p>

View File

@@ -1,5 +1,7 @@
const { root } = require('mdast-builder');
const find = require('unist-util-find');
const getAllBetween = require('./utils/between-headings');
const getAllBefore = require('./utils/before-heading');
const mdastToHtml = require('./utils/mdast-to-html');
const { splitOnThematicBreak } = require('./utils/split-on-thematic-break');
@@ -36,7 +38,27 @@ function getQuestion(textNodes, answersNodes, solutionNodes) {
function getAnswers(answersNodes) {
const answerGroups = splitOnThematicBreak(answersNodes);
return answerGroups.map(answer => mdastToHtml(answer));
return answerGroups.map(answerGroup => {
const answerTree = root(answerGroup);
const feedback = find(answerTree, { value: '--feedback--' });
if (feedback) {
const answerNodes = getAllBefore(answerTree, '--feedback--');
const feedbackNodes = getAllBetween(answerTree, '--feedback--');
if (answerNodes.length < 1) {
throw Error('Answer missing');
}
return {
answer: mdastToHtml(answerNodes),
feedback: mdastToHtml(feedbackNodes)
};
}
return { answer: mdastToHtml(answerGroup), feedback: null };
});
}
function getSolution(solutionNodes) {

View File

@@ -23,7 +23,7 @@ describe('add-video-question plugin', () => {
});
it('should generate a question object from a video challenge AST', () => {
expect.assertions(8);
expect.assertions(10);
plugin(mockVideoAST, file);
const testObject = file.data.question;
expect(Object.keys(testObject).length).toBe(3);
@@ -33,7 +33,9 @@ describe('add-video-question plugin', () => {
expect(typeof testObject.solution).toBe('number');
expect(testObject).toHaveProperty('answers');
expect(Array.isArray(testObject.answers)).toBe(true);
expect(typeof testObject.answers[0]).toBe('string');
expect(typeof testObject.answers[0]).toBe('object');
expect(testObject.answers[0]).toHaveProperty('answer');
expect(testObject.answers[0]).toHaveProperty('feedback');
});
it('should convert question and answer markdown into html', () => {
@@ -46,12 +48,19 @@ describe('add-video-question plugin', () => {
'</code></pre>'
);
expect(testObject.solution).toBe(3);
expect(testObject.answers[0]).toBe('<p>Some inline <code>code</code></p>');
expect(testObject.answers[1]).toBe(`<p>Some <em>italics</em></p>
<p>A second answer paragraph.</p>`);
expect(testObject.answers[2]).toBe(
'<p><code> code in </code> code tags</p>'
);
expect(testObject.answers[0]).toStrictEqual({
answer: '<p>Some inline <code>code</code></p>',
feedback: '<p>That is not correct.</p>'
});
expect(testObject.answers[1]).toStrictEqual({
answer: `<p>Some <em>italics</em></p>
<p>A second answer paragraph.</p>`,
feedback: null
});
expect(testObject.answers[2]).toStrictEqual({
answer: '<p><code> code in </code> code tags</p>',
feedback: null
});
});
// TODO: consider testing for more specific messages. Ideally we them to say

View File

@@ -0,0 +1,21 @@
const find = require('unist-util-find');
const findAllBefore = require('unist-util-find-all-before');
function getAllBefore(tree, marker) {
const start = find(tree, {
type: 'heading',
children: [
{
type: 'text',
value: marker
}
]
});
if (!start) return [];
// reverse because it goes up the tree backwards and adds nodes in that order
return findAllBefore(tree, start).reverse();
}
module.exports = getAllBefore;

View File

@@ -0,0 +1,24 @@
const isArray = require('lodash/isArray');
const simpleAst = require('../../__fixtures__/ast-simple.json');
const getAllBefore = require('./before-heading');
describe('before-headings', () => {
it('should return an array', () => {
expect.assertions(1);
const actual = getAllBefore(simpleAst, '--hints--');
expect(isArray(actual)).toBe(true);
});
it('should return an empty array if the marker is not present', () => {
expect.assertions(2);
const actual = getAllBefore(simpleAst, '--not-a-marker--');
expect(isArray(actual)).toBe(true);
expect(actual.length).toBe(0);
});
it('should include the whole AST before the marker', () => {
expect.assertions(1);
const actual = getAllBefore(simpleAst, '--hints--');
expect(actual).toHaveLength(6);
});
});