mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-05 00:00:18 -04:00
feat(challenge-parser): add feedback to mc questions (#51942)
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user