diff --git a/client/src/__tests__/pages/ManageRoom/ManageRoom.test.tsx b/client/src/__tests__/pages/ManageRoom/ManageRoom.test.tsx index 01957df..3e964d2 100644 --- a/client/src/__tests__/pages/ManageRoom/ManageRoom.test.tsx +++ b/client/src/__tests__/pages/ManageRoom/ManageRoom.test.tsx @@ -75,36 +75,36 @@ describe('ManageRoom', () => { ); }); - + 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', () => { ); }); - + 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', () => { ); }); - + 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,75 @@ describe('ManageRoom', () => { expect(screen.queryByText('Student 1')).not.toBeInTheDocument(); }); }); + + test('handles user joined and leaves but name still seeable', async () => { + await act(async () => { + render( + + + + ); + }); + + await act(async () => { + const createSuccessCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'create-success')[1]; + createSuccessCallback('Test Room'); + }); + + 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 userJoinedCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'user-joined')[1]; + userJoinedCallback(mockStudents[1]); + }); + + await waitFor(() => { + expect(screen.getByText('Student 1')).toBeInTheDocument(); + + }); + await waitFor(() => { + expect(screen.getByText('Student 2')).toBeInTheDocument(); + + }); + + 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('2/60')).toBeInTheDocument(); + + }); + + await act(async () => { + const userDisconnectedCallback = (mockSocket.on as jest.Mock).mock.calls.find(call => call[0] === 'user-disconnected')[1]; + userDisconnectedCallback(mockStudents[1].id); + }); + + + await waitFor(() => { + expect(screen.getByText('Résultats du quiz')).toBeInTheDocument(); + + }); + const toggleUsernamesSwitch = screen.getByLabelText('Afficher les noms'); + + // Toggle the display of usernames back + fireEvent.click(toggleUsernamesSwitch); + + expect(screen.getByText('Student 1')).toBeInTheDocument(); + + expect(screen.getByText('Student 2')).toBeInTheDocument(); + + await waitFor(() => { + expect(screen.getByText('1/60')).toBeInTheDocument(); + }); + }); }); diff --git a/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx b/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx index 8c3d699..c41a2fd 100644 --- a/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx +++ b/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx @@ -24,8 +24,9 @@ import { checkIfIsCorrect } from './useRooms'; const ManageRoom: React.FC = () => { const navigate = useNavigate(); const [socket, setSocket] = useState(null); - const [students, setStudents] = useState([]); - const { quizId = '', roomName = '' } = useParams<{ quizId: string, roomName: string }>(); + const [connectedStudents, setConnectedStudents] = useState([]); + const [totalStudents, setTotalStudents] = useState([]); + const { quizId = '', roomName = '' } = useParams<{ quizId: string, roomName: string }>(); const [quizQuestions, setQuizQuestions] = useState(); const [quiz, setQuiz] = useState(null); const [quizMode, setQuizMode] = useState<'teacher' | 'student'>('teacher'); @@ -40,14 +41,15 @@ const ManageRoom: React.FC = () => { useEffect(() => { if (newlyConnectedUser) { console.log(`Handling newly connected user: ${newlyConnectedUser.name}`); - setStudents((prevStudents) => [...prevStudents, newlyConnectedUser]); - + setConnectedStudents((prevStudents) => [...prevStudents, newlyConnectedUser]); + setTotalStudents((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,7 +62,7 @@ const ManageRoom: React.FC = () => { } else { console.error('Invalid quiz mode:', quizMode); } - + // Reset the newly connected user state setNewlyConnectedUser(null); } @@ -91,7 +93,7 @@ const ManageRoom: React.FC = () => { return () => { disconnectWebSocket(); }; - }, [roomName, navigate]); + }, [roomName, navigate]); useEffect(() => { if (quizId) { @@ -128,7 +130,9 @@ const ManageRoom: React.FC = () => { setSocket(null); setQuizQuestions(undefined); setCurrentQuestion(undefined); - setStudents(new Array()); + setConnectedStudents(new Array()); + setTotalStudents(new Array()); + } }; @@ -172,7 +176,7 @@ const ManageRoom: React.FC = () => { socket.on('user-disconnected', (userId: string) => { console.log(`Student left: id = ${userId}`); - setStudents((prevUsers) => prevUsers.filter((user) => user.id !== userId)); + setConnectedStudents((prevUsers) => prevUsers.filter((user) => user.id !== userId)); }); setSocket(socket); @@ -193,7 +197,7 @@ const ManageRoom: React.FC = () => { } // Update the students state using the functional form of setStudents - setStudents((prevStudents) => { + setConnectedStudents((prevStudents) => { console.log('Current students:'); prevStudents.forEach((student) => { console.log(student.name); @@ -213,14 +217,56 @@ 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 { + const newAnswer = { + idQuestion, + answer, + isCorrect: checkIfIsCorrect(answer, idQuestion, quizQuestions!) + }; + updatedAnswers = [...student.answers, newAnswer]; + } + return { ...student, answers: updatedAnswers }; + } + return student; + }); + if (!foundStudent) { + console.log(`Student ${username} not found in the list.`); + } + return updatedStudents; + }); + setTotalStudents((prevStudents) => { + let foundStudent = false; + const updatedStudents = prevStudents.map((student) => { + console.log(`Comparing ${student.id} to ${idUser}`); + if (student.id === idUser) { + foundStudent = true; + const existingAnswer = student.answers.find( + (ans) => ans.idQuestion === idQuestion + ); + let updatedAnswers: Answer[] = []; + if (existingAnswer) { + updatedAnswers = student.answers.map((ans) => { + console.log(`Comparing ${ans.idQuestion} to ${idQuestion}`); + return ans.idQuestion === idQuestion + ? { + ...ans, + answer, + isCorrect: checkIfIsCorrect( + answer, + idQuestion, + quizQuestions! + ) + } : ans; }); } else { @@ -253,10 +299,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 +314,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 +342,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 = () => { @@ -331,7 +379,7 @@ 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 }); } } }; @@ -388,7 +436,7 @@ const ManageRoom: React.FC = () => { style={{ display: "flex", justifyContent: "flex-end" }} > - {students.length}/60 + {connectedStudents.length}/60 )} @@ -425,7 +473,7 @@ const ManageRoom: React.FC = () => { )} @@ -434,7 +482,7 @@ const ManageRoom: React.FC = () => { socket={socket} questions={quizQuestions} showSelectedQuestion={showSelectedQuestion} - students={students} + students={totalStudents} > @@ -470,7 +518,7 @@ const ManageRoom: React.FC = () => { ) : (