From dbaa517d2560497bb8a8f199053db9cbf8b2f2f6 Mon Sep 17 00:00:00 2001 From: sergiorodriguezgarcia <113514397+sergiorodriguezgarcia@users.noreply.github.com> Date: Mon, 8 Apr 2024 23:50:28 +0200 Subject: [PATCH 1/3] feat: Adding tests to the new impl. of Game --- webapp/src/components/game/Game.js | 30 ++++++-- webapp/src/pages/Game.jsx | 1 + webapp/src/tests/Game.test.js | 113 +++++++++++++---------------- 3 files changed, 77 insertions(+), 67 deletions(-) diff --git a/webapp/src/components/game/Game.js b/webapp/src/components/game/Game.js index ffe3ac04..edcf768b 100644 --- a/webapp/src/components/game/Game.js +++ b/webapp/src/components/game/Game.js @@ -1,4 +1,4 @@ -import {HttpStatusCode} from "axios"; +import { HttpStatusCode } from "axios"; import AuthManager from "components/auth/AuthManager"; const authManager = new AuthManager(); @@ -15,11 +15,25 @@ export async function newGame() { } export async function startRound(gameId) { - return await authManager.getAxiosInstance().post(process.env.REACT_APP_API_ENDPOINT + "/games/" + gameId + "/startRound"); + try { + let requestAnswer = await authManager.getAxiosInstance().post(process.env.REACT_APP_API_ENDPOINT + "/games/" + gameId + "/startRound"); + if (HttpStatusCode.Ok === requestAnswer.status) { + return requestAnswer.data; + } + } catch { + + } } export async function getCurrentQuestion(gameId) { - return await authManager.getAxiosInstance().get(process.env.REACT_APP_API_ENDPOINT + "/games/" + gameId + "/question"); + try { + let requestAnswer = await authManager.getAxiosInstance().get(process.env.REACT_APP_API_ENDPOINT + "/games/" + gameId + "/question"); + if (HttpStatusCode.Ok === requestAnswer.status) { + return requestAnswer.data; + } + } catch { + + } } export async function changeLanguage(gameId, language) { @@ -34,7 +48,14 @@ export async function changeLanguage(gameId, language) { } export async function answerQuestion(gameId, aId) { - return await authManager.getAxiosInstance().post(process.env.REACT_APP_API_ENDPOINT + "/games/" + gameId + "/answer", {answer_id:aId}); + try { + let requestAnswer = await authManager.getAxiosInstance().post(process.env.REACT_APP_API_ENDPOINT + "/games/" + gameId + "/answer", {answer_id:aId}); + if (HttpStatusCode.Ok === requestAnswer.status) { + return requestAnswer.data; + } + } catch { + + } } export async function getGameDetails(gameId) { @@ -47,4 +68,3 @@ export async function getGameDetails(gameId) { } } - diff --git a/webapp/src/pages/Game.jsx b/webapp/src/pages/Game.jsx index 918c4a61..2ab6ad76 100644 --- a/webapp/src/pages/Game.jsx +++ b/webapp/src/pages/Game.jsx @@ -204,6 +204,7 @@ export default function Game() { {loading ? ( ({ - useTranslation: () => { - return { - t: (str) => str, - i18n: { - changeLanguage: () => new Promise(() => {}), - }, - } - }, -})); +import { MemoryRouter } from 'react-router'; +import Game from "../pages/Game"; +import { HttpStatusCode } from "axios"; +import AuthManager from "components/auth/AuthManager"; +import MockAdapter from "axios-mock-adapter"; -jest.mock('../components/game/Questions', () => ({ - getQuestion: jest.fn(), -})); +describe("Game Component", () => { + const authManager = new AuthManager(); + let mockAxios; -describe('Game component', () => { - /* beforeEach(() => { - getQuestion.mockResolvedValue({ - content: 'Test question', - answers: [ - { id: 1, text: 'Test answer 1', category: 'Test category 1' }, - { id: 2, text: 'Test answer 2', category: 'Test category 2' }, - ], - }); + authManager.reset(); + mockAxios = new MockAdapter(authManager.getAxiosInstance()); }); - afterEach(() => { - jest.restoreAllMocks(); + afterAll(() => { + mockAxios = null; + authManager.reset(); }); - */ - test('selects an option when clicked', async () => { - /* - render(); - const option1Button = await screen.findByTestId('Option1'); - - act(() => fireEvent.click(option1Button)); - expect(option1Button).toHaveClass('chakra-button custom-button effect1 css-m4hh83'); - */ + it("renders loading spinner initially", () => { + const { getByTestId } = render(); + expect(getByTestId("loading-spinner")).toBeInTheDocument(); }); - /* - test('disables next button when no option is selected', async () => { - render(); - const nextButton = await screen.findByTestId('Next'); - expect(nextButton).toBeDisabled(); + it("renders round number and correct answers count", async () => { + const { getByText } = render(); + expect(getByText("game.round1")).toBeInTheDocument(); + expect(getByText("Correct answers: 0")).toBeInTheDocument(); }); - test('enables next button when an option is selected', async () => { - render(); - const option1Button = await screen.findByTestId('Option1'); - const nextButton = await screen.findByTestId('Next'); - - act(() => fireEvent.click(option1Button)); - - expect(nextButton).toBeEnabled(); + it("displays question and options after loading", async () => { + const data = { + question: "What is the capital of Spain?", + options: ["Madrid", "Barcelona", "Seville", "Valencia"], + }; + mockAxios.onGet().reply(HttpStatusCode.Ok, data); + const { container } = render(); + waitFor(() => { + expect(container).toHaveTextContent("What is the capital of Spain?"); + expect(container).toHaveTextContent("Madrid"); + expect(container).toHaveTextContent("Barcelona"); + expect(container).toHaveTextContent("Seville"); + expect(container).toHaveTextContent("Valencia"); + }); }); - test('renders ButtonEf component correctly', async () => { - render(); - const option2Button = await screen.findByTestId('Option2'); - - expect(option2Button).toHaveClass('chakra-button custom-button effect1 css-147pzm2'); - - act(() => fireEvent.click(option2Button)); - - expect(option2Button).toHaveClass('chakra-button custom-button effect1 css-m4hh83'); + it("allows selecting an answer and enables next button", async () => { + const data = { + question: "What is the capital of Spain?", + options: ["Madrid", "Barcelona", "Seville", "Valencia"], + }; + mockAxios.onGet().reply(HttpStatusCode.Ok, data); + const { container } = render(); + waitFor(() => { + const optionButton = container.querySelector("button"); + fireEvent.click(optionButton); + expect(optionButton).toHaveStyle("background-color: green"); + const nextButton = container.querySelector("button"); + expect(nextButton).not.toBeDisabled(); + }); }); - */ }); From c6e6a12b5ee013ef295b491420543cbe1218adc6 Mon Sep 17 00:00:00 2001 From: sergiorodriguezgarcia <113514397+sergiorodriguezgarcia@users.noreply.github.com> Date: Tue, 9 Apr 2024 00:06:36 +0200 Subject: [PATCH 2/3] feat: Adding tests to the Game class to connect to the API --- webapp/src/tests/GameAPI.test.js | 193 +++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 webapp/src/tests/GameAPI.test.js diff --git a/webapp/src/tests/GameAPI.test.js b/webapp/src/tests/GameAPI.test.js new file mode 100644 index 00000000..c67109dd --- /dev/null +++ b/webapp/src/tests/GameAPI.test.js @@ -0,0 +1,193 @@ +import MockAdapter from "axios-mock-adapter"; +import { newGame, startRound, getCurrentQuestion, changeLanguage, answerQuestion, getGameDetails } from "components/game/Game"; +import axios, { HttpStatusCode } from "axios"; +import AuthManager from "components/auth/AuthManager"; + +jest.mock('react-i18next', () => ({ + useTranslation: () => { + return { + t: (str) => str, + i18n: { + changeLanguage: () => new Promise(() => {}), + }, + } + }, +})); + +const authManager = new AuthManager(); +let mockAxios; + +describe("Game Service tests", () => { + beforeEach(() => { + authManager.reset(); + mockAxios = new MockAdapter(authManager.getAxiosInstance()); + }); + + describe("newGame function", () => { + it("successfully creates a new game", async () => { + const mockResponse = { gameId: 123, status: "created" }; + + mockAxios.onPost(process.env.REACT_APP_API_ENDPOINT + "/games/new").replyOnce( + HttpStatusCode.Ok, + mockResponse + ); + + const result = await newGame(); + + expect(result).toEqual(mockResponse); + }); + + it("handles errors when creating a new game", async () => { + mockAxios.onPost(process.env.REACT_APP_API_ENDPOINT + "/games/new").replyOnce( + HttpStatusCode.InternalServerError + ); + + const result = await newGame(); + + expect(result).toBeUndefined(); + }); + }); + + describe("startRound function", () => { + it("successfully starts a new round", async () => { + const gameId = 123; + const mockResponse = { roundId: 456, status: "started" }; + + mockAxios.onPost(process.env.REACT_APP_API_ENDPOINT + `/games/${gameId}/startRound`).replyOnce( + HttpStatusCode.Ok, + mockResponse + ); + + const result = await startRound(gameId); + + expect(result).toEqual(mockResponse); + }); + + it("handles errors when starting a new round", async () => { + const gameId = 123; + + mockAxios.onPost(process.env.REACT_APP_API_ENDPOINT + `/games/${gameId}/startRound`).replyOnce( + HttpStatusCode.NotFound + ); + + const result = await startRound(gameId); + + expect(result).toBeUndefined(); + }); + }); + describe("getCurrentQuestion function", () => { + it("successfully retrieves current question", async () => { + const gameId = 123; + const mockResponse = { questionId: 456, text: "What's your name?" }; + + mockAxios.onGet(process.env.REACT_APP_API_ENDPOINT + `/games/${gameId}/question`).replyOnce( + HttpStatusCode.Ok, + mockResponse + ); + + const result = await getCurrentQuestion(gameId); + + expect(result).toEqual(mockResponse); + }); + + it("handles errors when retrieving current question", async () => { + const gameId = 123; + + mockAxios.onGet(process.env.REACT_APP_API_ENDPOINT + `/games/${gameId}/question`).replyOnce( + HttpStatusCode.NotFound + ); + + const result = await getCurrentQuestion(gameId); + + expect(result).toBeUndefined(); + }); + }); + + describe("changeLanguage function", () => { + it("successfully changes language", async () => { + const gameId = 123; + const language = "en"; + const mockResponse = { success: true, message: "Language changed successfully." }; + + mockAxios.onPut(process.env.REACT_APP_API_ENDPOINT + `/games/${gameId}/language?language=${language}`).replyOnce( + HttpStatusCode.Ok, + mockResponse + ); + + const result = await changeLanguage(gameId, language); + + expect(result).toEqual(mockResponse); + }); + + it("handles errors when changing language", async () => { + const gameId = 123; + const language = "en"; + + mockAxios.onPut(process.env.REACT_APP_API_ENDPOINT + `/games/${gameId}/language?language=${language}`).replyOnce( + HttpStatusCode.BadRequest + ); + + const result = await changeLanguage(gameId, language); + + expect(result).toBeUndefined(); + }); + }); + + describe("answerQuestion function", () => { + it("successfully submits an answer", async () => { + const gameId = 123; + const answerId = "a1"; + const mockResponse = { success: true, message: "Answer submitted successfully." }; + + mockAxios.onPost(process.env.REACT_APP_API_ENDPOINT + `/games/${gameId}/answer`, { answer_id: answerId }).replyOnce( + HttpStatusCode.Ok, + mockResponse + ); + + const result = await answerQuestion(gameId, answerId); + + expect(result).toEqual(mockResponse); + }); + + it("handles errors when submitting an answer", async () => { + const gameId = 123; + const answerId = "a1"; + + mockAxios.onPost(process.env.REACT_APP_API_ENDPOINT + `/games/${gameId}/answer`, { answer_id: answerId }).replyOnce( + HttpStatusCode.InternalServerError + ); + + const result = await answerQuestion(gameId, answerId); + + expect(result).toBeUndefined(); + }); + }); + + describe("getGameDetails function", () => { + it("successfully retrieves game details", async () => { + const gameId = 123; + const mockResponse = { gameId: 123, status: "started" }; + + mockAxios.onGet(process.env.REACT_APP_API_ENDPOINT + `/games/${gameId}/details`).replyOnce( + HttpStatusCode.Ok, + mockResponse + ); + + const result = await getGameDetails(gameId); + + expect(result).toEqual(mockResponse); + }); + + it("handles errors when retrieving game details", async () => { + const gameId = 123; + + mockAxios.onGet(process.env.REACT_APP_API_ENDPOINT + `/games/${gameId}/details`).replyOnce( + HttpStatusCode.NotFound + ); + + const result = await getGameDetails(gameId); + + expect(result).toBeUndefined(); + }); + }); +}); From 270f566ca38418414dc2376c498a0cb00ccb4880 Mon Sep 17 00:00:00 2001 From: sergiorodriguezgarcia <113514397+sergiorodriguezgarcia@users.noreply.github.com> Date: Tue, 9 Apr 2024 00:28:37 +0200 Subject: [PATCH 3/3] feat: Adding test to coverage --- webapp/src/tests/Game.test.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/webapp/src/tests/Game.test.js b/webapp/src/tests/Game.test.js index 0f47d72f..74c8e69a 100644 --- a/webapp/src/tests/Game.test.js +++ b/webapp/src/tests/Game.test.js @@ -65,4 +65,30 @@ describe("Game Component", () => { expect(nextButton).not.toBeDisabled(); }); }); + it("displays correct answer after selecting wrong answer", async () => { + const data = { + question: "What is the capital of Spain?", + options: ["Madrid", "Barcelona", "Seville", "Valencia"], + }; + mockAxios.onGet().reply(HttpStatusCode.Ok, data); + const { container } = render(); + waitFor(() => { + const optionButton = container.querySelector("button"); + fireEvent.click(optionButton); + expect(optionButton).toHaveStyle("background-color: red"); + }); + }); + it("displays correct answer after selecting correct answer", async () => { + const data = { + question: "What is the capital of Spain?", + options: ["Madrid", "Barcelona", "Seville", "Valencia"], + }; + mockAxios.onGet().reply(HttpStatusCode.Ok, data); + const { container } = render(); + waitFor(() => { + const optionButton = container.querySelector("button"); + fireEvent.click(optionButton); + expect(optionButton).toHaveStyle("background-color: green"); + }); + }); });