diff --git a/webapp/src/components/Game/Game.test.tsx b/webapp/src/components/Game/Game.test.tsx index 46e306d..e967a5c 100644 --- a/webapp/src/components/Game/Game.test.tsx +++ b/webapp/src/components/Game/Game.test.tsx @@ -1,13 +1,87 @@ -import { render, screen } from '@testing-library/react'; +import { render, fireEvent ,screen, waitFor } from '@testing-library/react'; import React from 'react'; -import Game from './Game'; +import Game, { formatNumberWithDots} from './Game'; +import { act } from 'react-dom/test-utils'; +const wait = (milliseconds: number) => { + return new Promise((resolve) => { + setTimeout(resolve, milliseconds); + }); +}; + +jest.mock("../../services/question-service", () => { + return { + getHardString : () => 'hard', + getQuestionsFromApi: () => { + return Promise.resolve([ + { + text: '¿Cuál es la capital de España?', + correctAnswer: 0, + answers: ['Madrid','Barcelona', 'Sevilla', 'Valencia'], + wikiLink: '' + }, + { + text: '¿Cuál es la capital de Francia?', + correctAnswer: 0, + answers: ['Paris','Barcelona', 'Sevilla', 'Valencia'], + wikiLink: '' + } + ]); + } + } +}); + +describe('Game component', () => { + + + it('should render the game',async () => { + await act( async () => { + render(); + }); + expect(screen.getByTestId('game-component')).toBeInTheDocument(); + }); -describe('Game component', () => { - it('should render the game', () => { - render( ); + it('should render the game in hard mode',async () => { + await act( async () => { + render(); + }); expect(screen.getByTestId('game-component')).toBeInTheDocument(); }); + it('should go to the next question', async () => { + await act( async () => { + render(); + }); + + expect(screen.getByTestId('game-container')).toBeInTheDocument(); + + expect(screen.getByText('Madrid')).toBeInTheDocument(); + fireEvent.click(screen.getByText('Madrid')); + + await wait(4000); + expect(screen.getByText('Paris')).toBeInTheDocument(); + + }); + + it('format a number with the dots', () => { + const shortNumber = '700'; + expect(formatNumberWithDots(shortNumber)).toBe('700'); + + const number = '100000'; + expect(formatNumberWithDots(number)).toBe('100.000'); + }); + + //mockear la llegada de preguntas de la api + it('should display the question and answers when the questions arrive', async () => { + + await act( async () => { + render(); + }); + + expect(screen.getByText('Madrid')).toBeInTheDocument(); + }); + + + }); \ No newline at end of file diff --git a/webapp/src/components/Game/Game.tsx b/webapp/src/components/Game/Game.tsx index 8b165a9..58fed46 100644 --- a/webapp/src/components/Game/Game.tsx +++ b/webapp/src/components/Game/Game.tsx @@ -4,14 +4,30 @@ import AnswerPanel from "./AnswerPanel"; import GameOver from "./GameOver"; import Counter from "./Counter"; import Countdown from "./Countdown"; -import {getHardString, Question as questionType} from "../../services/question-service"; -import { getQuestionsFromApi } from "../../services/question-service"; +import {getHardString, getQuestionsFromApi, Question as questionType} from "../../services/question-service"; import { updateStats } from "../../services/auth-service"; type Props = { difficulty: string; }; +export const formatNumberWithDots = (str : string) => { + + if (str.length < 5 || str.includes('.')) { + return str; + } + let result = ''; + for (let i = str.length - 1, count = 0; i >= 0; i--, count++) { + result = str[i] + result; + if (count % 3 === 2 && i !== 0) { + result = '.' + result; + } + } + + return result; +}; + + export default function Game(props: Props) { const [answered, setAnswered] = useState(false); const [loading, setLoading] = useState(false); @@ -32,28 +48,11 @@ export default function Game(props: Props) { useEffect(() => { getQuestionsFromApi().then((questions : questionType[]) => { - setQuestions(questions) setLoadingData(false); }) }, []); - function formatNumberWithDots(str : string) : string { - - if (str.length < 5 || str.includes('.')) { - return str; - } - let result = ''; - for (let i = str.length - 1, count = 0; i >= 0; i--, count++) { - result = str[i] + result; - if (count % 3 === 2 && i !== 0) { - result = '.' + result; - } - } - - return result; - } - const goToNextQuestion = () => { setCount(questionTime); setCorrectSelected(false); @@ -95,7 +94,7 @@ export default function Game(props: Props) { if (questionCount === 10) { updateStats(questionCount, score/10); - return ; + return ; } @@ -103,7 +102,7 @@ export default function Game(props: Props) { return (
{loadingdata ?

Loading...

: -
+
{questionCount+1}/{questions.length} diff --git a/webapp/src/components/Game/Trivia/TriviaGame.test.tsx b/webapp/src/components/Game/Trivia/TriviaGame.test.tsx index cdadea5..062e043 100644 --- a/webapp/src/components/Game/Trivia/TriviaGame.test.tsx +++ b/webapp/src/components/Game/Trivia/TriviaGame.test.tsx @@ -1,36 +1,84 @@ import React from 'react'; import { render, fireEvent, waitFor, screen } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; -import { TriviaGame } from './TriviaGame'; +import { TriviaGame, formatNumberWithDots, isNumber, generateDiceRandomNumber, getQuestion} from './TriviaGame'; import { getEasyString, getHardString } from '../../../services/question-service'; +// jest.mock('./trivia_service', () => ({ +// getSportQuestions: jest.fn().mockResolvedValue({ +// text: 'Sports question', +// answers: ['answer1', 'answer2', 'answer3', 'answer4'], +// correctAnswer: 0, +// wikiLink: '' +// }), +// getScienceQuestions: jest.fn().mockResolvedValue({ +// question: 'Science question', +// answers: ['answer1', 'answer2', 'answer3', 'answer4'], +// correctAnswer: 0, +// wikiLink: '' +// }), +// getHistoryQuestions: jest.fn().mockResolvedValue({ +// question: 'History question', +// answers: ['answer1', 'answer2', 'answer3', 'answer4'], +// correctAnswer: 0, +// wikiLink: '' +// }), +// getGeographyQuestions: jest.fn().mockResolvedValue({ +// question: 'Geography question', +// answers: ['answer1', 'answer2', 'answer3', 'answer4'], +// correctAnswer: 0, +// wikiLink: '' +// }), +// getEntertainmentQuestions: jest.fn().mockResolvedValue({ +// question: 'Entertainment question', +// answers: ['answer1', 'answer2', 'answer3', 'answer4'], +// correctAnswer: 0, +// wikiLink: '' +// }), +// })); + jest.mock('./trivia_service', () => ({ - getSportQuestions: jest.fn().mockResolvedValue({ - question: 'Sport question', - answers: ['answer1', 'answer2', 'answer3', 'answer4'], - correctAnswer: 0, - }), - getScienceQuestions: jest.fn().mockResolvedValue({ - question: 'Science question', + getSportQuestions: () => { + return ({ + text: 'Sports question', + correctAnswer: 0, + answers: ['answer1', 'answer2', 'answer3', 'answer4'], + wikiLink: '' + }); + }, + getScienceQuestions: ()=>{ + return ({ + text: 'Science question', answers: ['answer1', 'answer2', 'answer3', 'answer4'], correctAnswer: 0, - }), - getHistoryQuestions: jest.fn().mockResolvedValue({ - question: 'History question', + wikiLink: '' + } + )}, + getHistoryQuestions: ()=>{ + return ({ + text: 'History question', + answers: ['answer1', 'answer2', 'answer3', 'answer4'], + correctAnswer: 0, + wikiLink: '' + })}, + getGeographyQuestions: ()=>{ + return ({ + text: 'Geography question', answers: ['answer1', 'answer2', 'answer3', 'answer4'], correctAnswer: 0, - }), - getGeographyQuestions: jest.fn().mockResolvedValue({ - question: 'Geography question', + wikiLink: '' + })}, + getEntertainmentQuestions: ()=>{ + return ({ + text: 'Entertainment question', answers: ['answer1', 'answer2', 'answer3', 'answer4'], correctAnswer: 0, - }), - getEntertainmentQuestions: jest.fn().mockResolvedValue({ - question: 'Entertainment question', - answers: ['answer1', 'answer2', 'answer3', 'answer4'], - correctAnswer: 0, - }), - })); + wikiLink: '' + })}, +})); + + + jest.mock('./categories', () => ({ getCategoryColor: jest.fn(), @@ -52,4 +100,58 @@ describe('TriviaGame', () => { fireEvent.click(rollButton); await waitFor(() => expect(screen.getByText(/Category:/)).toBeInTheDocument()); }); + + it('format a number with the dots', () => { + const shortNUmber = '700'; + expect(formatNumberWithDots(shortNUmber)).toBe('700'); + + const number = '700000'; + expect(formatNumberWithDots(number)).toBe('700.000'); + }); + + it('returns if a string is a number', () => { + const number = '100000'; + expect(isNumber(number)).toBe(true); + + const notNumber = 'not a number'; + expect(isNumber(notNumber)).toBe(false); + }); + + it('generates a random number between 1 and 5', () => { + let number = generateDiceRandomNumber(); + expect(number).toBeGreaterThanOrEqual(1); + expect(number).toBeLessThanOrEqual(5); + + number = generateDiceRandomNumber(); + expect(number).toBeGreaterThanOrEqual(1); + expect(number).toBeLessThanOrEqual(5); + }); + + it('should return a question based on category', async () => { + + const sportQuestion = await getQuestion('Sport'); + + expect(sportQuestion.text).toBe('Sports question'); + expect(sportQuestion.answers).toEqual(['answer1', 'answer2', 'answer3', 'answer4']); + expect(sportQuestion.correctAnswer).toBe(0); + expect(sportQuestion.wikiLink).toBe(''); + + const scienceQuestion = await getQuestion('Science'); + expect(scienceQuestion.text).toBe('Science question'); + + const historyQuestion = await getQuestion('History'); + expect(historyQuestion.text).toBe('History question'); + + const geographyQuestion = await getQuestion('Geography'); + expect(geographyQuestion.text).toBe('Geography question'); + + const entertainmentQuestion = await getQuestion('Entertainment'); + expect(entertainmentQuestion.text).toBe('Entertainment question'); + + //default is sports + const defaultQuestion = await getQuestion('Other'); + expect(defaultQuestion.text).toBe('Sports question'); + + }); + }); \ No newline at end of file diff --git a/webapp/src/components/Game/Trivia/TriviaGame.tsx b/webapp/src/components/Game/Trivia/TriviaGame.tsx index 95d3845..c20efd1 100644 --- a/webapp/src/components/Game/Trivia/TriviaGame.tsx +++ b/webapp/src/components/Game/Trivia/TriviaGame.tsx @@ -13,6 +13,63 @@ type Props = { difficulty: string; }; +export const getCategory = (diceResult: number) => { + return getCategoryWithNumber(diceResult); +}; + +export const formatNumberWithDots = (str : string)=> { + + if (str.length < 5 || str.includes('.')) { + return str; + } + let result = ''; + for (let i = str.length - 1, count = 0; i >= 0; i--, count++) { + result = str[i] + result; + if (count % 3 === 2 && i !== 0) { + result = '.' + result; + } + } + + return result; +} + +export const isNumber = (str : string) => { + return !isNaN(Number(str)); +} + +export const generateDiceRandomNumber = () => { + return Math.floor(Math.random() * 5) + 1; +} + +export const getQuestion = async (category: string): Promise => { + try { + let question: questionType; + switch (category) { + case "Sport": + question = await getSportQuestions(); + break; + case "Science": + question = await getScienceQuestions(); + break; + case "History": + question = await getHistoryQuestions(); + break; + case "Geography": + question = await getGeographyQuestions(); + break; + case "Entertainment": + question = await getEntertainmentQuestions(); + break; + default: + question = await getSportQuestions(); + } + return question; + } catch (error) { + console.error("Error getting question:", error); + throw error; + } +}; + export const TriviaGame = (props : Props) => { const [showBlue, setShowBlue] = useState(false); const [showGreen, setShowGreen] = useState(false); @@ -59,20 +116,15 @@ const getSetColor: (n: number) => SetColorFunction = (n: number) => { return setShowPink; default: return setShowBlue; - } - }; - const generateDiceRandomNumber = () => { - return Math.floor(Math.random() * 5) + 1; - } + useEffect(() => { if(isShowingQuestion || diceResult === 0){ return } - else { sleep(1000).then(() => { getQuestion(getCategory(diceResult)).then((question) => { @@ -89,38 +141,9 @@ const getSetColor: (n: number) => SetColorFunction = (n: number) => { }, [diceResult]); - const getQuestion = async (category: string): Promise => { - try { - let question: questionType; - switch (category) { - case "Sport": - question = await getSportQuestions(); - break; - case "Science": - question = await getScienceQuestions(); - break; - case "History": - question = await getHistoryQuestions(); - break; - case "Geography": - question = await getGeographyQuestions(); - break; - case "Entertainment": - question = await getEntertainmentQuestions(); - break; - default: - question = await getSportQuestions(); - } - return question; - } catch (error) { - console.error("Error getting question:", error); - throw error; - } - }; - const getCategory = (diceResult: number) => { - return getCategoryWithNumber(diceResult); - }; + + const saveAnswer = (answer: string) => { answerSelected.push(answer); @@ -132,25 +155,7 @@ const getSetColor: (n: number) => SetColorFunction = (n: number) => { setQuestions(questions); } - function formatNumberWithDots(str : string) : string { - - if (str.length < 5 || str.includes('.')) { - return str; - } - let result = ''; - for (let i = str.length - 1, count = 0; i >= 0; i--, count++) { - result = str[i] + result; - if (count % 3 === 2 && i !== 0) { - result = '.' + result; - } - } - return result; - } - - function isNumber(str : string) : boolean { - return !isNaN(Number(str)); - } const getCheeseCount = () => { let count = 0; diff --git a/webapp/src/components/general/SimpleNav.test.tsx b/webapp/src/components/general/SimpleNav.test.tsx index 9a2c903..f01dbd0 100644 --- a/webapp/src/components/general/SimpleNav.test.tsx +++ b/webapp/src/components/general/SimpleNav.test.tsx @@ -34,6 +34,37 @@ describe('SimpleNav', () => { expect(getByTestId('audio-button')).toBeInTheDocument(); }); + test('renders audio button', () => { + const { getByTestId } = render( + + + + ); + + // Check if audio button is rendered + expect(getByTestId('audio-button')).toBeInTheDocument(); + }); + + test('toggle audio playback', () => { + // Mock useRef hook + jest.spyOn(React, 'useRef').mockReturnValueOnce({ + current: { + play: jest.fn(), + pause: jest.fn() + } + }); + + // Render SimpleNav component + const { getByTestId } = render( ); + + // Click on audio button + fireEvent.click(getByTestId('audio-button')); + + // Click on audio button again + fireEvent.click(getByTestId('audio-button')); + }); + + /*test('toggles audio playback when button is clicked', () => { const { getByTestId } = render( ); diff --git a/webapp/src/components/leaderboard/RankingTable.test.tsx b/webapp/src/components/leaderboard/RankingTable.test.tsx index 9de944f..ef30cb5 100644 --- a/webapp/src/components/leaderboard/RankingTable.test.tsx +++ b/webapp/src/components/leaderboard/RankingTable.test.tsx @@ -62,4 +62,23 @@ describe('RankingTable', () => { expect(percentageUser1).toHaveTextContent('50%'); expect(percentageUser2).toHaveTextContent('30%'); }); + + it('handles error during user retrieval', async () => { + // Mock the getAllUsers function to simulate an error + (getAllUsers as jest.Mock).mockRejectedValue(new Error('Failed to retrieve users')); + + // Spy on console.error to check if it's called with the expected error message + const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + + await act(async () => { + render(); + }); + + // Check if console.error was called with the expected error message + expect(consoleErrorSpy).toHaveBeenCalledWith('Error during retrieving all the users', expect.any(Error)); + + // Restore the original console.error implementation + consoleErrorSpy.mockRestore(); + }); + }); \ No newline at end of file diff --git a/webapp/src/components/leaderboard/TrivialRankingTable.test.tsx b/webapp/src/components/leaderboard/TrivialRankingTable.test.tsx index 150e98e..6e453e6 100644 --- a/webapp/src/components/leaderboard/TrivialRankingTable.test.tsx +++ b/webapp/src/components/leaderboard/TrivialRankingTable.test.tsx @@ -22,7 +22,7 @@ describe('TrivialRankingTable', () => { await act(async () => { render(); }); - }); + }); it('displays users with cheeseCount greater than 0', async () => { await act(async () => { @@ -45,4 +45,31 @@ describe('TrivialRankingTable', () => { expect(users[0]).toHaveTextContent('user2'); expect(users[1]).toHaveTextContent('user1'); }); + + it('logs error message when getAllUsers fails', async () => { + const consoleErrorSpy = jest.spyOn(console, 'error'); + const errorMessage = 'Error during retrieving all the users'; + const error = new Error('Test error'); + (getAllUsers as jest.Mock).mockRejectedValue(error); + + await act(async () => { + render(); + }); + await waitFor(() => expect(getAllUsers).toHaveBeenCalled()); + + expect(consoleErrorSpy).toHaveBeenCalledWith(errorMessage, error); + }); + + it('does not render table when getAllUsers fails', async () => { + const errorMessage = 'Error during retrieving all the users'; + const error = new Error('Test error'); + (getAllUsers as jest.Mock).mockRejectedValue(error); + + await act(async () => { + render(); + }); + + expect(screen.queryByTestId('user-row')).not.toBeInTheDocument(); + expect(screen.queryByText(errorMessage)).not.toBeInTheDocument(); + }); }); \ No newline at end of file diff --git a/webapp/src/components/stats/Statistics.test.tsx b/webapp/src/components/stats/Statistics.test.tsx index 3ea3ee3..9d745c1 100644 --- a/webapp/src/components/stats/Statistics.test.tsx +++ b/webapp/src/components/stats/Statistics.test.tsx @@ -9,6 +9,15 @@ jest.mock('../../stores/user-store'); jest.mock('../../services/auth-service'); describe('Statistics component', () => { + let originalConsoleError; + + beforeAll(() => { + // Guardar la función original de console.error + originalConsoleError = console.error; + // Sustituir console.error con una función mock + console.error = jest.fn(); + }); + it('renders user information correctly', async () => { const mockUser = { username: 'testuser', email: 'testuser@example.com' }; (useUserStore.getState as jest.Mock).mockReturnValue({ user: mockUser }); @@ -23,4 +32,22 @@ describe('Statistics component', () => { expect(screen.getByText(mockUser.username)).toBeInTheDocument(); expect(screen.getByText(mockUser.email)).toBeInTheDocument(); }); -}); \ No newline at end of file + + + + it('handles error during user retrieval', async () => { + const errorMessage = 'Failed to retrieve user'; + const mockError = new Error(errorMessage); + (useUserStore.getState as jest.Mock).mockReturnValue({ user: { username: 'testuser' } }); + (getUser as jest.Mock).mockRejectedValue(mockError); + + await act(async () => { + render( + + ); + }); + + // Verifica que console.error haya sido llamado con el mensaje de error correcto + expect(console.error).toHaveBeenCalledWith('Error during retrieving the user', mockError); + }); +}); \ No newline at end of file diff --git a/webapp/src/services/question-service.test.tsx b/webapp/src/services/question-service.test.tsx new file mode 100644 index 0000000..1304c06 --- /dev/null +++ b/webapp/src/services/question-service.test.tsx @@ -0,0 +1,49 @@ +import axios from 'axios'; +import { getQuestionsFromApi, getEasyString, getHardString } from './question-service'; + +// Mockear axios +jest.mock('axios'); + +describe('getQuestionsFromApi function', () => { + it('fetches questions from API and returns data', async () => { + // Datos de ejemplo que quieres que devuelva el mock de axios + const mockedData = [ + { + text: 'Example question', + answers: ['Answer 1', 'Answer 2', 'Answer 3'], + correctAnswer: 0, + wikiLink: 'https://example.com' + } + // Puedes agregar más datos de ejemplo si lo deseas + ]; + + // Mockear la función axios.get para que devuelva los datos de ejemplo + (axios.get as jest.MockedFunction).mockResolvedValueOnce({ data: mockedData }); + + // Llamar a la función que quieres probar + const questions = await getQuestionsFromApi(); + + // Verificar que axios.get haya sido llamado con la URL correcta + expect(axios.get).toHaveBeenCalledWith('http://localhost:8000/GetQuestions'); + + // Verificar que la función retorna los datos esperados + expect(questions).toEqual(mockedData); + }); + + +}); + +describe('getEasyString function', () => { + it('returns the string "easy"', () => { + const result = getEasyString(); + expect(result).toBe('easy'); + }); + }); + + describe('getHardString function', () => { + it('returns the string "hard"', () => { + const result = getHardString(); + expect(result).toBe('hard'); + }); + +});