diff --git a/.gitignore b/.gitignore index 8bbe72a8..7058afaa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules coverage -docs/build \ No newline at end of file +docs/build +.idea/ diff --git a/webapp/src/components/GameSettings.js b/webapp/src/components/GameSettings.js index c9b32195..05c7f1ae 100644 --- a/webapp/src/components/GameSettings.js +++ b/webapp/src/components/GameSettings.js @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import { Box, Typography, Slider, TextField, FormGroup, FormControlLabel, Checkbox, Tab } from '@mui/material'; import { TabContext, TabList, TabPanel } from '@mui/lab'; +import PropTypes from 'prop-types'; const GameSettings = ({ setSettings, currentUser }) => { const [isWarningVisible, setIsWarningVisible] = useState(false); @@ -195,4 +196,9 @@ const GameSettings = ({ setSettings, currentUser }) => { ); }; +GameSettings.propTypes = { + setSettings: PropTypes.func.isRequired, + currentUser: PropTypes.string.isRequired, +}; + export default GameSettings; diff --git a/webapp/src/components/GeneratedQuestionsList.js b/webapp/src/components/GeneratedQuestionsList.js index b4621516..f5861d54 100644 --- a/webapp/src/components/GeneratedQuestionsList.js +++ b/webapp/src/components/GeneratedQuestionsList.js @@ -1,8 +1,9 @@ import React, { useState, useEffect } from 'react'; import axios from 'axios'; +import PropTypes from 'prop-types'; -const GeneratedQuestionsList = () => { +const GeneratedQuestionsList = ({setError}) => { const [listquestions, setListquestions] = useState([]); const [sortColumn, setSortColumn] = useState(null); @@ -22,10 +23,10 @@ const GeneratedQuestionsList = () => { setListquestions(qList); } else { - console.error('Error obteniendo la lista de preguntas generadas'); + setError('Error obteniendo la lista de preguntas generadas'); } } catch (error) { - console.error('Error obteniendo la lista de preguntas generadas:', error); + setError('Error obteniendo la lista de preguntas generadas:', error); } }; @@ -76,4 +77,8 @@ const GeneratedQuestionsList = () => { ); }; +GeneratedQuestionsList.propTypes = { + setError: PropTypes.func.isRequired, +}; + export default GeneratedQuestionsList; diff --git a/webapp/src/components/GeneratedQuestionsList.test.js b/webapp/src/components/GeneratedQuestionsList.test.js index 6cc4adba..cd3b4903 100644 --- a/webapp/src/components/GeneratedQuestionsList.test.js +++ b/webapp/src/components/GeneratedQuestionsList.test.js @@ -1,43 +1,131 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { render, screen, act } from '@testing-library/react'; import GeneratedQuestionsList from './GeneratedQuestionsList'; +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; + +jest.mock('axios'); + +const mockAxios = new MockAdapter(axios); describe('GeneratedQuestionsList component', () => { - // Test for rendering the component and checking the main heading - test('renders GeneratedQuestionsList component and main heading', () => { - render(); + beforeEach(() => { + axios.get.mockResolvedValue({ + status: 200, + data: [ + { + generatedQuestionBody: "¿A qué género literario pertenece 'Cinco horas con Mario'?", + correctAnswer: 'Narrativo' + }, + { + generatedQuestionBody: "¿De qué grupo es la canción 'Vino Tinto'?", + correctAnswer: 'Estopa' + }, + { + generatedQuestionBody: "¿Cuál es la capital de Portugal?", + correctAnswer: 'Lisboa' + }, + { + generatedQuestionBody: "¿Quién escribió la novela 'El Extranjero'?", + correctAnswer: 'Albert Camus' + }, + ], + }); + }); - // Check if the main heading is in the document + test('renders GeneratedQuestionsList component and main heading', async () => { + await act( async () => { + render( {}} />); + }); const heading = screen.getByRole('heading', { name: /Lista de preguntas/i }); expect(heading).toBeInTheDocument(); }); - // Test for rendering the table - it('should display the table', () => { - render(); - + it('should display the table', async () => { + await act( async () => { + render( {}} />); + }); const table = screen.getByRole('table'); expect(table).toBeInTheDocument(); }); - // Test for rendering the table headers - test('renders table headers', () => { - render(); - - // Check if the table headers are in the document + test('renders table headers', async () => { + await act( async () => { + render( {}} />); + }); const questionHeader = screen.getByRole('columnheader', { name: /Pregunta/i }); const answerHeader = screen.getByRole('columnheader', { name: /Respuesta Correcta/i }); expect(questionHeader).toBeInTheDocument(); expect(answerHeader).toBeInTheDocument(); }); - // Test for rendering the table rows -test('renders table rows', () => { - render(); + test('renders table rows', async () => { + await act( async () => { + render( {}} />); + }); + const tableRows = screen.getAllByRole('row'); + expect(tableRows).not.toHaveLength(0); + }); + + test('should order questions by questionBody correctly', async () => { + await act(async () => { + render( {}} />); + }); + + const questionBodyHeader = screen.getByRole('columnheader', { name: /Pregunta/i }); + + await act(async() => { + questionBodyHeader.click(); + }); + + let rows = await screen.findAllByRole('row'); + + expect(rows[1]).toHaveTextContent("¿A qué género literario pertenece 'Cinco horas con Mario'?"); + expect(rows[2]).toHaveTextContent("¿Cuál es la capital de Portugal?"); + expect(rows[3]).toHaveTextContent("¿De qué grupo es la canción 'Vino Tinto'?"); + expect(rows[4]).toHaveTextContent("¿Quién escribió la novela 'El Extranjero'?"); + + await act(async() => { + questionBodyHeader.click(); + }); + + rows = await screen.findAllByRole('row'); - // Check if the table rows are in the document - const tableRows = screen.getAllByRole('row'); - expect(tableRows).not.toHaveLength(0); -}); + expect(rows[4]).toHaveTextContent("¿A qué género literario pertenece 'Cinco horas con Mario'?"); + expect(rows[3]).toHaveTextContent("¿Cuál es la capital de Portugal?"); + expect(rows[2]).toHaveTextContent("¿De qué grupo es la canción 'Vino Tinto'?"); + expect(rows[1]).toHaveTextContent("¿Quién escribió la novela 'El Extranjero'?"); + }); + + test('should order questions by answer correctly', async () => { + await act(async () => { + render( {}} />); + }); + + const answerHeader = screen.getByRole('columnheader', { name: /Respuesta Correcta/i }); + + await act(async() => { + answerHeader.click(); + }); + + let rows = await screen.findAllByRole('row'); + + expect(rows[1]).toHaveTextContent("Albert Camus"); + expect(rows[2]).toHaveTextContent("Estopa"); + expect(rows[3]).toHaveTextContent("Lisboa"); + expect(rows[4]).toHaveTextContent("Narrativo"); + + + await act(async() => { + answerHeader.click(); + }); + + rows = await screen.findAllByRole('row'); + + expect(rows[4]).toHaveTextContent("Albert Camus"); + expect(rows[3]).toHaveTextContent("Estopa"); + expect(rows[2]).toHaveTextContent("Lisboa"); + expect(rows[1]).toHaveTextContent("Narrativo"); + }); }); \ No newline at end of file diff --git a/webapp/src/components/Login.js b/webapp/src/components/Login.js index 0ecabaa4..b9323ada 100644 --- a/webapp/src/components/Login.js +++ b/webapp/src/components/Login.js @@ -45,16 +45,14 @@ const Login = ({ setLogged }) => { try { const response = await axios.post(`${apiEndpoint}/login`, { username, password }); const { createdAt: userCreatedAt } = response.data; - const usersResponse = await axios.get(`${apiEndpoint}/getAllUsers`); - const users = usersResponse.data; - + await axios.get(`${apiEndpoint}/getAllUsers`); setCreatedAt(userCreatedAt); setLoginSuccess(true); setLogged(); setLoading(true); - // Envía todos los nombres de usuario en una sola solicitud - await axios.post(`${apiEndpoint}/createUserRank`, { username }); + // Envía todos los nombres de usuario en una sola solicitud + await axios.post(`${apiEndpoint}/createUserRank`, { username }); setLoading(false); setOpenSnackbar(true); @@ -64,7 +62,7 @@ const Login = ({ setLogged }) => { } else if (error.request) { setError('No response from server. Please try again later.'); } else { - setError('An unexpected error occurred.'); + setError('An unexpected error occurred'); } } }; @@ -142,10 +140,10 @@ const Login = ({ setLogged }) => { {showComponent === 'game' && } - {showComponent === 'userList' && } - {showComponent === 'questionList' && } - {showComponent === 'recordList' && } - {showComponent === 'rankingList' && } + {showComponent === 'userList' && } + {showComponent === 'questionList' && } + {showComponent === 'recordList' && } + {showComponent === 'rankingList' && } {showComponent === 'settings' && } {showComponent === 'login' && (
diff --git a/webapp/src/components/Login.test.js b/webapp/src/components/Login.test.js index f1aa7841..a4bea4ac 100644 --- a/webapp/src/components/Login.test.js +++ b/webapp/src/components/Login.test.js @@ -1,7 +1,13 @@ // Import necessary dependencies import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { render, screen, act, fireEvent, waitFor } from '@testing-library/react'; import Login from './Login'; +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; + +jest.mock('axios'); + +const mockAxios = new MockAdapter(axios); // Define the test suite describe('Login Component', () => { @@ -14,4 +20,189 @@ describe('Login Component', () => { const loginButton = screen.getByRole('button', { name: /Iniciar sesión/i }); expect(loginButton).toBeInTheDocument(); }); + + function setupMocksSuccess() { + const setLogged = jest.fn(); + + // Mock para la petición POST de login exitosa + axios.post.mockResolvedValueOnce({ + data: { + createdAt: new Date().toISOString() + } + }); + + // Mock para la petición GET de obtener todos los usuarios + axios.get.mockResolvedValueOnce({ + data: [] // Puedes ajustar esto según lo que necesites en tu test + }); + + // Mock para la petición POST de createUserRank exitosa + axios.post.mockResolvedValueOnce({ + data: {} // Puedes ajustar esto según lo que necesites en tu test + }); + + return setLogged; + } + + async function loginAndSearch(setLogged, username, password, search=true, all = false){ + await act(async () => { + render(); + }); + + const usernameInput = screen.getByLabelText(/Username/i); + const passwordInput = screen.getByLabelText(/Password/i); + const loginButton = screen.getByRole('button', { name: /Iniciar sesión/i }); + + await act(async () => { + fireEvent.change(usernameInput, { target: { value: username } }); + fireEvent.change(passwordInput, { target: { value: password } }); + + fireEvent.click(loginButton); + }); + + if(search){ + await waitFor(() => { + expect(setLogged).toHaveBeenCalledTimes(1); + + expect(screen.getAllByText(/Jugar/i)).toHaveLength(2); + expect(screen.getByText(/Historial de jugadas/i)).toBeInTheDocument(); + expect(screen.getByText(/Ranking/i)).toBeInTheDocument(); + expect(screen.getByText(/Ajustes de partida/i)).toBeInTheDocument(); + + expect(screen.getByText(new RegExp(`Hola ${username}!`, 'i'))).toBeInTheDocument(); + expect(screen.getByText(/Tu cuenta fue creada el/i)).toBeInTheDocument(); + expect(screen.getByText(/Comenzar a jugar/i)).toBeInTheDocument(); + + if(all){ // only for admin + expect(screen.getByText(/Historial de Usuarios/i)).toBeInTheDocument(); + expect(screen.getByText(/Historial de Preguntas Generadas/i)).toBeInTheDocument(); + } + }); + } + } + + test('login with valid normal (not "admin") credentials', async () => { + const setLogged = setupMocksSuccess(); + + await loginAndSearch(setLogged, 'testUser', 'testPassword'); + }); + + test('login with valid admin credentials', async () => { + const setLogged = setupMocksSuccess(); + + await loginAndSearch(setLogged, 'admin', 'testPassword'); + }); + + describe('sucessful login cases trying to access to: userList, questionList, recordList, rankingList, settings', () => { + beforeEach(async () => { + const setLogged = jest.fn(); + + axios.post.mockResolvedValueOnce({ + data: { + createdAt: new Date().toISOString() + } + }); + + axios.get.mockResolvedValueOnce({ + data: [] + }); + + axios.post.mockResolvedValueOnce({ + data: {} + }); + + await loginAndSearch(setLogged, 'admin', 'testPassword', true, true); + }); + + async function accessToTab(tabName, tabText){ + const tab = screen.getByText(new RegExp(tabName, 'i')); + await act(async () => { + fireEvent.click(tab); + }); + + await waitFor(async () => { + expect((await screen.findAllByText(new RegExp(tabText, 'i'))).length).toBeGreaterThan(0); + }); + } + + test('from login try to access to usersList', async () => { + await accessToTab('Historial de Usuarios', 'Nombre de Usuario'); + }); + + test('from login try to access to generatedQuestionsList', async () => { + await accessToTab('Historial de Preguntas Generadas', 'Lista de preguntas'); + }); + + test('from login try to access to recordList', async () => { + await accessToTab('Historial de jugadas', 'Tu historial de jugadas'); + }); + + test('from login try to access to rankingList', async () => { + await accessToTab('Ranking', 'Ranking'); + }); + + test('from login try to access to gameSettings', async () => { + await accessToTab('Ajustes de partida', 'Número de preguntas'); + }); + + }); + + async function performLoginFail(setLogged, username = 'testUser', password = 'testPassword', error = 'Internal Server Error', loggedIn = false) { + await loginAndSearch(setLogged, username, password, false); + + await waitFor(() => { + if (!loggedIn) { + expect(setLogged).not.toHaveBeenCalled(); + } else { + expect(setLogged).toHaveBeenCalled(); + } + expect(screen.getByText(new RegExp(error, 'i'))).toBeInTheDocument(); + expect(screen.queryByText(/Comenzar a jugar/i)).not.toBeInTheDocument(); + }); + } + + test('login fails on post /login and error is handled ', async () => { + const setLogged = jest.fn(); + + // Mock para la petición POST de login fallada + axios.post.mockRejectedValueOnce({ response: { status: 500, data: { error: 'Internal Server Error' } } }); + + await performLoginFail(setLogged); + }); + + test('login fails on get /getAllUsers and error is handled ', async () => { + const setLogged = jest.fn(); + + // Mock para la petición POST de login exitosa + axios.post.mockResolvedValueOnce({ + data: { + createdAt: new Date().toISOString() + } + }); + // Mock para la petición get de login fallada + axios.get.mockRejectedValueOnce({ response: { status: 500, data: { error: 'Internal Server Error' } } }); + + await performLoginFail(setLogged); + }); + + test('login fails on post /createUserRank and error is handled ', async () => { + const setLogged = jest.fn(); + + // Mock para la petición POST de login exitosa + axios.post.mockResolvedValueOnce({ + data: { + createdAt: new Date().toISOString() + } + }); + + // Mock para la petición GET de obtener todos los usuarios + axios.get.mockResolvedValueOnce({ + data: [] // Puedes ajustar esto según lo que necesites en tu test + }); + + // Mock para la petición POST de login fallada + axios.post.mockRejectedValueOnce({ response: { status: 500, data: { error: 'Internal Server Error' } } }); + + await performLoginFail(setLogged, 'testUser', 'testPassword', 'Espere, estamos cargando sus datos...', true); + }); }); diff --git a/webapp/src/components/RankingList.js b/webapp/src/components/RankingList.js index ee9918f0..7ba00ec9 100644 --- a/webapp/src/components/RankingList.js +++ b/webapp/src/components/RankingList.js @@ -1,7 +1,8 @@ import React, { useState, useEffect } from 'react'; import axios from 'axios'; +import PropTypes from 'prop-types'; -const RankingList = () => { +const RankingList = ({setError}) => { const [listUsers, setListUsers] = useState([]); const [sortColumn, setSortColumn] = useState('porcentajeAciertos'); const [sortOrder, setSortOrder] = useState('desc'); @@ -23,10 +24,10 @@ const RankingList = () => { const sortedUsers = [...uList].sort((a, b) => b.porcentajeAciertos - a.porcentajeAciertos); setTopThreeUsers(sortedUsers.slice(0, 3)); } else { - console.error('Error obteniendo la lista de usuarios'); + setError('Error obteniendo el ranking del usuario'); } } catch (error) { - console.error('Error obteniendo la lista de usuarios:', error); + setError(`Error obteniendo el ranking del usuario: ${error}`); } }; @@ -99,4 +100,9 @@ const RankingList = () => { ); }; + +RankingList.propTypes = { + setError: PropTypes.func.isRequired, +}; + export default RankingList; diff --git a/webapp/src/components/RankingList.test.js b/webapp/src/components/RankingList.test.js index 0837377d..0dbbd0c2 100644 --- a/webapp/src/components/RankingList.test.js +++ b/webapp/src/components/RankingList.test.js @@ -2,9 +2,12 @@ import React from 'react'; import { render, screen, waitFor, act } from '@testing-library/react'; import RankingList from './RankingList'; import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; jest.mock('axios'); +const mockAxios = new MockAdapter(axios); + describe('RankingList', () => { describe('successful requests', () => { beforeEach(() => { @@ -43,17 +46,23 @@ describe('RankingList', () => { }); }); - it('renders without crashing', async () => { + function emptyFunction() { + return; + } + + async function renderRankingList() { await act(async () => { - render(); + render(); }); + } + + it('renders without crashing', async () => { + await renderRankingList(); }); test('renders RankingList component and main heading', async () => { - await act(async () => { - render(); - }); + await renderRankingList(); // Check if the main heading is in the document const heading = screen.getByRole('heading', { name: /Top 3 usuarios con mejor porcentaje de aciertos/i }); @@ -62,9 +71,7 @@ describe('RankingList', () => { // Test for rendering the column headers test('renders column headers', async () => { - await act(async () => { - render(); - }); + await renderRankingList(); // Check if the column headers are in the document const columnHeaders = screen.getAllByRole('columnheader'); @@ -73,9 +80,7 @@ describe('RankingList', () => { // Test for rendering the table it('should display the table', async () => { - await act(async () => { - render(); - }); + await renderRankingList(); const table = screen.getByRole('table'); expect(table).toBeInTheDocument(); @@ -83,9 +88,7 @@ describe('RankingList', () => { test('tests tabla ranking', async () => { - await act(async () => { - render(); - }); + await renderRankingList(); expect(screen.queryByText("Ranking")).toBeInTheDocument(); expect(screen.getByText(/Nombre de Usuario/i)).toBeInTheDocument(); @@ -96,18 +99,14 @@ describe('RankingList', () => { }); test('show ranking table with content', async () => { - await act(async () => { - render(); - }); + await renderRankingList(); const rows = await screen.findAllByRole('row'); expect(rows).toHaveLength(5); }); test('show users ordered by "porcentajeAciertos" BY DEFAULT correctly', async () => { - await act(async () => { - render(); - }); + await renderRankingList(); // We wait for the users to be loaded and the table to be updated let rows = await screen.findAllByRole('row'); @@ -120,10 +119,40 @@ describe('RankingList', () => { }); - test('show users ordered by "porcentajeAciertos" correctly', async () => { - await act(async () => { - render(); + test('show users ordered by "username" correctly', async () => { + await renderRankingList(); + const usernameHeader = screen.getByRole('columnheader', { name: /Nombre de Usuario/i }); + + await act(async() => { + usernameHeader.click(); // DESC }); + + // We wait for the users to be loaded and the table to be updated + let rows = await screen.findAllByRole('row'); + + // We check if the first row is the one with the username 'troll' + expect(rows[4]).toHaveTextContent('manuel'); + expect(rows[3]).toHaveTextContent('maría'); + expect(rows[2]).toHaveTextContent('pedro'); + expect(rows[1]).toHaveTextContent('troll'); + + await act(async() => { + usernameHeader.click(); // ASC + }); + + // We wait for the users to be loaded and the table to be updated + rows = await screen.findAllByRole('row'); + + // We check if the first row is the one with the username 'manuel' + expect(rows[1]).toHaveTextContent('manuel'); + expect(rows[2]).toHaveTextContent('maría'); + expect(rows[3]).toHaveTextContent('pedro'); + expect(rows[4]).toHaveTextContent('troll'); + + }); + + test('show users ordered by "porcentajeAciertos" correctly', async () => { + await renderRankingList(); const porcentajeAciertosHeader = screen.getByRole('columnheader', { name: /Porcentaje de Aciertos/i }); await act(async() => { @@ -155,9 +184,7 @@ describe('RankingList', () => { }); test('show users ordered by "preguntasCorrectas" correctly', async () => { - await act(async () => { - render(); - }); + await renderRankingList(); const preguntasCorrectasHeader = screen.getByRole('columnheader', { name: /Preguntas Correctas/i }); await act(async() => { @@ -188,9 +215,7 @@ describe('RankingList', () => { }); test('show users ordered by "preguntasFalladas" correctly', async () => { - await act(async () => { - render(); - }); + await renderRankingList(); const preguntasFalladasHeader = screen.getByRole('columnheader', { name: /Preguntas Falladas/i }); await act(async() => { @@ -221,9 +246,7 @@ describe('RankingList', () => { }); test('show users ordered by "numeroPartidas" correctly', async () => { - await act(async () => { - render(); - }); + await renderRankingList(); const numPartidasHeader = screen.getByRole('columnheader', { name: /Número de Partidas/i }); await act(async() => { @@ -255,4 +278,28 @@ describe('RankingList', () => { }); // fin tests correctos + test('should display an error message when the request fails', async () => { + let errorShown = ""; + await act(async () => { + render( {errorShown=errorMsg}} />); + }); + + // simulate a failed request + mockAxios.onPost('http://localhost:8000/obtainRank').reply(500, { error: 'Internal Server Error' }); + + // Check if the table headers are in the document + expect(screen.queryByText("Ranking")).toBeInTheDocument(); + expect(screen.getByText(/Nombre de Usuario/i)).toBeInTheDocument(); + expect(screen.queryAllByText(/Porcentaje de Aciertos/i)).not.toHaveLength(0); + expect(screen.getByText(/Preguntas Correctas/i)).toBeInTheDocument(); + expect(screen.getByText(/Preguntas Falladas/i)).toBeInTheDocument(); + expect(screen.getByText(/Número de Partidas/i)).toBeInTheDocument(); + + // and no users rows are shown + const rows = await screen.findAllByRole('row'); + expect(rows.length).toBe(1); + + expect(errorShown).toBe("Error obteniendo el ranking del usuario: TypeError: Cannot read properties of undefined (reading 'status')"); + }); + }); diff --git a/webapp/src/components/RecordList.js b/webapp/src/components/RecordList.js index e7fee959..da88832f 100644 --- a/webapp/src/components/RecordList.js +++ b/webapp/src/components/RecordList.js @@ -1,7 +1,8 @@ import React, { useState, useEffect } from 'react'; import axios from 'axios'; +import PropTypes from 'prop-types'; -const RecordList = ({ username }) => { +const RecordList = ({ username, setError }) => { const [listRecords, setListRecords] = useState([]); const apiEndpoint = process.env.REACT_APP_API_ENDPOINT || 'http://localhost:8000'; @@ -17,10 +18,10 @@ const RecordList = ({ username }) => { })); setListRecords(userRecords); } else { - console.error('Error obtaining the user records list'); + setError('Error obtaining the user records list'); } } catch (error) { - console.error('Error obtaining the user records list:', error); + setError('Error obtaining the user records list: '+ error); } }; @@ -56,4 +57,9 @@ const RecordList = ({ username }) => { ); }; +RecordList.propTypes = { + username: PropTypes.string.isRequired, + setError: PropTypes.func.isRequired, +}; + export default RecordList; diff --git a/webapp/src/components/RecordList.test.js b/webapp/src/components/RecordList.test.js index f7ea2c02..5945fd6d 100644 --- a/webapp/src/components/RecordList.test.js +++ b/webapp/src/components/RecordList.test.js @@ -29,7 +29,7 @@ describe('RecordList', () => { }); it('renders record list correctly', async () => { - const { getByText } = render(); + const { getByText } = render( {}} username="testuser" />); await waitFor(() => { expect(getByText('Tu historial de jugadas')).toBeInTheDocument(); diff --git a/webapp/src/components/UsersList.js b/webapp/src/components/UsersList.js index d3d6af00..aa9650af 100644 --- a/webapp/src/components/UsersList.js +++ b/webapp/src/components/UsersList.js @@ -1,9 +1,11 @@ import React, { useState, useEffect } from 'react'; import axios from 'axios'; +import PropTypes from 'prop-types'; + //import { Container, Typography, TextField, Button, Snackbar } from '@mui/material'; -const UsersList = () => { +const UsersList = ({ setError }) => { const [listUsers, setListUsers] = useState([]); @@ -25,13 +27,12 @@ const UsersList = () => { setListUsers(uList); } else { - console.error('Error obteniendo la lista de usurios'); + setError('Error obteniendo la lista de usurios'); } } catch (error) { - console.error('Error obteniendo la lista de usurios:', error); + setError(`Error obteniendo la lista de usurios: ${error}`); } }; - fetchUsers(); }, [apiEndpoint]); @@ -81,4 +82,8 @@ const UsersList = () => { ); }; +UsersList.propTypes = { + setError: PropTypes.func.isRequired, +}; + export default UsersList; \ No newline at end of file diff --git a/webapp/src/components/UsersList.test.js b/webapp/src/components/UsersList.test.js index def7d975..fb6573b6 100644 --- a/webapp/src/components/UsersList.test.js +++ b/webapp/src/components/UsersList.test.js @@ -34,9 +34,13 @@ describe('UsersList', () => { }); }); + function emptyFunction() { + return; + } + it('renders headers list correctly', async () => { await act(async () => { - render(); + render(); }); // Check if the table headers are in the document @@ -49,7 +53,7 @@ describe('UsersList', () => { it('renders all the users rows', async () => { await act(async () => { - render(); + render(); }); // Check if the table rows are in the document const tableRows = screen.getAllByRole('row'); @@ -58,7 +62,7 @@ describe('UsersList', () => { it('should order users by username correctly', async () => { await act(async () => { - render(); + render(); }); // We click the username header to order the users by username @@ -92,7 +96,7 @@ describe('UsersList', () => { it('should order users by createdAt date correctly', async () => { await act(async () => { - render(); + render(); }); // We click the username header to order the users by username @@ -125,24 +129,19 @@ describe('UsersList', () => { }); }); + function errorFunction(errorMsg) { + expect(errorMsg).toBe("Error obteniendo la lista de usurios: TypeError: Cannot read properties of undefined (reading 'status')"); + } describe('failing requests', () => { - beforeEach(() => { - axios.get.mockRejectedValue({ - response: { - status: 500, - data: { - error: 'Internal Server Error' - }, - }, - }); - }); - - it('users list is empty (only headers are shown) when petition fails', async () => { + test('users list is empty (only headers are shown) when petition fails', async () => { await act(async () => { - render(); + render(); }); + // simulate a failed request + mockAxios.onPost('http://localhost:8000/getAllUsers').reply(500, { error: 'Internal Server Error' }); + // Check if the table headers are in the document const usernameHeader = screen.getByRole('columnheader', { name: /Nombre de Usuario/i }); const createdAtHeader = screen.getByRole('columnheader', { name: /Fecha de Registro/i });