rluca6448

Untitled

Oct 20th, 2024
10
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //App.js:
  2. import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
  3. import LandingPage from "./components/Pages/LandingPage/LandingPage";
  4. import HomePage from "./components/Pages/HomePage/HomePage";
  5. import Contact from "./components/Pages/Support/Support";
  6. import RegisterPage from "./components/Pages/Register/Register";
  7. import Login from "./components/Pages/Login/Login";
  8. import BenefitDetail from "./components/Pages/BenefitDetail/BenefitDetail";
  9. import Verification from "./components/Pages/Verification/Verification";
  10. import Verified from "./components/Pages/Verified/Verified";
  11. import ActivityPage from "./components/Pages/Activities/ActivityPage";
  12. import TuristicPage from "./components/Pages/Activities/TuristicPage";
  13. import SocialPage from "./components/Pages/Activities/SocialPage";
  14. import AcademicPage from "./components/Pages/Activities/AcademicPage";
  15. import AcademicDetail from "./components/Pages/Activities/AcademicDetail";
  16. import SocialDetail from "./components/Pages/Activities/SocialDetail";
  17. import TuristicDetail from "./components/Pages/Activities/TuristicDetail";
  18.  
  19. const App = () => {
  20.   return (
  21.     <div className="bg-pearl min-h-screen text-roboto">
  22.       <Router>
  23.         <Routes>
  24.           <Route path="/" element={<LandingPage />} />
  25.           <Route path="/Beneficios" element={<HomePage />} />
  26.           <Route path="/Contact" element={<Contact />} />
  27.           <Route path="/Register" element={<RegisterPage />} />
  28.           <Route path="/Login" element={<Login />} />
  29.           <Route path="/benefit/:benefitId" element={<BenefitDetail />} />
  30.           <Route path="/Actividades/:id/academicDetail" element={<AcademicDetail />} />
  31.           <Route path="/Actividades/:id/socialDetail" element={<SocialDetail />} />
  32.           <Route path="/Actividades/:id/turisticDetail" element={<TuristicDetail />} />
  33.           <Route path="/Verification" element={<Verification />} />
  34.           <Route path="/Verified/:token" element={<Verified />} />
  35.           <Route path="/Actividades" element={<ActivityPage/>}/>
  36.           <Route path="/Actividades/:university_id/turisticPage" element={<TuristicPage/>}/>
  37.           <Route path="/Actividades/:university_id/socialPage" element={<SocialPage/>}/>
  38.           <Route path="/Actividades/:university_id/academicPage" element={<AcademicPage/>}/>
  39.       </Routes>
  40.       </Router>
  41.     </div>
  42.   );
  43. };
  44.  
  45. export default App;
  46. ------------------------------------------------------------
  47.  
  48. //HomePage.js:
  49. import { useState, useEffect } from 'react';
  50. import { useLocation } from 'react-router-dom';
  51. import CategoryButton from '../../CategoryButton';
  52. import BenefitSearch from '../../BenefitSearch';
  53. import NavBar from '../../NavBar';
  54. import Carousel from '../../Carousel';
  55. import BenefitCard from '../../BenefitCard';
  56. import { useNavigate } from "react-router-dom"; // Importa useNavigate
  57. import BenefitFloatingButton from '../../BenefitFloatingButton';
  58.  
  59. function HomePage() {
  60.   const location = useLocation();
  61.   const queryParams = new URLSearchParams(location.search);
  62.   const [categories, setCategories] = useState([]);
  63.   const [activeCategory, setActiveCategory] = useState(null); // Estado para saber qué botón está subrayado
  64.   const universityId = queryParams.get('university');
  65.   const [images, setImages] = useState([]);
  66.   const [selectedCategory, setSelectedCategory] = useState(null);
  67.   const [benefits, setBenefits] = useState([]);
  68.  
  69.   const navigate = useNavigate(); //inicializa useNavigate
  70.  
  71.   useEffect(() => {
  72.     const fetchCategories = async () => {
  73.       try {
  74.         const response = await fetch(
  75.           `${process.env.REACT_APP_API_URL}/benefits/${universityId}/categories`,
  76.           {
  77.             method: 'GET',
  78.             headers: {
  79.               'Content-Type': 'application/json',
  80.             },
  81.           }
  82.         );
  83.  
  84.         if (!response.ok) {
  85.           throw new Error('Error fetching categories');
  86.         }
  87.  
  88.         const categories = await response.json();
  89.         setCategories(categories);
  90.       } catch (error) {
  91.         console.error('Error fetching categories:', error);
  92.       }
  93.     };
  94.  
  95.     fetchCategories();
  96.   }, [universityId]);
  97.  
  98.   useEffect(() => {
  99.     const fetchImages = async () => {
  100.       try {
  101.         const response = await fetch(
  102.           `${process.env.REACT_APP_API_URL}/benefits/${universityId}/featured_images`,
  103.           {
  104.             method: "GET",
  105.             headers: {
  106.               "Content-Type": "application/json",
  107.             },
  108.           }
  109.         );
  110.  
  111.         if (!response.ok) {
  112.           throw new Error("Error fetching categories");
  113.         }
  114.  
  115.         const featured_images = await response.json();
  116.  
  117.         setImages(featured_images);
  118.       } catch (error) {
  119.         console.error("Error fetching featured images:", error);
  120.       }
  121.     };
  122.  
  123.     fetchImages();
  124.   }, [universityId]);
  125.  
  126.  
  127.   useEffect(() => {
  128.     const fetchBenefitsByCategory = async () => {
  129.       if (!selectedCategory) return; // Si no hay categoría seleccionada, no hacer nada
  130.  
  131.       try {
  132.         const response = await fetch(
  133.           `${process.env.REACT_APP_API_URL}/benefits/${universityId}/${selectedCategory}`,
  134.           {
  135.             method: "GET",
  136.             headers: {
  137.               "Content-Type": "application/json",
  138.             },
  139.           }
  140.         );
  141.  
  142.         if (!response.ok) {
  143.           throw new Error("Error fetching benefits");
  144.         }
  145.  
  146.         const benefits = await response.json();
  147.  
  148.         // Actualizar el estado con los beneficios filtrados
  149.         setBenefits((prevBenefits) => ({
  150.           ...prevBenefits,
  151.           [selectedCategory]: benefits,
  152.         }));
  153.       } catch (error) {
  154.         console.error("Error fetching benefits:", error);
  155.       }
  156.     };
  157.  
  158.     fetchBenefitsByCategory();
  159.   }, [selectedCategory, universityId]);
  160.  
  161.   const handleCategoryClick = (categoryName) => {
  162.     setActiveCategory(categoryName); // Actualiza la categoría activa
  163.     setSelectedCategory(categoryName); // Actualiza la categoría seleccionada para filtrar los beneficios
  164.   };
  165.  
  166.   const handleCardClick = (benefitId, category) => {
  167.     navigate(`/benefit/${benefitId}?benefitId=${benefitId}`); // Redirige con benefitId y category
  168.   };
  169.  
  170.   return (
  171.     <div>
  172.       <div className="relative">
  173.         {/* NavBar */}
  174.         <div>
  175.           <NavBar sections={["Beneficios", "Actividades", "Hospedajes", "Conectarse", "Chats"]} />
  176.         </div>
  177.  
  178.         {/* Benefit Search positioned above the carousel */}
  179.       <div className="absolute top-15 left-1/2 transform -translate-x-1/2 z-20">
  180.         <BenefitSearch />
  181.       </div>
  182.  
  183.         {/* Carousel */}
  184.         <div>
  185.           <Carousel images={images} />
  186.         </div>
  187.  
  188.         {/* Category Buttons */}
  189.         <div className="absolute top-1/5 left-1/2 transform -translate-x-1/2 -translate-y-1/2 flex justify-center items-center space-x-[43px] z-20">
  190.           {categories.length > 0 ? (
  191.             categories.map((category, index) => (
  192.               <CategoryButton
  193.                 key={index}
  194.                 categoryName={category.name}
  195.                 icon={category.base64image}
  196.                 isActive={activeCategory === category.name} // Compara si esta categoría está activa
  197.                 onClick={() => handleCategoryClick(category.name)} // Asigna la función para manejar clics
  198.               />
  199.             ))
  200.           ) : (
  201.             <p className="col-span-3 text-center">No categories available</p>
  202.           )}
  203.         </div>
  204.       </div>
  205.  
  206.       {/* Benefit Cards */}
  207.       <div className="relative mt-40 flex flex-wrap justify-center space-x-4 z-10">
  208.         {selectedCategory && benefits[selectedCategory] &&
  209.           benefits[selectedCategory].map((benefit, index) => (
  210.             <BenefitCard
  211.               key={index}
  212.               imageUrl={benefit.images[0]}
  213.               alt={benefit.name}
  214.               title={benefit.name}
  215.               onClick={() => handleCardClick(benefit.id, selectedCategory)}
  216.             />
  217.           ))
  218.         }
  219.       </div>
  220.  
  221.       <BenefitFloatingButton/>
  222.      
  223.     </div>
  224.   );
  225.  
  226. }
  227.  
  228. export default HomePage;
  229.  
  230. HomePage.test.js:
  231. import React from 'react';//Es necesario importar React cuando se trabaja con componentes de React, aunque no se utilice directamente en el test.
  232. import { render, screen } from '@testing-library/react';//render:Función de @testing-library/react que permite renderizar un componente React en un entorno de prueba.screen: Herramienta que facilita la selección de elementos renderizados dentro del DOM de pruebas (por ejemplo, getByText, findByText).
  233. import HomePage from '../components/Pages/HomePage/HomePage';
  234. import { BrowserRouter } from 'react-router-dom';//BrowserRouter: Es necesario para envolver el componente en pruebas ya que HomePage depende del enrutamiento
  235. import { act } from 'react';
  236.  
  237.  
  238. test('renders HomePage with NavBar and Category buttons', async () => {
  239.   //global.fetch: Aquí se está creando un mock para la función fetch. fetch se utiliza normalmente para hacer llamadas a la API, y este mock evita que se realicen llamadas reales en el test.
  240.   global.fetch = jest.fn(() => //jest.fn(): Crea un mock de la función fetch, que se comporta de una manera controlada.
  241.     Promise.resolve({ //Promise.resolve(): Simula una respuesta exitosa de la API devolviendo una promesa resuelta.
  242.       ok: true, //ok: true: Simula una respuesta HTTP exitosa.
  243.       //json: () => Promise.resolve([...]): Simula que la respuesta de la API tiene un método json() que devuelve una promesa con una lista de categorías, cada una con un name (nombre) y base64image (una imagen codificada en base64).
  244.       json: () => Promise.resolve([
  245.         { name: "Deportes", base64image: "icon_deportes" },
  246.         { name: "Comida", base64image: "icon_comida" }
  247.       ]),
  248.     })
  249.   );
  250.  
  251.   //render: Renderiza el componente HomePage dentro de un BrowserRouter. Esto es necesario porque HomePage podría usar funciones o enlaces de React Router, que necesitan un contexto de router para funcionar
  252.   //correctamente.
  253.   render(
  254.     <BrowserRouter>
  255.       <HomePage />
  256.     </BrowserRouter>
  257.   );
  258.  
  259.   //screen.getByText(): Busca en el DOM de prueba un elemento que contenga el texto "Beneficios". El uso de /Beneficios/i es una expresión regular que busca el texto sin importar mayúsculas o minúsculas.
  260.   //expect(...).toBeInTheDocument(): Verifica que este elemento realmente exista en el DOM. Esto asegura que el NavBar (o algún otro componente relacionado) que contiene la palabra "Beneficios" se haya renderizado correctamente.
  261.   expect(screen.getByText(/Beneficios/i)).toBeInTheDocument();
  262.  
  263.   // Verificar que los botones de categorías se renderizan
  264.   const categoryButton = await screen.findByText("Deportes");
  265.   expect(categoryButton).toBeInTheDocument();
  266.  
  267.   // Limpieza del mock
  268.   global.fetch.mockClear();
  269. });
  270.  
  271. //En resumen: El propósito de HomePage.test.js es verificar que los componentes principales de la página de inicio (HomePage.js) se rendericen correctamente y funcionen según lo esperado.
  272.  
  273.  
  274. ActivityPage.test.js:
  275. // ActivityPage.test.js
  276. import { render, screen, fireEvent } from '@testing-library/react';
  277. import ActivityPage from '../components/Pages/Activities/ActivityPage';
  278. import { BrowserRouter } from 'react-router-dom';
  279. import '@testing-library/jest-dom'; //Agrega funciones adicionales de jest-dom que extienden Jest para hacer más fácil verificar la presencia de elementos en el DOM, como toBeInTheDocument().
  280. import { useNavigate } from 'react-router-dom';
  281. import { act } from 'react';
  282.  
  283.  
  284. // Mueve el mock de `useNavigate` fuera de la función de prueba
  285. jest.mock('react-router-dom', () => ({ //jest.mock: Sobrescribe el módulo react-router-dom en el contexto del test
  286.   ...jest.requireActual('react-router-dom'), // Mantén las funcionalidades originales de react-router-dom
  287.   useNavigate: jest.fn(), // Crea un mock del hook useNavigate, que reemplaza la implementación real por una función simulada (jest.fn()). Esto permite controlar y verificar cuándo se llama a navigate en las pruebas.
  288. }));
  289.  
  290. test('renders activity type buttons and handles navigation', () => { //Define una prueba con Jest. El nombre de la prueba es 'renders activity type buttons and handles navigation' y el contenido es una función anónima que realiza las verificaciones.
  291.   const mockNavigate = jest.fn(); //Crea un mock manual para navigate, que simula la función de navegación en el componente.
  292.   useNavigate.mockReturnValue(mockNavigate); // Define que cuando useNavigate sea llamado en el componente, en lugar de usar la versión real, devuelva la función mockNavigate, que es un mock y permite capturar su uso durante el test.
  293.  
  294.   // render: Renderiza el componente ActivityPage envuelto en un BrowserRouter, ya que ActivityPage necesita un router para manejar la navegación.
  295. //<BrowserRouter>: Proporciona el contexto necesario de enrutamiento para el componente.
  296.   render(
  297.     <BrowserRouter>
  298.       <ActivityPage />
  299.     </BrowserRouter>
  300.   );
  301.  
  302.   // Verifica que se rendericen los botones de actividad
  303.   const turisticButton = screen.getByText('Turísticas');
  304.   const socialButton = screen.getByText('Sociales');
  305.   const academicButton = screen.getByText('Académicas');
  306.  
  307.   //Verifica que los botones correspondientes efectivamente estén presentes en el DOM usando expect con el matcher toBeInTheDocument
  308.   expect(turisticButton).toBeInTheDocument();
  309.   expect(socialButton).toBeInTheDocument();
  310.   expect(academicButton).toBeInTheDocument();
  311.  
  312.   // Simula clic en el botón de actividades académicas
  313.   fireEvent.click(academicButton);
  314.  
  315.   // Verifica que, después de hacer clic en el botón, la función navigate haya sido llamada con la URL esperada
  316.   expect(mockNavigate).toHaveBeenCalledWith('/Actividades/de61ec4a-dc96-46ec-a951-572332f10477/academicPage');
  317. });
  318.  
  319.  
  320. //En resumen: Este test verifica que los botones se rendericen correctamente y que, al hacer clic en el botón "Académicas", se llame a navigate con la URL correcta para la página académica.
  321. -----------------------------------------------------------------------------------------------------------------------------------------------------------
  322. ActivityPage.test.js:
  323. // ActivityPage.test.js
  324. import { render, screen, fireEvent } from '@testing-library/react';
  325. import ActivityPage from '../components/Pages/Activities/ActivityPage';
  326. import { BrowserRouter } from 'react-router-dom';
  327. import '@testing-library/jest-dom'; //Agrega funciones adicionales de jest-dom que extienden Jest para hacer más fácil verificar la presencia de elementos en el DOM, como toBeInTheDocument().
  328. import { useNavigate } from 'react-router-dom';
  329. import { act } from 'react';
  330.  
  331.  
  332. // Mueve el mock de `useNavigate` fuera de la función de prueba
  333. jest.mock('react-router-dom', () => ({ //jest.mock: Sobrescribe el módulo react-router-dom en el contexto del test
  334.   ...jest.requireActual('react-router-dom'), // Mantén las funcionalidades originales de react-router-dom
  335.   useNavigate: jest.fn(), // Crea un mock del hook useNavigate, que reemplaza la implementación real por una función simulada (jest.fn()). Esto permite controlar y verificar cuándo se llama a navigate en las pruebas.
  336. }));
  337.  
  338. test('renders activity type buttons and handles navigation', () => { //Define una prueba con Jest. El nombre de la prueba es 'renders activity type buttons and handles navigation' y el contenido es una función anónima que realiza las verificaciones.
  339.   const mockNavigate = jest.fn(); //Crea un mock manual para navigate, que simula la función de navegación en el componente.
  340.   useNavigate.mockReturnValue(mockNavigate); // Define que cuando useNavigate sea llamado en el componente, en lugar de usar la versión real, devuelva la función mockNavigate, que es un mock y permite capturar su uso durante el test.
  341.  
  342.   // render: Renderiza el componente ActivityPage envuelto en un BrowserRouter, ya que ActivityPage necesita un router para manejar la navegación.
  343. //<BrowserRouter>: Proporciona el contexto necesario de enrutamiento para el componente.
  344.   render(
  345.     <BrowserRouter>
  346.       <ActivityPage />
  347.     </BrowserRouter>
  348.   );
  349.  
  350.   // Verifica que se rendericen los botones de actividad
  351.   const turisticButton = screen.getByText('Turísticas');
  352.   const socialButton = screen.getByText('Sociales');
  353.   const academicButton = screen.getByText('Académicas');
  354.  
  355.   //Verifica que los botones correspondientes efectivamente estén presentes en el DOM usando expect con el matcher toBeInTheDocument
  356.   expect(turisticButton).toBeInTheDocument();
  357.   expect(socialButton).toBeInTheDocument();
  358.   expect(academicButton).toBeInTheDocument();
  359.  
  360.   // Simula clic en el botón de actividades académicas
  361.   fireEvent.click(academicButton);
  362.  
  363.   // Verifica que, después de hacer clic en el botón, la función navigate haya sido llamada con la URL esperada
  364.   expect(mockNavigate).toHaveBeenCalledWith('/Actividades/de61ec4a-dc96-46ec-a951-572332f10477/academicPage');
  365. });
  366.  
  367.  
  368. //En resumen: Este test verifica que los botones se rendericen correctamente y que, al hacer clic en el botón "Académicas", se llame a navigate con la URL correcta para la página académica.
  369.  
  370. ----------------------------------------------------------------------------------------------------------------------------------------------------------
  371. Es entonces que me gustaría poder realizar otro test con jest donde se puedan mostrar otras funcionalidades de jest como beforeach, aftereach, describe para ponerle nombre a lo que estoy evaluando, etc.
  372. El archivo con el que quise realizar este otro test sería:
  373.  
  374. AcademicDetail.js:
  375. import { useEffect, useState } from "react";
  376. import { supabase } from '../../../tests/supabaseClient';
  377. import NavBar from "../../NavBar";
  378. import { useParams } from "react-router-dom"; // Para obtener el ID de la actividad desde la URL
  379. import DetailCard from "../../DetailCard";
  380.  
  381. export default function AcademicDetail() {
  382.   const { id } = useParams(); // Obtenemos el id de la actividad desde la URL
  383.   const [activity, setActivity] = useState(null); // Estado para la actividad
  384.  
  385.   useEffect(() => {
  386.     const fetchActivityDetail = async () => {
  387.       const { data, error } = await supabase
  388.         .from('activity_academic') // Asegúrate de que el nombre de la tabla esté correcto
  389.         .select(`name, description, image: id_image (base64image)`) // Selecciona los campos necesarios
  390.         .eq('id', id) // Filtra por id de la actividad
  391.         .single(); // Solo esperamos un resultado
  392.  
  393.       if (error) {
  394.         console.error("Error fetching data: ", error);
  395.       } else {
  396.         // Guarda los detalles de la actividad en el estado
  397.         setActivity({
  398.           name: data.name,
  399.           description: data.description,
  400.           id_image: data.image.base64image,
  401.         });
  402.       }
  403.     };
  404.  
  405.     fetchActivityDetail();
  406.   }, [id]); // Ejecutar el efecto cuando cambie el id
  407.  
  408.   if (!activity) {
  409.     return <div>Loading...</div>; // Mientras cargan los detalles
  410.   }
  411.  
  412.   return (
  413.     <div>
  414.       {/* NavBar */}
  415.       <NavBar sections={["Beneficios", "Actividades", "Hospedajes", "Conectarse", "Chats"]} />
  416.      
  417.       {/* Details */}
  418.       <DetailCard title={activity.name} description={activity.description} image={activity.id_image} bgColor="bg-gray-purple"/>
  419.     </div>
  420.   );
  421. }
  422.  
  423.  
Add Comment
Please, Sign In to add comment