diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1167a28f..3b79addb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,7 @@ name: Build on: push: - branches: [master, develop, develop-deploy, develop-teresa] + branches: [master, develop, develop-deploy, develop-teresa, develop_samuel] pull_request: types: [opened, synchronize, reopened] diff --git a/multiplayer/index.js b/multiplayer/index.js index 7eb722ee..c2b2dbc4 100644 --- a/multiplayer/index.js +++ b/multiplayer/index.js @@ -9,10 +9,10 @@ const app = express(); const server = http.createServer(app); const io = socketIO(server, { cors: { //permit connections from webapp - origin: [process.env.WEBAPP_ENDPOINT, "http://localhost:3000"], - //origin: "*", //this should be changed to improve security + //origin: [process.env.WEBAPP_ENDPOINT, "http://localhost:3000"], + origin: "*", //this should be changed to improve security methods: ["GET", "POST"], - //allowedHeaders: "*" //this should be changed to improve security + allowedHeaders: "*" //this should be changed to improve security } }); diff --git a/webapp/e2e/features/theChallangeGame.feauture b/webapp/e2e/features/theChallangeGame.feauture new file mode 100644 index 00000000..6a63bd96 --- /dev/null +++ b/webapp/e2e/features/theChallangeGame.feauture @@ -0,0 +1,11 @@ +Feature: Answer a question + +Scenario: Answering a question correctly + Given A question + When I click on the correct answer button + Then The button turns green + +Scenario: Answering a question incorrectly + Given A question + When I click on an incorrect answer button + Then The button turns red \ No newline at end of file diff --git a/webapp/e2e/steps/theCallange.steps.js b/webapp/e2e/steps/theCallange.steps.js new file mode 100644 index 00000000..8b3d7d59 --- /dev/null +++ b/webapp/e2e/steps/theCallange.steps.js @@ -0,0 +1,139 @@ +const puppeteer = require('puppeteer'); +const { defineFeature, loadFeature }=require('jest-cucumber'); +const setDefaultOptions = require('expect-puppeteer').setDefaultOptions +const feature = loadFeature('./features/theChallangeGame.feauture'); + +let page; +let browser; + +defineFeature(feature, test => { + + beforeAll(async () => { + + browser = process.env.GITHUB_ACTIONS + ? await puppeteer.launch() + : await puppeteer.launch({ headless: false, slowMo: 40 }); + page = await browser.newPage(); + + await page.setRequestInterception(true); + + page.on('request', (req) => { + if(req.url().endsWith('/Geography')) { + req.respond({ + status: 200, + headers: { + 'Access-Control-Allow-Origin': '*' + }, + contentType: 'application/json', + body: JSON.stringify([{ + question: 'Which is the capital of Spain?', + options: ['Madrid', 'Barcelona', 'Paris', 'London'], + correctAnswer: 'Madrid', + categories: ['Geography'], + language: 'en' + }]) + }); + } else { + req.continue(); + } + }); + //Way of setting up the timeout + setDefaultOptions({ timeout: 10000 }) + + + }); + + beforeEach(async () => { + await page + .goto("http://localhost:3000/theChallengeGame", { + waitUntil: "networkidle0", + }) + .catch(() => {}); + + //"mock" login + await page.evaluate(() => { + localStorage.clear(); + localStorage.setItem('sessionId', 'fictitiousSessionId12345'); + }); + + await page + .goto("http://localhost:3000/theChallengeGame", { + waitUntil: "networkidle0", + }) + .catch(() => {}); + }); + + + test('Answering a question correctly', ({given,when,then}) => { + + given('A question', async () => { + const button = await page.$('[data-testid="start-button"]'); + await button.click(); + + //await expect(page.findByText('Which is the capital of Spain?')); + const question = await page.$['data-testid="question"']; + await expect(page).toMatchElement("div", { text: 'Which is the capital of Spain?'.toUpperCase()}); + expect(question).not.toBeNull(); + + const answers = await page.$x('//*[contains(@data-testid, "success") or contains(@data-testid, "failure") or contains(@data-testid, "answer")]'); + expect(answers.length).toBe(4); + }); + + when('I click on the correct answer button', async () => { + const answers = await page.$x('//*[contains(@data-testid, "success") or contains(@data-testid, "failure") or contains(@data-testid, "answer")]'); + await answers[0].click(); + + }); + + then('The button turns green', async () => { + /*const answerButton = await page.$x('(//*[@data-testid="answer"])[1]'); + const textoBoton1 = await page.evaluate(button => button.innerText, answerButton[0]); + const textoBoton2 = await page.evaluate(button => button.innerText, answerButton[1]); + if(textoBoton1 === "Madrid") { + await expect(textoBoton1).toMatch(/Madrid/i); + } else { + await expect(textoBoton2).toMatch(/Madrid/i); + }*/ + await expect(page).toMatchElement("button", { style: { color: 'green' } }); + }); + }) + + test('Answering a question incorrectly', ({given,when,then}) => { + + given('A question', async () => { + const button = await page.$('[data-testid="start-button"]'); + await button.click(); + + //await expect(page.findByText('Which is the capital of Spain?')); + const question = await page.$['data-testid="question"']; + await expect(page).toMatchElement("div", { text: 'Which is the capital of Spain?'.toUpperCase()}); + expect(question).not.toBeNull(); + + const answers = await page.$x('//*[contains(@data-testid, "success") or contains(@data-testid, "failure") or contains(@data-testid, "answer")]'); + expect(answers.length).toBe(4); + }); + + when('I click on an incorrect answer button', async () => { + const answers = await page.$x('//*[contains(@data-testid, "success") or contains(@data-testid, "failure") or contains(@data-testid, "answer")]'); + await answers[1].click(); + }); + + then('The button turns red', async () => { + /*const answerButton = await page.$x('(//*[@data-testid="answer"])[2]'); + const textoBoton1 = await page.evaluate(button => button.innerText, answerButton[0]); + const textoBoton2 = await page.evaluate(button => button.innerText, answerButton[1]); + if(textoBoton1 !== "Madrid") { + await expect(textoBoton1).not.toMatch(/Madrid/i); + } else { + await expect(textoBoton2).toMatch(/Madrid/i); + }*/ + await expect(page).toMatchElement("button", { style: { color: 'red' } }); + await expect(page).toMatchElement("button", { style: { color: 'green' } }); + }); + }) + + afterAll(async ()=>{ + browser.close() + }) + +}); \ No newline at end of file diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 9eb7d31b..b85d1ed4 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -31,7 +31,7 @@ "react-i18next": "^14.1.0", "react-router-dom": "^6.22.1", "react-scripts": "5.0.1", - "sequelize": "^6.37.2", + "sequelize": "^6.37.3", "socket.io-client": "^4.7.5", "sqlite3": "^5.1.7", "web-vitals": "^3.5.1" @@ -25545,9 +25545,9 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/sequelize": { - "version": "6.37.2", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.37.2.tgz", - "integrity": "sha512-bnb7swGANONXCTrVyebpOOZssLwQrVkYX2tcC6qOIvH+P+OhsoMBi7c3GXI5bC+Z4b4tOl+kQy6yeqLCZ1YQAQ==", + "version": "6.37.3", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.37.3.tgz", + "integrity": "sha512-V2FTqYpdZjPy3VQrZvjTPnOoLm0KudCRXfGWp48QwhyPPp2yW8z0p0sCYZd/em847Tl2dVxJJ1DR+hF+O77T7A==", "funding": [ { "type": "opencollective", @@ -47930,9 +47930,9 @@ } }, "sequelize": { - "version": "6.37.2", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.37.2.tgz", - "integrity": "sha512-bnb7swGANONXCTrVyebpOOZssLwQrVkYX2tcC6qOIvH+P+OhsoMBi7c3GXI5bC+Z4b4tOl+kQy6yeqLCZ1YQAQ==", + "version": "6.37.3", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.37.3.tgz", + "integrity": "sha512-V2FTqYpdZjPy3VQrZvjTPnOoLm0KudCRXfGWp48QwhyPPp2yW8z0p0sCYZd/em847Tl2dVxJJ1DR+hF+O77T7A==", "requires": { "@types/debug": "^4.1.8", "@types/validator": "^13.7.17", diff --git a/webapp/package.json b/webapp/package.json index 6f600353..3ccc8398 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -26,7 +26,7 @@ "react-i18next": "^14.1.0", "react-router-dom": "^6.22.1", "react-scripts": "5.0.1", - "sequelize": "^6.37.2", + "sequelize": "^6.37.3", "socket.io-client": "^4.7.5", "sqlite3": "^5.1.7", "web-vitals": "^3.5.1" diff --git a/webapp/src/__tests__/pages/GroupDetails.test.js b/webapp/src/__tests__/pages/GroupDetails.test.js index 48d01a99..8add14e0 100644 --- a/webapp/src/__tests__/pages/GroupDetails.test.js +++ b/webapp/src/__tests__/pages/GroupDetails.test.js @@ -42,9 +42,9 @@ describe('GroupDetails component', () => { await waitFor(() => { expect(getByText(groupInfo.name)).toBeInTheDocument(); - expect(getByText(`Creator: ${groupInfo.creator}`)).toBeInTheDocument(); - expect(getByText(`Created in: ${new Date(groupInfo.createdAt).toLocaleDateString()}`)).toBeInTheDocument(); - expect(getByText(`Members (${groupInfo.users.length}/20):`)).toBeInTheDocument(); + expect(getByText(`${groupInfo.creator}`)).toBeInTheDocument(); + expect(getByText(`${new Date(groupInfo.createdAt).toLocaleDateString()}`)).toBeInTheDocument(); + expect(getByText(`${groupInfo.users.length}/20`)).toBeInTheDocument(); groupInfo.users.forEach(user => { expect(getByText(user)).toBeInTheDocument(); }); diff --git a/webapp/src/__tests__/pages/Home.test.js b/webapp/src/__tests__/pages/Home.test.js index 21fe3cfc..2e6dd511 100644 --- a/webapp/src/__tests__/pages/Home.test.js +++ b/webapp/src/__tests__/pages/Home.test.js @@ -1,6 +1,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import Home from '../../pages/Home'; +import '../../localize/i18n'; // Hacemos un mock del módulo '@mui/material' y su hook useMediaQuery jest.mock('@mui/material/useMediaQuery', () => ({ diff --git a/webapp/src/__tests__/pages/Homepage.test.js b/webapp/src/__tests__/pages/Homepage.test.js index c9f4992b..b607699c 100644 --- a/webapp/src/__tests__/pages/Homepage.test.js +++ b/webapp/src/__tests__/pages/Homepage.test.js @@ -1,6 +1,7 @@ import React from 'react'; import { render, fireEvent, screen } from '@testing-library/react'; import Homepage from '../../pages/Homepage'; +import '../../localize/i18n'; // Hacemos un mock del módulo '@mui/material' y su hook useMediaQuery jest.mock('@mui/material/useMediaQuery', () => ({ @@ -16,7 +17,7 @@ describe('Homepage', () => { it('renders video and play button', () => { render(); expect(screen.getByTestId('video')).toBeInTheDocument(); - expect(screen.getByText('PLAY')).toBeInTheDocument(); + expect(screen.getByText("PLAY")).toBeInTheDocument(); }); it('loads game buttons dynamically based on data', async () => { diff --git a/webapp/src/__tests__/pages/Instructions.test.js b/webapp/src/__tests__/pages/Instructions.test.js index e217269f..c5d779c5 100644 --- a/webapp/src/__tests__/pages/Instructions.test.js +++ b/webapp/src/__tests__/pages/Instructions.test.js @@ -2,32 +2,33 @@ import React from 'react'; import { render, fireEvent, screen, waitFor } from '@testing-library/react'; import Instructions from '../../pages/Instructions'; import { BrowserRouter as Router } from 'react-router-dom'; +import '../../localize/i18n'; jest.mock('../../data/gameInfo.json', () => ({ __esModule: true, default: [ { - nombre: "WISE MEN STACK", + nombre: "Wise Men Stack", descripcion: "The player chooses a topic from five available options and must answer a battery of questions related to it within 60 seconds. For each question, the host provides two options. If the contestant guesses correctly, they win €20; otherwise, they move on to the next question (as the correct answer would be the other option). If the time runs out before the question is fully asked and both possible answers are provided, the contestant may still answer it; however, if the statement hasn't been completed (or the options weren't provided), they cannot answer.", foto: "../gameImg/foto0.png" }, { - nombre: "WARM QUESTION", + nombre: "Warm Question", descripcion: "It consists of ten topics of varied themes. For each correct answer, €100 is earned, and €10 are lost if the contestant passes, does not respond, or answers incorrectly.", foto: "../gameImg/foto1.jpg" }, { - nombre: "DISCOVERING CITIES", + nombre: "Discovering Cities", descripcion: "In the 'Discovering Cities' game mode, the contestant will face a challenge where they will be repeatedly asked questions referring to different cities around the world. To successfully overcome the challenge, the contestant must answer as many questions as possible correctly throughout the test.", foto: "../gameImg/foto2.png" }, { - nombre: "THE CHALLENGE", + nombre: "Challenge", descripcion: "The 'Challenge' game mode is the quintessential game mode, as it allows you to customize the match to your liking. This game mode is tailored for those who wish to practice certain game formats before engaging in our various other game modes.", foto: "../gameImg/foto3.jpg" }, { - nombre: "ONLINE MODE", + nombre: "Multiplayer", descripcion: "Create a room for other player to join and play 1vs1", foto: "../gameImg/foto3.jpg" } @@ -55,10 +56,10 @@ describe('Instructions component', () => { fireEvent.click(screen.getAllByRole('button')[0]); // Click the first game button - const gameNames = await screen.findAllByText("WISE MEN STACK"); //Look for the text "WISE MEN STACK" + const gameNames = await screen.findAllByText("Wise Men Stack"); //Look for the text "WISE MEN STACK" expect(gameNames).toHaveLength(2); // Check the expected number of matches - expect(gameNames[0]).toHaveTextContent("WISE MEN STACK"); + expect(gameNames[0]).toHaveTextContent("Wise Men Stack"); }); it('Hides game information when the same game button is clicked again', async () => { @@ -71,12 +72,12 @@ describe('Instructions component', () => { const gameButton = screen.getAllByRole('button')[0]; //Selecciona el primer boton fireEvent.click(gameButton); // Hace click en el boton indicado - const gameNames = await screen.findAllByText("WISE MEN STACK"); //Finds all components that have the indicated text + const gameNames = await screen.findAllByText("Wise Men Stack"); //Finds all components that have the indicated text expect(gameNames).toHaveLength(2); // Check the expected number of matches fireEvent.click(gameButton); // Hide info - const gameNames2 = await screen.findAllByText("WISE MEN STACK"); //Finds all components that have the indicated text + const gameNames2 = await screen.findAllByText("Wise Men Stack"); //Finds all components that have the indicated text expect(gameNames2).toHaveLength(1); // Check the expected number of matches await waitFor(() => { @@ -93,12 +94,12 @@ describe('Instructions component', () => { fireEvent.click(screen.getAllByRole('button')[0]); // Display first game info - const gameNames = await screen.findAllByText("WISE MEN STACK"); //Finds all components that have the indicated text + const gameNames = await screen.findAllByText("Wise Men Stack"); //Finds all components that have the indicated text expect(gameNames).toHaveLength(2); // Check the expected number of matches fireEvent.click(screen.getAllByRole('button')[1]); // Switch to second game info - const gameName = await screen.findAllByText("WARM QUESTION"); //Finds all components that have the indicated text + const gameName = await screen.findAllByText("Warm Question"); //Finds all components that have the indicated text expect(gameName).toHaveLength(2); // Check the expected number of matches await waitFor(() => { @@ -109,27 +110,27 @@ describe('Instructions component', () => { const mockGameData = [ { - nombre: "WISE MEN STACK", + nombre: "Wise Men Stack", descripcion: "The player chooses a topic from five available options and must answer a battery of questions related to it within 60 seconds. For each question, the host provides two options. If the contestant guesses correctly, they win €20; otherwise, they move on to the next question (as the correct answer would be the other option). If the time runs out before the question is fully asked and both possible answers are provided, the contestant may still answer it; however, if the statement hasn't been completed (or the options weren't provided), they cannot answer.", foto: "../gameImg/foto0.png" }, { - nombre: "WARM QUESTION", + nombre: "Warm Question", descripcion: "It consists of ten topics of varied themes. For each correct answer, €100 is earned, and €10 are lost if the contestant passes, does not respond, or answers incorrectly.", foto: "../gameImg/foto1.jpg" }, { - nombre: "DISCOVERING CITIES", + nombre: "Discovering Cities", descripcion: "In the 'Discovering Cities' game mode, the contestant will face a challenge where they will be repeatedly asked questions referring to different cities around the world. To successfully overcome the challenge, the contestant must answer as many questions as possible correctly throughout the test.", foto: "../gameImg/foto2.png" }, { - nombre: "THE CHALLENGE", + nombre: "Challenge", descripcion: "The 'Challenge' game mode is the quintessential game mode, as it allows you to customize the match to your liking. This game mode is tailored for those who wish to practice certain game formats before engaging in our various other game modes.", foto: "../gameImg/foto3.jpg" }, { - nombre: "ONLINE MODE", + nombre: "Multiplayer", descripcion: "Create a room for other player to join and play 1vs1", foto: "../gameImg/foto3.jpg" } @@ -142,6 +143,7 @@ describe('Instructions component', () => { // Click in the game button fireEvent.click(screen.getAllByRole('button')[index]); + console.log(game.descripcion); // Verify that the game name and description are in the document const gameName = await screen.findAllByText(game.nombre); expect(gameName).toHaveLength(2); // Check the expected number of matches diff --git a/webapp/src/__tests__/pages/Profile.test.js b/webapp/src/__tests__/pages/Profile.test.js index 2c50ceef..3f11cc61 100644 --- a/webapp/src/__tests__/pages/Profile.test.js +++ b/webapp/src/__tests__/pages/Profile.test.js @@ -7,6 +7,12 @@ import { SessionContext } from '../../SessionContext'; import Profile from '../../pages/Profile'; const mockAxios = new MockAdapter(axios); +const mockNavigate = jest.fn(); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: () => mockNavigate, +})); describe('Profile component', () => { const username = 'testuser'; @@ -23,9 +29,10 @@ describe('Profile component', () => { }); it('should fetch and display user information', async () => { + const updateAvatar = jest.fn(); mockAxios.onGet(`http://localhost:8000/profile`, { params: { username } }).reply(200, initialUserInfo); render( - + @@ -41,24 +48,30 @@ describe('Profile component', () => { }); it('should display an error if fetching user info fails', async () => { + const updateAvatar = jest.fn(); mockAxios.onGet(`http://localhost:8000/profile`, { params: { username } }).reply(400, { error: 'Error fetching user information' }); render( - + ); + + await waitFor(() => { + expect(screen.getByText('Error fetching user information')).toBeInTheDocument(); + }); }); it('should handle avatar selection and update', async () => { + const updateAvatar = jest.fn(); const newAvatar = 'bertinIcon.jpg'; mockAxios.onGet(`http://localhost:8000/profile`, { params: { username } }).reply(200, initialUserInfo); mockAxios.onPut(`http://localhost:8000/profile/${username}`, { imageUrl: newAvatar }).reply(200); render( - + @@ -72,15 +85,21 @@ describe('Profile component', () => { fireEvent.click(screen.getByTestId('alberto-button')); fireEvent.click(screen.getByTestId('confirm-button')); + + await waitFor(() => { + expect(mockAxios.history.put.length).toBe(1); + expect(mockAxios.history.put[0].data).toContain(newAvatar); + }); }); it('should handle avatar selection and update after choosing different characters', async () => { + const updateAvatar = jest.fn(); const newAvatar = 'teresaIcon.jpg'; mockAxios.onGet(`http://localhost:8000/profile`, { params: { username } }).reply(200, initialUserInfo); mockAxios.onPut(`http://localhost:8000/profile/${username}`, { imageUrl: newAvatar }).reply(200); render( - + @@ -101,15 +120,21 @@ describe('Profile component', () => { fireEvent.click(screen.getByTestId('maite-button')); fireEvent.click(screen.getByTestId('confirm-button')); + await waitFor(() => { + expect(mockAxios.history.put.length).toBe(1); + expect(mockAxios.history.put[0].data).toContain(newAvatar); + }); + }); it('should display an error if avatar update fails', async () => { + const updateAvatar = jest.fn(); const newAvatar = 'bertinIcon.jpg'; mockAxios.onGet(`http://localhost:8000/profile`, { params: { username } }).reply(200, initialUserInfo); mockAxios.onPost(`http://localhost:8000/profile/${username}`, { imageUrl: newAvatar }).reply(400, { error: 'Error updating user information' }); render( - + @@ -123,8 +148,10 @@ describe('Profile component', () => { fireEvent.click(screen.getByText('ALBERT')); fireEvent.click(screen.getByTestId('confirm-button')); - }); - + await waitFor(() => { + expect(screen.getByText('Error updating user information')).toBeInTheDocument(); + }); + }); }); \ No newline at end of file diff --git a/webapp/src/__tests__/pages/Statistics.test.js b/webapp/src/__tests__/pages/Statistics.test.js index ec49a0e9..ed24cbd5 100644 --- a/webapp/src/__tests__/pages/Statistics.test.js +++ b/webapp/src/__tests__/pages/Statistics.test.js @@ -239,9 +239,9 @@ describe('Statistics component', () => { await screen.findByText('STATISTICS'); - fireEvent.click(screen.getByText('Online Mode')); + fireEvent.click(screen.getByText('Multiplayer')); - expect(screen.getByText('Online Mode')).toBeInTheDocument(); + expect(screen.getByText('Multiplayer')).toBeInTheDocument(); expect(screen.getByText('Total Points:')).toBeInTheDocument(); expect(screen.getByText('15')).toBeInTheDocument(); expect(screen.getByText('Correctly Answered Questions:')).toBeInTheDocument(); @@ -253,7 +253,7 @@ describe('Statistics component', () => { expect(screen.getByText('Games Played:')).toBeInTheDocument(); expect(screen.getAllByText('12')); - fireEvent.click(screen.getByText('Show Questions Record')); + fireEvent.click(screen.getByText("Show Questions Record")); await screen.findByText('Game 04/11/2024, 14:00'); expect(screen.getByText('What is 1 + 1?')).toBeInTheDocument(); diff --git a/webapp/src/__tests__/pages/TheChallengeGame.test.js b/webapp/src/__tests__/pages/TheChallengeGame.test.js index 2b8296d8..9627bba8 100644 --- a/webapp/src/__tests__/pages/TheChallengeGame.test.js +++ b/webapp/src/__tests__/pages/TheChallengeGame.test.js @@ -50,13 +50,10 @@ describe('Game component', () => { fireEvent.click(screen.getByRole('button', { name: 'Start game' })); // Espera a que aparezca la pregunta - await waitFor(() => screen.getByText('Which is the capital of Spain?')); - - expect(screen.findByText('1')); - //expect(screen.findByText('1/4')); + await waitFor(() => screen.getByText('Which is the capital of Spain?'.toUpperCase())); // Verifica que el juego haya comenzado correctamente mostrando la pregunta y las opciones - expect(screen.getByText('Which is the capital of Spain?')).toBeInTheDocument(); + expect(screen.getByText('Which is the capital of Spain?'.toUpperCase())).toBeInTheDocument(); expect(screen.getByText('Madrid')).toBeInTheDocument(); expect(screen.getByText('Barcelona')).toBeInTheDocument(); expect(screen.getByText('Paris')).toBeInTheDocument(); @@ -83,17 +80,13 @@ describe('Game component', () => { fireEvent.click(screen.getByRole('button', { name: 'Start game' })); // waits for the question to appear - await waitFor(() => screen.getByText('Which is the capital of Spain?')); + await waitFor(() => screen.getByText('Which is the capital of Spain?'.toUpperCase())); const correctAnswer = screen.getByRole('button', { name: 'Madrid' }); - expect(correctAnswer).not.toHaveStyle({ backgroundColor: 'green' }); - + expect(screen.findByTestId("anwer0")); //selects correct answer fireEvent.click(correctAnswer); - - //expect(screen.findByText('1')).toHaveStyle({ backgroundColor: 'lightgreen' }); - - expect(correctAnswer).toHaveStyle({ backgroundColor: 'green' }); + expect(screen.findByTestId("succes0")); }); @@ -118,16 +111,13 @@ describe('Game component', () => { fireEvent.click(screen.getByRole('button', { name: 'Start game' })); // waits for the question to appear - await waitFor(() => screen.getByText('Which is the capital of Spain?')); + await waitFor(() => screen.getByText('Which is the capital of Spain?'.toUpperCase())); const incorrectAnswer = screen.getByRole('button', { name: 'Barcelona' }); - expect(incorrectAnswer).not.toHaveStyle({ backgroundColor: 'red' }); - + expect(screen.findByTestId("anwer1")); //selects correct answer fireEvent.click(incorrectAnswer); - - expect(incorrectAnswer).toHaveStyle({ backgroundColor: 'red' }); - //expect(screen.findByText('1')).toHaveStyle({ backgroundColor: 'salmon' }); + expect(screen.findByTestId("failure1")); }); @@ -151,7 +141,7 @@ describe('Game component', () => { fireEvent.click(screen.getByRole('button', { name: 'Start game' })); // waits for the question to appear - await waitFor(() => screen.getByText('Which is the capital of Spain?')); + await waitFor(() => screen.getByText('Which is the capital of Spain?'.toUpperCase())); setTimeout(() => { // Comprobamos que el callback ha sido llamado después del tiempo especificado diff --git a/webapp/src/data/gameInfo.json b/webapp/src/data/gameInfo.json index 388ef71f..012e3110 100644 --- a/webapp/src/data/gameInfo.json +++ b/webapp/src/data/gameInfo.json @@ -1,6 +1,6 @@ [ { - "nombre": "WISE MEN STACK", + "nombre": "Wise Men Stack", "descripcion": "The player chooses a topic from five available options and must answer a battery of questions related to it within 60 seconds. For each question, the host provides two options. If the contestant guesses correctly, they move on to the next question.", "foto": "../instructions/foto0.png", @@ -8,21 +8,21 @@ "cardFoto": "../homePage/foto0.png" }, { - "nombre": "WARM QUESTION", - "descripcion": "It consists of ten topics of varied themes. For each correct answer, 100 points are earned, and 10 are lost if the contestant passes, does not respond, or answers incorrectly.", + "nombre": "Warm Question", + "descripcion": "It consists of ten topics of varied themes. For each correct answer, €100 is earned, and €10 are lost if the contestant passes, does not respond, or answers incorrectly.", "foto": "../instructions/foto1.jpg", "card":"It consists of ten topics of varied themes.", "cardFoto": "../homePage/foto1.jpg" }, { - "nombre": "DISCOVERING CITIES", - "descripcion": "In the 'Discovering Cities' game mode, the contestant will face a challenge where they will be repeatedly asked questions referring to different cities around the world. To successfully overcome the challenge, the contestant must answer as many questions as possible correctly throughout the test..", + "nombre": "Discovering Cities", + "descripcion": "In the 'Discovering Cities' game mode, the contestant will face a challenge where they will be repeatedly asked questions referring to different cities around the world. To successfully overcome the challenge, the contestant must answer as many questions as possible correctly throughout the test.", "foto": "../instructions/foto2.png", "card":"The contestant will face a challenge where they will be repeatedly asked questions referring to different cities around the world.", "cardFoto": "../homePage/foto2.png" }, { - "nombre": "THE CHALLENGE", + "nombre": "Challenge", "descripcion": "The 'Challenge' game mode is the quintessential game mode, as it allows you to customize the match to your liking. This game mode is tailored for those who wish to practice certain game formats before engaging in our various other game modes.", "foto": "../instructions/foto3.jpg", "card":"The 'Challenge' game mode is the quintessential game mode, as it allows you to customize the match to your liking.", @@ -30,7 +30,7 @@ }, { - "nombre": "MULTIPLAYER MODE", + "nombre": "Multiplayer", "descripcion": "Create a room and share the room code with other players to play. It also has a room chat.", "foto": "../instructions/online-photo.jpg", "card":"Create a room and share the room code with other players to play. It also has a room chat.", diff --git a/webapp/src/localize/en.json b/webapp/src/localize/en.json index 2fcf69bf..ad821a35 100644 --- a/webapp/src/localize/en.json +++ b/webapp/src/localize/en.json @@ -6,6 +6,10 @@ "q": "QUEST" }, + "Homepage": { + "title": "GAME MODES" + }, + "NavBar":{ "play": "Play", "statistics": "Statistics", @@ -25,27 +29,26 @@ }, "Games": { - "wise_men": { + "Wise Men Stack": { "name": "Wise Men Stack", "desc": "The player chooses a topic from five available options and must answer a battery of questions related to it within 60 seconds. For each question, the host provides two options. If the contestant guesses correctly, they win €20; otherwise, they move on to the next question (as the correct answer would be the other option). If the time runs out before the question is fully asked and both possible answers are provided, the contestant may still answer it; however, if the statement hasn't been completed (or the options weren't provided), they cannot answer." }, - "warm_quest": { + "Warm Question": { "name": "Warm Question", "desc": "It consists of ten topics of varied themes. For each correct answer, €100 is earned, and €10 are lost if the contestant passes, does not respond, or answers incorrectly." }, - "discover": { + "Discovering Cities": { "name": "Discovering Cities", - "desc": "In the 'Discovering Cities' game mode, the contestant will face a challenge where they will be repeatedly asked questions referring to different cities around the world. To successfully overcome the challenge, the contestant must answer as many questions as possible correctly throughout the test.." + "desc": "In the 'Discovering Cities' game mode, the contestant will face a challenge where they will be repeatedly asked questions referring to different cities around the world. To successfully overcome the challenge, the contestant must answer as many questions as possible correctly throughout the test." }, - "challenge": { + "Challenge": { "name": "Challenge", "desc": "The 'Challenge' game mode is the quintessential game mode, as it allows you to customize the match to your liking. This game mode is tailored for those who wish to practice certain game formats before engaging in our various other game modes." }, - "multiplayer": { + "Multiplayer": { "name": "Multiplayer", "desc": "Create a room for other player to join and play 1vs1" } - }, "Game": { @@ -109,6 +112,7 @@ "Statistics": { "title": "STATISTICS", + "game": "Game", "table": { "money": "Total Points", "questions_corr": "Correctly Answered Questions", @@ -118,6 +122,10 @@ "total_time": "Total Time Played", "cities_corr": "Correctly Answered Cities", "cities_incorr": "Incorrectly Answered Cities" + }, + "button": { + "hide_record": "Hide Questions Record", + "show_record": "Show Questions Record" } }, @@ -160,7 +168,7 @@ "users":"Users", "groups": "Groups", - "total_money": "MONEY", + "total_money": "POINTS", "correct_answers": "CORRECT ANSWERS", "incorrect_answers": "INCORRECT ANSWERS", "total_games": "GAMES PLAYED" diff --git a/webapp/src/localize/es.json b/webapp/src/localize/es.json index e437e9cb..5b51732b 100644 --- a/webapp/src/localize/es.json +++ b/webapp/src/localize/es.json @@ -6,6 +6,10 @@ "q": "QUESTIONARIO" }, + "Homepage": { + "title": "MODOS DE JUEGO" + }, + "NavBar":{ "play": "Jugar", "statistics": "Estadísticas", @@ -25,24 +29,24 @@ }, "Games": { - "wise_men": { - "name": "Hombres Sabiondos", + "Wise Men Stack": { + "name": "Wise Men Stack", "desc": "El jugador elige un tema entre cinco opciones disponibles y debe responder una batería de preguntas relacionadas con él en un plazo de 60 segundos. Para cada pregunta, el presentador proporciona dos opciones. Si el concursante acierta, gana €20; de lo contrario, pasa a la siguiente pregunta (ya que la respuesta correcta sería la otra opción). Si el tiempo se agota antes de que se formule por completo la pregunta y se proporcionen ambas posibles respuestas, el concursante aún puede responderla; sin embargo, si la afirmación no se ha completado (o las opciones no se proporcionaron), no pueden responder." }, - "warm_quest": { - "name": "Pregunta Calentorra", + "Warm Question": { + "name": "Warm Question", "desc": "Consta de diez temas de diferentes temáticas. Por cada respuesta correcta, se ganan €100, y se pierden €10 si el concursante pasa, no responde o responde incorrectamente." }, - "discover": { - "name": "Descubriendo Ciudades", + "Discovering Cities": { + "name": "Discovering Cities", "desc": "En el modo de juego 'Descubriendo Ciudades', el concursante enfrentará un desafío donde se le harán preguntas repetidas referentes a diferentes ciudades de todo el mundo. Para superar con éxito el desafío, el concursante debe responder tantas preguntas como sea posible correctamente a lo largo de la prueba." }, - "challenge": { - "name": "Desafío", + "Challenge": { + "name": "Challenge", "desc": "El modo de juego 'Desafío' es el modo de juego por excelencia, ya que te permite personalizar el enfrentamiento a tu gusto. Este modo de juego está diseñado para aquellos que deseen practicar ciertos formatos de juego antes de participar en nuestros diversos otros modos de juego." }, - "multiplayer": { - "name": "Multijugador", + "Multiplayer": { + "name": "Multiplayer", "desc": "Crea una sala para que otros jugadores se unan y jueguen 1 contra 1." } }, @@ -108,6 +112,7 @@ "Statistics": { "title": "ESTADÍSTICAS", + "game": "Partida", "table": { "money": "Puntos Ganado", "questions_corr": "Preguntas Respondidas Correctamente", @@ -117,6 +122,10 @@ "total_time": "Tiempo Total Jugado", "cities_corr": "Ciudades Respondidas Correctamente", "cities_incorr": "Ciudades Respondidas Incorrectamente" + }, + "button": { + "hide_record": "Ocultar registro de preguntas", + "show_record": "Mostrar registro de preguntas" } }, @@ -160,7 +169,7 @@ "users":"Usuarios", "groups": "Grupos", "name":"NOMBRE", - "total_money": "DINERO", + "total_money": "PUNTOS", "correct_answers": "RESPUESTAS CORRECTAS", "incorrect_answers": "RESPUESTAS INCORRECTAS", "total_games": "PARTIDAS JUGADAS" diff --git a/webapp/src/localize/fr.json b/webapp/src/localize/fr.json index 5368553f..6ae2d1e5 100644 --- a/webapp/src/localize/fr.json +++ b/webapp/src/localize/fr.json @@ -6,6 +6,10 @@ "q": "QUEST" }, + "Homepage": { + "title": "MODES DE JEU" + }, + "NavBar":{ "play": "Jouer", "statistics": "Statistiques", @@ -25,24 +29,24 @@ }, "Games": { - "wise_men": { - "name": "Pile de Sages", + "Wise Men Stack": { + "name": "Wise Men Stack", "desc": "Le joueur choisit un sujet parmi cinq options disponibles et doit répondre à une batterie de questions qui y sont liées dans un délai de 60 secondes. Pour chaque question, l'hôte fournit deux options. Si le participant devine correctement, il gagne 20 € ; sinon, il passe à la question suivante (car la bonne réponse serait l'autre option). Si le temps s'écoule avant que la question ne soit entièrement posée et que les deux réponses possibles soient fournies, le participant peut toujours y répondre ; cependant, si l'énoncé n'a pas été complété (ou si les options n'ont pas été fournies), il ne peut pas répondre." }, - "warm_quest": { - "name": "Question Chaleureuse", + "Warm Question": { + "name": "Warm Question", "desc": "Il se compose de dix sujets de thèmes variés. Pour chaque réponse correcte, 100 € sont gagnés, et 10 € sont perdus si le participant passe, ne répond pas ou répond incorrectement." }, - "discover": { - "name": "Découverte des Villes", + "Discovering Cities": { + "name": "Discovering Cities", "desc": "Dans le mode de jeu 'Découverte des Villes', le participant sera confronté à un défi où il lui sera posé à plusieurs reprises des questions se référant à différentes villes du monde entier. Pour surmonter avec succès le défi, le participant doit répondre correctement à autant de questions que possible tout au long du test." }, - "challenge": { - "name": "Défi", + "Challenge": { + "name": "Challenge", "desc": "Le mode de jeu 'Défi' est le mode de jeu par excellence, car il vous permet de personnaliser le match à votre guise. Ce mode de jeu est adapté à ceux qui souhaitent s'entraîner à certains formats de jeu avant de s'engager dans nos divers autres modes de jeu." }, - "multiplayer": { - "name": "Multijoueur", + "Multiplayer": { + "name": "Multiplayer", "desc": "Créez une salle pour que d'autres joueurs se joignent et jouent en 1 contre 1." } @@ -110,6 +114,7 @@ "Statistics": { "title": "STATISTIQUES", + "game": "Partie", "table": { "money": "Points gagnés", "questions_corr": "Questions Correctement Répondues", @@ -119,6 +124,10 @@ "total_time": "Temps Total Joué", "cities_corr": "Villes Répondus Correctement", "cities_incorr": "Villes Répondus Incorrectement" + }, + "button": { + "hide_record": "Masquer l'historique des questions", + "show_record": "Afficher l'historique des questions" } }, @@ -157,7 +166,7 @@ "Ranking": { "users": "Utilisateurs", "groups": "Groupes", - "total_money": "MONEY", + "total_money": "POINTS", "correct_answers": "CORRECT ANSWERS", "incorrect_answers": "INCORRECT ANSWERS", "total_games": "GAMES PLAYED" diff --git a/webapp/src/pages/GroupDetails.js b/webapp/src/pages/GroupDetails.js index 1337ac25..621fa121 100644 --- a/webapp/src/pages/GroupDetails.js +++ b/webapp/src/pages/GroupDetails.js @@ -50,21 +50,19 @@ const GroupDetails = () => { // Returns all group data including the creator, the creation date and the members list return ( - - {groupInfo.name} + + {groupInfo.name} - { `${t("Groups.Details.creator")}: ${groupInfo.creator}` } + {t("Groups.Details.creator")}: {groupInfo.creator} - { `${t("Groups.Details.date")}: ${new Date(groupInfo.createdAt).toLocaleDateString()}` } + {t("Groups.Details.date")}: {new Date(groupInfo.createdAt).toLocaleDateString()} - { - `${ t("Groups.Details.members") } (${totalMembers}/${expectedMembers}):` - } + {t("Groups.Details.members")}: {totalMembers}/{expectedMembers} diff --git a/webapp/src/pages/Groups.js b/webapp/src/pages/Groups.js index 3ab716ee..e30383fd 100644 --- a/webapp/src/pages/Groups.js +++ b/webapp/src/pages/Groups.js @@ -97,7 +97,7 @@ const Groups = () => { return ( - + { t("Groups.title") } diff --git a/webapp/src/pages/Home.js b/webapp/src/pages/Home.js index 381a6c74..fcfa9336 100644 --- a/webapp/src/pages/Home.js +++ b/webapp/src/pages/Home.js @@ -1,10 +1,11 @@ import * as React from "react"; import {Box, Button} from "@mui/material"; import useMediaQuery from '@mui/material/useMediaQuery'; - +import { useTranslation } from 'react-i18next'; const Home = () => { const xxl = useMediaQuery('(min-width:1920px)'); + const { t } = useTranslation(); const styles = { logo:{ @@ -96,7 +97,7 @@ const Home = () => { Logo - +