From 15a54cd8bbfa1f837acf193f51870d38bee3365d Mon Sep 17 00:00:00 2001 From: Zohaib Akhtar Kausar Date: Mon, 29 Apr 2024 00:21:10 +0200 Subject: [PATCH 1/4] Mejora de coverage en addUser? --- webapp/src/components/pages/AddUser.test.js | 182 +++++++++++++------- 1 file changed, 117 insertions(+), 65 deletions(-) diff --git a/webapp/src/components/pages/AddUser.test.js b/webapp/src/components/pages/AddUser.test.js index e98ec50..96442d0 100644 --- a/webapp/src/components/pages/AddUser.test.js +++ b/webapp/src/components/pages/AddUser.test.js @@ -1,72 +1,124 @@ -import React from 'react'; -import { render, fireEvent, screen, waitFor } from '@testing-library/react'; -import axios from 'axios'; -import MockAdapter from 'axios-mock-adapter'; +import { render, screen } from '@testing-library/react'; import AddUser from './AddUser'; -import { BrowserRouter as Router } from 'react-router-dom'; -import {AuthProvider} from "../../AuthContext"; -const mockAxios = new MockAdapter(axios); +import { BrowserRouter } from 'react-router-dom'; +import { AuthContext } from '../../AuthContext'; +import { fireEvent, waitFor } from '@testing-library/react'; +import axios from 'axios'; +jest.mock('axios'); +const mockHandleLogin = jest.fn(); + +test('renderiza el formulario de registro', () => { + render( + + + + + + ); + + expect(screen.getByLabelText(/nombre de usuario/i)).toBeInTheDocument(); + expect(screen.getByLabelText(/contraseña/i)).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /registrarse/i })).toBeInTheDocument(); +}); +test('Errores de validacion al crear una nueva cuenta', async () => { + render( + + + + + + ); + + fireEvent.change(screen.getByLabelText(/nombre de usuario/i), { target: { value: 'abc' } }); + fireEvent.click(screen.getByRole('button', { name: /registrarse/i })); + + await waitFor(() => { + expect(screen.getByText(/el nombre de usuario debe tener al menos 4 caracteres/i)).toBeInTheDocument(); + }); +}); + +test('La contraseña debe tener al menos 8 caracteres', async () => { + render( + + + + + + ); + + fireEvent.change(screen.getByLabelText(/nombre de usuario/i), { target: { value: 'testuser' } }); + fireEvent.change(screen.getByLabelText(/contraseña/i), { target: { value: 'abc' } }); + fireEvent.click(screen.getByRole('button', { name: /registrarse/i })); + + await waitFor(() => { + expect(screen.getByText(/la contraseña debe tener al menos 8 caracteres/i)).toBeInTheDocument(); + }); +}); + +test('El user debe tener al menos 4 caracteres', async () => { + render( + + + + + + ); + + fireEvent.change(screen.getByLabelText(/nombre de usuario/i), { target: { value: 'testuser' } }); + fireEvent.change(screen.getByLabelText(/contraseña/i), { target: { value: 'abcdefgh' } }); + fireEvent.click(screen.getByRole('button', { name: /registrarse/i })); -describe('AddUser component', () => { - beforeEach(() => { - mockAxios.reset(); + await waitFor(() => { + expect(screen.getByText(/la contraseña debe contener al menos una letra mayúscula/i)).toBeInTheDocument(); }); +}); + +test('La contraseña debe contener al menos un número', async () => { + render( + + + + + + ); + + fireEvent.change(screen.getByLabelText(/nombre de usuario/i), { target: { value: 'testuser' } }); + fireEvent.change(screen.getByLabelText(/contraseña/i), { target: { value: 'Abcdefgh' } }); + fireEvent.click(screen.getByRole('button', { name: /registrarse/i })); - it('should add user successfully', async () => { - render( - - - - - - ); - - const usernameInput = screen.getByLabelText(/Nombre de Usuario/i); - const passwordInput = screen.getByLabelText(/Contraseña/i); - const addUserButton = screen.getByRole('button', { name: /Registrarse/i }); - - // Mock the axios.post request to simulate a successful response - mockAxios.onPost('http://localhost:8000/adduser').reply(200); - - // Simulate user input - fireEvent.change(usernameInput, { target: { value: 'testUser' } }); - fireEvent.change(passwordInput, { target: { value: 'testPassword2' } }); - - // Trigger the add user button click - fireEvent.click(addUserButton); - - // Wait for the Snackbar to be open - await waitFor(() => { - expect(screen.getByText(/Usuario añadido correctamente/i)).toBeInTheDocument(); - }); + await waitFor(() => { + expect(screen.getByText(/la contraseña debe contener al menos un número/i)).toBeInTheDocument(); }); +}); +test('Registro exitoso de usuario', async () => { + // Simular respuesta exitosa de la API + axios.post.mockImplementation((url) => { + if (url.includes('/adduser')) { + return Promise.resolve({ status: 200 }); + } else if (url.includes('/login')) { + return Promise.resolve({ data: { token: 'fakeToken123' } }); + } + }); + + render( + + + + + + ); + + // Llenar el formulario con datos válidos + fireEvent.change(screen.getByLabelText(/nombre de usuario/i), { target: { value: 'validUser' } }); + fireEvent.change(screen.getByLabelText(/contraseña/i), { target: { value: 'Valid1234' } }); + fireEvent.click(screen.getByRole('button', { name: /registrarse/i })); - it('should handle error when adding user', async () => { - render( - - - - - - ); - - const usernameInput = screen.getByLabelText(/Nombre de Usuario/i); - const passwordInput = screen.getByLabelText(/Contraseña/i); - const addUserButton = screen.getByRole('button', { name: /Registrarse/i }); - - // Mock the axios.post request to simulate an error response - mockAxios.onPost('http://localhost:8000/adduser').reply(500, { error: 'Internal Server Error' }); - - // Simulate user input - fireEvent.change(usernameInput, { target: { value: 'testUser' } }); - fireEvent.change(passwordInput, { target: { value: 'testPassword2' } }); - - // Trigger the add user button click - fireEvent.click(addUserButton); - - // Wait for the error Snackbar to be open - await waitFor(() => { - expect(screen.getByText(/Error: Internal Server Error/i)).toBeInTheDocument(); - }); + // Esperar que se llame a handleLogin y luego navegar a '/' + await waitFor(() => { + expect(screen.getByText('Usuario añadido correctamente')).toBeInTheDocument(); }); -}); \ No newline at end of file + + // Verificar redireccionamiento a la página inicial + expect(window.location.pathname).toBe('/'); +}); + From 9a96b0c326cf515d58791f17982c70b9ddaed49e Mon Sep 17 00:00:00 2001 From: Zohaib Akhtar Kausar Date: Mon, 29 Apr 2024 00:40:31 +0200 Subject: [PATCH 2/4] Mejora de coverage en AboutUs? --- webapp/src/components/pages/AboutUS.test.js | 59 +++++++++++++++------ 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/webapp/src/components/pages/AboutUS.test.js b/webapp/src/components/pages/AboutUS.test.js index 0b3847d..53f7e82 100644 --- a/webapp/src/components/pages/AboutUS.test.js +++ b/webapp/src/components/pages/AboutUS.test.js @@ -4,30 +4,59 @@ import '@testing-library/jest-dom'; import AboutUS from './AboutUS'; import {BrowserRouter as Router} from "react-router-dom"; -// Describimos la suite de pruebas para el componente AboutUS describe('AboutUS Component', () => { - test('renders the header text', () => { - + beforeEach(() => { render( ); - // Verificamos que el texto del encabezado esté presente en el documento - expect(screen.getByText(/Conoce las áreas clave manejadas por los estudiantes en el proyecto WIQ/i)).toBeInTheDocument(); }); - // Test para verificar si el componente renderiza los elementos CardItem correctamente - test('renders the correct number of CardItem elements', () => { - render( - - - - ); - // Usamos queryAllByTestId para seleccionar todos los elementos con el data-testid "card-item" + test('renders the header text and the card items', () => { + expect(screen.getByText(/Conoce las áreas clave manejadas por los estudiantes en el proyecto WIQ/i)).toBeInTheDocument(); const cardItems = screen.queryAllByTestId('card-item'); - // Verificamos que el número de elementos encontrados sea el esperado - expect(cardItems).toHaveLength(5); // Cambia el número esperado según cuántos CardItem esperas renderizar + expect(cardItems).toHaveLength(5); + }); + + test('links point to the correct paths', () => { + const creditosLink = screen.getByText(/Créditos de la Aplicación/i).closest('a'); + expect(creditosLink).toHaveAttribute('href', '/creditos'); + + const githubLink = screen.getByText(/Explora nuestro código en GitHub y contribuye al desarrollo del proyecto WIQ./i).closest('a'); + expect(githubLink).toHaveAttribute('href', 'https://github.com/Arquisoft/wiq_es04d'); + + const databaseLink = screen.getByText(/Implementación de soluciones de bases de datos para gestionar eficientemente la información./i).closest('a'); + expect(databaseLink).toHaveAttribute('href', 'https://github.com/Arquisoft/wiq_es04d/wiki/ADR-4-%E2%80%90-Base-de-datos'); + + const documentationLink = screen.getByText(/Creación de documentación detallada para facilitar la comprensión y el uso del proyecto./i).closest('a'); + expect(documentationLink).toHaveAttribute('href', 'https://arquisoft.github.io/wiq_es04d/'); + + const apiLink = screen.getByText(/Desarrollo de la lógica de integración con la API de Wikidata para enriquecer nuestro proyecto./i).closest('a'); + expect(apiLink).toHaveAttribute('href', `${process.env.REACT_APP_API_ENDPOINT || 'http://localhost:8000'}/api-doc`); }); + test('each CardItem has the correct label', () => { + // Asegúrate de que ya has renderizado el componente en un beforeEach o directamente en el test + const figures = document.querySelectorAll('figure[data-category]'); + const expectedLabels = ['Créditos', 'GitHub WIQ4D', 'Base de Datos', 'Documentación', 'API de Wikidata']; + + expect(figures.length).toBe(expectedLabels.length); // Verifica que el número de elementos coincide + figures.forEach((figure, index) => { + expect(figure.getAttribute('data-category')).toBe(expectedLabels[index]); + }); + }); + test('each CardItem has the correct src', () => { + const images = document.querySelectorAll('img[src]'); // Correctamente selecciona las imágenes + const expectedSrcs = ['images/creditos.jpg', 'images/github.jpg', 'images/database.jpg', 'images/documentation.jpg', 'images/api-logic.jpg']; + + expect(images.length).toBe(expectedSrcs.length); + images.forEach((img, index) => { + expect(img.src).toContain(expectedSrcs[index]); + }); + }); + + + + }); From a2918c79ab89f3ba7435b480700d851b40f65ad5 Mon Sep 17 00:00:00 2001 From: Zohaib Akhtar Kausar Date: Mon, 29 Apr 2024 00:52:29 +0200 Subject: [PATCH 3/4] Mejora de coverage en gatewayservice? --- gatewayservice/gateway-service.test.js | 90 +++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/gatewayservice/gateway-service.test.js b/gatewayservice/gateway-service.test.js index 5d0267b..13b05fe 100644 --- a/gatewayservice/gateway-service.test.js +++ b/gatewayservice/gateway-service.test.js @@ -1,7 +1,7 @@ const request = require('supertest'); const axios = require('axios'); const app = require('./gateway-service'); - +const userServiceUrl = process.env.USER_SERVICE_URL || 'http://localhost:8001'; afterAll(async () => { app.close(); }); @@ -275,7 +275,95 @@ describe('Gateway Service', () => { expect(response.statusCode).toBe(404); expect(response.body.error).toBe('User not found'); }); +}); +describe('User API Endpoints', () => { + beforeEach(() => { + jest.resetAllMocks(); // Clear previous mocks between tests + }); + + // Test for GET /user + it('should retrieve user data successfully', async () => { + const mockUserData = [{ id: 'user1', name: 'John Doe' }]; + axios.get.mockResolvedValueOnce({ data: mockUserData }); + + const response = await request(app).get('/user'); + + expect(response.statusCode).toBe(200); + expect(response.body).toEqual(mockUserData); + expect(axios.get).toHaveBeenCalledWith(`${userServiceUrl}/user`); + }); + + it('should handle failure when retrieving user data', async () => { + axios.get.mockRejectedValueOnce({ response: { status: 404, data: { error: 'User not found' } } }); + + const response = await request(app).get('/user'); + + expect(response.statusCode).toBe(404); + expect(response.body.error).toBe('User not found'); + }); + + // Test for POST /user + it('should create a user successfully', async () => { + const newUser = { username: 'newuser', password: 'password123' }; + axios.post.mockResolvedValueOnce({ data: { userId: '12345' } }); + + const response = await request(app).post('/user').send(newUser); + + expect(response.statusCode).toBe(201); + expect(response.body.userId).toBe('12345'); + expect(axios.post).toHaveBeenCalledWith(`${userServiceUrl}/adduser`, newUser); + }); + + it('should handle failure when creating a user', async () => { + const newUser = { username: 'newuser', password: 'password123' }; + axios.post.mockRejectedValueOnce({ response: { status: 500, data: { error: 'Error creating the user' } } }); + const response = await request(app).post('/user').send(newUser); + + expect(response.statusCode).toBe(500); + expect(response.body.error).toBe('Error creating the user'); + }); + // Test for PATCH /user/:id + it('should update user data successfully', async () => { + const updates = { name: 'Jane Doe' }; + axios.patch.mockResolvedValueOnce({ data: { status: 'OK' } }); + const response = await request(app).patch('/user/1').send(updates); + + expect(response.statusCode).toBe(200); + expect(response.body.status).toBe('OK'); + expect(axios.patch).toHaveBeenCalledWith(`${userServiceUrl}/user/1`, updates); + }); + + it('should handle failure when updating user data', async () => { + const updates = { name: 'Jane Doe' }; + axios.patch.mockRejectedValueOnce({ response: { status: 404, data: { error: 'User not found' } } }); + + const response = await request(app).patch('/user/1').send(updates); + + expect(response.statusCode).toBe(404); + expect(response.body.error).toBe('User not found'); + }); + + // Test for DELETE /user/:id + it('should delete a user successfully', async () => { + axios.delete.mockResolvedValueOnce({ data: { status: 'OK' } }); + + const response = await request(app).delete('/user/1'); + + expect(response.statusCode).toBe(200); + expect(response.body.status).toBe('OK'); + expect(axios.delete).toHaveBeenCalledWith(`${userServiceUrl}/user/1`, {}); + }); + + it('should handle failure when deleting a user', async () => { + axios.delete.mockRejectedValueOnce({ response: { status: 404, data: { error: 'User not found' } } }); + + const response = await request(app).delete('/user/1'); + + expect(response.statusCode).toBe(404); + expect(response.body.error).toBe('User not found'); + }); }); + From 8c79a126bd6a61335517da34901f238d5aaed0c9 Mon Sep 17 00:00:00 2001 From: Zohaib Akhtar Kausar Date: Mon, 29 Apr 2024 01:03:59 +0200 Subject: [PATCH 4/4] Refactorizacion para reducir codigo duplicado --- webapp/src/components/pages/AddUser.test.js | 169 ++++++++------------ 1 file changed, 66 insertions(+), 103 deletions(-) diff --git a/webapp/src/components/pages/AddUser.test.js b/webapp/src/components/pages/AddUser.test.js index 96442d0..0b6fc8b 100644 --- a/webapp/src/components/pages/AddUser.test.js +++ b/webapp/src/components/pages/AddUser.test.js @@ -1,124 +1,87 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import AddUser from './AddUser'; import { BrowserRouter } from 'react-router-dom'; import { AuthContext } from '../../AuthContext'; -import { fireEvent, waitFor } from '@testing-library/react'; import axios from 'axios'; + jest.mock('axios'); const mockHandleLogin = jest.fn(); +function renderAddUser() { + return render( + + + + + + ); +} + +function fillAndSubmitForm(username, password) { + fireEvent.change(screen.getByLabelText(/nombre de usuario/i), { target: { value: username } }); + fireEvent.change(screen.getByLabelText(/contraseña/i), { target: { value: password } }); + fireEvent.click(screen.getByRole('button', { name: /registrarse/i })); +} + test('renderiza el formulario de registro', () => { - render( - - - - - - ); - - expect(screen.getByLabelText(/nombre de usuario/i)).toBeInTheDocument(); - expect(screen.getByLabelText(/contraseña/i)).toBeInTheDocument(); - expect(screen.getByRole('button', { name: /registrarse/i })).toBeInTheDocument(); + renderAddUser(); + expect(screen.getByLabelText(/nombre de usuario/i)).toBeInTheDocument(); + expect(screen.getByLabelText(/contraseña/i)).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /registrarse/i })).toBeInTheDocument(); }); + test('Errores de validacion al crear una nueva cuenta', async () => { - render( - - - - - - ); - - fireEvent.change(screen.getByLabelText(/nombre de usuario/i), { target: { value: 'abc' } }); - fireEvent.click(screen.getByRole('button', { name: /registrarse/i })); - - await waitFor(() => { - expect(screen.getByText(/el nombre de usuario debe tener al menos 4 caracteres/i)).toBeInTheDocument(); - }); + renderAddUser(); + fillAndSubmitForm('abc', '12345678'); + + await waitFor(() => { + expect(screen.getByText(/el nombre de usuario debe tener al menos 4 caracteres/i)).toBeInTheDocument(); + }); }); test('La contraseña debe tener al menos 8 caracteres', async () => { - render( - - - - - - ); - - fireEvent.change(screen.getByLabelText(/nombre de usuario/i), { target: { value: 'testuser' } }); - fireEvent.change(screen.getByLabelText(/contraseña/i), { target: { value: 'abc' } }); - fireEvent.click(screen.getByRole('button', { name: /registrarse/i })); - - await waitFor(() => { - expect(screen.getByText(/la contraseña debe tener al menos 8 caracteres/i)).toBeInTheDocument(); - }); + renderAddUser(); + fillAndSubmitForm('testuser', 'abc'); + + await waitFor(() => { + expect(screen.getByText(/la contraseña debe tener al menos 8 caracteres/i)).toBeInTheDocument(); + }); }); -test('El user debe tener al menos 4 caracteres', async () => { - render( - - - - - - ); - - fireEvent.change(screen.getByLabelText(/nombre de usuario/i), { target: { value: 'testuser' } }); - fireEvent.change(screen.getByLabelText(/contraseña/i), { target: { value: 'abcdefgh' } }); - fireEvent.click(screen.getByRole('button', { name: /registrarse/i })); - - await waitFor(() => { - expect(screen.getByText(/la contraseña debe contener al menos una letra mayúscula/i)).toBeInTheDocument(); - }); +test('La contraseña debe contener al menos una letra mayúscula', async () => { + renderAddUser(); + fillAndSubmitForm('testuser', 'abcdefgh'); + + await waitFor(() => { + expect(screen.getByText(/la contraseña debe contener al menos una letra mayúscula/i)).toBeInTheDocument(); + }); }); test('La contraseña debe contener al menos un número', async () => { - render( - - - - - - ); - - fireEvent.change(screen.getByLabelText(/nombre de usuario/i), { target: { value: 'testuser' } }); - fireEvent.change(screen.getByLabelText(/contraseña/i), { target: { value: 'Abcdefgh' } }); - fireEvent.click(screen.getByRole('button', { name: /registrarse/i })); - - await waitFor(() => { - expect(screen.getByText(/la contraseña debe contener al menos un número/i)).toBeInTheDocument(); - }); + renderAddUser(); + fillAndSubmitForm('testuser', 'Abcdefgh'); + + await waitFor(() => { + expect(screen.getByText(/la contraseña debe contener al menos un número/i)).toBeInTheDocument(); + }); }); + test('Registro exitoso de usuario', async () => { - // Simular respuesta exitosa de la API - axios.post.mockImplementation((url) => { - if (url.includes('/adduser')) { - return Promise.resolve({ status: 200 }); - } else if (url.includes('/login')) { - return Promise.resolve({ data: { token: 'fakeToken123' } }); - } - }); - - render( - - - - - - ); - - // Llenar el formulario con datos válidos - fireEvent.change(screen.getByLabelText(/nombre de usuario/i), { target: { value: 'validUser' } }); - fireEvent.change(screen.getByLabelText(/contraseña/i), { target: { value: 'Valid1234' } }); - fireEvent.click(screen.getByRole('button', { name: /registrarse/i })); - - // Esperar que se llame a handleLogin y luego navegar a '/' - await waitFor(() => { - expect(screen.getByText('Usuario añadido correctamente')).toBeInTheDocument(); - }); - - // Verificar redireccionamiento a la página inicial - expect(window.location.pathname).toBe('/'); + axios.post.mockImplementation((url) => { + if (url.includes('/adduser')) { + return Promise.resolve({ status: 200 }); + } else if (url.includes('/login')) { + return Promise.resolve({ data: { token: 'fakeToken123' } }); + } + }); + + renderAddUser(); + fillAndSubmitForm('validUser', 'Valid1234'); + + await waitFor(() => { + expect(screen.getByText('Usuario añadido correctamente')).toBeInTheDocument(); + }); + + // Verificar redireccionamiento a la página inicial + expect(window.location.pathname).toBe('/'); }); -