diff --git a/webapp/e2e/features/addUser.feature b/webapp/e2e/features/addUser.feature new file mode 100644 index 00000000..df43f29c --- /dev/null +++ b/webapp/e2e/features/addUser.feature @@ -0,0 +1,6 @@ +Feature: Register page functionality + + Scenario: Register + Given I register a user + Then I am in /menu + diff --git a/webapp/e2e/features/competitiveGame.feature b/webapp/e2e/features/competitiveGame.feature new file mode 100644 index 00000000..30620078 --- /dev/null +++ b/webapp/e2e/features/competitiveGame.feature @@ -0,0 +1,9 @@ +Feature: Game Configurator and Competitive Game functionality + Scenario: Create Competitive Game should go to /questions + Given I am on the game configurator + When I click on new competitive game + Then I am in /questions + Scenario: Create Customized Game should go to /questions + Given I am on the game configurator + When I click on new customized game + Then I am in /questions \ No newline at end of file diff --git a/webapp/e2e/features/home.feature b/webapp/e2e/features/home.feature index dfc7601a..660bcb41 100644 --- a/webapp/e2e/features/home.feature +++ b/webapp/e2e/features/home.feature @@ -12,5 +12,4 @@ Feature: Home page functionality Scenario: Closing the text container Given I am on the home page When I click on the toggle button to open and then I click it to close - Then The text container should be visible - + Then The text container should be visible \ No newline at end of file diff --git a/webapp/e2e/features/instructions.feature b/webapp/e2e/features/instructions.feature new file mode 100644 index 00000000..f59fda00 --- /dev/null +++ b/webapp/e2e/features/instructions.feature @@ -0,0 +1,9 @@ +Feature: Instructions page functionality + + Scenario: Instructions view is well rendered + Given I am on the instructions page + Then The instructions title is rendered + Then The instructions content is rendered + + + diff --git a/webapp/e2e/features/login.feature b/webapp/e2e/features/login.feature new file mode 100644 index 00000000..77a23db2 --- /dev/null +++ b/webapp/e2e/features/login.feature @@ -0,0 +1,10 @@ +Feature: Login page functionality + + Scenario: Login + Given I login a user + Then I am in /menu + Scenario: Failed login + Given I am on the login page + When I try to login + Then I am in /login + diff --git a/webapp/e2e/features/navBar.feature b/webapp/e2e/features/navBar.feature new file mode 100644 index 00000000..87c66b97 --- /dev/null +++ b/webapp/e2e/features/navBar.feature @@ -0,0 +1,13 @@ +Feature: NavBar functionality + + Scenario: Displaying navbar elements correctly + Given I am on the home page + Then The navbar elements are visible + + Scenario: Changing language + Given I am on the home page + When I click on the language button + Then The language options menu should be visible + Then I choose Spanish + Then The navbar should be in Spanish + diff --git a/webapp/e2e/steps/addUser.steps.js b/webapp/e2e/steps/addUser.steps.js new file mode 100644 index 00000000..2fbb720e --- /dev/null +++ b/webapp/e2e/steps/addUser.steps.js @@ -0,0 +1,44 @@ +const puppeteer = require('puppeteer'); +const { defineFeature, loadFeature } = require('jest-cucumber'); +const setDefaultOptions = require('expect-puppeteer').setDefaultOptions; + +const feature = loadFeature('./features/addUser.feature'); + +const { register, login, logout } = require("../utils"); + +let page; +let browser; + +const email = "testUserAddUser@example.com"; +const username = "testUserAddUser" +const password = "testUserPassword" + +defineFeature(feature, test => { + + beforeAll(async () => { + browser = await puppeteer.launch({ + headless: "new", + slowMo: 40, + defaultViewport: { width: 1920, height: 1080 }, + args: ['--window-size=1920,1080'] + }); + + page = await browser.newPage(); + setDefaultOptions({ timeout: 30000 }); + + }, 60000); + + + test('Register', ({ given,when, then }) => { + given('I register a user', async () => { + await register(page, email, username, password); + }); + + then('I am in /menu', async () => { + await expect(page).toMatchElement('.divMenu'); + }); + }, 60000); + + + +}); \ No newline at end of file diff --git a/webapp/e2e/steps/competitiveGame.steps.js b/webapp/e2e/steps/competitiveGame.steps.js new file mode 100644 index 00000000..ab5ad9e2 --- /dev/null +++ b/webapp/e2e/steps/competitiveGame.steps.js @@ -0,0 +1,63 @@ +const puppeteer = require('puppeteer'); +const { defineFeature, loadFeature } = require('jest-cucumber'); +const setDefaultOptions = require('expect-puppeteer').setDefaultOptions; + +const feature = loadFeature('./features/competitiveGame.feature'); + +const { register, login, logout } = require("../utils"); + +let page; +let browser; + +const email = "testUserCompetitiveGame@example.com"; +const username = "testUserCompetitiveGame" +const password = "testUserPassword" + +defineFeature(feature, test => { + + beforeAll(async () => { + browser = await puppeteer.launch({ + headless: "new", + slowMo: 40, + defaultViewport: { width: 1920, height: 1080 }, + args: ['--window-size=1920,1080'] + }); + + page = await browser.newPage(); + setDefaultOptions({ timeout: 30000 }); + + await register(page, email, username, password); + }); + + beforeEach(async () => { + await logout(page); + await login(page, username, password); + }) + + test('Create Competitive Game should go to /questions', ({ given,when, then }) => { + given('I am on the game configurator', async () => { + await page.goto('http://localhost:3000/configurator'); + await page.waitForSelector('.GameConfiguratorDiv'); + }); + when('I click on new competitive game', async () => { + await page.click('#competitive'); + }); + then('I am in /questions', async () => { + await expect(page).toMatchElement('.questionContainer'); + }); + }); + + test('Create Customized Game should go to /questions', ({ given,when, then }) => { + given('I am on the game configurator', async () => { + await page.goto('http://localhost:3000/configurator'); + await page.waitForSelector('.GameConfiguratorDiv'); + }); + when('I click on new customized game', async () => { + await page.click('.linkButton'); + }); + then('I am in /questions', async () => { + await expect(page).toMatchElement('.questionContainer'); + }); + }); + +}); \ No newline at end of file diff --git a/webapp/e2e/steps/home.steps.js b/webapp/e2e/steps/home.steps.js index 3bae6848..a0f5b484 100644 --- a/webapp/e2e/steps/home.steps.js +++ b/webapp/e2e/steps/home.steps.js @@ -20,17 +20,17 @@ defineFeature(feature, test => { page = await browser.newPage(); setDefaultOptions({ timeout: 10000 }); }); + + test('The text container is initially visible', ({ given, then }) => { + given('I am on the home page', async () => { + await page.goto('http://localhost:3000/home'); + await page.waitForSelector('.general'); + }); - test('The text container is initially visible', ({ given, then }) => { - given('I am on the home page', async () => { - await page.goto('http://localhost:3000/home'); - await page.waitForSelector('.general'); - }); - - then('The text container should be visible', async () => { - await expect(page).toMatchElement('.text-container.visible'); - }); - }); + then('The text container should be visible', async () => { + await expect(page).toMatchElement('.text-container.visible'); + }); + }); test('Opening the text container', ({ given, when, then }) => { given('I am on the home page', async () => { @@ -47,26 +47,25 @@ defineFeature(feature, test => { }); }); - test('Closing the text container', ({ given, when, then }) => { - given('I am on the home page', async () => { - await page.goto('http://localhost:3000/home'); - await page.waitForSelector('.general'); - }); - - when('I click on the toggle button to open and then I click it to close', async () => { + test('Closing the text container', ({ given, when, then }) => { + given('I am on the home page', async () => { + await page.goto('http://localhost:3000/home'); + await page.waitForSelector('.general'); + }); + when('I click on the toggle button to open and then I click it to close', async () => { - await page.click('label[for="toggleOpen"]'); + await page.click('label[for="toggleOpen"]'); // Wait for label to be render, visible : true - await page.waitForSelector(`label[for="toggleClose"]`, {visible: true}); - await page.click('label[for="toggleClose"]'); + await page.waitForSelector(`label[for="toggleClose"]`, {visible: true}); + await page.click('label[for="toggleClose"]'); - }); + }); - then('The text container should be visible', async () => { - await expect(page).toMatchElement('.text-container.visible'); - }); - }); + then('The text container should be visible', async () => { + await expect(page).toMatchElement('.text-container.visible'); + }); + }); afterAll(async () => { await browser.close(); diff --git a/webapp/e2e/steps/instructions.steps.js b/webapp/e2e/steps/instructions.steps.js new file mode 100644 index 00000000..1b7382aa --- /dev/null +++ b/webapp/e2e/steps/instructions.steps.js @@ -0,0 +1,42 @@ +const puppeteer = require('puppeteer'); +const { defineFeature, loadFeature } = require('jest-cucumber'); +const setDefaultOptions = require('expect-puppeteer').setDefaultOptions; + +const feature = loadFeature('./features/instructions.feature'); + +let page; +let browser; + +defineFeature(feature, test => { + + beforeAll(async () => { + browser = await puppeteer.launch({ + headless: "new", + slowMo: 20, + defaultViewport: { width: 1920, height: 1080 }, + args: ['--window-size=1920,1080'] + }); + + page = await browser.newPage(); + setDefaultOptions({ timeout: 10000 }); + }); + + test('Instructions view is well rendered', ({ given, then }) => { + given('I am on the instructions page', async () => { + await page.goto('http://localhost:3000/instructions'); + await page.waitForSelector('.instructions_title'); + }); + + then('The instructions title is rendered', async () => { + await expect(page).toMatchElement('.instructions_title'); + }); + + then('The instructions content is rendered', async () => { + await expect(page).toMatchElement('.ins_ul'); + }); + }); + + afterAll(async () => { + await browser.close(); + }); +}); diff --git a/webapp/e2e/steps/login.steps.js b/webapp/e2e/steps/login.steps.js new file mode 100644 index 00000000..0a0f07a0 --- /dev/null +++ b/webapp/e2e/steps/login.steps.js @@ -0,0 +1,63 @@ +const puppeteer = require('puppeteer'); +const { defineFeature, loadFeature } = require('jest-cucumber'); +const setDefaultOptions = require('expect-puppeteer').setDefaultOptions; + +const feature = loadFeature('./features/login.feature'); + +const { register, login, logout } = require("../utils"); + +let page; +let browser; + +const email = "testUserLogin@example.com"; +const username = "testUserLogin" +const password = "testUserPassword" + +defineFeature(feature, test => { + +beforeAll(async () => { + browser = await puppeteer.launch({ + headless: "new", + slowMo: 20, + defaultViewport: { width: 1920, height: 1080 }, + args: ['--window-size=1920,1080'] +}); + +page = await browser.newPage(); +setDefaultOptions({ timeout: 10000 }); +await register(page, email, username, password); +await logout(page); +},60000); + + + test('Login', ({ given, then }) => { + given('I login a user', async () => { + await login(page, username, password); + + }); + then('I am in /menu', async () => { + await expect(page).toMatchElement('.divMenu'); + await logout(page); + }); + }, 60000); + + test('Failed login', ({ given,when, then }) => { + given('I am on the login page', async () => { + await page.goto('http://localhost:3000/login'); + }); + when('I try to login', async () => { + await page.goto('http://localhost:3000/login'); + await page.waitForSelector('.general'); + + await page.type('input[type="text"]', 'lau'); + await page.type('input[type="password"]', '123'); + await page.click('button[type="submit"]'); + }); + then('I am in /login', async () => { + await expect(page).toMatchElement('.title-login'); + }, 60000); + }); + + + +}); \ No newline at end of file diff --git a/webapp/e2e/steps/navBar.steps.js b/webapp/e2e/steps/navBar.steps.js new file mode 100644 index 00000000..09cd50ff --- /dev/null +++ b/webapp/e2e/steps/navBar.steps.js @@ -0,0 +1,64 @@ +const puppeteer = require('puppeteer'); +const { defineFeature, loadFeature } = require('jest-cucumber'); +const setDefaultOptions = require('expect-puppeteer').setDefaultOptions; + +const feature = loadFeature('./features/navBar.feature'); + +let page; +let browser; + +defineFeature(feature, test => { + + beforeAll(async () => { + browser = await puppeteer.launch({ + headless: "new", + slowMo: 20, + defaultViewport: { width: 1920, height: 1080 }, + args: ['--window-size=1920,1080'] + }); + + page = await browser.newPage(); + setDefaultOptions({ timeout: 10000 }); +}); + + test('Displaying navbar elements correctly', ({ given, then }) => { + given('I am on the home page', async () => { + await page.goto('http://localhost:3000/'); + await page.waitForSelector('.navbar-container'); + }); + + then('The navbar elements are visible', async () => { + await expect(page).toMatchElement('.navbar-text', { text: 'Know and win!' }); + await expect(page).toMatchElement('.language-button', { text: 'Language' }); + await expect(page).toMatchElement('.help-button'); + }); + }); + + test('Changing language', ({ given, when, then }) => { + given('I am on the home page', async () => { + await page.goto('http://localhost:3000/'); + await page.waitForSelector('.navbar-container'); + }); + + when('I click on the language button', async () => { + await page.click('.language-button'); + }); + + then('The language options menu should be visible', async () => { + await page.waitForSelector('.MuiMenu-paper', { visible: true }); + }); + + then('I choose Spanish', async () => { + await page.click('text=Spanish'); + }); + + then('The navbar should be in Spanish', async () => { + const navbarText = await page.$eval('.navbar-text', el => el.textContent.trim()); + expect(navbarText).toBe('¡Saber y ganar!'); + }); + }); + + afterAll(async () => { + await browser.close(); + }); +}); diff --git a/webapp/e2e/steps/register-form.steps.txt b/webapp/e2e/steps/register-form.steps.txt deleted file mode 100644 index 0c329391..00000000 --- a/webapp/e2e/steps/register-form.steps.txt +++ /dev/null @@ -1,55 +0,0 @@ -WAIT UNTIL REGISTER IS FINALIZED (Add email) - -const puppeteer = require('puppeteer'); -const { defineFeature, loadFeature }=require('jest-cucumber'); -const setDefaultOptions = require('expect-puppeteer').setDefaultOptions -const feature = loadFeature('./features/register-form.feature'); - -let page; -let browser; - -defineFeature(feature, test => { - - beforeAll(async () => { - browser = process.env.GITHUB_ACTIONS - ? await puppeteer.launch() - : await puppeteer.launch({ headless: false, slowMo: 100 }); - page = await browser.newPage(); - //Way of setting up the timeout - setDefaultOptions({ timeout: 10000 }) - - await page - .goto("http://localhost:3000/login", { - waitUntil: "networkidle0", - }) - .catch(() => {}); - }); - - test('The user is not registered in the site', ({given,when,then}) => { - - let username; - let password; - - given('An unregistered user', async () => { - username = "pablo" - password = "pabloasw" - await expect(page).toClick("a", { text: "Don't have an account? Register here." }); - }); - - when('I fill the data in the form and press submit', async () => { - await expect(page).toFill('input[name="username"]', username); - await expect(page).toFill('input[name="password"]', password); - await expect(page).toFill('input[name="repeat_password"]', password); - await expect(page).toClick('button', { text: 'Add User' }) - }); - - then('A confirmation message should be shown in the screen', async () => { - await expect(page).toMatchElement("div", { text: "User added successfully" }); - }); - }) - - afterAll(async ()=>{ - browser.close() - }) - -}); \ No newline at end of file diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 2a9213a2..e71a4dd5 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -11693,6 +11693,19 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", diff --git a/webapp/webapp/package-lock.json b/webapp/webapp/package-lock.json new file mode 100644 index 00000000..b73ba1cc --- /dev/null +++ b/webapp/webapp/package-lock.json @@ -0,0 +1,56 @@ +{ + "name": "webapp", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "webapp": "file:.." + } + }, + "..": { + "version": "0.1.0", + "dependencies": { + "@emotion/react": "^11.11.3", + "@emotion/styled": "^11.11.0", + "@mui/material": "^5.15.3", + "@testing-library/jest-dom": "^5.17.0", + "@testing-library/react": "^14.1.2", + "@testing-library/user-event": "^14.5.2", + "axios": "^1.6.5", + "bcrypt": "^5.1.1", + "express": "^4.19.2", + "i18n": "^0.15.1", + "jquery": "^3.7.1", + "js-cookie": "^3.0.5", + "jsonwebtoken": "^9.0.2", + "mongoose": "^8.3.0", + "react": "^18.2.0", + "react-countdown": "^2.3.5", + "react-dom": "^18.2.0", + "react-i18next": "^14.0.5", + "react-icons": "^5.0.1", + "react-router-dom": "^6.22.3", + "react-scripts": "^5.0.1", + "web-vitals": "^3.5.1", + "zxcvbn": "^4.4.2" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "axios-mock-adapter": "^1.22.0", + "expect-puppeteer": "^9.0.2", + "jest": "^29.3.1", + "jest-cucumber": "^3.0.1", + "jest-environment-node": "^29.7.0", + "mongodb-memory-server": "^9.1.4", + "puppeteer": "^21.7.0", + "serve": "^14.2.1", + "start-server-and-test": "^2.0.3" + } + }, + "node_modules/webapp": { + "resolved": "..", + "link": true + } + } +} diff --git a/webapp/webapp/package.json b/webapp/webapp/package.json new file mode 100644 index 00000000..96fd912b --- /dev/null +++ b/webapp/webapp/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "webapp": "file:.." + } +}