This commit is contained in:
Juba.M 2025-03-21 13:30:53 -04:00 committed by GitHub
commit b0d798ec10
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 149 additions and 57 deletions

View file

@ -75,36 +75,36 @@ describe('ManageRoom', () => {
</MemoryRouter>
);
});
await act(async () => {
const createSuccessCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'create-success')[1];
createSuccessCallback('Test Room');
});
await waitFor(() => {
expect(ApiService.getQuiz).toHaveBeenCalledWith('test-quiz-id');
});
const launchButton = screen.getByText('Lancer');
fireEvent.click(launchButton);
const rythmeButton = screen.getByText('Rythme du professeur');
fireEvent.click(rythmeButton);
const secondLaunchButton = screen.getAllByText('Lancer');
fireEvent.click(secondLaunchButton[1]);
await waitFor(() => {
expect(screen.getByText('Test Quiz')).toBeInTheDocument();
const roomHeader = document.querySelector('h1');
expect(roomHeader).toHaveTextContent('Salle : TEST ROOM');
expect(screen.getByText('0/60')).toBeInTheDocument();
expect(screen.getByText('Question 1/2')).toBeInTheDocument();
});
});
test('handles create-success event', async () => {
await act(async () => {
render(
@ -171,30 +171,30 @@ describe('ManageRoom', () => {
</MemoryRouter>
);
});
await act(async () => {
const createSuccessCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'create-success')[1];
createSuccessCallback('Test Room');
});
fireEvent.click(screen.getByText('Lancer'));
fireEvent.click(screen.getByText('Rythme du professeur'));
fireEvent.click(screen.getAllByText('Lancer')[1]);
await waitFor(() => {
screen.debug();
});
const nextQuestionButton = await screen.findByRole('button', { name: /Prochaine question/i });
expect(nextQuestionButton).toBeInTheDocument();
fireEvent.click(nextQuestionButton);
await waitFor(() => {
expect(screen.getByText('Question 2/2')).toBeInTheDocument();
});
});
test('handles disconnect', async () => {
await act(async () => {
render(
@ -230,38 +230,38 @@ describe('ManageRoom', () => {
</MemoryRouter>
);
});
await act(async () => {
const createSuccessCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'create-success')[1];
createSuccessCallback('Test Room');
});
const launchButton = screen.getByText('Lancer');
fireEvent.click(launchButton);
const rythmeButton = screen.getByText('Rythme du professeur');
fireEvent.click(rythmeButton);
const secondLaunchButton = screen.getAllByText('Lancer');
fireEvent.click(secondLaunchButton[1]);
await act(async () => {
const userJoinedCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'user-joined')[1];
userJoinedCallback(mockStudents[0]);
});
await act(async () => {
const submitAnswerCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'submit-answer-room')[1];
submitAnswerCallback(mockAnswerData);
});
await waitFor(() => {
// console.info(consoleSpy.mock.calls);
expect(consoleSpy).toHaveBeenCalledWith(
'Received answer from Student 1 for question 1: Answer1'
);
});
consoleSpy.mockRestore();
});
@ -294,5 +294,66 @@ describe('ManageRoom', () => {
expect(screen.queryByText('Student 1')).not.toBeInTheDocument();
});
});
test('initializes isQuestionShown based on quizMode', async() => {
render(<MemoryRouter>
<ManageRoom />
</MemoryRouter>);
await act(async () => {
const createSuccessCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'create-success')[1];
createSuccessCallback('Test Room');
});
await waitFor(() => {
expect(ApiService.getQuiz).toHaveBeenCalledWith('test-quiz-id');
});
const launchButton = screen.getByText('Lancer');
fireEvent.click(launchButton);
const rythmeButton = screen.getByText(`Rythme de l'étudiant`);
fireEvent.click(rythmeButton);
const secondLaunchButton = screen.getAllByText('Lancer');
fireEvent.click(secondLaunchButton[1]);
expect(screen.queryByText('Question')).not.toBeInTheDocument();
});
test('renders the close button when quizMode is student and isQuestionShown is true', async() => {
render(<MemoryRouter>
<ManageRoom />
</MemoryRouter>);
await act(async () => {
const createSuccessCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'create-success')[1];
createSuccessCallback('Test Room');
});
await waitFor(() => {
expect(ApiService.getQuiz).toHaveBeenCalledWith('test-quiz-id');
});
const launchButton = screen.getByText('Lancer');
fireEvent.click(launchButton);
const rythmeButton = screen.getByText(`Rythme de l'étudiant`);
fireEvent.click(rythmeButton);
const secondLaunchButton = screen.getAllByText('Lancer');
fireEvent.click(secondLaunchButton[1]);
const tableHeader = screen.getByText('Q1');
fireEvent.click(tableHeader);
const questionVisibilitySwitch = screen.getByTestId('question-visibility-switch'); // Get the specific switch
expect(screen.getByText(/Question 1\//i)).toBeInTheDocument();
fireEvent.click(questionVisibilitySwitch);
expect(screen.queryByRole('button', { name: /✖/i })).not.toBeInTheDocument();
expect(screen.queryByText(/Question 1\//i)).not.toBeInTheDocument();
});
});

View file

@ -18,14 +18,14 @@ import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
import QuestionDisplay from 'src/components/QuestionsDisplay/QuestionDisplay';
import ApiService from '../../../services/ApiService';
import { QuestionType } from 'src/Types/QuestionType';
import { Button } from '@mui/material';
import { Button, FormControlLabel, Switch } from '@mui/material';
import { checkIfIsCorrect } from './useRooms';
const ManageRoom: React.FC = () => {
const navigate = useNavigate();
const [socket, setSocket] = useState<Socket | null>(null);
const [students, setStudents] = useState<StudentType[]>([]);
const { quizId = '', roomName = '' } = useParams<{ quizId: string, roomName: string }>();
const { quizId = '', roomName = '' } = useParams<{ quizId: string, roomName: string }>();
const [quizQuestions, setQuizQuestions] = useState<QuestionType[] | undefined>();
const [quiz, setQuiz] = useState<QuizType | null>(null);
const [quizMode, setQuizMode] = useState<'teacher' | 'student'>('teacher');
@ -34,6 +34,7 @@ const ManageRoom: React.FC = () => {
const [quizStarted, setQuizStarted] = useState<boolean>(false);
const [formattedRoomName, setFormattedRoomName] = useState("");
const [newlyConnectedUser, setNewlyConnectedUser] = useState<StudentType | null>(null);
const [isQuestionShown, setIsQuestionShown] = useState<boolean>(quizMode === 'student' ? false : true);
// Handle the newly connected user in useEffect, because it needs state info
// not available in the socket.on() callback
@ -41,13 +42,13 @@ const ManageRoom: React.FC = () => {
if (newlyConnectedUser) {
console.log(`Handling newly connected user: ${newlyConnectedUser.name}`);
setStudents((prevStudents) => [...prevStudents, newlyConnectedUser]);
// only send nextQuestion if the quiz has started
if (!quizStarted) {
console.log(`!quizStarted: returning.... `);
return;
}
if (quizMode === 'teacher') {
webSocketService.nextQuestion({
roomName: formattedRoomName,
@ -60,12 +61,16 @@ const ManageRoom: React.FC = () => {
} else {
console.error('Invalid quiz mode:', quizMode);
}
// Reset the newly connected user state
setNewlyConnectedUser(null);
}
}, [newlyConnectedUser]);
useEffect(() => {
setIsQuestionShown(quizMode === 'student' ? false : true);
}, [quizMode]);
useEffect(() => {
const verifyLogin = async () => {
if (!ApiService.isLoggedIn()) {
@ -91,7 +96,7 @@ const ManageRoom: React.FC = () => {
return () => {
disconnectWebSocket();
};
}, [roomName, navigate]);
}, [roomName, navigate]);
useEffect(() => {
if (quizId) {
@ -213,14 +218,14 @@ const ManageRoom: React.FC = () => {
console.log(`Comparing ${ans.idQuestion} to ${idQuestion}`);
return ans.idQuestion === idQuestion
? {
...ans,
answer,
isCorrect: checkIfIsCorrect(
answer,
idQuestion,
quizQuestions!
)
}
...ans,
answer,
isCorrect: checkIfIsCorrect(
answer,
idQuestion,
quizQuestions!
)
}
: ans;
});
} else {
@ -253,10 +258,12 @@ const ManageRoom: React.FC = () => {
if (nextQuestionIndex === undefined || nextQuestionIndex > quizQuestions.length - 1) return;
setCurrentQuestion(quizQuestions[nextQuestionIndex]);
webSocketService.nextQuestion({roomName: formattedRoomName,
questions: quizQuestions,
questionIndex: nextQuestionIndex,
isLaunch: false});
webSocketService.nextQuestion({
roomName: formattedRoomName,
questions: quizQuestions,
questionIndex: nextQuestionIndex,
isLaunch: false
});
};
const previousQuestion = () => {
@ -266,7 +273,7 @@ const ManageRoom: React.FC = () => {
if (prevQuestionIndex === undefined || prevQuestionIndex < 0) return;
setCurrentQuestion(quizQuestions[prevQuestionIndex]);
webSocketService.nextQuestion({roomName: formattedRoomName, questions: quizQuestions, questionIndex: prevQuestionIndex, isLaunch: false});
webSocketService.nextQuestion({ roomName: formattedRoomName, questions: quizQuestions, questionIndex: prevQuestionIndex, isLaunch: false });
};
const initializeQuizQuestion = () => {
@ -294,7 +301,7 @@ const ManageRoom: React.FC = () => {
}
setCurrentQuestion(quizQuestions[0]);
webSocketService.nextQuestion({roomName: formattedRoomName, questions: quizQuestions, questionIndex: 0, isLaunch: true});
webSocketService.nextQuestion({ roomName: formattedRoomName, questions: quizQuestions, questionIndex: 0, isLaunch: true });
};
const launchStudentMode = () => {
@ -306,6 +313,7 @@ const ManageRoom: React.FC = () => {
return;
}
setQuizQuestions(quizQuestions);
setCurrentQuestion(quizQuestions[0]);
webSocketService.launchStudentModeQuiz(formattedRoomName, quizQuestions);
};
@ -331,9 +339,11 @@ const ManageRoom: React.FC = () => {
if (quiz?.content && quizQuestions) {
setCurrentQuestion(quizQuestions[questionIndex]);
if (quizMode === 'teacher') {
webSocketService.nextQuestion({roomName: formattedRoomName, questions: quizQuestions, questionIndex, isLaunch: false});
webSocketService.nextQuestion({ roomName: formattedRoomName, questions: quizQuestions, questionIndex, isLaunch: false });
}
setIsQuestionShown(true);
}
};
const handleReturn = () => {
@ -398,15 +408,35 @@ const ManageRoom: React.FC = () => {
{/* the following breaks the css (if 'room' classes are nested) */}
<div className="">
{quizQuestions ? (
<div style={{ display: 'flex', flexDirection: 'column' }}>
<div className="title center-h-align mb-2">{quiz?.title}</div>
{!isNaN(Number(currentQuestion?.question.id)) && (
<strong className="number of questions">
Question {Number(currentQuestion?.question.id)}/
{quizQuestions?.length}
</strong>
)}
<div className='close-button-wrapper'>
<FormControlLabel
label={<div className="text-sm">Afficher les questions</div>}
control={
<Switch
data-testid="question-visibility-switch" // Add a unique test ID
checked={isQuestionShown}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setIsQuestionShown(e.target.checked)
}
/>
}
/>
</div>
{!isNaN(Number(currentQuestion?.question.id))
&& isQuestionShown && (
<strong className="number of questions">
Question {Number(currentQuestion?.question.id)}/
{quizQuestions?.length}
</strong>
)
}
{quizMode === 'teacher' && (
<div className="mb-1">
@ -421,11 +451,11 @@ const ManageRoom: React.FC = () => {
<div className="mb-2 flex-column-wrapper">
<div className="preview-and-result-container">
{currentQuestion && (
{currentQuestion && isQuestionShown && (
<QuestionDisplay
showAnswer={false}
question={currentQuestion?.question as Question}
/>
)}

View file

@ -37,10 +37,11 @@
/* align-items: center; */
}
.close-button-wrapper{
display: flex;
justify-content: flex-start;
margin-right: 1rem;
}
/* .create-room-container {
display: flex;