diff --git a/docs/index.adoc b/docs/index.adoc
index 2905e55c..c2adcc83 100644
--- a/docs/index.adoc
+++ b/docs/index.adoc
@@ -78,9 +78,13 @@ include::src/10_quality_requirements.adoc[]
include::src/11_technical_risks.adoc[]
<<<<
-// 12. Glossary
-include::src/12_glossary.adoc[]
+// 12. Testing
+include::src/12_test.adoc[]
+
+<<<<
+// 13. Glossary
+include::src/13_glossary.adoc[]
<<<<
// 13. Annex
-include::src/13_annex.adoc[]
+include::src/14_annex.adoc[]
diff --git a/docs/src/09_architecture_decisions.adoc b/docs/src/09_architecture_decisions.adoc
index 3daf3d02..83314426 100644
--- a/docs/src/09_architecture_decisions.adoc
+++ b/docs/src/09_architecture_decisions.adoc
@@ -6,33 +6,109 @@ ifndef::imagesdir[:imagesdir: ../images]
During the application development process, decisions had to be made as issues emerged. The most interesting design decisions are reflected in this architectural records:
-[options="header",cols="1,4"]
-|===
-|Decision|Explanation
-|React
-|Offers a powerful combination of performance, flexibility, and developer experience, making it a popular choice for building modern web applications. One of the members of the group has already worked with it in the past. It allows us to build a good user interface for the application.
+=== Main webapp technology
+*Date Recorded:* 01/02/2024
-|SpringBoot
-|This choice is based on the extensive experience accumulated by our team in developing with Java, as well as the familiarity and comfort offered by the tools and practices associated with the Spring Boot ecosystem.
+*Scope:* frontend, webapp
-|PostgreSQL
-|We have chosen to use the PostgreSQL database instead of MongoDB due to the relational nature of PostgreSQL, which offers a robust and coherent structure for storing and relating data. We made this decision to ensure data integrity, perform complex queries, and maintain consistency in our storage operations.
+*Description:*
+Offers a powerful combination of performance, flexibility, and developer experience, making it a popular choice for building modern web applications. One of the members of the group has already worked with it in the past. It allows us to build a good user interface for the application.
-|React Libraries
-|To enhance the efficiency and effectiveness of our development process, we've taken proactive steps to incorporate specific libraries into our project. These carefully chosen libraries, meticulously outlined in detail within issue #16.
+*Decision taken:*
+The frontend team has agreed to use *React* or a React framework, as all members agree they are not up to the task of maintaining a personalised stylesheet.
-|HTTPS
-|To improve security we have decided to make HTTPS as one main requirements in out project as can be seen in issue #51.
+=== React technology to be used
+*Date Recorded:* 01/02/2024
-|Architecture of the Question Generator
-|It has been decided to implement the QG in an independent module so it is only run once and it is not generating questions at real time, this way, we are not dependent on wikidata for having our application available.
+*Scope:* frontend, webapp
+
+*Description:*
+The frontend team has been discussing whether to use React or a React framework like Next.js as it is the currently recommended option.
+
+*Decision taken:*
+The frontend team has agreed to use a *pure React-based approach* due to most members not having any kind of prior experience with React and those that do have it are do not feel confident enough in their skills.
+
+=== Main backend technology
+
+*Date Recorded:* 01/02/2024
+
+*Scope:* backend, API
+
+*Description:*
+The backend team wants to deprecate the given Node.js microservices system in favour of a monolithic Springboot-based approach. This is mainly due to only one member having prior experience in Node.js development. No members support keeping the current approach, and when asked if SpringBoot would allow a possible microservices constraint, a member of the backend team has stated that a proper-developed SpringBoot application should be easy to divide between different microservices.
+
+*Decision taken:*
+The backend team has agreed to use *SpringBoot* and *JPA* for the backend.
+
+=== Replacing MongoDB with a relational DBMS
+
+*Date Recorded:* 01/02/2024
+
+*Scope:* database
+
+*Description:*
+A member of the backend has proposed the replacement of MongoDB as DBMS, with PostgreSQL replacing it. A member of the frontend team has supported it, remarking modern DBMS have built-in JSON support if needed. Other members of the backend team have stated their agreement, as many of them do not have prior experience with MongoDB and prefer relational databases.
+
+*Decision taken:*
+The team has agreed to drop MongoDB and to use *PostgreSQL*.
+
+=== Libraries for React
+*Date Recorded:* 09/02/2024
+
+*Scope:* frontend, webapp
+
+*Description:*
+To enhance the efficiency and effectiveness of our development process, we've taken proactive steps to incorporate specific libraries into our project. These carefully chosen libraries, meticulously outlined in detail within issue #16.
+
+*Decision taken:*
+The team has agreed to use Chakra UI as the main library for the frontend.
+
+
+=== HTTP/2 and HTTPS
+*Date Recorded:* 23/02/2024
+
+*Scope:* security
+
+*Description:*
+To improve security we have decided to make HTTP/2 and HTTPS one of the main requirements in our project as can be seen in issue #51.
+
+*Decision taken:*
+The team has agreed to use *HTTP/2* and *HTTPS*.
+
+=== Architecture of the question generator process
+*Date Recorded:* 03/03/2024
+
+*Scope:* backend, question generator
+
+*Description:*
+The question generator must be a part of our application, but different to the webapp or the API, it doesnt need to be running on a loop. It just needs to be run once everytime we want to load or update questions. Implementing it in the API module would result on more coupling but not duplicating code for the model. On the other hand, implementing it in a new module would make the application cleaner and easier to change.
+
+*Decision taken:*
+The team has decided to implement the question generator as a *separate module* of our application.
+
+=== Connect to the database with the question generator
+*Date Recorded:* 10/03/2024
+
+*Scope:* backend, question generator, database
+
+*Description:*
+The backend team has been discussing whether to use JPA or JDBC to connect to the database with the question generator. When researching JPA it was found that although it is easier to use since the models already exist in our API, the models cannot be used from a different package, which makes us duplicate code as we do not have time to research another way of implementing it. On the other hand, JDBC would be more complex to use and does not have the same level of flexibility as JPA.
+
+
+*Decision taken:*
+The team has agreed to use *JPA* to connect to the database with the question generator. Although this will generate duplication of code in the models, it should be manageable due to the small size of the project. This will be recorded as technical debt and new approach should be looked into if the project grows in size.
+
+=== Workflow of the game logic
+*Date Recorded:* 19/03/2024
+
+*Scope:* backend, game logic
+
+*Description:*
+The game logic must be implemented in the backend, since implementing it in the frontend would make it very dependent on performance and prone to allowing cheating and exploits. The questions will be served to the frontend each round but then validated in the backend, to prevent cheating. Points will also be automatically calculated in the backend.
+
+*Decision taken:*
+The team has agreed to implement the game logic in the backend to make it more robust and prevent cheating.
-|Template method pattern
-|We chose to apply our software design knowledge and generate the questions following a template method in Java. This allows us to create new questions easily and without duplicating too much code.
-|Use of JPA in the Question Generator
-|We used JPA in favor of JDBC as when tables are related in a DB, JPA makes it easier to write into the DB.
-|===
-If needed, more details are given in the link:https://github.com/Arquisoft/wiq_en2b/wiki[wiki].
diff --git a/docs/src/10_quality_requirements.adoc b/docs/src/10_quality_requirements.adoc
index b9cb0680..8330d1c4 100644
--- a/docs/src/10_quality_requirements.adoc
+++ b/docs/src/10_quality_requirements.adoc
@@ -20,11 +20,9 @@ To obtain a measurable system response to stimulus corresponding to the various
| Reliability | The system shall reliably generate accurate and diverse questions from Wikidata. User registrations, logins, and game data storage shall be handled without errors. | High, Medium
| Availability | The system shall be available 99% of the time when a user attempts to access it. | High, High
| Performance efficiency | The system shall deliver optimal performance, ensuring responsive interactions for users. It shall efficiently generate questions from Wikidata and handle real-time gameplay with up to 1000 concurrent users. | High, High
-| Usability | The system shall provide a user-friendly interface, allowing users to register, log in, and play the game with a learning time of less than 4 hours. | High, Medium
+| Usability | The system shall provide a user-friendly interface, allowing users to register, log in, and play the game with a learning time of less than 15 minutes. Other functionalities that are not that obvious, such us rules or about pages, are allowed for 2 hours. | High, Medium
| Security | User data shall be securely handled. Robust authentication mechanisms shall be in place for user registration and login. API access points for user information and generated questions shall be secured with proper authorization. | Medium, High
| Compatibility | The system shall be compatible with various web browsers and devices, providing a seamless experience for users regardless of their choice of platform. It shall be well-optimized for different screen sizes and functionalities. | High, Medium
-| Testability | The unit tests shall have at least 80% coverage. | High, Medium
-| Monitoring | The system shall have monitoring in place to track the performance and availability of the system. | High, Medium
|===
==== Change Scenarios
[options="header",cols="1,3,1"]
@@ -32,41 +30,32 @@ To obtain a measurable system response to stimulus corresponding to the various
|Quality attribute|Scenario|Priority
| Modifiability | The system shall be designed and implemented in a way that allows for easy maintenance and updates. | High, Medium
| Maintainability | The code of the system shall be well-documented, and modular, allowing for efficient troubleshooting and modifications. | High, Medium
+| Testability | The unit tests shall have at least 80% coverage. | High, Medium
+| Monitoring | The system shall have monitoring in place to track the performance and availability of the system. | High, Medium
|===
==== Implementation
+===== Security
+The system is secured using Spring Security. The user data is stored in a database and the passwords are hashed using BCrypt. The API access points are secured with proper authorization. HTTPS is used to encrypt the data in transit.
-===== Performance efficiency
-The tests were done with a 2 core and 4 GB of memory system.
-This system's efficiency has been measured with Gatling. For the script that we used, a user already created, logged in and played a full game. After that, the user clicked to look the statistics.
-The scripts were run a total of 4 times. One with 1 user, other with 100 users, another one with 1000 users and finally one with 10000 users.
-The results of this scripts show that response times are reasonable up until 1000 users. Having 10000 users playing a game at the same time make a lot of failures.
-Here are the results.
-
-**1 user:**
-
-image::Gatling_1_user.png[align="center", title="Gatling results with 1 user"]
-
-**100 users:**
-
-image::Gatling_100_users.png[align="center", title="Gatling results with 100 user"]
+The system is also protected against SQL injection via using JPA repositories and prepared statements.
-**1000 users:**
+The system is also designed in such a way that prevents cheating, by limiting the options available for the user and doing all validation in the backend, such as checking if the answer is correct, preventing request forgery.
-image::Gatling_1000_users.png[align="center", title="Gatling results with 1000 user"]
+===== Testability
+Many different tests were done to this project as they were considered as a critical requirement for the development.
-**10000 users:**
+* **Unit tests:** The strongest constraint, as an 80% code coverage is mandatory to ensure code works properly.
-image::Gatling_10000_users.png[align="center", title="Gatling results with 10000 user"]
+* **Load tests:** They show how the system will behave under expected workloads.
-===== Security
-The system is secured using Spring Security. The user data is stored in a database and the passwords are hashed using BCrypt. The API access points are secured with proper authorization. HTTPS is used to encrypt the data in transit.
+* **Stress tests:** This way we can the behaviour of the system under unexpected loads, such as DDoS attacks. Although we are not protected against them yet, we could do it by using CloudFare as discussed issue #266.
-The system is also protected against SQL injection via using JPA repositories and prepared statements.
+* **Acceptance (e2e) tests:** The idea behind them is to ensure the correct functionality of the whole system so real user interactions will work as expected.
-The system is also designed in such a way that prevents cheating, by limiting the options available for the user and doing all validation in the backend, such as checking if the answer is correct, preventing request forgery.
+* **Usability tests:** They aim for the idea of knowing how easy the product is to learn and to use.
-===== Testability
+More information about testing can be seen in Section 12.
===== Monitoring
The system is monitored using Spring Boot Actuator and Prometheus. The monitoring data is visualized using Grafana.
diff --git a/docs/src/12_test.adoc b/docs/src/12_test.adoc
new file mode 100644
index 00000000..cb5cb55d
--- /dev/null
+++ b/docs/src/12_test.adoc
@@ -0,0 +1,50 @@
+ifndef::imagesdir[:imagesdir: ../images]
+
+== Testing
+=== Performance efficiency
+The tests were done with a 2 core and 4 GB of memory system. However, real used VM has 2GB and 1 vCPU in order to keep costs low.
+If required, a more powerful machine could be easily used instead of the current one.
+The difference between machines is not such significant as real VM only loads API and the docker image for the DB, while the testing machine must also take care of loading the front of the website.
+
+This system's efficiency has been measured with Gatling. For the script that we used, a user already created, logged in and played a full game. After that, the user clicked to look the statistics.
+
+The scripts were run a total of 4 times. For load testing, one with 1 user, other with 100 users and another one with 1000 users. Finally one with 10000 for stress testing.
+Regarding load testing, the results of these scripts show that response times are reasonable up until 1000 users, although roughly 25% of the requests fail.
+Here are the results.
+
+**1 user:**
+
+image::Gatling_1_user.png[align="center", title="Gatling results with 1 user"]
+
+**100 users:**
+
+image::Gatling_100_users.png[align="center", title="Gatling results with 100 user"]
+
+**1000 users:**
+
+image::Gatling_1000_users.png[align="center", title="Gatling results with 1000 user"]
+
+**10000 users:**
+
+Having 10000 users playing a game at the same time make a lot of failures. However, the server does not get down so after all those users leave, the system could still run normally.
+
+image::Gatling_10000_users.png[align="center", title="Gatling results with 10000 user"]
+
+=== Functional Suitability
+To ensure the users are able to do what they are supposed to do and nothing else, both unit and acceptance testing were done.
+
+Acceptance testing tries to see if the user is able to use the application properly without crashing. However, as security is one of the most important requirements, unit testing from a 'back-end' point of view, so that as few unexpected inputs or bugs may happen in any part of the application (front-end included).
+
+On top of it, strong e2e testing was built to reensure the integrity of the software, as negative and positive test cases were introduced. Via e2e, we can also know what the user is capable of by means of normal application usage and how the system reacts to it.
+
+Unit testing was done via Jupyter for API while Jest and React Testing Library for React components in front-end views.
+Gherkin was used for acceptance testing and user story building.
+Finally, e2e tests were done in JS using Cucumber and Puppeteer.
+
+=== Usability tests
+Although they were not as much as desired, 4 usability tests were done as a way to know how easy our product is. The people tested all use internet daily, although they do not share the same level of expertise.
+
+Most people had no problem to complete the basic task (registering and playing a full game). However, one wanted to log in before signing up (probably that was just a dumb mistake).
+Regarding some more complex task, such us seeing the rules, some of the users had problems as they had not noticed the button for deploying the lateral menu.
+
+Overall, usability tests were good enough, although we would like to have some more people with a wider range of age
\ No newline at end of file
diff --git a/docs/src/12_glossary.adoc b/docs/src/13_glossary.adoc
similarity index 100%
rename from docs/src/12_glossary.adoc
rename to docs/src/13_glossary.adoc
diff --git a/docs/src/13_annex.adoc b/docs/src/14_annex.adoc
similarity index 100%
rename from docs/src/13_annex.adoc
rename to docs/src/14_annex.adoc
diff --git a/webapp/e2e/features/about_features/positive_non_logged_user_seeing_about_screen.feature b/webapp/e2e/features/about_features/positive_non_logged_user_seeing_about_screen.feature
index 4d049f39..7185b089 100644
--- a/webapp/e2e/features/about_features/positive_non_logged_user_seeing_about_screen.feature
+++ b/webapp/e2e/features/about_features/positive_non_logged_user_seeing_about_screen.feature
@@ -3,5 +3,5 @@ Feature: Seeing the about screen of the webpage
Scenario: A non-logged user wants to see the about screen of the webpage
Given A non-logged user in the main menu
When The user presses the button for deploying the lateral menu
- And the user presses the button for seeing the about secction (i)
- Then The screen shows redirects the user to the about screen
\ No newline at end of file
+ And the user presses the button for seeing the about section (i)
+ Then The user is presented to the about screen
\ No newline at end of file
diff --git a/webapp/e2e/features/login_features/negative_blank_email_login.feature b/webapp/e2e/features/login_features/negative_blank_email_login.feature
index 83795c21..2239ea5f 100644
--- a/webapp/e2e/features/login_features/negative_blank_email_login.feature
+++ b/webapp/e2e/features/login_features/negative_blank_email_login.feature
@@ -1,9 +1,9 @@
Feature: Preventing wrong login accesses
-Scenario: A registered user wants to log in using his credentials but leaving the password in blank
+Scenario: A registered user wants to log in using his credentials but leaving the email in blank
Given A registered user in the root screen
When User presses the log in button
And User enters in the log in screen
- And User fills the form with his proper email but leaves the password in blank
+ And User fills the form with his proper password but leaves the email in blank
And User presses the log in button
Then Log in screen shows an informative error message and does not allow the user to log in
\ No newline at end of file
diff --git a/webapp/e2e/features/login_features/negative_blank_password_login.feature b/webapp/e2e/features/login_features/negative_blank_password_login.feature
index 2239ea5f..83795c21 100644
--- a/webapp/e2e/features/login_features/negative_blank_password_login.feature
+++ b/webapp/e2e/features/login_features/negative_blank_password_login.feature
@@ -1,9 +1,9 @@
Feature: Preventing wrong login accesses
-Scenario: A registered user wants to log in using his credentials but leaving the email in blank
+Scenario: A registered user wants to log in using his credentials but leaving the password in blank
Given A registered user in the root screen
When User presses the log in button
And User enters in the log in screen
- And User fills the form with his proper password but leaves the email in blank
+ And User fills the form with his proper email but leaves the password in blank
And User presses the log in button
Then Log in screen shows an informative error message and does not allow the user to log in
\ No newline at end of file
diff --git a/webapp/e2e/features/login_features/negative_incorrect_credentials.feature b/webapp/e2e/features/login_features/negative_incorrect_credentials_login.feature
similarity index 75%
rename from webapp/e2e/features/login_features/negative_incorrect_credentials.feature
rename to webapp/e2e/features/login_features/negative_incorrect_credentials_login.feature
index 662052c5..3e579c5a 100644
--- a/webapp/e2e/features/login_features/negative_incorrect_credentials.feature
+++ b/webapp/e2e/features/login_features/negative_incorrect_credentials_login.feature
@@ -1,9 +1,9 @@
Feature: Preventing wrong login accesses
- Scenario: A registered user wants to log in using his credentials but leaving the email in blank
+ Scenario: A registered user wants to log in using his credentials but they do not match any registered user
Given A registered user in the root screen
When User presses the log in button
And User enters in the log in screen
- And User fills the form with his proper password but leaves the email in blank
+ And User fills the form with credentials that do not match
And User presses the log in button
Then Log in screen shows an informative error message and does not allow the user to log in
\ No newline at end of file
diff --git a/webapp/e2e/features/logout_features/positive_logged_user_logout.feature b/webapp/e2e/features/logout_features/positive_logged_user_logout.feature
index 61ed0986..2e2bc2bc 100644
--- a/webapp/e2e/features/logout_features/positive_logged_user_logout.feature
+++ b/webapp/e2e/features/logout_features/positive_logged_user_logout.feature
@@ -2,5 +2,6 @@ Feature: Logging out an account
Scenario: A logged user wants to log out the webpage
Given A logged user in main menu
- When User presses the log out button
- Then The login screen shows on the user device
+ When User presses the button for deploying the lateral menu
+ And User presses the log out button
+ Then The login screen shows on the user device and the user is no longer logged in
diff --git a/webapp/e2e/features/playing_game_features/negative_non_logged_user_playing_game.feature b/webapp/e2e/features/playing_game_features/negative_non_logged_user_playing_game.feature
index 4e4d90e8..373a1d52 100644
--- a/webapp/e2e/features/playing_game_features/negative_non_logged_user_playing_game.feature
+++ b/webapp/e2e/features/playing_game_features/negative_non_logged_user_playing_game.feature
@@ -1,7 +1,7 @@
Feature: Preventing starting a new game
- Scenario: A logged user wants to play a new game
- Given A non-logged user in the main menu
+ Scenario: A non-logged user wants to play a new game
+ Given A non-logged user in the root directory
When Entering the endpoint via URL
Then No new game is created and the user is redirected to the log in screen
diff --git a/webapp/e2e/features/playing_game_features/positive_playing_full_game.feature b/webapp/e2e/features/playing_game_features/positive_playing_full_game.feature
new file mode 100644
index 00000000..03129b89
--- /dev/null
+++ b/webapp/e2e/features/playing_game_features/positive_playing_full_game.feature
@@ -0,0 +1,54 @@
+Feature: Starting an entire game
+
+Scenario: A non-logged user wants to play an entire game (Kiwi Quest gamemode)
+ Given A non-logged user in the main menu
+ When Clicking the button to start a new game (Kiwi Quest gamemode)
+
+ And Waiting for the question to load
+ And Checking user is on round 1/9
+ And Clicking on a random answer
+ And Sending the answer
+
+ And Waiting for the question to load
+ And Checking user is on round 2/9
+ And Clicking on a random answer
+ And Sending the answer
+
+ And Waiting for the question to load
+ And Checking user is on round 3/9
+ And Clicking on a random answer
+ And Sending the answer
+
+ And Waiting for the question to load
+ And Checking user is on round 4/9
+ And Clicking on a random answer
+ And Sending the answer
+
+ And Waiting for the question to load
+ And Checking user is on round 5/9
+ And Clicking on a random answer
+ And Sending the answer
+
+ And Waiting for the question to load
+ And Checking user is on round 6/9
+ And Clicking on a random answer
+ And Sending the answer
+
+ And Waiting for the question to load
+ And Checking user is on round 7/9
+ And Clicking on a random answer
+ And Sending the answer
+
+ And Waiting for the question to load
+ And Checking user is on round 8/9
+ And Clicking on a random answer
+ And Sending the answer
+
+ And Waiting for the question to load
+ And Checking user is on round 9/9
+ And Clicking on a random answer
+ And Sending the answer
+
+
+ Then The user statistics are shown
+
diff --git a/webapp/e2e/features/playing_game_features/positive_playing_game.feature b/webapp/e2e/features/playing_game_features/positive_playing_game.feature
deleted file mode 100644
index 1f4ae9ee..00000000
--- a/webapp/e2e/features/playing_game_features/positive_playing_game.feature
+++ /dev/null
@@ -1,7 +0,0 @@
-Feature: Starting a new game
-
-Scenario: A logged user wants to play a new game
- Given A logged user in the main menu
- When Clicking the button to start a new game
- Then A new game is created and the first question appears on the screen
-
diff --git a/webapp/e2e/features/register_form_features/negative_register_blank_email.feature b/webapp/e2e/features/register_form_features/negative_register_blank_email.feature
index ceaf28dc..93fb2db3 100644
--- a/webapp/e2e/features/register_form_features/negative_register_blank_email.feature
+++ b/webapp/e2e/features/register_form_features/negative_register_blank_email.feature
@@ -1,6 +1,6 @@
Feature: Preventing wrong user creation
- Scenario: The user is not registered in the site
+ Scenario: The user is not registered in the site and tries to create an account
Given An unregistered user
When I fill the data in the form leaving the email in blank and press submit
Then Log in screen shows an informative error message and does not allow the user to log in
\ No newline at end of file
diff --git a/webapp/e2e/features/register_form_features/negative_register_blank_password.feature b/webapp/e2e/features/register_form_features/negative_register_blank_password.feature
index 443a4818..b30c5776 100644
--- a/webapp/e2e/features/register_form_features/negative_register_blank_password.feature
+++ b/webapp/e2e/features/register_form_features/negative_register_blank_password.feature
@@ -1,6 +1,7 @@
Feature: Preventing wrong user creation
- Scenario: The user is not registered in the site and tries to create an account
+ Scenario: The user is not registered in the root directory of the website and tries to create an account
Given An unregistered user
- When I fill the data in the form leaving the password in blank and press submit
+ When The user fills its data in the form leaving the password field in blank
+ And Press Log in button
Then Log in screen shows an informative error message and does not allow the user to log in
\ No newline at end of file
diff --git a/webapp/e2e/features/register_form_features/negative_register_blank_repeated_password.feature b/webapp/e2e/features/register_form_features/negative_register_blank_repeated_password.feature
index 951abeb6..b30c5776 100644
--- a/webapp/e2e/features/register_form_features/negative_register_blank_repeated_password.feature
+++ b/webapp/e2e/features/register_form_features/negative_register_blank_repeated_password.feature
@@ -1,6 +1,7 @@
Feature: Preventing wrong user creation
- Scenario: The user is not registered in the site and tries to create an account
+ Scenario: The user is not registered in the root directory of the website and tries to create an account
Given An unregistered user
- When I fill the data in the form leaving the repeat password field in blank and press submit
+ When The user fills its data in the form leaving the password field in blank
+ And Press Log in button
Then Log in screen shows an informative error message and does not allow the user to log in
\ No newline at end of file
diff --git a/webapp/e2e/features/register_form_features/negative_register_blank_username.feature b/webapp/e2e/features/register_form_features/negative_register_blank_username.feature
index f77368c3..3ad7e59f 100644
--- a/webapp/e2e/features/register_form_features/negative_register_blank_username.feature
+++ b/webapp/e2e/features/register_form_features/negative_register_blank_username.feature
@@ -1,6 +1,7 @@
Feature: Preventing wrong user creation
- Scenario: The user is not registered in the site and tries to create an account
+ Scenario: The user is not registered in the root directory of the website and tries to create an account
Given An unregistered user
- When I fill the data in the form leaving the username field in blank and press submit
+ When The user fills its data in the form leaving the username field in blank
+ And Press log in button
Then Log in screen shows an informative error message and does not allow the user to log in
\ No newline at end of file
diff --git a/webapp/e2e/features/register_form_features/negative_register_email_already_in_use.feature b/webapp/e2e/features/register_form_features/negative_register_email_already_in_use.feature
index f1b19991..ebb84c7c 100644
--- a/webapp/e2e/features/register_form_features/negative_register_email_already_in_use.feature
+++ b/webapp/e2e/features/register_form_features/negative_register_email_already_in_use.feature
@@ -1,6 +1,7 @@
Feature: Preventing wrong user creation
- Scenario: The user is not registered in the site and tries to create an account
+ Scenario: The user is not registered in the root directory of the website
Given An unregistered user
- When I fill the data in the form using an already used email and press submit
+ When the user fills the data in the form using an already used email
+ And click the sign in button
Then Log in screen shows an informative error message and does not allow the user to log in
\ No newline at end of file
diff --git a/webapp/e2e/features/register_form_features/negative_register_username_already_in_use.feature b/webapp/e2e/features/register_form_features/negative_register_username_already_in_use.feature
index 776727c4..c7f0e875 100644
--- a/webapp/e2e/features/register_form_features/negative_register_username_already_in_use.feature
+++ b/webapp/e2e/features/register_form_features/negative_register_username_already_in_use.feature
@@ -1,6 +1,7 @@
Feature: Preventing wrong user creation
- Scenario: The user is not registered in the site and tries to create an account
+ Scenario: The user is not registered in the root directory of the website and tries to create an account
Given An unregistered user
- When I fill the data in the form using an already used username and press submit
+ When The user fills the data in the form using an already used username
+ And Press Log in button
Then Log in screen shows an informative error message and does not allow the user to log in
\ No newline at end of file
diff --git a/webapp/e2e/features/register_form_features/negative_register_wrong_email_format.feature b/webapp/e2e/features/register_form_features/negative_register_wrong_email_format.feature
index 6b80e175..264f6ef1 100644
--- a/webapp/e2e/features/register_form_features/negative_register_wrong_email_format.feature
+++ b/webapp/e2e/features/register_form_features/negative_register_wrong_email_format.feature
@@ -1,6 +1,7 @@
Feature: Preventing wrong user creation
- Scenario: The user is not registered in the site and tries to create an account
+ Scenario: The user is not registered in the root directory of the website and tries to create an account
Given An unregistered user
- When I fill the data in the form with a wrong email format and press submit
+ When The user fills its data in the form placing a wrong email format
+ And Press Log in button
Then Log in screen shows an informative error message and does not allow the user to log in
\ No newline at end of file
diff --git a/webapp/e2e/features/register_form_features/positive_register_form.feature b/webapp/e2e/features/register_form_features/positive_register_form.feature
index 6917adf4..f79f064a 100644
--- a/webapp/e2e/features/register_form_features/positive_register_form.feature
+++ b/webapp/e2e/features/register_form_features/positive_register_form.feature
@@ -1,6 +1,7 @@
Feature: Registering a new user
-Scenario: The user is not registered in the site
+Scenario: The user is not registered in the root directory of the website
Given An unregistered user
- When I fill the data in the form and press submit
- Then The main menu screen is shown and the new user is created
\ No newline at end of file
+ When I fill the data in the form
+ And click the sign in button
+ Then The main menu screen is shown
\ No newline at end of file
diff --git a/webapp/e2e/features/seeing_rules_features/negative_non_logged_user_seeing_rules.feature b/webapp/e2e/features/seeing_rules_features/negative_non_logged_user_seeing_rules.feature
index 8de07602..7f8c65d3 100644
--- a/webapp/e2e/features/seeing_rules_features/negative_non_logged_user_seeing_rules.feature
+++ b/webapp/e2e/features/seeing_rules_features/negative_non_logged_user_seeing_rules.feature
@@ -1,6 +1,6 @@
Feature: Preventing seeing the rules of the game
Scenario: A non-logged user wants to see the rules for the game
- Given A non-logged user
- When The user accesses to the rules via URL
+ Given A non-logged user in main menu
+ When User accesses de /rules endpoint via URL
Then The user is redirected to the log in screen
\ No newline at end of file
diff --git a/webapp/e2e/features/seeing_rules_features/positive_seeing_rules.feature b/webapp/e2e/features/seeing_rules_features/positive_seeing_rules.feature
index 4c7142eb..0fb53312 100644
--- a/webapp/e2e/features/seeing_rules_features/positive_seeing_rules.feature
+++ b/webapp/e2e/features/seeing_rules_features/positive_seeing_rules.feature
@@ -3,5 +3,5 @@ Feature: Seeing the rules of the game
Scenario: A logged user wants to see the rules for the game
Given A logged user in the main menu
When The user presses the button for deploying the lateral menu
- And the user presses the button for seeing the rules
+ And The user presses the button for seeing the rules
Then The screen shows redirects the user to the rules' screen
\ No newline at end of file
diff --git a/webapp/e2e/features/seeing_stats_features/negative_non_logged_user_seeing_stats_stories.feature b/webapp/e2e/features/seeing_stats_features/negative_non_logged_user_seeing_stats_stories.feature
index b464cd64..e92203a0 100644
--- a/webapp/e2e/features/seeing_stats_features/negative_non_logged_user_seeing_stats_stories.feature
+++ b/webapp/e2e/features/seeing_stats_features/negative_non_logged_user_seeing_stats_stories.feature
@@ -1,7 +1,6 @@
Feature: Seeing the leader board
Scenario: A non-logged user wants to see its stats
- Given A non-logged user
- And A full leader board (many other users with many other games)
+ Given A non-logged user in main menu
When The user accesses to the leader board via URL
Then The user is redirected to the log in screen
\ No newline at end of file
diff --git a/webapp/e2e/features/seeing_stats_features/positive_seeing-stats.feature b/webapp/e2e/features/seeing_stats_features/positive_seeing-stats.feature
index 464b6bd9..d7b06353 100644
--- a/webapp/e2e/features/seeing_stats_features/positive_seeing-stats.feature
+++ b/webapp/e2e/features/seeing_stats_features/positive_seeing-stats.feature
@@ -2,7 +2,6 @@ Feature: Seeing the leader board
Scenario: A logged user with many games wants to see its stats
Given A logged user in the main menu with many games
- And A full leader board (many other users with many other games)
When The user presses the button for deploying the lateral menu
- And the user presses the button for seeing stats
- Then it successfully displays both, the leader board and the logged user statistics
\ No newline at end of file
+ And The user presses the button for seeing stats
+ Then It successfully displays both, the leader board and the logged user statistics
\ No newline at end of file
diff --git a/webapp/e2e/steps/about_positive_logged_user_seeing_about_screen.steps.js b/webapp/e2e/steps/about_positive_logged_user_seeing_about_screen.steps.js
new file mode 100644
index 00000000..311d0908
--- /dev/null
+++ b/webapp/e2e/steps/about_positive_logged_user_seeing_about_screen.steps.js
@@ -0,0 +1,62 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/about_features/positive_logged_user_seeing_about_screen.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A logged user wants to see the about screen of the webpage", ({given,when,and,then}) => {
+
+ let username;
+ let password;
+
+ given("A logged user in the main menu", async () => {
+ username = "test@email.com"
+ password = "password"
+
+ await expect(page).toClick("button[data-testid='Login'");
+ await expect(page).toFill("#user", username);
+ await expect(page).toFill("#password", password);
+ await expect(page).toClick("button[data-testid='Login'");
+ });
+
+ when("The user presses the button for deploying the lateral menu", async () => {
+ await expect(page).toClick("#lateralMenuButton");
+ });
+
+ and("the user presses the button for seeing the about section (i)", async () => {
+ await expect(page).toClick("#aboutButton");
+ });
+
+ then("The user is presented to the about screen", async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("h2", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "About" || header === "Sobre nosotros";
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/about_positive_non_logged_user_seeing_about_screen.steps.js b/webapp/e2e/steps/about_positive_non_logged_user_seeing_about_screen.steps.js
new file mode 100644
index 00000000..9072d93f
--- /dev/null
+++ b/webapp/e2e/steps/about_positive_non_logged_user_seeing_about_screen.steps.js
@@ -0,0 +1,53 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/about_features/positive_non_logged_user_seeing_about_screen.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A non-logged user wants to see the about screen of the webpage", ({given,when,and,then}) => {
+
+ given("A non-logged user in the main menu", async () => {
+
+ });
+
+ when("The user presses the button for deploying the lateral menu", async () => {
+ await expect(page).toClick("#lateralMenuButton");
+ });
+
+ and("the user presses the button for seeing the about section (i)", async () => {
+ await expect(page).toClick("#aboutButton");
+ });
+
+ then("The user is presented to the about screen", async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("h2", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "About" || header === "Sobre nosotros";
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/login_positive.steps.js b/webapp/e2e/steps/login_positive.steps.js
new file mode 100644
index 00000000..7a9a4678
--- /dev/null
+++ b/webapp/e2e/steps/login_positive.steps.js
@@ -0,0 +1,78 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/login_features/positive_login.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A registered user wants to log in using his correct credentials", ({given,when,and,then}) => {
+ let username = "pepe"
+ let user = username + "@pepe.com"
+ let password = "pepe"
+
+ given('A registered user in the root screen', async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("button[data-testid='Login']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ when('User presses the log in button', async() => {
+ await expect(page).toClick("button[data-testid='Login'");
+ });
+
+ and('User enters in the log in screen', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("h2", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ and('User fills the form with his credentials properly', async() => {
+ await expect(page).toFill("#user", user);
+ await expect(page).toFill("#password", password);
+ });
+
+ and('User presses the log in button', async() => {
+ await expect(page).toClick("button[data-testid='Login'");
+ });
+
+ then('The main menu screen shows on the user device', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("h2", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Bienvenid@ " + username || header === "Welcome " + username;
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/login_register_negative_bad_email_format.steps.js b/webapp/e2e/steps/login_register_negative_bad_email_format.steps.js
new file mode 100644
index 00000000..7df25a3b
--- /dev/null
+++ b/webapp/e2e/steps/login_register_negative_bad_email_format.steps.js
@@ -0,0 +1,79 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/login_features/negative_bad_format_email_login.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A registered user wants to log in using his credentials but with an invalid email", ({given,when,and,then}) => {
+ let username = "pepe"
+ let user = username + "email.com" // Bad formatted email
+ let password = "Password"
+
+ given('A registered user in the root screen', async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("button[data-testid='Login']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ when('User presses the log in button', async() => {
+ await expect(page).toClick("button[data-testid='Login'");
+ });
+
+ and('User enters in the log in screen', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("h2", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ and('User fills the form with his proper password but writes a wrong formatted email', async() => {
+ await expect(page).toFill("#user", user);
+ await expect(page).toFill("#password", password);
+ });
+
+ and('User presses the log in button', async() => {
+ await expect(page).toClick("button[data-testid='Login'");
+ });
+
+ then('Log in screen shows an informative error message and does not allow the user to log in', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("div[class='chakra-alert__desc css-zzks76'", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "El formato del correo electrónico no es correcto"
+ || header === "Invalid email format";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/login_register_negative_blank_email_credentials.steps.js b/webapp/e2e/steps/login_register_negative_blank_email_credentials.steps.js
new file mode 100644
index 00000000..077730cf
--- /dev/null
+++ b/webapp/e2e/steps/login_register_negative_blank_email_credentials.steps.js
@@ -0,0 +1,79 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/login_features/negative_blank_email_login.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A registered user wants to log in using his credentials but leaving the email in blank", ({given,when,and,then}) => {
+ let username = "pepe"
+ let user = ""
+ let password = "Password"
+
+ given('A registered user in the root screen', async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("button[data-testid='Login']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ when('User presses the log in button', async() => {
+ await expect(page).toClick("button[data-testid='Login'");
+ });
+
+ and('User enters in the log in screen', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("h2", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ and('User fills the form with his proper password but leaves the email in blank', async() => {
+ await expect(page).toFill("#user", user);
+ await expect(page).toFill("#password", password);
+ });
+
+ and('User presses the log in button', async() => {
+ await expect(page).toClick("button[data-testid='Login'");
+ });
+
+ then('Log in screen shows an informative error message and does not allow the user to log in', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("div[class='chakra-alert__desc css-zzks76'", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "El formato del correo electrónico no es correcto"
+ || header === "Invalid email format";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/login_register_negative_blank_password_credentials.steps.js b/webapp/e2e/steps/login_register_negative_blank_password_credentials.steps.js
new file mode 100644
index 00000000..ea59247b
--- /dev/null
+++ b/webapp/e2e/steps/login_register_negative_blank_password_credentials.steps.js
@@ -0,0 +1,79 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/login_features/negative_blank_password_login.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A registered user wants to log in using his credentials but leaving the password in blank", ({given,when,and,then}) => {
+ let username = "pepe"
+ let user = username + "@email.com"
+ let password = "" // Blank password
+
+ given('A registered user in the root screen', async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("button[data-testid='Login']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ when('User presses the log in button', async() => {
+ await expect(page).toClick("button[data-testid='Login'");
+ });
+
+ and('User enters in the log in screen', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("h2", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ and('User fills the form with his proper email but leaves the password in blank', async() => {
+ await expect(page).toFill("#user", user);
+ await expect(page).toFill("#password", password);
+ });
+
+ and('User presses the log in button', async() => {
+ await expect(page).toClick("button[data-testid='Login'");
+ });
+
+ then('Log in screen shows an informative error message and does not allow the user to log in', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("div[class='chakra-alert__desc css-zzks76'", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "El formato del correo electrónico no es correcto" // Wrong message shown from frontend
+ || header === "Invalid email format";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/login_register_negative_incorrect_credentials.steps.js b/webapp/e2e/steps/login_register_negative_incorrect_credentials.steps.js
new file mode 100644
index 00000000..3f1cddfc
--- /dev/null
+++ b/webapp/e2e/steps/login_register_negative_incorrect_credentials.steps.js
@@ -0,0 +1,79 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/login_features/negative_incorrect_credentials_login.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A registered user wants to log in using his credentials but they do not match any registered user", ({given,when,and,then}) => {
+ let username = "pepe"
+ let user = username + "@pepe.com"
+ let password = "notPepesPassword"
+
+ given('A registered user in the root screen', async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("button[data-testid='Login']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ when('User presses the log in button', async() => {
+ await expect(page).toClick("button[data-testid='Login'");
+ });
+
+ and('User enters in the log in screen', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("h2", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ and('User fills the form with credentials that do not match', async() => {
+ await expect(page).toFill("#user", user);
+ await expect(page).toFill("#password", password);
+ });
+
+ and('User presses the log in button', async() => {
+ await expect(page).toClick("button[data-testid='Login'");
+ });
+
+ then('Log in screen shows an informative error message and does not allow the user to log in', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("div[class='chakra-alert__desc css-zzks76'", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Correo electrónico o contraseña no válidos, verifique que sean correctos"
+ || header === "Invalid email or password, check for them to be correct";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/logout_positive_logged_user.steps.js b/webapp/e2e/steps/logout_positive_logged_user.steps.js
new file mode 100644
index 00000000..f953de75
--- /dev/null
+++ b/webapp/e2e/steps/logout_positive_logged_user.steps.js
@@ -0,0 +1,79 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/logout_features/positive_logged_user_logout.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A logged user wants to log out the webpage", ({given,when,and,then}) => {
+ let username = "pepe"
+ let user = username + "@pepe.com"
+ let password = "pepe"
+
+ let gameURL = "http://localhost:3000/dashboard/game";
+
+ given('A logged user in main menu', async () => {
+ let header = await page.$eval("button[data-testid='Login']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+
+ await expect(page).toClick("button[data-testid='Login'");
+ await expect(page).toFill("#user", user);
+ await expect(page).toFill("#password", password);
+ await expect(page).toClick("button[data-testid='Login'");
+
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let newHeader = await page.$eval("h2", (element) => {
+ return element.innerHTML
+ })
+ let newValue = newHeader === "Bienvenid@ " + username || header === "Welcome " + username;
+ expect(newValue).toBeTruthy();
+ });
+
+ when('User presses the button for deploying the lateral menu', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+ await expect(page).toClick("#lateralMenuButton");
+
+ });
+
+ and('User presses the log out button', async() => {
+ await expect(page).toClick("button[data-testid='LogOut']");
+
+ });
+
+ then('The login screen shows on the user device and the user is no longer logged in', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("button[data-testid='Login']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/logout_positive_non_logged_user.steps.js b/webapp/e2e/steps/logout_positive_non_logged_user.steps.js
new file mode 100644
index 00000000..508d3c73
--- /dev/null
+++ b/webapp/e2e/steps/logout_positive_non_logged_user.steps.js
@@ -0,0 +1,65 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/logout_features/positive_non_logged_user_logout.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A non-logged user wants to log out the webpage", ({given,when,then}) => {
+ let username = "pepe"
+ let user = username + "@pepe.com"
+ let password = "pepe"
+
+ let gameURL = "http://localhost:3000/dashboard/game";
+
+ given('A non-logged user in main menu', async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("button[data-testid='Login']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ when('User accesses de /logout endpoint via URL', async() => {
+ await page
+ .goto("http://localhost:3000/logout", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ then('The login screen shows on the user device', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+ let header = await page.$eval("button[data-testid='Login']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/playing_full_game_positive.steps.js b/webapp/e2e/steps/playing_full_game_positive.steps.js
new file mode 100644
index 00000000..98567029
--- /dev/null
+++ b/webapp/e2e/steps/playing_full_game_positive.steps.js
@@ -0,0 +1,347 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/playing_game_features/positive_playing_full_game.feature');
+let page;
+let browser;
+let NUMBER_OF_ANSWERS = 4;
+let TEST_TIMEOUT = 300 * 1000; // 5minutes
+const crypto = require('crypto');
+
+
+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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A non-logged user wants to play an entire game (Kiwi Quest gamemode)", ({given,when,and,then}) => {
+ // Trying to avoid repeated users:
+ // Generate random bytes
+ let randomBytes = crypto.randomBytes(8); // 8 bytes = 64 bits
+ // Convert bytes to hex
+ let hexString = randomBytes.toString('hex');
+ // Take the first 16 characters
+ let randomHash = hexString.substring(0, 8);
+
+
+
+ let username = "test" + randomHash
+ let user = username + "@pepe.com"
+ let password = "pepe" + randomHash
+
+ given('A non-logged user in the main menu', async () => {
+ // Registering a new user for simplicity of testing purposes
+ await expect(page).toClick("span[class='chakra-link css-1bicqx'");
+ await expect(page).toFill("input[id='user'", user);
+ await expect(page).toFill("input[id='username'", username);
+ await expect(page).toFill("#password", password);
+ await expect(page).toFill("input[id='field-:r5:']", password);
+ await expect(page).toClick("button[data-testid='Sign up'");
+
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ // Checking user is in main screen
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Bienvenid@ " + username || header === "Welcome " + username;
+
+ expect(value).toBeTruthy();
+
+ });
+
+ when('Clicking the button to start a new game (Kiwi Quest gamemode)', async() => {
+ await expect(page).toClick("button[class='chakra-button css-4ctvp9'");
+ await expect(page).toClick("button[data-testid='Play']");
+ });
+
+ and('Waiting for the question to load', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+
+ });
+
+ and('Checking user is on round 1/9', async() => {
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let round = 1;
+ let value = header === "Ronda " + round + " de 9" || header === "Round " + round + " of 9";
+ expect(value).toBeTruthy();
+
+ });
+
+ and('Clicking on a random answer', async() => {
+ let chosen = Math.floor(Math.random() * NUMBER_OF_ANSWERS) + 1; // choses a int in between [1,4] (index of answers range)
+ await expect(page).toClick("button[data-testid='Option" + chosen + "']");
+
+ });
+
+ and('Sending the answer', async() => {
+ await expect(page).toClick("button[data-testid='Next']");
+
+ });
+
+
+
+
+ and('Waiting for the question to load', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+
+ });
+
+ and('Checking user is on round 2/9', async() => {
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let round = 2;
+ let value = header === "Ronda " + round + " de 9" || header === "Round " + round + " of 9";
+ expect(value).toBeTruthy();
+
+ });
+
+ and('Clicking on a random answer', async() => {
+ let chosen = Math.floor(Math.random() * NUMBER_OF_ANSWERS) + 1; // choses a int in between [1,4] (index of answers range)
+ await expect(page).toClick("button[data-testid='Option" + chosen + "']");
+
+ });
+
+ and('Sending the answer', async() => {
+ await expect(page).toClick("button[data-testid='Next']");
+
+ });
+
+
+
+
+
+ and('Waiting for the question to load', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+
+ });
+
+ and('Checking user is on round 3/9', async() => {
+
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let round = 3;
+ let value = header === "Ronda " + round + " de 9" || header === "Round " + round + " of 9";
+ expect(value).toBeTruthy();
+
+ });
+
+ and('Clicking on a random answer', async() => {
+ let chosen = Math.floor(Math.random() * NUMBER_OF_ANSWERS) + 1; // choses a int in between [1,4] (index of answers range)
+ await expect(page).toClick("button[data-testid='Option" + chosen + "']");
+
+ });
+
+ and('Sending the answer', async() => {
+ await expect(page).toClick("button[data-testid='Next']");
+
+ });
+
+
+
+
+ and('Waiting for the question to load', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+
+ });
+
+ and('Checking user is on round 4/9', async() => {
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let round = 4;
+ let value = header === "Ronda " + round + " de 9" || header === "Round " + round + " of 9";
+ expect(value).toBeTruthy();
+
+ });
+
+ and('Clicking on a random answer', async() => {
+ let chosen = Math.floor(Math.random() * NUMBER_OF_ANSWERS) + 1; // choses a int in between [1,4] (index of answers range)
+ await expect(page).toClick("button[data-testid='Option" + chosen + "']");
+
+ });
+
+ and('Sending the answer', async() => {
+ await expect(page).toClick("button[data-testid='Next']");
+
+ });
+
+
+
+
+
+ and('Waiting for the question to load', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+
+ });
+
+ and('Checking user is on round 5/9', async() => {
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let round = 5;
+ let value = header === "Ronda " + round + " de 9" || header === "Round " + round + " of 9";
+ expect(value).toBeTruthy();
+
+ });
+
+ and('Clicking on a random answer', async() => {
+ let chosen = Math.floor(Math.random() * NUMBER_OF_ANSWERS) + 1; // choses a int in between [1,4] (index of answers range)
+ await expect(page).toClick("button[data-testid='Option" + chosen + "']");
+
+ });
+
+ and('Sending the answer', async() => {
+ await expect(page).toClick("button[data-testid='Next']");
+
+ });
+
+
+
+
+ and('Waiting for the question to load', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+
+ });
+
+ and('Checking user is on round 6/9', async() => {
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let round = 6;
+ let value = header === "Ronda " + round + " de 9" || header === "Round " + round + " of 9";
+ expect(value).toBeTruthy();
+
+ });
+
+ and('Clicking on a random answer', async() => {
+ let chosen = Math.floor(Math.random() * NUMBER_OF_ANSWERS) + 1; // choses a int in between [1,4] (index of answers range)
+ await expect(page).toClick("button[data-testid='Option" + chosen + "']");
+
+ });
+
+ and('Sending the answer', async() => {
+ await expect(page).toClick("button[data-testid='Next']");
+
+ });
+
+
+
+
+ and('Waiting for the question to load', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+
+ });
+
+ and('Checking user is on round 7/9', async() => {
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let round = 7;
+ let value = header === "Ronda " + round + " de 9" || header === "Round " + round + " of 9";
+ expect(value).toBeTruthy();
+
+ });
+
+ and('Clicking on a random answer', async() => {
+ let chosen = Math.floor(Math.random() * NUMBER_OF_ANSWERS) + 1; // choses a int in between [1,4] (index of answers range)
+ await expect(page).toClick("button[data-testid='Option" + chosen + "']");
+
+ });
+
+ and('Sending the answer', async() => {
+ await expect(page).toClick("button[data-testid='Next']");
+
+ });
+
+
+
+
+
+ and('Waiting for the question to load', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+
+ });
+
+ and('Checking user is on round 8/9', async() => {
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let round = 8;
+ let value = header === "Ronda " + round + " de 9" || header === "Round " + round + " of 9";
+ expect(value).toBeTruthy();
+
+ });
+
+ and('Clicking on a random answer', async() => {
+ let chosen = Math.floor(Math.random() * NUMBER_OF_ANSWERS) + 1; // choses a int in between [1,4] (index of answers range)
+ await expect(page).toClick("button[data-testid='Option" + chosen + "']");
+
+ });
+
+ and('Sending the answer', async() => {
+ await expect(page).toClick("button[data-testid='Next']");
+
+ });
+
+
+
+
+
+ and('Waiting for the question to load', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+
+ });
+
+ and('Checking user is on round 9/9', async() => {
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let round = 9;
+ let value = header === "Ronda " + round + " de 9" || header === "Round " + round + " of 9";
+ expect(value).toBeTruthy();
+
+ });
+
+ and('Clicking on a random answer', async() => {
+ let chosen = Math.floor(Math.random() * NUMBER_OF_ANSWERS) + 1; // choses a int in between [1,4] (index of answers range)
+ await expect(page).toClick("button[data-testid='Option" + chosen + "']");
+
+ });
+
+ and('Sending the answer', async() => {
+ await expect(page).toClick("button[data-testid='Next']");
+
+ });
+
+ then('The user statistics are shown', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting till page is loaded
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Resultados" || header === "Results";
+
+ expect(value).toBeTruthy();
+ });
+
+ }, TEST_TIMEOUT);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/playing_game_negative_non_logged_user.steps.js b/webapp/e2e/steps/playing_game_negative_non_logged_user.steps.js
new file mode 100644
index 00000000..a644b5a7
--- /dev/null
+++ b/webapp/e2e/steps/playing_game_negative_non_logged_user.steps.js
@@ -0,0 +1,62 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/playing_game_features/negative_non_logged_user_playing_game.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A non-logged user wants to play a new game", ({given,when,then}) => {
+ let username = "pepe"
+ let user = username + "@pepe.com"
+ let password = "pepe"
+
+ let gameURL = "http://localhost:3000/dashboard/game";
+
+ given('A non-logged user in the root directory', async () => {
+
+ });
+
+ when('Entering the endpoint via URL', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+ await page
+ .goto(gameURL, {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+
+
+ then('No new game is created and the user is redirected to the log in screen', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("button[data-testid='Login']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/register_negative_blank_password.steps.js b/webapp/e2e/steps/register_negative_blank_password.steps.js
new file mode 100644
index 00000000..5977074a
--- /dev/null
+++ b/webapp/e2e/steps/register_negative_blank_password.steps.js
@@ -0,0 +1,75 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/register_form_features/negative_register_blank_password.feature');
+const crypto = require('crypto');
+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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("The user is not registered in the root directory of the website and tries to create an account", ({given,when,and,then}) => {
+ // Trying to avoid repeated users:
+ // Generate random bytes
+ let randomBytes = crypto.randomBytes(8); // 8 bytes = 64 bits
+ // Convert bytes to hex
+ let hexString = randomBytes.toString('hex');
+ // Take the first 16 characters
+ let randomHash = hexString.substring(0, 20);
+
+
+
+ let username = "test" + randomHash
+ let user = username + "@email.com"
+ let password = "password"
+
+ given("An unregistered user", async () => {
+
+ });
+
+ when("The user fills its data in the form leaving the password field in blank", async () => {
+ await expect(page).toClick("span[class='chakra-link css-1bicqx'");
+ await expect(page).toFill("input[id='user'", user);
+ await expect(page).toFill("input[id='username'", username);
+ await expect(page).toFill("#password", ""); // Blank password
+ await expect(page).toFill("input[id='field-:r5:']", password);
+
+ });
+
+ and("Press Log in button", async () => {
+ await expect(page).toClick("button[data-testid='Sign up'");
+
+ });
+
+ then("Log in screen shows an informative error message and does not allow the user to log in", async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("div[class='chakra-alert__desc css-zzks76'", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Formato de correo electrónico no válido o credenciales (nombre de usuario o correo electrónico) ya en uso"
+ || header === "Invalid email format or credentials (username or email) already in use";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/register_negative_blank_repeated_password.steps.js b/webapp/e2e/steps/register_negative_blank_repeated_password.steps.js
new file mode 100644
index 00000000..96349b77
--- /dev/null
+++ b/webapp/e2e/steps/register_negative_blank_repeated_password.steps.js
@@ -0,0 +1,75 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/register_form_features/negative_register_blank_repeated_password.feature');
+const crypto = require('crypto');
+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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("The user is not registered in the root directory of the website and tries to create an account", ({given,when,and,then}) => {
+ // Trying to avoid repeated users:
+ // Generate random bytes
+ let randomBytes = crypto.randomBytes(8); // 8 bytes = 64 bits
+ // Convert bytes to hex
+ let hexString = randomBytes.toString('hex');
+ // Take the first 16 characters
+ let randomHash = hexString.substring(0, 20);
+
+
+
+ let username = "test" + randomHash
+ let user = username + "@email.com"
+ let password = "password"
+
+ given("An unregistered user", async () => {
+
+ });
+
+ when("The user fills its data in the form leaving the password field in blank", async () => {
+ await expect(page).toClick("span[class='chakra-link css-1bicqx'");
+ await expect(page).toFill("input[id='user'", user);
+ await expect(page).toFill("input[id='username'", username);
+ await expect(page).toFill("#password", password);
+ await expect(page).toFill("input[id='field-:r5:']", ""); // Blank password
+
+ });
+
+ and("Press Log in button", async () => {
+ await expect(page).toClick("button[data-testid='Sign up'");
+
+ });
+
+ then("Log in screen shows an informative error message and does not allow the user to log in", async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("div[class='chakra-alert__desc css-zzks76'", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "La confirmación de contraseña no puede estar vacía"
+ || header === "The confirm password label can not be empty";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/register_negative_blank_username.steps.js b/webapp/e2e/steps/register_negative_blank_username.steps.js
new file mode 100644
index 00000000..fa8d7e29
--- /dev/null
+++ b/webapp/e2e/steps/register_negative_blank_username.steps.js
@@ -0,0 +1,65 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/register_form_features/negative_register_blank_username.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("The user is not registered in the root directory of the website and tries to create an account", ({given,when,and,then}) => {
+ let username = "" // Blank username
+ let user = "test@email.com"
+ let password = "password"
+
+ given("An unregistered user", async () => {
+
+ });
+
+ when("The user fills its data in the form leaving the username field in blank", async () => {
+ await expect(page).toClick("span[class='chakra-link css-1bicqx'");
+ await expect(page).toFill("input[id='user'", user);
+ await expect(page).toFill("input[id='username'", username);
+ await expect(page).toFill("#password", password);
+ await expect(page).toFill("input[id='field-:r5:']", password);
+
+ });
+
+ and("Press Log in button", async () => {
+ await expect(page).toClick("button[data-testid='Sign up'");
+
+ });
+
+ then("Log in screen shows an informative error message and does not allow the user to log in", async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("div[class='chakra-alert__desc css-zzks76'", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Formato de correo electrónico no válido o credenciales (nombre de usuario o correo electrónico) ya en uso"
+ || header === "Invalid email format or credentials (username or email) already in use";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/register_negative_email_already_in_use_form.steps.js b/webapp/e2e/steps/register_negative_email_already_in_use_form.steps.js
new file mode 100644
index 00000000..8cd00a7b
--- /dev/null
+++ b/webapp/e2e/steps/register_negative_email_already_in_use_form.steps.js
@@ -0,0 +1,72 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/register_form_features/negative_register_email_already_in_use.feature');
+const crypto = require('crypto');
+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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("The user is not registered in the root directory of the website", ({given,when,and,then}) => {
+ // Trying to avoid repeated users:
+ // Generate random bytes
+ let randomBytes = crypto.randomBytes(8); // 8 bytes = 64 bits
+ // Convert bytes to hex
+ let hexString = randomBytes.toString('hex');
+ // Take the first 16 characters
+ let randomHash = hexString.substring(0, 20);
+ let username = "test"
+ let user = "test" + "@email.com"
+ let password = "password"
+
+ given("An unregistered user", async () => {
+
+ });
+
+ when("the user fills the data in the form using an already used email", async () => {
+ await expect(page).toClick("span[class='chakra-link css-1bicqx'");
+ await expect(page).toFill("input[id='user'", user);
+ await expect(page).toFill("input[id='username'", username);
+ await expect(page).toFill("#password", password);
+ await expect(page).toFill("input[id='field-:r5:']", password);
+
+ });
+
+ and("click the sign in button", async () => {
+ await expect(page).toClick("button[data-testid='Sign up'");
+
+ });
+
+ then("Log in screen shows an informative error message and does not allow the user to log in", async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("div[class='chakra-alert__desc css-zzks76'", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Formato de correo electrónico no válido o credenciales (nombre de usuario o correo electrónico) ya en uso"
+ || header === "Invalid email format or credentials (username or email) already in use";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/register_negative_username_already_in_use_form.steps.js b/webapp/e2e/steps/register_negative_username_already_in_use_form.steps.js
new file mode 100644
index 00000000..68e4971d
--- /dev/null
+++ b/webapp/e2e/steps/register_negative_username_already_in_use_form.steps.js
@@ -0,0 +1,65 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/register_form_features/negative_register_username_already_in_use.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("The user is not registered in the root directory of the website and tries to create an account", ({given,when,and,then}) => {
+ let username = "test"
+ let user = username + "@emailNonRepeated.com"
+ let password = "password"
+
+ given("An unregistered user", async () => {
+
+ });
+
+ when("The user fills the data in the form using an already used username", async () => {
+ await expect(page).toClick("span[class='chakra-link css-1bicqx'");
+ await expect(page).toFill("input[id='user'", user);
+ await expect(page).toFill("input[id='username'", username);
+ await expect(page).toFill("#password", password);
+ await expect(page).toFill("input[id='field-:r5:']", password);
+
+ });
+
+ and("Press Log in button", async () => {
+ await expect(page).toClick("button[data-testid='Sign up'");
+
+ });
+
+ then("Log in screen shows an informative error message and does not allow the user to log in", async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("div[class='chakra-alert__desc css-zzks76'", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Formato de correo electrónico no válido o credenciales (nombre de usuario o correo electrónico) ya en uso"
+ || header === "Invalid email format or credentials (username or email) already in use";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/register_negative_wrong_email_format.steps.js b/webapp/e2e/steps/register_negative_wrong_email_format.steps.js
new file mode 100644
index 00000000..18ad8805
--- /dev/null
+++ b/webapp/e2e/steps/register_negative_wrong_email_format.steps.js
@@ -0,0 +1,75 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/register_form_features/negative_register_wrong_email_format.feature');
+const crypto = require('crypto');
+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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("The user is not registered in the root directory of the website and tries to create an account", ({given,when,and,then}) => {
+ // Trying to avoid repeated users:
+ // Generate random bytes
+ let randomBytes = crypto.randomBytes(8); // 8 bytes = 64 bits
+ // Convert bytes to hex
+ let hexString = randomBytes.toString('hex');
+ // Take the first 16 characters
+ let randomHash = hexString.substring(0, 20);
+
+
+
+ let username = "test" + randomHash
+ let user = username + "email.com" // Bad format email
+ let password = "password"
+
+ given("An unregistered user", async () => {
+
+ });
+
+ when("The user fills its data in the form placing a wrong email format", async () => {
+ await expect(page).toClick("span[class='chakra-link css-1bicqx'");
+ await expect(page).toFill("input[id='user'", user);
+ await expect(page).toFill("input[id='username'", username);
+ await expect(page).toFill("#password", password);
+ await expect(page).toFill("input[id='field-:r5:']", password);
+
+ });
+
+ and("Press Log in button", async () => {
+ await expect(page).toClick("button[data-testid='Sign up'");
+
+ });
+
+ then("Log in screen shows an informative error message and does not allow the user to log in", async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("div[class='chakra-alert__desc css-zzks76'", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Formato de correo electrónico no válido o credenciales (nombre de usuario o correo electrónico) ya en uso"
+ || header === "Invalid email format or credentials (username or email) already in use";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/register_positive_form.steps.js b/webapp/e2e/steps/register_positive_form.steps.js
new file mode 100644
index 00000000..ccb366e9
--- /dev/null
+++ b/webapp/e2e/steps/register_positive_form.steps.js
@@ -0,0 +1,75 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/register_form_features/positive_register_form.feature');
+const crypto = require('crypto');
+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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("The user is not registered in the root directory of the website", ({given,when,and,then}) => {
+ // Trying to avoid repeated users:
+ // Generate random bytes
+ let randomBytes = crypto.randomBytes(8); // 8 bytes = 64 bits
+ // Convert bytes to hex
+ let hexString = randomBytes.toString('hex');
+ // Take the first 16 characters
+ let randomHash = hexString.substring(0, 20);
+
+
+
+ let username = "test" + randomHash
+ let user = username + "@email.com"
+ let password = "password"
+
+
+ given("An unregistered user", async () => {
+
+ });
+
+ when("I fill the data in the form", async () => {
+ await expect(page).toClick("span[class='chakra-link css-1bicqx'");
+ await expect(page).toFill("input[id='user'", user);
+ await expect(page).toFill("input[id='username'", username);
+ await expect(page).toFill("#password", password);
+ await expect(page).toFill("input[id='field-:r5:']", password);
+
+ });
+
+ and("click the sign in button", async () => {
+ await expect(page).toClick("button[data-testid='Sign up'");
+
+ });
+
+ then("The main menu screen is shown", async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("h2", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Bienvenid@ " + username || header === "Welcome " + username;
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/seeing_rules_negative_non_logged_user.steps.js b/webapp/e2e/steps/seeing_rules_negative_non_logged_user.steps.js
new file mode 100644
index 00000000..71dcbc2c
--- /dev/null
+++ b/webapp/e2e/steps/seeing_rules_negative_non_logged_user.steps.js
@@ -0,0 +1,64 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/seeing_rules_features/negative_non_logged_user_seeing_rules.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A non-logged user wants to see the rules for the game", ({given,when,then}) => {
+ let username = "pepe"
+ let user = username + "@pepe.com"
+ let password = "pepe"
+
+ let gameURL = "http://localhost:3000/dashboard/game";
+
+ given('A non-logged user in main menu', async () => {
+ let header = await page.$eval("button[data-testid='Login']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ when('User accesses de /rules endpoint via URL', async() => {
+ await page
+ .goto("http://localhost:3000/dashboard/rules", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ then('The user is redirected to the log in screen', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/seeing_rules_positive.steps.js b/webapp/e2e/steps/seeing_rules_positive.steps.js
new file mode 100644
index 00000000..05bd5159
--- /dev/null
+++ b/webapp/e2e/steps/seeing_rules_positive.steps.js
@@ -0,0 +1,79 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/seeing_rules_features/positive_seeing_rules.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A logged user wants to see the rules for the game", ({given,when,and,then}) => {
+ let username = "pepe"
+ let user = username + "@pepe.com"
+ let password = "pepe"
+
+ let gameURL = "http://localhost:3000/dashboard/game";
+
+ given('A logged user in the main menu', async () => {
+ // Entering login screen from root directory
+ await expect(page).toClick("button[data-testid='Login'");
+
+ // Filling the credentials
+ await expect(page).toFill("#user", user);
+ await expect(page).toFill("#password", password);
+
+ // Clicking to send the login request
+ await expect(page).toClick("button[data-testid='Login'");
+
+ // Checking user is in main screen
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Bienvenid@ " + username || header === "Welcome " + username;
+
+ expect(value).toBeTruthy();
+
+ });
+
+ when('The user presses the button for deploying the lateral menu', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+ await expect(page).toClick("#lateralMenuButton");
+
+ });
+
+ and('The user presses the button for seeing the rules', async() => {
+ await expect(page).toClick("button[data-testid='rules']");
+
+ });
+
+ then("The screen shows redirects the user to the rules' screen", async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Rules" || "Reglas";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/seeing_stats_negative_non_logged_user.steps.js b/webapp/e2e/steps/seeing_stats_negative_non_logged_user.steps.js
new file mode 100644
index 00000000..1a97a1cc
--- /dev/null
+++ b/webapp/e2e/steps/seeing_stats_negative_non_logged_user.steps.js
@@ -0,0 +1,65 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/seeing_stats_features/negative_non_logged_user_seeing_stats_stories.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A non-logged user wants to see its stats", ({given,when,then}) => {
+ let username = "pepe"
+ let user = username + "@pepe.com"
+ let password = "pepe"
+
+ let gameURL = "http://localhost:3000/dashboard/game";
+
+ given('A non-logged user in main menu', async () => {
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+ let header = await page.$eval("button[data-testid='Login']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+
+ when('The user accesses to the leader board via URL', async() => {
+ await page
+ .goto("http://localhost:3000/dashboard/statistics", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ then('The user is redirected to the log in screen', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Login" || "Iniciar sesión";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/e2e/steps/seeing_stats_positive.steps.js b/webapp/e2e/steps/seeing_stats_positive.steps.js
new file mode 100644
index 00000000..7db3e127
--- /dev/null
+++ b/webapp/e2e/steps/seeing_stats_positive.steps.js
@@ -0,0 +1,80 @@
+const { defineFeature, loadFeature }=require('jest-cucumber');
+const puppeteer = require('puppeteer');
+const setDefaultOptions = require("expect-puppeteer").setDefaultOptions;
+const feature = loadFeature('./features/seeing_stats_features/positive_seeing-stats.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", {
+ waitUntil: "networkidle0",
+ })
+ .catch(() => {});
+ });
+
+ test("A logged user with many games wants to see its stats", ({given,when,and,then}) => {
+ let username = "pepe"
+ let user = username + "@pepe.com"
+ let password = "pepe"
+
+ let gameURL = "http://localhost:3000/dashboard/game";
+
+ given('A logged user in the main menu with many games', async () => {
+ // Entering login screen from root directory
+ await expect(page).toClick("button[data-testid='Login'");
+
+ // Filling the credentials
+ await expect(page).toFill("#user", user);
+ await expect(page).toFill("#password", password);
+
+ // Clicking to send the login request
+ await expect(page).toClick("button[data-testid='Login'");
+ await new Promise(resolve => setTimeout(resolve, 6000)); // Waiting for page to fully load
+
+ // Checking user is in main screen
+ let header = await page.$eval("h2[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Bienvenid@ " + username || header === "Welcome " + username;
+
+ expect(value).toBeTruthy();
+
+ });
+
+ when('The user presses the button for deploying the lateral menu', async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+ await expect(page).toClick("#lateralMenuButton");
+
+ });
+
+ and('The user presses the button for seeing stats', async() => {
+ await expect(page).toClick("button[data-testid='statistics']");
+
+ });
+
+ then("It successfully displays both, the leader board and the logged user statistics", async() => {
+ await new Promise(resolve => setTimeout(resolve, 6000));
+ let header = await page.$eval("h1[class='chakra-heading css-79qjat']", (element) => {
+ return element.innerHTML
+ })
+ let value = header === "Estadísiticas" || "Statistics";
+
+ expect(value).toBeTruthy();
+ });
+ }, 600000);
+
+ afterAll((done) => {
+ done();
+ });
+});
\ No newline at end of file
diff --git a/webapp/public/img/kiwi-2.gif b/webapp/public/img/kiwi-2.gif
new file mode 100644
index 00000000..19590de3
Binary files /dev/null and b/webapp/public/img/kiwi-2.gif differ
diff --git a/webapp/public/img/kiwi-3.gif b/webapp/public/img/kiwi-3.gif
new file mode 100644
index 00000000..e005034e
Binary files /dev/null and b/webapp/public/img/kiwi-3.gif differ
diff --git a/webapp/public/img/kiwi.gif b/webapp/public/img/kiwi.gif
new file mode 100644
index 00000000..a5205b74
Binary files /dev/null and b/webapp/public/img/kiwi.gif differ
diff --git a/webapp/public/img/kiwi.png b/webapp/public/img/kiwi.png
new file mode 100644
index 00000000..dbdac5df
Binary files /dev/null and b/webapp/public/img/kiwi.png differ
diff --git a/webapp/public/locales/en/translation.json b/webapp/public/locales/en/translation.json
index 3bd09ec6..bcc4745e 100644
--- a/webapp/public/locales/en/translation.json
+++ b/webapp/public/locales/en/translation.json
@@ -98,5 +98,9 @@
"title": "About",
"description1": "We are the WIQ_EN2B group and we are delighted that you like 🥝KIWIQ🥝. Enjoy your meal!!!",
"tableheader": "Developers"
+ },
+ "page404": {
+ "title": "404 - Page not found",
+ "text": "Woops! You seem lost! Click on go back to find your way."
}
}
\ No newline at end of file
diff --git a/webapp/public/locales/es/translation.json b/webapp/public/locales/es/translation.json
index 0b17fb8b..8571b983 100644
--- a/webapp/public/locales/es/translation.json
+++ b/webapp/public/locales/es/translation.json
@@ -97,5 +97,9 @@
"title": "Sobre nosotros",
"description1": "Somos el grupo WIQ_EN2B y estamos encantados de que te guste 🥝KIWIQ🥝. Que aproveche!!!",
"tableheader": "Desarrolladores"
+ },
+ "page404": {
+ "title": "404 - Página no encontrada",
+ "text": "Qué liaste ho? Haz click en volver para regresar pa casina."
}
}
\ No newline at end of file
diff --git a/webapp/src/components/Router.jsx b/webapp/src/components/Router.jsx
index 3ef7bd6d..d3fa1261 100644
--- a/webapp/src/components/Router.jsx
+++ b/webapp/src/components/Router.jsx
@@ -12,6 +12,7 @@ import Statistics from "pages/Statistics";
import ProtectedRoute from "./utils/ProtectedRoute";
import Logout from "pages/Logout";
import About from "pages/About";
+import NotFound from "pages/NotFound";
export default createRoutesFromElements(
@@ -27,5 +28,6 @@ export default createRoutesFromElements(
} />
} />
+ } />
)
diff --git a/webapp/src/components/menu/LateralMenu.jsx b/webapp/src/components/menu/LateralMenu.jsx
index f51a592b..fa964b03 100644
--- a/webapp/src/components/menu/LateralMenu.jsx
+++ b/webapp/src/components/menu/LateralMenu.jsx
@@ -100,6 +100,7 @@ const LateralMenu = ({ isOpen, onClose, changeLanguage, isDashboard }) => {
+
{isLoggedIn && (
diff --git a/webapp/src/pages/NotFound.jsx b/webapp/src/pages/NotFound.jsx
new file mode 100644
index 00000000..d9ace535
--- /dev/null
+++ b/webapp/src/pages/NotFound.jsx
@@ -0,0 +1,36 @@
+import React, { useState } from "react";
+import { useTranslation } from 'react-i18next';
+import { Center, Heading, Stack, Box, Text, Image, Container} from '@chakra-ui/react';
+import { InfoIcon } from '@chakra-ui/icons';
+
+import LateralMenu from '../components/menu/LateralMenu';
+import MenuButton from '../components/menu/MenuButton';
+import GoBack from "components/GoBack";
+import "../styles/animations.css";
+export default function About() {
+ const { t, i18n } = useTranslation();
+ const [isMenuOpen, setIsMenuOpen] = useState(false);
+
+ const changeLanguage = (selectedLanguage) => {
+ i18n.changeLanguage(selectedLanguage);
+ };
+
+ return (
+