Merge pull request #219 from ets-cfuhrman-pfe/JubaAzul/issue218
Some checks are pending
CI/CD Pipeline for Backend / build_and_push_backend (push) Waiting to run
CI/CD Pipeline for Nginx Router / build_and_push_nginx (push) Waiting to run
CI/CD Pipeline for Frontend / build_and_push_frontend (push) Waiting to run
Tests / tests (client) (push) Waiting to run
Tests / tests (server) (push) Waiting to run

L'affichage de la bonne réponse dans les rétroactions ne fonctionne plus
This commit is contained in:
Christopher (Cris) Fuhrman 2025-01-31 22:58:29 -05:00 committed by GitHub
commit 4b9ded9a26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 146 additions and 39 deletions

View file

@ -1,4 +1,4 @@
import React from 'react'; import React, { useState } from 'react';
import { render, screen, fireEvent } from '@testing-library/react'; import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';
import { act } from 'react'; import { act } from 'react';
@ -17,21 +17,30 @@ const question = questions[0];
describe('MultipleChoiceQuestionDisplay', () => { describe('MultipleChoiceQuestionDisplay', () => {
const mockHandleOnSubmitAnswer = jest.fn(); const mockHandleOnSubmitAnswer = jest.fn();
const sampleProps = {
question: question, const TestWrapper = ({ showAnswer }: { showAnswer: boolean }) => {
handleOnSubmitAnswer: mockHandleOnSubmitAnswer, const [showAnswerState, setShowAnswerState] = useState(showAnswer);
showAnswer: false
const handleOnSubmitAnswer = (answer: string) => {
mockHandleOnSubmitAnswer(answer);
setShowAnswerState(true);
};
return (
<MemoryRouter>
<MultipleChoiceQuestionDisplay
question={question}
handleOnSubmitAnswer={handleOnSubmitAnswer}
showAnswer={showAnswerState}
/>
</MemoryRouter>
);
}; };
const choices = question.choices; const choices = question.choices;
beforeEach(() => { beforeEach(() => {
render( render(<TestWrapper showAnswer={false} />);
<MemoryRouter>
<MultipleChoiceQuestionDisplay
{...sampleProps}
/>
</MemoryRouter>);
}); });
test('renders the question and choices', () => { test('renders the question and choices', () => {
@ -55,7 +64,6 @@ describe('MultipleChoiceQuestionDisplay', () => {
act(() => { act(() => {
fireEvent.click(choiceButton); fireEvent.click(choiceButton);
}); });
const submitButton = screen.getByText('Répondre'); const submitButton = screen.getByText('Répondre');
act(() => { act(() => {
fireEvent.click(submitButton); fireEvent.click(submitButton);
@ -63,4 +71,51 @@ describe('MultipleChoiceQuestionDisplay', () => {
expect(mockHandleOnSubmitAnswer).toHaveBeenCalledWith('Choice 1'); expect(mockHandleOnSubmitAnswer).toHaveBeenCalledWith('Choice 1');
}); });
});
it('should show ✅ next to the correct answer and ❌ next to the wrong answers when showAnswer is true', async () => {
const choiceButton = screen.getByText('Choice 1').closest('button');
if (!choiceButton) throw new Error('Choice button not found');
// Click on choiceButton
act(() => {
fireEvent.click(choiceButton);
});
const button = screen.getByText("Répondre");
act(() => {
fireEvent.click(button);
});
// Wait for the DOM to update
const correctAnswer = screen.getByText("Choice 1").closest('button');
expect(correctAnswer).toBeInTheDocument();
expect(correctAnswer?.textContent).toContain('✅');
const wrongAnswer1 = screen.getByText("Choice 2").closest('button');
expect(wrongAnswer1).toBeInTheDocument();
expect(wrongAnswer1?.textContent).toContain('❌');
});
it('should not show ✅ or ❌ when repondre button is not clicked', async () => {
const choiceButton = screen.getByText('Choice 1').closest('button');
if (!choiceButton) throw new Error('Choice button not found');
// Click on choiceButton
act(() => {
fireEvent.click(choiceButton);
});
// Check for correct answer
const correctAnswer = screen.getByText("Choice 1").closest('button');
expect(correctAnswer).toBeInTheDocument();
expect(correctAnswer?.textContent).not.toContain('✅');
// Check for wrong answers
const wrongAnswer1 = screen.getByText("Choice 2");
expect(wrongAnswer1).toBeInTheDocument();
expect(wrongAnswer1?.textContent).not.toContain('❌');
});
});

View file

@ -1,5 +1,5 @@
// TrueFalseQuestion.test.tsx // TrueFalseQuestion.test.tsx
import React from 'react'; import React, { useState } from 'react';
import { render, fireEvent, screen, act } from '@testing-library/react'; import { render, fireEvent, screen, act } from '@testing-library/react';
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
@ -12,17 +12,28 @@ describe('TrueFalseQuestion Component', () => {
const trueFalseQuestion = const trueFalseQuestion =
parse(`${sampleStem}{T}`)[0] as TrueFalseQuestion; parse(`${sampleStem}{T}`)[0] as TrueFalseQuestion;
const sampleProps = {
question: trueFalseQuestion, const TestWrapper = ({ showAnswer }: { showAnswer: boolean }) => {
handleOnSubmitAnswer: mockHandleSubmitAnswer, const [showAnswerState, setShowAnswerState] = useState(showAnswer);
showAnswer: false
const handleOnSubmitAnswer = (answer: boolean) => {
mockHandleSubmitAnswer(answer);
setShowAnswerState(true);
};
return (
<MemoryRouter>
<TrueFalseQuestionDisplay
question={trueFalseQuestion}
handleOnSubmitAnswer={handleOnSubmitAnswer}
showAnswer={showAnswerState}
/>
</MemoryRouter>
);
}; };
beforeEach(() => { beforeEach(() => {
render( render(<TestWrapper showAnswer={false} />);
<MemoryRouter>
<TrueFalseQuestionDisplay {...sampleProps} />
</MemoryRouter>);
}); });
it('renders correctly', () => { it('renders correctly', () => {
@ -73,4 +84,50 @@ describe('TrueFalseQuestion Component', () => {
expect(mockHandleSubmitAnswer).toHaveBeenCalledWith(false); expect(mockHandleSubmitAnswer).toHaveBeenCalledWith(false);
}); });
it('should show ✅ next to the correct answer and ❌ next to the wrong answers when showAnswer is true', async () => {
const choiceButton = screen.getByText('Vrai').closest('button');
if (!choiceButton) throw new Error('T button not found');
// Click on choiceButton
act(() => {
fireEvent.click(choiceButton);
});
const button = screen.getByText("Répondre");
act(() => {
fireEvent.click(button);
});
// Wait for the DOM to update
const correctAnswer = screen.getByText("Vrai").closest('button');
expect(correctAnswer).toBeInTheDocument();
expect(correctAnswer?.textContent).toContain('✅');
const wrongAnswer1 = screen.getByText("Faux").closest('button');
expect(wrongAnswer1).toBeInTheDocument();
expect(wrongAnswer1?.textContent).toContain('❌');
});
it('should not show ✅ or ❌ when repondre button is not clicked', async () => {
const choiceButton = screen.getByText('Vrai').closest('button');
if (!choiceButton) throw new Error('Choice button not found');
// Click on choiceButton
act(() => {
fireEvent.click(choiceButton);
});
// Check for correct answer
const correctAnswer = screen.getByText("Vrai").closest('button');
expect(correctAnswer).toBeInTheDocument();
expect(correctAnswer?.textContent).not.toContain('✅');
// Check for wrong answers
const wrongAnswer1 = screen.getByText("Faux");
expect(wrongAnswer1).toBeInTheDocument();
expect(wrongAnswer1?.textContent).not.toContain('❌');
});
}); });

View file

@ -12,7 +12,6 @@ interface Props {
} }
const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => { const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
const { question, showAnswer, handleOnSubmitAnswer } = props; const { question, showAnswer, handleOnSubmitAnswer } = props;
const [answer, setAnswer] = useState<string>(); const [answer, setAnswer] = useState<string>();
@ -24,7 +23,6 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
setAnswer(choice); setAnswer(choice);
}; };
const alpha = Array.from(Array(26)).map((_e, i) => i + 65); const alpha = Array.from(Array(26)).map((_e, i) => i + 65);
const alphabet = alpha.map((x) => String.fromCharCode(x)); const alphabet = alpha.map((x) => String.fromCharCode(x));
return ( return (
@ -40,22 +38,20 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
<Button <Button
variant="text" variant="text"
className="button-wrapper" className="button-wrapper"
onClick={() => !showAnswer && handleOnClickAnswer(choice.formattedText.text)} onClick={() => !showAnswer && handleOnClickAnswer(choice.formattedText.text)}>
> {showAnswer? (<div> {(choice.isCorrect ? '✅' : '❌')}</div>)
{choice.formattedFeedback === null && :``}
showAnswer &&
(choice.isCorrect ? '✅' : '❌')}
<div className={`circle ${selected}`}>{alphabet[i]}</div> <div className={`circle ${selected}`}>{alphabet[i]}</div>
<div className={`answer-text ${selected}`}> <div className={`answer-text ${selected}`}>
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedText) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedText) }} />
</div> </div>
</Button>
{choice.formattedFeedback && showAnswer && ( {choice.formattedFeedback && showAnswer && (
<div className="feedback-container mb-1 mt-1/2"> <div className="feedback-container mb-1 mt-1/2">
{choice.isCorrect ? '✅' : '❌'}
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedFeedback) }} /> <div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(choice.formattedFeedback) }} />
</div> </div>
)} )}
</Button>
</div> </div>
); );
})} })}

View file

@ -22,7 +22,6 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
const selectedTrue = answer ? 'selected' : ''; const selectedTrue = answer ? 'selected' : '';
const selectedFalse = answer !== undefined && !answer ? 'selected' : ''; const selectedFalse = answer !== undefined && !answer ? 'selected' : '';
const correctAnswer = question.isTrue === answer;
return ( return (
<div className="question-container"> <div className="question-container">
<div className="question content"> <div className="question content">
@ -34,7 +33,7 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
onClick={() => !showAnswer && setAnswer(true)} onClick={() => !showAnswer && setAnswer(true)}
fullWidth fullWidth
> >
{showAnswer && (correctAnswer ? '✅' : '❌')} {showAnswer? (<div> {(question.isTrue ? '✅' : '❌')}</div>):``}
<div className={`circle ${selectedTrue}`}>V</div> <div className={`circle ${selectedTrue}`}>V</div>
<div className={`answer-text ${selectedTrue}`}>Vrai</div> <div className={`answer-text ${selectedTrue}`}>Vrai</div>
</Button> </Button>
@ -43,7 +42,7 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
onClick={() => !showAnswer && setAnswer(false)} onClick={() => !showAnswer && setAnswer(false)}
fullWidth fullWidth
> >
{showAnswer && (!correctAnswer ? '✅' : '❌')} {showAnswer? (<div> {(!question.isTrue ? '✅' : '❌')}</div>):``}
<div className={`circle ${selectedFalse}`}>F</div> <div className={`circle ${selectedFalse}`}>F</div>
<div className={`answer-text ${selectedFalse}`}>Faux</div> <div className={`answer-text ${selectedFalse}`}>Faux</div>
</Button> </Button>

View file

@ -31,7 +31,7 @@
"supertest": "^6.3.4" "supertest": "^6.3.4"
}, },
"engines": { "engines": {
"node": "18.x" "node": "20.x"
} }
}, },
"node_modules/@ampproject/remapping": { "node_modules/@ampproject/remapping": {