diff --git a/TestResults/coverage.cobertura.xml b/TestResults/coverage.cobertura.xml index cd37073b..43bc9bf3 100644 --- a/TestResults/coverage.cobertura.xml +++ b/TestResults/coverage.cobertura.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/frontend/.env.production b/frontend/.env.production index 9318b8a4..a3060845 100644 --- a/frontend/.env.production +++ b/frontend/.env.production @@ -1,2 +1,2 @@ VITE_REACT_APP_OAUTH_CLIENT_ID="257697450661-a69l9bv939uuso551n6pcf1gngpv9ql0.apps.googleusercontent.com" -VITE_BASE_URL=https://cafe-deux-devel.acom.ucar.edu/api/api \ No newline at end of file +VITE_BASE_URL=https://cafe-deux.acom.ucar.edu/api/api \ No newline at end of file diff --git a/frontend/README.md b/frontend/README.md index 6b8504d3..827e2d06 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -27,14 +27,14 @@ ChemistryCafe is a web application built with React, Vite, and TypeScript. The a - `node_modules/`: Folder for dependencies. - `public/`: Folder for static assets (images, fonts, etc.). - `src/`: Source code folder, organized as follows: - - `API/`: Functions for API interaction. - - `assets/`: Static assets. - - `components/`: Reusable components - - `pages/`: Pages: - - `styles/`: Style sheets: - - `index.css`: Global CSS styles. - - `main.tsx`: Entry point for the application. - - `vite-env.d.ts`: Vite environment TypeScript declarations. + - `API/`: Functions for API interaction. + - `assets/`: Static assets. + - `components/`: Reusable components + - `pages/`: Pages: + - `styles/`: Style sheets: + - `index.css`: Global CSS styles. + - `main.tsx`: Entry point for the application. + - `vite-env.d.ts`: Vite environment TypeScript declarations. - `test/`: Folder for test files. - `.eslintrc.cjs`: ESLint configuration file. - `.gitignore`: Git ignore file. @@ -62,20 +62,23 @@ ChemistryCafe is a web application built with React, Vite, and TypeScript. The a ## Setup 1. **Clone the repository**: - ```shell - git clone https://github.com/NCAR/chemistrycafe.git - cd chemistrycafe - ``` + + ```shell + git clone https://github.com/NCAR/chemistrycafe.git + cd chemistrycafe + ``` 2. **Install dependencies**: - ```shell - npm install - ``` + + ```shell + npm install + ``` 3. **Start the development server**: - ```shell - npm run dev - ``` + + ```shell + npm run dev + ``` 4. The app will run on [http://localhost:5173](http://localhost:5173). You can view it in your browser. @@ -103,5 +106,3 @@ To generate a coverage report, use the following command: ```shell npm run test:coverage ``` - - diff --git a/frontend/eslint-report.html b/frontend/eslint-report.html index eff035ca..2c00d155 100644 --- a/frontend/eslint-report.html +++ b/frontend/eslint-report.html @@ -1,7 +1,6 @@ - - + Eslint Report @@ -12,20 +11,29 @@ - - - + + + - +
- - - - - \ No newline at end of file + + + diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index ac5942f5..eac31fb5 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -3,12 +3,11 @@ import pluginJs from "@eslint/js"; import tseslint from "typescript-eslint"; import pluginReact from "eslint-plugin-react"; - /** @type {import('eslint').Linter.Config[]} */ export default [ - {files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"]}, - {languageOptions: { globals: globals.browser }}, + { files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"] }, + { languageOptions: { globals: globals.browser } }, pluginJs.configs.recommended, ...tseslint.configs.recommended, pluginReact.configs.flat.recommended, -]; \ No newline at end of file +]; diff --git a/frontend/index.html b/frontend/index.html index 8547e8df..a5783062 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -5,15 +5,18 @@ Chemistry Cafe - - - + + +
- + diff --git a/frontend/src/API/API_CreateMethods.tsx b/frontend/src/API/API_CreateMethods.tsx index 69b88d6b..0c476448 100644 --- a/frontend/src/API/API_CreateMethods.tsx +++ b/frontend/src/API/API_CreateMethods.tsx @@ -16,15 +16,11 @@ import { BASE_URL } from "./API_config"; export async function createFamily(familyData: Family) { try { console.log("Family data: ", familyData); - const response = await axios.post( - `${BASE_URL}/families`, - familyData, - { - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await axios.post(`${BASE_URL}/families`, familyData, { + headers: { + "Content-Type": "application/json", + }, + }); return response.data as Family; } catch (error) { console.error(error); @@ -34,15 +30,11 @@ export async function createFamily(familyData: Family) { export async function createMechanism(mechanismData: Mechanism) { try { - const response = await axios.post( - `${BASE_URL}/mechanism`, - mechanismData, - { - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await axios.post(`${BASE_URL}/mechanism`, mechanismData, { + headers: { + "Content-Type": "application/json", + }, + }); return response.data as Mechanism; } catch (error) { console.error(error); @@ -53,15 +45,11 @@ export async function createMechanism(mechanismData: Mechanism) { export async function createReaction(reactionData: Reaction) { try { console.log("Reaction data: ", reactionData); - const response = await axios.post( - `${BASE_URL}/reactions`, - reactionData, - { - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await axios.post(`${BASE_URL}/reactions`, reactionData, { + headers: { + "Content-Type": "application/json", + }, + }); return response.data as Reaction; } catch (error) { console.error(error); @@ -71,15 +59,11 @@ export async function createReaction(reactionData: Reaction) { export async function createSpecies(speciesData: Species) { try { - const response = await axios.post( - `${BASE_URL}/species`, - speciesData, - { - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await axios.post(`${BASE_URL}/species`, speciesData, { + headers: { + "Content-Type": "application/json", + }, + }); return response.data as Species; } catch (error) { console.error(error); @@ -88,7 +72,7 @@ export async function createSpecies(speciesData: Species) { } export async function addSpeciesToReaction( - reactionSpeciesData: ReactionSpecies + reactionSpeciesData: ReactionSpecies, ) { try { const response = await axios.post( @@ -98,7 +82,7 @@ export async function addSpeciesToReaction( headers: { "Content-Type": "application/json", }, - } + }, ); return response.data as ReactionSpecies; } catch (error) { @@ -108,7 +92,7 @@ export async function addSpeciesToReaction( } export async function addReactionToMechanism( - mechanismReactionData: MechanismReaction + mechanismReactionData: MechanismReaction, ) { try { const response = await axios.post( @@ -118,7 +102,7 @@ export async function addReactionToMechanism( headers: { "Content-Type": "application/json", }, - } + }, ); return response.data as MechanismReaction; } catch (error) { @@ -128,7 +112,7 @@ export async function addReactionToMechanism( } export async function addSpeciesToMechanism( - mechanismSpeciesData: MechanismSpecies + mechanismSpeciesData: MechanismSpecies, ) { try { const response = await axios.post( @@ -138,7 +122,7 @@ export async function addSpeciesToMechanism( headers: { "Content-Type": "application/json", }, - } + }, ); return response.data as MechanismSpecies; } catch (error) { @@ -149,15 +133,11 @@ export async function addSpeciesToMechanism( export async function createUser(userData: User) { try { - const response = await axios.post( - `${BASE_URL}/users`, - userData, - { - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await axios.post(`${BASE_URL}/users`, userData, { + headers: { + "Content-Type": "application/json", + }, + }); return response.data as User; } catch (error) { console.error(error); @@ -174,7 +154,7 @@ export async function addUserToMechanism(userMechanismData: UserMechanism) { headers: { "Content-Type": "application/json", }, - } + }, ); return response.data as UserMechanism; } catch (error) { @@ -186,13 +166,13 @@ export async function addUserToMechanism(userMechanismData: UserMechanism) { export async function createProperty(propertyData: Property) { try { const response = await axios.post( - `${BASE_URL}/properties`, // Adjust the URL to match your properties API endpoint + `${BASE_URL}/properties`, // Adjust the URL to match your properties API endpoint propertyData, { headers: { "Content-Type": "application/json", }, - } + }, ); return response.data as Property; } catch (error) { diff --git a/frontend/src/API/API_DeleteMethods.tsx b/frontend/src/API/API_DeleteMethods.tsx index 597d2dd1..e679d286 100644 --- a/frontend/src/API/API_DeleteMethods.tsx +++ b/frontend/src/API/API_DeleteMethods.tsx @@ -3,18 +3,14 @@ import axios from "axios"; import { BASE_URL } from "./API_config"; - // Delete a family export async function deleteFamily(id: string) { try { - const response = await axios.delete( - `${BASE_URL}/families/${id}`, - { - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await axios.delete(`${BASE_URL}/families/${id}`, { + headers: { + "Content-Type": "application/json", + }, + }); return response.data; // Return response or a success indicator } catch (error) { console.error(error); @@ -25,9 +21,7 @@ export async function deleteFamily(id: string) { // Delete a mechanism export async function deleteMechanism(id: string) { try { - const response = await axios.delete( - `${BASE_URL}/mechanism/${id}` - ); + const response = await axios.delete(`${BASE_URL}/mechanism/${id}`); return response.data; } catch (error) { console.error(error); @@ -38,14 +32,11 @@ export async function deleteMechanism(id: string) { // Delete a species export async function deleteSpecies(id: string) { try { - const response = await axios.delete( - `${BASE_URL}/species/${id}`, - { - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await axios.delete(`${BASE_URL}/species/${id}`, { + headers: { + "Content-Type": "application/json", + }, + }); return response.data; } catch (error) { console.error(error); @@ -56,14 +47,11 @@ export async function deleteSpecies(id: string) { // Delete a reaction export async function deleteReaction(id: string) { try { - const response = await axios.delete( - `${BASE_URL}/reactions/${id}`, - { - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await axios.delete(`${BASE_URL}/reactions/${id}`, { + headers: { + "Content-Type": "application/json", + }, + }); return response.data; } catch (error) { console.error(error); @@ -74,14 +62,11 @@ export async function deleteReaction(id: string) { // Delete a user (if applicable) export async function deleteUser(id: string) { try { - const response = await axios.delete( - `${BASE_URL}/users/${id}`, - { - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await axios.delete(`${BASE_URL}/users/${id}`, { + headers: { + "Content-Type": "application/json", + }, + }); return response.data; } catch (error) { console.error(error); @@ -91,14 +76,11 @@ export async function deleteUser(id: string) { export async function deleteProperty(id: string) { try { - const response = await axios.delete( - `${BASE_URL}/properties/${id}`, - { - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await axios.delete(`${BASE_URL}/properties/${id}`, { + headers: { + "Content-Type": "application/json", + }, + }); return response.data; } catch (error) { console.error(error); diff --git a/frontend/src/API/API_GetMethods.tsx b/frontend/src/API/API_GetMethods.tsx index d6a65346..095dd6fa 100644 --- a/frontend/src/API/API_GetMethods.tsx +++ b/frontend/src/API/API_GetMethods.tsx @@ -10,16 +10,14 @@ import { User, ReactionSpeciesDto, InitialConditionSpecies, - Property + Property, } from "./API_Interfaces"; import { BASE_URL } from "./API_config"; // Get all families export async function getFamilies(): Promise { try { - const response = await axios.get( - `${BASE_URL}/families` - ); + const response = await axios.get(`${BASE_URL}/families`); return response.data; } catch (error: any) { console.error(`Error fetching families: ${error.message}`, error); @@ -30,9 +28,7 @@ export async function getFamilies(): Promise { // Get a specific family by ID export async function getFamily(id: string): Promise { try { - const response = await axios.get( - `${BASE_URL}/families/${id}` - ); + const response = await axios.get(`${BASE_URL}/families/${id}`); return response.data; } catch (error: any) { console.error(`Error fetching family ${id}: ${error.message}`, error); @@ -43,9 +39,7 @@ export async function getFamily(id: string): Promise { // Get all mechanisms export async function getMechanisms(): Promise { try { - const response = await axios.get( - `${BASE_URL}/mechanism` - ); + const response = await axios.get(`${BASE_URL}/mechanism`); return response.data; } catch (error: any) { console.error(`Error fetching Mechanisms: ${error.message}`, error); @@ -55,11 +49,11 @@ export async function getMechanisms(): Promise { // Get mechanisms by family ID export async function getMechanismsByFamilyId( - familyId: string + familyId: string, ): Promise { try { const response = await axios.get( - `${BASE_URL}/mechanism/family/${familyId}` + `${BASE_URL}/mechanism/family/${familyId}`, ); return response.data; } catch (error: any) { @@ -71,9 +65,7 @@ export async function getMechanismsByFamilyId( // Get a specific mechanism by ID export async function getMechanism(id: string): Promise { try { - const response = await axios.get( - `${BASE_URL}/mechanism/${id}` - ); + const response = await axios.get(`${BASE_URL}/mechanism/${id}`); return response.data; } catch (error: any) { console.error(`Error fetching mechanism ${id}: ${error.message}`, error); @@ -84,9 +76,7 @@ export async function getMechanism(id: string): Promise { // Get all species export async function getAllSpecies(): Promise { try { - const response = await axios.get( - `${BASE_URL}/species` - ); + const response = await axios.get(`${BASE_URL}/species`); return response.data; } catch (error: any) { console.error(`Error fetching species: ${error.message}`, error); @@ -97,9 +87,7 @@ export async function getAllSpecies(): Promise { // Get a specific species by ID export async function getSpecies(id: string): Promise { try { - const response = await axios.get( - `${BASE_URL}/species/${id}` - ); + const response = await axios.get(`${BASE_URL}/species/${id}`); return response.data; } catch (error: any) { console.error(`Error fetching species ${id}: ${error.message}`, error); @@ -109,11 +97,11 @@ export async function getSpecies(id: string): Promise { // Get species associated with a mechanism export async function getSpeciesByMechanismId( - mechanismId: string + mechanismId: string, ): Promise { try { const response = await axios.get( - `${BASE_URL}/mechanismspecies/mechanism/${mechanismId}` + `${BASE_URL}/mechanismspecies/mechanism/${mechanismId}`, ); return response.data; } catch (error: any) { @@ -123,11 +111,11 @@ export async function getSpeciesByMechanismId( } export async function getSpeciesByFamilyId( - familyId: string + familyId: string, ): Promise { try { const response = await axios.get( - `${BASE_URL}/species/family/${familyId}` + `${BASE_URL}/species/family/${familyId}`, ); return response.data; } catch (error: any) { @@ -139,9 +127,7 @@ export async function getSpeciesByFamilyId( // Get all reactions export async function getReactions(): Promise { try { - const response = await axios.get( - `${BASE_URL}/reactions` - ); + const response = await axios.get(`${BASE_URL}/reactions`); return response.data; } catch (error: any) { console.error(`Error fetching species with reactions: ${error.message}`, error); @@ -152,9 +138,7 @@ export async function getReactions(): Promise { // Get a specific reaction by ID export async function getReaction(id: string): Promise { try { - const response = await axios.get( - `${BASE_URL}/reactions/${id}` - ); + const response = await axios.get(`${BASE_URL}/reactions/${id}`); return response.data; } catch (error: any) { console.error(`Error fetching reaction ${id}: ${error.message}`, error); @@ -164,11 +148,11 @@ export async function getReaction(id: string): Promise { // Get reactions associated with a mechanism export async function getReactionsByMechanismId( - mechanismId: string + mechanismId: string, ): Promise { try { const response = await axios.get( - `${BASE_URL}/reactions/mechanism/${mechanismId}` + `${BASE_URL}/reactions/mechanism/${mechanismId}`, ); return response.data; } catch (error: any) { @@ -178,11 +162,11 @@ export async function getReactionsByMechanismId( } export async function getReactionsByFamilyId( - familyId: string + familyId: string, ): Promise { try { const response = await axios.get( - `${BASE_URL}/reactions/family/${familyId}` + `${BASE_URL}/reactions/family/${familyId}`, ); return response.data; } catch (error: any) { @@ -192,11 +176,11 @@ export async function getReactionsByFamilyId( } export async function getReactantsByReactionIdAsync( - reactionId: string + reactionId: string, ): Promise { try { const response = await axios.get( - `${BASE_URL}/reactionspecies/reaction/${reactionId}/reactants` + `${BASE_URL}/reactionspecies/reaction/${reactionId}/reactants`, ); return response.data; } catch (error: any) { @@ -206,11 +190,11 @@ export async function getReactantsByReactionIdAsync( } export async function getProductsByReactionIdAsync( - reactionId: string + reactionId: string, ): Promise { try { const response = await axios.get( - `${BASE_URL}/reactionspecies/reaction/${reactionId}/products` + `${BASE_URL}/reactionspecies/reaction/${reactionId}/products`, ); return response.data; } catch (error: any) { @@ -234,9 +218,7 @@ export async function getUsers(): Promise { export async function getUserByEmail(email: string): Promise { try { // const encodedEmail = encodeURIComponent(email); - const response = await axios.get( - `${BASE_URL}/users/email/${email}` - ); + const response = await axios.get(`${BASE_URL}/users/email/${email}`); return response.data; } catch (error: any) { console.error(`Error fetching user by email ${email}: ${error.message}`, error); @@ -246,9 +228,7 @@ export async function getUserByEmail(email: string): Promise { export async function getUserById(id: string): Promise { try { - const response = await axios.get( - `${BASE_URL}/users/id/${id}` - ); + const response = await axios.get(`${BASE_URL}/users/id/${id}`); return response.data; } catch (error: any) { console.error(`Error fetching user ${id}: ${error.message}`, error); @@ -259,7 +239,7 @@ export async function getUserById(id: string): Promise { export async function getPropertyById(id: string): Promise { try { const response = await axios.get( - `${BASE_URL}/properties/id/${id}` + `${BASE_URL}/properties/id/${id}`, ); return response.data; } catch (error: any) { @@ -268,19 +248,22 @@ export async function getPropertyById(id: string): Promise { } } -export async function getPropertyBySpeciesAndMechanism(species: string, mechanism: string): Promise { +export async function getPropertyBySpeciesAndMechanism( + species: string, + mechanism: string, +): Promise { try { const response = await axios.get( - `${BASE_URL}/properties/id/${species}/${mechanism}` + `${BASE_URL}/properties/id/${species}/${mechanism}`, ); return response.data; } catch (error: any) { if (axios.isAxiosError(error) && error.response?.status !== 404) { - console.error("Error response data:", error.response?.data); + console.error("Error response data:", error.response?.data); } throw error; -}} - + } +} // Download OpenAtmos JSON for a mechanism export async function downloadOAJSON(mechanismId?: string) { @@ -294,7 +277,7 @@ export async function downloadOAJSON(mechanismId?: string) { headers: { "Content-Type": "text/plain", }, - } + }, ); return response.data; } catch (error: any) { @@ -315,7 +298,7 @@ export async function downloadOAYAML(mechanismId?: string) { headers: { "Content-Type": "text/plain", }, - } + }, ); return response.data; } catch (error: any) { @@ -334,9 +317,9 @@ export async function downloadOAMusicbox(mechanismId?: string) { { responseType: "arraybuffer", // Handle binary data headers: { - "Accept": "application/zip", // Expecting a zip file + Accept: "application/zip", // Expecting a zip file }, - } + }, ); // Return the response data as an array buffer for further processing @@ -349,15 +332,15 @@ export async function downloadOAMusicbox(mechanismId?: string) { // species properties export async function getSpeciesPropertiesByMechanismIDAsync( - mechanismId: string + mechanismId: string, ): Promise { try { const response = await axios.get( - `${BASE_URL}/initialconditionspecies/mechanism/${mechanismId}` + `${BASE_URL}/initialconditionspecies/mechanism/${mechanismId}`, ); return response.data; } catch (error: any) { console.error(error); return []; } -} \ No newline at end of file +} diff --git a/frontend/src/API/API_Interfaces.tsx b/frontend/src/API/API_Interfaces.tsx index ef84b638..5626bfa7 100644 --- a/frontend/src/API/API_Interfaces.tsx +++ b/frontend/src/API/API_Interfaces.tsx @@ -92,4 +92,3 @@ export interface Property { concentration?: number; // Concentration value (optional) diffusion?: number; // Diffusion value (optional) } - diff --git a/frontend/src/API/API_UpdateMethods.tsx b/frontend/src/API/API_UpdateMethods.tsx index ed1b355d..e971d7f5 100644 --- a/frontend/src/API/API_UpdateMethods.tsx +++ b/frontend/src/API/API_UpdateMethods.tsx @@ -1,7 +1,14 @@ // API_UpdateMethods.ts import axios from "axios"; -import { Family, Mechanism, Species, Reaction, User, Property } from "./API_Interfaces"; +import { + Family, + Mechanism, + Species, + Reaction, + User, + Property, +} from "./API_Interfaces"; import { BASE_URL } from "./API_config"; // Update a family @@ -14,7 +21,7 @@ export async function updateFamily(family: Family) { headers: { "Content-Type": "application/json", }, - } + }, ); return response.data as Family; } catch (error) { @@ -33,7 +40,7 @@ export async function updateMechanism(mechanism: Mechanism) { headers: { "Content-Type": "application/json", }, - } + }, ); return response.data as Mechanism; } catch (error) { @@ -52,7 +59,7 @@ export async function updateSpecies(species: Species) { headers: { "Content-Type": "application/json", }, - } + }, ); return response.data as Species; } catch (error) { @@ -71,7 +78,7 @@ export async function updateReaction(reaction: Reaction) { headers: { "Content-Type": "application/json", }, - } + }, ); return response.data as Reaction; } catch (error) { @@ -82,15 +89,11 @@ export async function updateReaction(reaction: Reaction) { export async function updateUser(id: string, user: User) { try { - const response = await axios.put( - `${BASE_URL}/users/${id}`, - user, - { - headers: { - "Content-Type": "application/json", - }, - } - ); + const response = await axios.put(`${BASE_URL}/users/${id}`, user, { + headers: { + "Content-Type": "application/json", + }, + }); return response.data as User; } catch (error) { console.error(error); @@ -107,7 +110,7 @@ export async function updateProperty(property: Property) { headers: { "Content-Type": "application/json", }, - } + }, ); return response.data as Property; } catch (error) { @@ -115,4 +118,3 @@ export async function updateProperty(property: Property) { throw error; } } - diff --git a/frontend/src/API/API_config.tsx b/frontend/src/API/API_config.tsx index 1cfa40df..f28e8ba3 100644 --- a/frontend/src/API/API_config.tsx +++ b/frontend/src/API/API_config.tsx @@ -1 +1 @@ -export const BASE_URL = import.meta.env.VITE_BASE_URL; \ No newline at end of file +export const BASE_URL = import.meta.env.VITE_BASE_URL; diff --git a/frontend/src/components/CookieBanner.tsx b/frontend/src/components/CookieBanner.tsx index 25267eb6..6101c713 100644 --- a/frontend/src/components/CookieBanner.tsx +++ b/frontend/src/components/CookieBanner.tsx @@ -1,5 +1,5 @@ -import React, { useEffect, useState } from 'react'; -import '../styles/App.css'; // Assuming you're adding the CSS here +import React, { useEffect, useState } from "react"; +import "../styles/App.css"; // Assuming you're adding the CSS here const CookieBanner: React.FC = () => { // State to manage whether the banner is visible @@ -7,7 +7,7 @@ const CookieBanner: React.FC = () => { // UseEffect to check if the banner has already been accepted useEffect(() => { - const bannerAccepted = localStorage.getItem('bannerAccepted'); + const bannerAccepted = localStorage.getItem("bannerAccepted"); if (bannerAccepted) { setIsBannerVisible(false); } @@ -16,7 +16,7 @@ const CookieBanner: React.FC = () => { // Function to handle the acceptance of the banner const handleAccept = () => { setIsBannerVisible(false); - localStorage.setItem('bannerAccepted', 'true'); + localStorage.setItem("bannerAccepted", "true"); }; // Render the banner conditionally @@ -24,13 +24,20 @@ const CookieBanner: React.FC = () => { <> {isBannerVisible && (
-

- UCAR uses cookies to make our website function; however, UCAR cookies do not collect personal information about you. When using our website, you may encounter embedded content, such as YouTube videos and other social media links, that use their own cookies. - To learn more about third-party cookies on this website, and to set your cookie preferences, click here. Learn more -

- +

+ UCAR uses cookies to make our website function; however, UCAR + cookies do not collect personal information about you. When using + our website, you may encounter embedded content, such as YouTube + videos and other social media links, that use their own cookies. To + learn more about third-party cookies on this website, and to set + your cookie preferences, click here.{" "} + + Learn more + +

+
)} diff --git a/frontend/src/components/HeaderFooter.tsx b/frontend/src/components/HeaderFooter.tsx index 70c9bc95..8bc99d93 100644 --- a/frontend/src/components/HeaderFooter.tsx +++ b/frontend/src/components/HeaderFooter.tsx @@ -7,11 +7,11 @@ import Paper from "@mui/material/Paper"; import Container from "@mui/material/Container"; import DensitySmallSharpIcon from "@mui/icons-material/DensitySmallSharp"; import { useAuth } from "../pages/AuthContext"; -import Modal from '@mui/material/Modal'; -import Typography from '@mui/material/Typography'; -import TAMUlogo from '../assets/TAMULogo.png'; -import NSF_NCARlogo from '../assets/NSF-NCAR_Lockup-UCAR-Dark.png'; -import NSF_NCAR_Stackseallogo from '../assets/nsf-stackseal-logo-lockup-dark.png'; +import Modal from "@mui/material/Modal"; +import Typography from "@mui/material/Typography"; +import TAMUlogo from "../assets/TAMULogo.png"; +import NSF_NCARlogo from "../assets/NSF-NCAR_Lockup-UCAR-Dark.png"; +import NSF_NCAR_Stackseallogo from "../assets/nsf-stackseal-logo-lockup-dark.png"; export const Header = () => { const [openDrawer, setOpenDrawer] = useState(false); @@ -127,33 +127,33 @@ export const Footer = () => { }} > About - - - - The Chemistry Cafe tool was made possible by the collaboration - between NCAR and Texas A&M through the CSCE Capstone program. - -

- Credits - - Paul Cyr, Brandon Longuet, Brian Nguyen

Spring 2024 - Capstone Team

- Britt Schiller, Ore Ogunleye, Nishka Mittal, Josh Hare, Sydney Ferris

Fall 2024 - Capstone Team

- Kyle Shores

Spring 2024 Capstone Sponsor Representative -
+ + + + The Chemistry Cafe tool was made possible by the collaboration + between NCAR and Texas A&M through the CSCE Capstone program. + +

+ Credits + + Paul Cyr, Brandon Longuet, Brian Nguyen

Spring 2024 + Capstone Team

+ Britt Schiller, Ore Ogunleye, Nishka Mittal, Josh Hare, Sydney + Ferris

Fall 2024 Capstone Team

+ Kyle Shores

Spring 2024 Capstone Sponsor Representative +
); -}; \ No newline at end of file +}; diff --git a/frontend/src/components/Holidays.tsx b/frontend/src/components/Holidays.tsx index 3d592580..a5adeea7 100644 --- a/frontend/src/components/Holidays.tsx +++ b/frontend/src/components/Holidays.tsx @@ -2,67 +2,66 @@ import React, { useEffect, useState } from "react"; // Mapping holiday names to icons const holidayIcons: { [key: string]: string } = { - "Christmas Day": "🎄", // Christmas tree icon - "Halloween": "🎃", // Jack-o'-lantern icon - "Thanksgiving Day": "🦃", // Turkey icon - "New Year's Day": "🎉", // Party popper icon - "Valentine's Day": "❤️", // Heart icon - "Independence Day": "🇺🇸", // US flag icon - "Martin Luther King Jr. Day": "✊", // Raised fist icon - "Memorial Day": "🏵️", // Rosette icon + "Christmas Day": "🎄", // Christmas tree icon + Halloween: "🎃", // Jack-o'-lantern icon + "Thanksgiving Day": "🦃", // Turkey icon + "New Year's Day": "🎉", // Party popper icon + "Valentine's Day": "❤️", // Heart icon + "Independence Day": "🇺🇸", // US flag icon + "Martin Luther King Jr. Day": "✊", // Raised fist icon + "Memorial Day": "🏵️", // Rosette icon }; // Mapping months to a representative holiday name and icon const holidaysByMonth: { [key: number]: { name: string; icon: string } } = { - 1: { name: "New Year's Day", icon: holidayIcons["New Year's Day"] }, // January - 2: { name: "Valentine's Day", icon: holidayIcons["Valentine's Day"] }, // February - 3: { name: "Martin Luther King Jr. Day", icon: holidayIcons["Martin Luther King Jr. Day"] }, // March - 4: { name: "Rain", icon: "🌧️" }, // April - 5: { name: "Memorial Day", icon: holidayIcons["Memorial Day"] }, // May - 6: { name: "Sun", icon: "☀️" }, // June - 7: { name: "Fireworks", icon: "🎆" }, // July - 8: { name: "Swimming", icon: "🏊" }, // August - 9: { name: "Apple", icon: "🍏" }, // September - 10: { name: "Halloween", icon: holidayIcons.Halloween }, // October - 11: { name: "Thanksgiving Day", icon: holidayIcons["Thanksgiving Day"] }, // November - 12: { name: "Christmas Day", icon: holidayIcons["Christmas Day"] }, // December + 1: { name: "New Year's Day", icon: holidayIcons["New Year's Day"] }, // January + 2: { name: "Valentine's Day", icon: holidayIcons["Valentine's Day"] }, // February + 3: { + name: "Martin Luther King Jr. Day", + icon: holidayIcons["Martin Luther King Jr. Day"], + }, // March + 4: { name: "Rain", icon: "🌧️" }, // April + 5: { name: "Memorial Day", icon: holidayIcons["Memorial Day"] }, // May + 6: { name: "Sun", icon: "☀️" }, // June + 7: { name: "Fireworks", icon: "🎆" }, // July + 8: { name: "Swimming", icon: "🏊" }, // August + 9: { name: "Apple", icon: "🍏" }, // September + 10: { name: "Halloween", icon: holidayIcons.Halloween }, // October + 11: { name: "Thanksgiving Day", icon: holidayIcons["Thanksgiving Day"] }, // November + 12: { name: "Christmas Day", icon: holidayIcons["Christmas Day"] }, // December }; const Holidays: React.FC = () => { - const [currentIcon, setCurrentIcon] = useState(null); // Store the icon to display - const currentMonth = new Date().getMonth() + 1; // Get the current month (1-12) + const [currentIcon, setCurrentIcon] = useState(null); // Store the icon to display + const currentMonth = new Date().getMonth() + 1; // Get the current month (1-12) - useEffect(() => { - const fetchHolidays = async () => { - try { - // Get the representative holiday for the current month - const holidayThisMonth = holidaysByMonth[currentMonth]; + useEffect(() => { + const fetchHolidays = async () => { + try { + // Get the representative holiday for the current month + const holidayThisMonth = holidaysByMonth[currentMonth]; - if (holidayThisMonth && holidayThisMonth.icon) { - setCurrentIcon(holidayThisMonth.icon); - } else { - setCurrentIcon(null); // No holiday this month - } - } catch (error) { - console.error("Error fetching holidays:", error); - setCurrentIcon(null); // Default to no icon if error - } - }; + if (holidayThisMonth && holidayThisMonth.icon) { + setCurrentIcon(holidayThisMonth.icon); + } else { + setCurrentIcon(null); // No holiday this month + } + } catch (error) { + console.error("Error fetching holidays:", error); + setCurrentIcon(null); // Default to no icon if error + } + }; - fetchHolidays(); - }, [currentMonth]); + fetchHolidays(); + }, [currentMonth]); - return ( - // commented out stuff is for testing that all icons work properly -
- {/*

Current Holiday Icon:

*/} - {currentIcon && ( -
- {currentIcon} -
- )} -
- ); + return ( + // commented out stuff is for testing that all icons work properly +
+ {/*

Current Holiday Icon:

*/} + {currentIcon &&
{currentIcon}
} +
+ ); }; export default Holidays; diff --git a/frontend/src/components/Modals.tsx b/frontend/src/components/Modals.tsx index 34bc9c36..04b3d830 100644 --- a/frontend/src/components/Modals.tsx +++ b/frontend/src/components/Modals.tsx @@ -40,7 +40,11 @@ import { Select, MenuItem, } from "@mui/material"; -import { updateProperty, updateReaction, updateSpecies } from "../API/API_UpdateMethods"; +import { + updateProperty, + updateReaction, + updateSpecies, +} from "../API/API_UpdateMethods"; const style = { position: "absolute" as const, @@ -100,7 +104,6 @@ interface UpdateSpeciesModalProps { setSpeciesUpdated: React.Dispatch>; } - interface CreateReactionModalProps { open: boolean; onClose: () => void; @@ -131,7 +134,6 @@ interface CreateReactantModalProps { setReactionUpdated: React.Dispatch>; } - interface CreateProductModalProps { open: boolean; onClose: () => void; @@ -141,7 +143,6 @@ interface CreateProductModalProps { setReactionUpdated: React.Dispatch>; } - export const CreatePublishModal: React.FC = ({ open, onClose, @@ -274,7 +275,7 @@ export const CreateMechanismModal: React.FC = ({ .map((p) => p.species_name) .join(" + "); equations[reaction.id!] = `${reactantNames} -> ${productNames}`; - }) + }), ); setReactionEquations(equations); } catch (error) { @@ -396,7 +397,6 @@ export const CreateSpeciesModal: React.FC = ({ const [weight, setWeight] = useState(0); const [diffusion, setDiffusion] = useState(0); - const handleCreateSpeciesClick = async () => { try { if (selectedFamilyId && selectedMechanismId) { @@ -414,7 +414,7 @@ export const CreateSpeciesModal: React.FC = ({ species_id: newSpecies.id!, }; await addSpeciesToMechanism(mechanismSpecies); - + // make the corresponding property const propertyData: Property = { speciesId: newSpecies.id!, @@ -426,12 +426,9 @@ export const CreateSpeciesModal: React.FC = ({ }; const createdProperty = await createProperty(propertyData); console.log(createdProperty); - - } } - setSpeciesName(""); setSpeciesDescription(""); @@ -444,94 +441,136 @@ export const CreateSpeciesModal: React.FC = ({ }; return ( - - -

Create New Species

- - - - setSpeciesName(e.target.value)} - fullWidth - margin="normal" - /> - - - - setSpeciesDescription(e.target.value)} - fullWidth - margin="normal" - /> - - - - setConcentration(Number(e.target.value))} - fullWidth - margin="normal" - /> - - - - setTolerance(Number(e.target.value))} - fullWidth - margin="normal" - /> - - - setWeight(Number(e.target.value))} - fullWidth - margin="normal" - /> - - - - setDiffusion(Number(e.target.value))} - fullWidth - margin="normal" - /> - - - - - -
-
+ + +

Create New Species

+ + + setSpeciesName(e.target.value)} + fullWidth + margin="normal" + /> + + + + setSpeciesDescription(e.target.value)} + fullWidth + margin="normal" + /> + + + + setConcentration(Number(e.target.value))} + fullWidth + margin="normal" + /> + + + + setTolerance(Number(e.target.value))} + fullWidth + margin="normal" + /> + + + setWeight(Number(e.target.value))} + fullWidth + margin="normal" + /> + + + + setDiffusion(Number(e.target.value))} + fullWidth + margin="normal" + /> + + + +
+
); }; @@ -544,12 +583,13 @@ export const UpdateSpeciesModal: React.FC = ({ selectedSpeciesProperties, setSpeciesUpdated, }) => { - // console.log("in update species"); // console.log(selectedSpecies?.name); // set values to the current values of the selected species const [speciesName, setSpeciesName] = useState(selectedSpecies?.name || ""); - const [speciesDescription, setSpeciesDescription] = useState(selectedSpecies?.description || ""); + const [speciesDescription, setSpeciesDescription] = useState( + selectedSpecies?.description || "", + ); useEffect(() => { if (selectedSpecies) { @@ -558,13 +598,19 @@ export const UpdateSpeciesModal: React.FC = ({ } }, [selectedSpecies]); - // as we are updating an existing species, should never be empty - const [concentration, setConcentration] = useState(selectedSpeciesProperties?.concentration || 0); - const [tolerance, setTolerance] = useState(selectedSpeciesProperties?.tolerance || 0); - const [weight, setWeight] = useState(selectedSpeciesProperties?.weight || 0); - const [diffusion, setDiffusion] = useState(selectedSpeciesProperties?.diffusion || 0); - + const [concentration, setConcentration] = useState( + selectedSpeciesProperties?.concentration || 0, + ); + const [tolerance, setTolerance] = useState( + selectedSpeciesProperties?.tolerance || 0, + ); + const [weight, setWeight] = useState( + selectedSpeciesProperties?.weight || 0, + ); + const [diffusion, setDiffusion] = useState( + selectedSpeciesProperties?.diffusion || 0, + ); const handleUpdateSpeciesClick = async () => { try { @@ -594,7 +640,6 @@ export const UpdateSpeciesModal: React.FC = ({ console.log(updatedProperties); } - setSpeciesName(""); setSpeciesDescription(""); @@ -606,109 +651,145 @@ export const UpdateSpeciesModal: React.FC = ({ } }; + console.log("open status"); + console.log(open); return ( - - -

Edit Species

- - - - setSpeciesName(e.target.value)} - fullWidth - margin="normal" - /> - - - - setSpeciesDescription(e.target.value)} - fullWidth - margin="normal" - /> - - - - - setConcentration(Number(e.target.value) || 0) - } - fullWidth - margin="normal" - /> - - - - - setTolerance(Number(e.target.value) || 0) - } - fullWidth - margin="normal" - /> - - - - setWeight(Number(e.target.value) || 0) - } - fullWidth - margin="normal" - /> - - - - - setDiffusion(Number(e.target.value) || 0) - } - fullWidth - margin="normal" - /> - - - - - -
-
+ + +

Edit Species

+ + + setSpeciesName(e.target.value)} + fullWidth + margin="normal" + /> + + + + setSpeciesDescription(e.target.value)} + fullWidth + margin="normal" + /> + + + + setConcentration(Number(e.target.value) || 0)} + fullWidth + margin="normal" + /> + + + + setTolerance(Number(e.target.value) || 0)} + fullWidth + margin="normal" + /> + + + setWeight(Number(e.target.value) || 0)} + fullWidth + margin="normal" + /> + + + + setDiffusion(Number(e.target.value) || 0)} + fullWidth + margin="normal" + /> + + + +
+
); }; @@ -734,18 +815,16 @@ export const CreateReactionModal: React.FC = ({ const fetchReactions = async () => { try { if (selectedFamilyId && selectedMechanismId) { - const reactionsFamily = await getReactionsByFamilyId( - selectedFamilyId - ); - const reactionsMechanism = await getReactionsByMechanismId( - selectedMechanismId - ); + const reactionsFamily = + await getReactionsByFamilyId(selectedFamilyId); + const reactionsMechanism = + await getReactionsByMechanismId(selectedMechanismId); const uniqueReactions = reactionsFamily.filter( (reaction: Reaction) => !reactionsMechanism.some( - (mechReaction) => mechReaction.id === reaction.id - ) + (mechReaction) => mechReaction.id === reaction.id, + ), ); setReactionList(uniqueReactions); } @@ -771,7 +850,7 @@ export const CreateReactionModal: React.FC = ({ .map((p: ReactionSpeciesDto) => p.species_name) .join(" + "); equations[reaction.id!] = `${reactantNames} -> ${productNames}`; - }) + }), ); setReactionEquations(equations); } catch (error) { @@ -806,18 +885,22 @@ export const CreateReactionModal: React.FC = ({ // Name is mecanism name_reaction number // get the number of current reactions const reactionData: Reaction = { - name: selectedMechanismName + "_reaction" + String(reactionsCount+1), + name: + selectedMechanismName + "_reaction" + String(reactionsCount + 1), // Set description to the constructed equation - description: selectedReactionType.toUpperCase() + " Reaction " + - String(reactionsCount + 1) + ": " + - createReactionReactantsRef.current + " -> " + + description: + selectedReactionType.toUpperCase() + + " Reaction " + + String(reactionsCount + 1) + + ": " + + createReactionReactantsRef.current + + " -> " + createReactionProductsRef.current, createdBy: "current_user", }; //console.log(reactionData); const newReaction = await createReaction(reactionData); - //console.log(newReaction); const mechanismReaction: MechanismReaction = { @@ -876,20 +959,22 @@ export const CreateReactionModal: React.FC = ({ (createReactionReactantsRef.current = e.target.value)} - fullWidth - margin="normal" + id="reactants" + label="Reactants" + type="string" + onChange={(e) => + (createReactionReactantsRef.current = e.target.value) + } + fullWidth + margin="normal" /> (createReactionProductsRef.current = e.target.value)} - fullWidth - margin="normal" + id="products" + label="Products" + type="string" + onChange={(e) => (createReactionProductsRef.current = e.target.value)} + fullWidth + margin="normal" /> {reactionList.length > 0 && ( <> @@ -930,7 +1015,6 @@ export const CreateReactionModal: React.FC = ({ ); }; - export const UpdateReactionModal: React.FC = ({ open, onClose, @@ -957,10 +1041,13 @@ export const UpdateReactionModal: React.FC = ({ try { if (selectedFamilyId && selectedMechanismId && selectedReaction) { // get the current reaction data - if (selectedReaction.name !== null && selectedReaction.description !== null){ + if ( + selectedReaction.name !== null && + selectedReaction.description !== null + ) { // make regex expression - const regex = /^(Arrhenius|Branched|Emission|First-Order Loss|Photolysis|Surface \(Heterogeneous\)|Ternary Chemical Activation|Troe \(Fall-Off\)|Tunneling|N\/A)(?: Reaction \d+)?: ([^->]+) -> (.+)$/i; - + const regex = + /^(Arrhenius|Branched|Emission|First-Order Loss|Photolysis|Surface \(Heterogeneous\)|Ternary Chemical Activation|Troe \(Fall-Off\)|Tunneling|N\/A)(?: Reaction \d+)?: ([^->]+) -> (.+)$/i; const matches = selectedReaction.description.match(regex); @@ -968,7 +1055,11 @@ export const UpdateReactionModal: React.FC = ({ // console.log("matches:"); // console.log(matches); // getting the current data before editing - setSelectedReactionType(matches[1].toLowerCase().replace(/^./, char => char.toUpperCase()) ); + setSelectedReactionType( + matches[1] + .toLowerCase() + .replace(/^./, (char) => char.toUpperCase()), + ); const tempReactants = matches[2].trim(); const tempProducts = matches[3].trim(); setReactants(tempReactants); @@ -978,18 +1069,16 @@ export const UpdateReactionModal: React.FC = ({ createReactionReactantsRef.current = tempReactants; } } - const reactionsFamily = await getReactionsByFamilyId( - selectedFamilyId - ); - const reactionsMechanism = await getReactionsByMechanismId( - selectedMechanismId - ); + const reactionsFamily = + await getReactionsByFamilyId(selectedFamilyId); + const reactionsMechanism = + await getReactionsByMechanismId(selectedMechanismId); const uniqueReactions = reactionsFamily.filter( (reaction: Reaction) => !reactionsMechanism.some( - (mechReaction) => mechReaction.id === reaction.id - ) + (mechReaction) => mechReaction.id === reaction.id, + ), ); setReactionList(uniqueReactions); } @@ -1015,7 +1104,7 @@ export const UpdateReactionModal: React.FC = ({ .map((p: ReactionSpeciesDto) => p.species_name) .join(" + "); equations[reaction.id!] = `${reactantNames} -> ${productNames}`; - }) + }), ); setReactionEquations(equations); } catch (error) { @@ -1043,9 +1132,13 @@ export const UpdateReactionModal: React.FC = ({ id: selectedReaction!.id, name: selectedReaction!.name, // Set description to the constructed equation - description: selectedReactionType.toUpperCase() + " Reaction " + - String(reactionsCount + 1) + ": " + - createReactionReactantsRef.current + " -> " + + description: + selectedReactionType.toUpperCase() + + " Reaction " + + String(reactionsCount + 1) + + ": " + + createReactionReactantsRef.current + + " -> " + createReactionProductsRef.current, createdBy: "current_user", }; @@ -1056,11 +1149,8 @@ export const UpdateReactionModal: React.FC = ({ const updatedReaction = await updateReaction(reactionData); console.log(updatedReaction); - - } - setSelectedReactionType(""); setSelectedReactionIds([]); setReactionUpdated(true); @@ -1102,31 +1192,28 @@ export const UpdateReactionModal: React.FC = ({ { - setReactants(e.target.value); - (createReactionReactantsRef.current = e.target.value); - } - } - fullWidth - margin="normal" + id="reactants" + label="Reactants" + type="string" + value={reactants} + onChange={(e) => { + setReactants(e.target.value); + createReactionReactantsRef.current = e.target.value; + }} + fullWidth + margin="normal" /> { - setProducts(e.target.value); - (createReactionProductsRef.current = e.target.value); - } - } - - fullWidth - margin="normal" + id="products" + label="Products" + type="string" + value={products} + onChange={(e) => { + setProducts(e.target.value); + createReactionProductsRef.current = e.target.value; + }} + fullWidth + margin="normal" /> {reactionList.length > 0 && ( <> @@ -1167,11 +1254,6 @@ export const UpdateReactionModal: React.FC = ({ ); }; - - - - - export const CreateReactantModal: React.FC = ({ open, onClose, @@ -1182,7 +1264,7 @@ export const CreateReactantModal: React.FC = ({ }) => { const [speciesList, setSpeciesList] = useState([]); const [selectedSpeciesId, setSelectedSpeciesId] = useState( - null + null, ); const createReactantQuantityRef = useRef(""); @@ -1279,7 +1361,7 @@ export const CreateProductModal: React.FC = ({ }) => { const [speciesList, setSpeciesList] = useState([]); const [selectedSpeciesId, setSelectedSpeciesId] = useState( - null + null, ); const createProductQuantityRef = useRef(""); diff --git a/frontend/src/components/NavDropDown.tsx b/frontend/src/components/NavDropDown.tsx index 1bac0f8c..dd345878 100644 --- a/frontend/src/components/NavDropDown.tsx +++ b/frontend/src/components/NavDropDown.tsx @@ -1,24 +1,24 @@ -import { useNavigate } from 'react-router-dom'; -import Box from '@mui/material/Box'; -import List from '@mui/material/List'; -import ListItem from '@mui/material/ListItem'; -import ListItemText from '@mui/material/ListItemText'; -import ListItemButton from '@mui/material/ListItemButton'; -import { useAuth } from '../pages/AuthContext'; // Import useAuth to get the user data +import { useNavigate } from "react-router-dom"; +import Box from "@mui/material/Box"; +import List from "@mui/material/List"; +import ListItem from "@mui/material/ListItem"; +import ListItemText from "@mui/material/ListItemText"; +import ListItemButton from "@mui/material/ListItemButton"; +import { useAuth } from "../pages/AuthContext"; // Import useAuth to get the user data const NavDropDown = () => { const navigate = useNavigate(); - + // Get the logged-in user from the AuthContext const { user, setUser } = useAuth(); - const goHome = () => navigate('/LoggedIn'); - const goFamily = () => navigate('/FamilyPage'); + const goHome = () => navigate("/LoggedIn"); + const goFamily = () => navigate("/FamilyPage"); const goLogOut = () => { - setUser(null); - navigate('/'); + setUser(null); + navigate("/"); }; - const goRoles = () => navigate('/Roles'); // Add navigation to Roles page + const goRoles = () => navigate("/Roles"); // Add navigation to Roles page return ( @@ -34,7 +34,7 @@ const NavDropDown = () => { {/* Conditionally render the Roles option only if the user is an admin */} - {user && user.role === 'admin' && ( + {user && user.role === "admin" && ( diff --git a/frontend/src/components/ProtectedRoute.tsx b/frontend/src/components/ProtectedRoute.tsx index d32488f1..c14c5359 100644 --- a/frontend/src/components/ProtectedRoute.tsx +++ b/frontend/src/components/ProtectedRoute.tsx @@ -1,12 +1,15 @@ -import { Navigate } from 'react-router-dom'; -import { useAuth } from '../pages/AuthContext'; +import { Navigate } from "react-router-dom"; +import { useAuth } from "../pages/AuthContext"; interface ProtectedRouteProps { children: React.ReactNode; requiredRole: string; } -const ProtectedRoute: React.FC = ({ children, requiredRole }) => { +const ProtectedRoute: React.FC = ({ + children, + requiredRole, +}) => { const { user: loggedInUser } = useAuth(); // Check if the user is logged in and has the correct role diff --git a/frontend/src/components/RenderFamilyTree.tsx b/frontend/src/components/RenderFamilyTree.tsx index 1eb3101e..35354be6 100644 --- a/frontend/src/components/RenderFamilyTree.tsx +++ b/frontend/src/components/RenderFamilyTree.tsx @@ -105,7 +105,7 @@ const RenderFamilyTree: React.FC = ({ setLoading(false); const mechanismsPromises = fetchedFamilies.map((family) => - getMechanismsByFamilyId(family.id!) + getMechanismsByFamilyId(family.id!), ); const mechanismsArray = await Promise.all(mechanismsPromises); const mechanismsMap: Record = {}; @@ -136,12 +136,12 @@ const RenderFamilyTree: React.FC = ({ const blob = new Blob([body], { type: "application/json" }); blobUrl = window.URL.createObjectURL(blob); link.download = "openAtmos.json"; - } else if(format === "YAML"){ + } else if (format === "YAML") { const body = await downloadOAYAML(mechanismId); const blob = new Blob([body], { type: "application/json" }); blobUrl = window.URL.createObjectURL(blob); link.download = "openAtmos.yaml"; - }else if(format === "Musicbox"){ + } else if (format === "Musicbox") { const body = await downloadOAMusicbox(mechanismId); const blob = new Blob([body], { type: "application/zip" }); blobUrl = window.URL.createObjectURL(blob); @@ -157,7 +157,7 @@ const RenderFamilyTree: React.FC = ({ const handlePopOverClick = ( event: React.MouseEvent, - mechanismId: string + mechanismId: string, ) => { ref.current = mechanismId; setPopOver(event.currentTarget); @@ -166,7 +166,7 @@ const RenderFamilyTree: React.FC = ({ const handleItemExpansionToggle = ( _event: React.SyntheticEvent<{}>, itemId: string, - isExpanded: boolean + isExpanded: boolean, ) => { setExpandedItems((prevExpandedItems) => { if (isExpanded) { @@ -333,7 +333,10 @@ const RenderFamilyTree: React.FC = ({ -

- - - - -
-
-
- - - - ); - - } - - export default LoggedIn; \ No newline at end of file +const LoggedIn = () => { + const navigate = useNavigate(); + const handleClickFam = () => navigate("/FamilyPage"); + const handleClickSettings = () => navigate("/Settings"); + + const style = { + height: "75px", + width: "500px", + }; + return ( +
+
+
+
+ +
+ + +

+ +
+
+ +
+
+
+
+ ); +}; + +export default LoggedIn; diff --git a/frontend/src/pages/settings.tsx b/frontend/src/pages/settings.tsx index e0ac6d57..7c6d0d2b 100644 --- a/frontend/src/pages/settings.tsx +++ b/frontend/src/pages/settings.tsx @@ -1,42 +1,39 @@ -import { useNavigate } from 'react-router-dom'; +import { useNavigate } from "react-router-dom"; import Button from "@mui/material/Button"; -import ButtonGroup from '@mui/material/ButtonGroup'; -import { Header, Footer } from '../components/HeaderFooter'; - -import "../styles/settings.css" - - const Settings = () => { - const navigate = useNavigate(); - const handleClick = () => navigate('/LoggedIn'); - - const style = { - height: '75px', - width: '500px', - }; - - return ( -
-
-
-
- -
- - - - -
- -
-
-
-
- ); - - } - - export default Settings; \ No newline at end of file +import ButtonGroup from "@mui/material/ButtonGroup"; +import { Header, Footer } from "../components/HeaderFooter"; + +import "../styles/settings.css"; + +const Settings = () => { + const navigate = useNavigate(); + const handleClick = () => navigate("/LoggedIn"); + + const style = { + height: "75px", + width: "500px", + }; + + return ( +
+
+
+
+ +
+ + + + +
+ +
+
+
+
+ ); +}; + +export default Settings; diff --git a/frontend/src/react-accessibility.d.ts b/frontend/src/react-accessibility.d.ts index 450ae50f..b2885f7a 100644 --- a/frontend/src/react-accessibility.d.ts +++ b/frontend/src/react-accessibility.d.ts @@ -1,3 +1,3 @@ declare module "react-accessibility" { - export const AccessibilityWidget: React.FC; - } + export const AccessibilityWidget: React.FC; +} diff --git a/frontend/src/styles/App.css b/frontend/src/styles/App.css index 3a6d8ff8..8ba3ac51 100644 --- a/frontend/src/styles/App.css +++ b/frontend/src/styles/App.css @@ -1,27 +1,27 @@ .accessibility-widget { - padding: 16px; - background-color: #f0f0f0; - border: 1px solid #ccc; - border-radius: 4px; - margin-bottom: 20px; + padding: 16px; + background-color: #f0f0f0; + border: 1px solid #ccc; + border-radius: 4px; + margin-bottom: 20px; } /* Additional styles for responsiveness */ @media (max-width: 768px) { - div { - flex-direction: column; - } + div { + flex-direction: column; + } - .accessibility-widget { - padding: 12px; - margin-bottom: 15px; - } + .accessibility-widget { + padding: 12px; + margin-bottom: 15px; + } } /* Style for the banner */ .banner { - background-color: #00797C; - color: #FFF; + background-color: #00797c; + color: #fff; font-size: 14px; text-align: center; padding: 15px; @@ -59,7 +59,7 @@ box-shadow: none; color: #fff; font-family: Poppins, sans-serif; - font-size: .9375rem; + font-size: 0.9375rem; margin-top: 10px; padding: 7px 10px; text-shadow: none; @@ -68,7 +68,6 @@ border-radius: 0; } - .hidden { display: none; } diff --git a/frontend/src/styles/family.css b/frontend/src/styles/family.css index f0dbbeca..620d605e 100644 --- a/frontend/src/styles/family.css +++ b/frontend/src/styles/family.css @@ -3,7 +3,7 @@ width: 100vw; display: grid; - grid-template-areas: + grid-template-areas: "header header header" "familyMenu speciesReactions speciesReactions" "footer footer footer"; @@ -11,18 +11,23 @@ grid-template-columns: 1fr 2fr; /* 1/3 and 2/3 for the middle sections */ /* gap: 8px; */ } - - - -.headerBar { grid-area: header;} -.familiesMenu { grid-area: familyMenu;} -.speciesReactions {grid-area: speciesReactions;} -.footerBar { grid-area: footer;} +.headerBar { + grid-area: header; +} +.familiesMenu { + grid-area: familyMenu; +} +.speciesReactions { + grid-area: speciesReactions; +} +.footerBar { + grid-area: footer; +} .modal-visible { position: absolute; - animation: slideIn 2.5s cubic-bezier(0,-0.01,.01,1) infinite; + animation: slideIn 2.5s cubic-bezier(0, -0.01, 0.01, 1) infinite; } .modal-hidden { @@ -36,4 +41,4 @@ to { left: 0%; } -} \ No newline at end of file +} diff --git a/frontend/src/styles/logIn.css b/frontend/src/styles/logIn.css index f5bd2328..7775c970 100644 --- a/frontend/src/styles/logIn.css +++ b/frontend/src/styles/logIn.css @@ -1,47 +1,86 @@ .layoutLogIn { - height: 100vh; - width: 100vw; - - display: grid; - grid: - "L1 M1 R1" 1fr - "L2 M2 R2" 1fr - "L3 M3 R3" 1fr - "L4 M4 R4" 1fr - "L5 M5 R5" 1fr - "L6 M6 R6" 1fr - "L7 M7 R7" 1fr - "L8 M8 R8" 1fr - "L9LogIn M9 R9" 1fr - / 1fr 1fr 1fr; - background-color: #C3D7EE; - background-image: url("/src/assets/NCAR_ZoomBG_Blue.jpg"); - background-size: 100%; - background-repeat: no-repeat; - } - + height: 100vh; + width: 100vw; + display: grid; + grid: + "L1 M1 R1" 1fr + "L2 M2 R2" 1fr + "L3 M3 R3" 1fr + "L4 M4 R4" 1fr + "L5 M5 R5" 1fr + "L6 M6 R6" 1fr + "L7 M7 R7" 1fr + "L8 M8 R8" 1fr + "L9LogIn M9 R9" 1fr + / 1fr 1fr 1fr; + background-color: #c3d7ee; + background-image: url("/src/assets/NCAR_ZoomBG_Blue.jpg"); + background-size: 100%; + background-repeat: no-repeat; +} -.L1 { grid-area: L1; } -.M1 { grid-area: M1; } -.R1 { grid-area: R1; } -.L2 { grid-area: L2; } -.M2 { grid-area: M2; } -.R2 { grid-area: R2; } -.L3 { grid-area: L3; } -.M3 { grid-area: M3; } -.R3 { grid-area: R3; } -.L4 { grid-area: L4; } -.M4 { grid-area: M4; } -.R4 { grid-area: R4; } -.L5 { grid-area: L5; } -.M5 { grid-area: M5; } -.R5 { grid-area: R5; } -.L7 { grid-area: L7; } -.M7 { grid-area: M7; } -.R7 { grid-area: R7; } -.L9LogIn {grid-area: L9LogIn; grid-column: span 3;} -.M9 { grid-area: M9; } -.R9 { grid-area: R9; } - - +.L1 { + grid-area: L1; +} +.M1 { + grid-area: M1; +} +.R1 { + grid-area: R1; +} +.L2 { + grid-area: L2; +} +.M2 { + grid-area: M2; +} +.R2 { + grid-area: R2; +} +.L3 { + grid-area: L3; +} +.M3 { + grid-area: M3; +} +.R3 { + grid-area: R3; +} +.L4 { + grid-area: L4; +} +.M4 { + grid-area: M4; +} +.R4 { + grid-area: R4; +} +.L5 { + grid-area: L5; +} +.M5 { + grid-area: M5; +} +.R5 { + grid-area: R5; +} +.L7 { + grid-area: L7; +} +.M7 { + grid-area: M7; +} +.R7 { + grid-area: R7; +} +.L9LogIn { + grid-area: L9LogIn; + grid-column: span 3; +} +.M9 { + grid-area: M9; +} +.R9 { + grid-area: R9; +} diff --git a/frontend/src/styles/loggedIn.css b/frontend/src/styles/loggedIn.css index e5e83adf..93b2be9b 100644 --- a/frontend/src/styles/loggedIn.css +++ b/frontend/src/styles/loggedIn.css @@ -1,42 +1,75 @@ .layoutLoggedIn { - height: 100vh; - width: 100vw; - - display: grid; - grid: - "L1LoggedIn M1 R1" 1fr - "L2 M2 R2" 1fr - "L3 M3 R3" 1fr - "L4 M4 R4" 1fr - "L5 M5 R5" 1fr - "L6 M6 R6" 1fr - "L7 M7 R7" 1fr - "L8 M8 R8" 1fr - "L9LoggedIn M9 R9" 1fr - / 1fr 1fr 1fr; - background-color: #C3D7EE; - } - - - - .L1LoggedIn { grid-area: L1LoggedIn; grid-column: span 3;} - .M1 { grid-area: M1; } - .R1 { grid-area: R1; } - .L2 { grid-area: L2; } - .M2 { grid-area: M2; } - .R2 { grid-area: R2; } - .L3 { grid-area: L3; } - .M3 { grid-area: M3; } - .R3 { grid-area: R3; } - .L4 { grid-area: L4; } - .M4 { grid-area: M4; } - .R4 { grid-area: R4; } - .L5 { grid-area: L5; } - .M5 { grid-area: M5; } - .R5 { grid-area: R5; } - .L9LoggedIn {grid-area: L9LoggedIn; grid-column: span 3;} - .M9 { grid-area: M9; } - .R9 { grid-area: R9; } - - - \ No newline at end of file + height: 100vh; + width: 100vw; + + display: grid; + grid: + "L1LoggedIn M1 R1" 1fr + "L2 M2 R2" 1fr + "L3 M3 R3" 1fr + "L4 M4 R4" 1fr + "L5 M5 R5" 1fr + "L6 M6 R6" 1fr + "L7 M7 R7" 1fr + "L8 M8 R8" 1fr + "L9LoggedIn M9 R9" 1fr + / 1fr 1fr 1fr; + background-color: #c3d7ee; +} + +.L1LoggedIn { + grid-area: L1LoggedIn; + grid-column: span 3; +} +.M1 { + grid-area: M1; +} +.R1 { + grid-area: R1; +} +.L2 { + grid-area: L2; +} +.M2 { + grid-area: M2; +} +.R2 { + grid-area: R2; +} +.L3 { + grid-area: L3; +} +.M3 { + grid-area: M3; +} +.R3 { + grid-area: R3; +} +.L4 { + grid-area: L4; +} +.M4 { + grid-area: M4; +} +.R4 { + grid-area: R4; +} +.L5 { + grid-area: L5; +} +.M5 { + grid-area: M5; +} +.R5 { + grid-area: R5; +} +.L9LoggedIn { + grid-area: L9LoggedIn; + grid-column: span 3; +} +.M9 { + grid-area: M9; +} +.R9 { + grid-area: R9; +} diff --git a/frontend/src/styles/settings.css b/frontend/src/styles/settings.css index 302b045f..6a5be70b 100644 --- a/frontend/src/styles/settings.css +++ b/frontend/src/styles/settings.css @@ -1,41 +1,70 @@ .layoutSettings { - height: 100vh; - width: 100vw; - - display: grid; - grid: - "L1Settings M1 R1" 1fr - "L2 M2 R2" 1fr - "L3 M3Settings R3" 1fr - "L4 M4 R4" 1fr - "L5 M5 R5" 1fr - "L6 M6 R6" 1fr - "L7 M7 R7" 1fr - "L8 M8 R8" 1fr - "L9Settings M9 R9" 1fr - / 1fr 1fr 1fr; - gap: 8px; - background-color: #C3D7EE; - } - - - - .L1Settings { grid-area: L1Settings; grid-column: span 3;} - .M1 { grid-area: M1; } - .R1 { grid-area: R1; } - .L2 { grid-area: L2; } - .M2 { grid-area: M2; } - .R2 { grid-area: R2; } - .L3 { grid-area: L3; } - .M3Settings { grid-area: M3Settings; } - .R3 { grid-area: R3; } - .L4 { grid-area: L4; } - .M4 { grid-area: M4; } - .R4 { grid-area: R4; } - .L5 { grid-area: L5; } - .M5 { grid-area: M5; } - .R5 { grid-area: R5; } - .L9Settings { grid-area: L9Settings; grid-column: span 3;} - - - \ No newline at end of file + height: 100vh; + width: 100vw; + + display: grid; + grid: + "L1Settings M1 R1" 1fr + "L2 M2 R2" 1fr + "L3 M3Settings R3" 1fr + "L4 M4 R4" 1fr + "L5 M5 R5" 1fr + "L6 M6 R6" 1fr + "L7 M7 R7" 1fr + "L8 M8 R8" 1fr + "L9Settings M9 R9" 1fr + / 1fr 1fr 1fr; + gap: 8px; + background-color: #c3d7ee; +} + +.L1Settings { + grid-area: L1Settings; + grid-column: span 3; +} +.M1 { + grid-area: M1; +} +.R1 { + grid-area: R1; +} +.L2 { + grid-area: L2; +} +.M2 { + grid-area: M2; +} +.R2 { + grid-area: R2; +} +.L3 { + grid-area: L3; +} +.M3Settings { + grid-area: M3Settings; +} +.R3 { + grid-area: R3; +} +.L4 { + grid-area: L4; +} +.M4 { + grid-area: M4; +} +.R4 { + grid-area: R4; +} +.L5 { + grid-area: L5; +} +.M5 { + grid-area: M5; +} +.R5 { + grid-area: R5; +} +.L9Settings { + grid-area: L9Settings; + grid-column: span 3; +} diff --git a/frontend/test/API_CreateMethods.test.tsx b/frontend/test/API_CreateMethods.test.tsx index 013a12d4..6e000f60 100644 --- a/frontend/test/API_CreateMethods.test.tsx +++ b/frontend/test/API_CreateMethods.test.tsx @@ -1,6 +1,6 @@ -import { describe, expect, it, vi } from 'vitest'; -import type { Mock } from 'vitest'; -import axios, { AxiosHeaders, AxiosResponse } from 'axios'; +import { describe, expect, it, vi } from "vitest"; +import type { Mock } from "vitest"; +import axios, { AxiosHeaders, AxiosResponse } from "axios"; import { createFamily, createMechanism, @@ -11,158 +11,176 @@ import { addSpeciesToMechanism, createUser, addUserToMechanism, - createProperty -} from '../src/API/API_CreateMethods'; + createProperty, +} from "../src/API/API_CreateMethods"; -// Mock axios using vitest's built-in mock function -vi.mock('axios'); +// Mock axios using vitest's built-in mock function +vi.mock("axios"); -describe('API create functions tests', () => { +describe("API create functions tests", () => { const mockResponseData = { success: true }; function createMockResponse() { return { data: mockResponseData, status: 200, - statusText: 'OK', + statusText: "OK", headers: {}, config: { - headers: new AxiosHeaders({ 'Content-Type': 'application/json' }), + headers: new AxiosHeaders({ "Content-Type": "application/json" }), }, } as AxiosResponse; } - it('should create family and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const familyData = { id: '123', name: 'Test Family' }; + it("should create family and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const familyData = { id: "123", name: "Test Family" }; const result = await createFamily(familyData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/families', + "http://localhost:8080/api/families", familyData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should create mechanism and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const mechanismData = { id: '123', name: 'Test Mechanism' }; + it("should create mechanism and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const mechanismData = { id: "123", name: "Test Mechanism" }; const result = await createMechanism(mechanismData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/mechanism', + "http://localhost:8080/api/mechanism", mechanismData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should create reaction and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const reactionData = { id: '123', type: 'Test Reaction' }; + it("should create reaction and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const reactionData = { id: "123", type: "Test Reaction" }; const result = await createReaction(reactionData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/reactions', + "http://localhost:8080/api/reactions", reactionData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should create species and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const speciesData = { id: '123', name: 'Test Species' }; + it("should create species and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const speciesData = { id: "123", name: "Test Species" }; const result = await createSpecies(speciesData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/species', + "http://localhost:8080/api/species", speciesData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should add species to reaction and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const reactionSpeciesData = { reactionId: '123', speciesId: '456' }; + it("should add species to reaction and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const reactionSpeciesData = { reactionId: "123", speciesId: "456" }; const result = await addSpeciesToReaction(reactionSpeciesData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/reactionspecies', + "http://localhost:8080/api/reactionspecies", reactionSpeciesData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should add reaction to mechanism and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const mechanismReactionData = { mechanismId: '123', reactionId: '456' }; + it("should add reaction to mechanism and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const mechanismReactionData = { mechanismId: "123", reactionId: "456" }; const result = await addReactionToMechanism(mechanismReactionData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/mechanismreactions', + "http://localhost:8080/api/mechanismreactions", mechanismReactionData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should add species to mechanism and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const mechanismSpeciesData = { mechanismId: '123', speciesId: '456' }; + it("should add species to mechanism and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const mechanismSpeciesData = { mechanismId: "123", speciesId: "456" }; const result = await addSpeciesToMechanism(mechanismSpeciesData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/mechanismspecies', + "http://localhost:8080/api/mechanismspecies", mechanismSpeciesData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should create user and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const userData = { id: '123', name: 'Test User' }; + it("should create user and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const userData = { id: "123", name: "Test User" }; const result = await createUser(userData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/users', + "http://localhost:8080/api/users", userData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should add user to mechanism and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const userMechanismData = { userId: '123', mechanismId: '456' }; + it("should add user to mechanism and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const userMechanismData = { userId: "123", mechanismId: "456" }; const result = await addUserToMechanism(userMechanismData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/usermechanism', + "http://localhost:8080/api/usermechanism", userMechanismData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); }); -vi.mock('axios'); +vi.mock("axios"); -describe('API create functions tests', () => { +describe("API create functions tests", () => { const mockResponseData = { success: true }; function createMockResponse() { return { data: mockResponseData, status: 200, - statusText: 'OK', + statusText: "OK", headers: {}, config: { - headers: new AxiosHeaders({ 'Content-Type': 'application/json' }), + headers: new AxiosHeaders({ "Content-Type": "application/json" }), }, } as AxiosResponse; } @@ -171,139 +189,165 @@ describe('API create functions tests', () => { return { response: { status: 500, - data: { error: 'Internal Server Error' }, + data: { error: "Internal Server Error" }, }, }; } - it('should create family and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const familyData = { id: '123', name: 'Test Family' }; + it("should create family and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const familyData = { id: "123", name: "Test Family" }; const result = await createFamily(familyData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/families', + "http://localhost:8080/api/families", familyData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should create mechanism and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const mechanismData = { id: '123', name: 'Test Mechanism' }; + it("should create mechanism and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const mechanismData = { id: "123", name: "Test Mechanism" }; const result = await createMechanism(mechanismData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/mechanism', + "http://localhost:8080/api/mechanism", mechanismData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should create reaction and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const reactionData = { id: '123', type: 'Test Reaction' }; + it("should create reaction and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const reactionData = { id: "123", type: "Test Reaction" }; const result = await createReaction(reactionData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/reactions', + "http://localhost:8080/api/reactions", reactionData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should handle error when creating family', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockRejectedValue(createMockErrorResponse()) as Mock; - const familyData = { id: '123', name: 'Test Family' }; + it("should handle error when creating family", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockRejectedValue(createMockErrorResponse()) as Mock; + const familyData = { id: "123", name: "Test Family" }; try { await createFamily(familyData); } catch (error) { expect(error.response.status).toBe(500); - expect(error.response.data.error).toBe('Internal Server Error'); + expect(error.response.data.error).toBe("Internal Server Error"); } }); - it('should handle error when creating mechanism', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockRejectedValue(createMockErrorResponse()) as Mock; - const mechanismData = { id: '123', name: 'Test Mechanism' }; + it("should handle error when creating mechanism", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockRejectedValue(createMockErrorResponse()) as Mock; + const mechanismData = { id: "123", name: "Test Mechanism" }; try { await createMechanism(mechanismData); } catch (error) { expect(error.response.status).toBe(500); - expect(error.response.data.error).toBe('Internal Server Error'); + expect(error.response.data.error).toBe("Internal Server Error"); } }); - it('should handle non-200 status response when adding species to reaction', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValueOnce({ - data: { error: 'Bad Request' }, + it("should handle non-200 status response when adding species to reaction", async () => { + const mockedCreate = vi.spyOn(axios, "post").mockResolvedValueOnce({ + data: { error: "Bad Request" }, status: 400, }) as Mock; - const reactionSpeciesData = { reactionId: '123', speciesId: '456' }; + const reactionSpeciesData = { reactionId: "123", speciesId: "456" }; try { await addSpeciesToReaction(reactionSpeciesData); } catch (error) { expect(error.response.status).toBe(400); - expect(error.response.data.error).toBe('Bad Request'); + expect(error.response.data.error).toBe("Bad Request"); } }); - it('should validate user data when creating user', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const userData = { id: '123', name: 'Test User' }; + it("should validate user data when creating user", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const userData = { id: "123", name: "Test User" }; const result = await createUser(userData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/users', + "http://localhost:8080/api/users", userData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should add user to mechanism and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const userMechanismData = { userId: '123', mechanismId: '456' }; + it("should add user to mechanism and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const userMechanismData = { userId: "123", mechanismId: "456" }; const result = await addUserToMechanism(userMechanismData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/usermechanism', + "http://localhost:8080/api/usermechanism", userMechanismData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should create property and return data', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockResolvedValue(createMockResponse()) as Mock; - const propertyData = { id: '123', name: 'Test Property', value: 'Test Value' }; // Adjust the property data as needed + it("should create property and return data", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockResolvedValue(createMockResponse()) as Mock; + const propertyData = { + id: "123", + name: "Test Property", + value: "Test Value", + }; // Adjust the property data as needed const result = await createProperty(propertyData); expect(mockedCreate).toHaveBeenCalledWith( - 'http://localhost:8080/api/properties', + "http://localhost:8080/api/properties", propertyData, - { headers: { 'Content-Type': 'application/json' } } + { headers: { "Content-Type": "application/json" } }, ); expect(result).toEqual(mockResponseData); }); - it('should handle error when creating property', async () => { - const mockedCreate = vi.spyOn(axios, 'post').mockRejectedValue(createMockErrorResponse()) as Mock; - const propertyData = { id: '123', name: 'Test Property', value: 'Test Value' }; + it("should handle error when creating property", async () => { + const mockedCreate = vi + .spyOn(axios, "post") + .mockRejectedValue(createMockErrorResponse()) as Mock; + const propertyData = { + id: "123", + name: "Test Property", + value: "Test Value", + }; try { await createProperty(propertyData); } catch (error) { expect(error.response.status).toBe(500); - expect(error.response.data.error).toBe('Internal Server Error'); + expect(error.response.data.error).toBe("Internal Server Error"); } }); }); diff --git a/frontend/test/API_DeleteMethods.test.tsx b/frontend/test/API_DeleteMethods.test.tsx index e9ca04ef..a89439c0 100644 --- a/frontend/test/API_DeleteMethods.test.tsx +++ b/frontend/test/API_DeleteMethods.test.tsx @@ -1,106 +1,127 @@ -import { describe, expect, it, vi } from 'vitest'; -import type { Mock } from 'vitest'; -import axios, { AxiosResponse } from 'axios'; -import { deleteFamily, deleteMechanism, deleteSpecies, deleteReaction, deleteUser, deleteProperty } from '../src/API/API_DeleteMethods'; +import { describe, expect, it, vi } from "vitest"; +import type { Mock } from "vitest"; +import axios, { AxiosResponse } from "axios"; +import { + deleteFamily, + deleteMechanism, + deleteSpecies, + deleteReaction, + deleteUser, + deleteProperty, +} from "../src/API/API_DeleteMethods"; // Mock axios using vitest's built-in mock function -vi.mock('axios'); - -describe('API delete functions tests', () => { - const mockResponseData = { success: true }; - - function createMockResponse() { - return { - data: mockResponseData, - status: 200, - statusText: 'OK', - headers: {}, - config: {}, - } as AxiosResponse; - } - - it('should successfully delete a family', async () => { - const mockedDelete = vi.spyOn(axios, 'delete').mockResolvedValue(createMockResponse()) as Mock; - - const id = '12345'; - const result = await deleteFamily(id); - - expect(mockedDelete).toHaveBeenCalledWith( - `http://localhost:8080/api/families/${id}`, - { - headers: { 'Content-Type': 'application/json' }, - } - ); - expect(result).toEqual(mockResponseData); - }); - - it('should successfully delete a mechanism', async () => { - const mockedDelete = vi.spyOn(axios, 'delete').mockResolvedValue(createMockResponse()) as Mock; - - const id = '12345'; - const result = await deleteMechanism(id); - - expect(mockedDelete).toHaveBeenCalledWith(`http://localhost:8080/api/mechanism/${id}`); - expect(result).toEqual(mockResponseData); - }); - - it('should successfully delete a species', async () => { - const mockedDelete = vi.spyOn(axios, 'delete').mockResolvedValue(createMockResponse()) as Mock; - - const id = '12345'; - const result = await deleteSpecies(id); - - expect(mockedDelete).toHaveBeenCalledWith( - `http://localhost:8080/api/species/${id}`, - { - headers: { 'Content-Type': 'application/json' }, - } - ); - expect(result).toEqual(mockResponseData); - }); - - it('should successfully delete a reaction', async () => { - const mockedDelete = vi.spyOn(axios, 'delete').mockResolvedValue(createMockResponse()) as Mock; - - const id = '12345'; - const result = await deleteReaction(id); - - expect(mockedDelete).toHaveBeenCalledWith( - `http://localhost:8080/api/reactions/${id}`, - { - headers: { 'Content-Type': 'application/json' }, - } - ); - expect(result).toEqual(mockResponseData); - }); - - it('should successfully delete a user', async () => { - const mockedDelete = vi.spyOn(axios, 'delete').mockResolvedValue(createMockResponse()) as Mock; - - const id = '12345'; - const result = await deleteUser(id); - - expect(mockedDelete).toHaveBeenCalledWith( - `http://localhost:8080/api/users/${id}`, - { - headers: { 'Content-Type': 'application/json' }, - } - ); - expect(result).toEqual(mockResponseData); - }); - - it('should successfully delete a property', async () => { - const mockedDelete = vi.spyOn(axios, 'delete').mockResolvedValue(createMockResponse()) as Mock; - - const id = '12345'; // Test property ID - const result = await deleteProperty(id); - - expect(mockedDelete).toHaveBeenCalledWith( - `http://localhost:8080/api/properties/${id}`, // URL based on the deleteProperty function - { - headers: { 'Content-Type': 'application/json' }, // Request headers - } - ); - expect(result).toEqual(mockResponseData); // Ensure the result matches the expected response - }); +vi.mock("axios"); + +describe("API delete functions tests", () => { + const mockResponseData = { success: true }; + + function createMockResponse() { + return { + data: mockResponseData, + status: 200, + statusText: "OK", + headers: {}, + config: {}, + } as AxiosResponse; + } + + it("should successfully delete a family", async () => { + const mockedDelete = vi + .spyOn(axios, "delete") + .mockResolvedValue(createMockResponse()) as Mock; + + const id = "12345"; + const result = await deleteFamily(id); + + expect(mockedDelete).toHaveBeenCalledWith( + `http://localhost:8080/api/families/${id}`, + { + headers: { "Content-Type": "application/json" }, + }, + ); + expect(result).toEqual(mockResponseData); + }); + + it("should successfully delete a mechanism", async () => { + const mockedDelete = vi + .spyOn(axios, "delete") + .mockResolvedValue(createMockResponse()) as Mock; + + const id = "12345"; + const result = await deleteMechanism(id); + + expect(mockedDelete).toHaveBeenCalledWith( + `http://localhost:8080/api/mechanism/${id}`, + ); + expect(result).toEqual(mockResponseData); + }); + + it("should successfully delete a species", async () => { + const mockedDelete = vi + .spyOn(axios, "delete") + .mockResolvedValue(createMockResponse()) as Mock; + + const id = "12345"; + const result = await deleteSpecies(id); + + expect(mockedDelete).toHaveBeenCalledWith( + `http://localhost:8080/api/species/${id}`, + { + headers: { "Content-Type": "application/json" }, + }, + ); + expect(result).toEqual(mockResponseData); + }); + + it("should successfully delete a reaction", async () => { + const mockedDelete = vi + .spyOn(axios, "delete") + .mockResolvedValue(createMockResponse()) as Mock; + + const id = "12345"; + const result = await deleteReaction(id); + + expect(mockedDelete).toHaveBeenCalledWith( + `http://localhost:8080/api/reactions/${id}`, + { + headers: { "Content-Type": "application/json" }, + }, + ); + expect(result).toEqual(mockResponseData); + }); + + it("should successfully delete a user", async () => { + const mockedDelete = vi + .spyOn(axios, "delete") + .mockResolvedValue(createMockResponse()) as Mock; + + const id = "12345"; + const result = await deleteUser(id); + + expect(mockedDelete).toHaveBeenCalledWith( + `http://localhost:8080/api/users/${id}`, + { + headers: { "Content-Type": "application/json" }, + }, + ); + expect(result).toEqual(mockResponseData); + }); + + it("should successfully delete a property", async () => { + const mockedDelete = vi + .spyOn(axios, "delete") + .mockResolvedValue(createMockResponse()) as Mock; + + const id = "12345"; // Test property ID + const result = await deleteProperty(id); + + expect(mockedDelete).toHaveBeenCalledWith( + `http://localhost:8080/api/properties/${id}`, // URL based on the deleteProperty function + { + headers: { "Content-Type": "application/json" }, // Request headers + }, + ); + expect(result).toEqual(mockResponseData); // Ensure the result matches the expected response + }); }); diff --git a/frontend/test/API_GetMethods.test.tsx b/frontend/test/API_GetMethods.test.tsx index 05402586..59d9be87 100644 --- a/frontend/test/API_GetMethods.test.tsx +++ b/frontend/test/API_GetMethods.test.tsx @@ -1,492 +1,373 @@ -import { describe, expect, it, vi } from 'vitest'; -import type { Mock } from 'vitest'; -import axios, { AxiosHeaders, AxiosResponse } from 'axios'; +import { describe, expect, it, vi } from "vitest"; +import type { Mock } from "vitest"; +import axios, { AxiosHeaders, AxiosResponse } from "axios"; import { - downloadOAJSON, - downloadOAYAML, - getFamilies, - getFamily, - getReactions, - getReaction, - getReactionsByMechanismId, - getAllSpecies, - getSpecies, - getSpeciesByMechanismId, - getMechanisms, - getMechanism, - getMechanismsByFamilyId, - getSpeciesByFamilyId, - getReactionsByFamilyId, - getReactantsByReactionIdAsync, - getProductsByReactionIdAsync, - getUsers, - getUserByEmail, - getUserById, - getPropertyById, -} from '../src/API/API_GetMethods'; + downloadOAJSON, + downloadOAYAML, + getFamilies, + getFamily, + getReactions, + getReaction, + getReactionsByMechanismId, + getAllSpecies, + getSpecies, + getSpeciesByMechanismId, + getMechanisms, + getMechanism, + getMechanismsByFamilyId, + getSpeciesByFamilyId, + getReactionsByFamilyId, + getReactantsByReactionIdAsync, + getProductsByReactionIdAsync, + getUsers, + getUserByEmail, + getUserById, + getPropertyById, +} from "../src/API/API_GetMethods"; // Mock axios using vitest's built-in mock function -vi.mock('axios'); - -describe('API get functions tests', () => { - const mockResponseData = { success: true }; - - function createMockResponse() { - return { - data: mockResponseData, - status: 200, - statusText: 'OK', - headers: {}, - config: { - headers: new AxiosHeaders({ 'Content-Type': 'text/plain' }), - }, - } as AxiosResponse; - } - -// Tests for getFamilies -it('should successfully get all families', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; - const result = await getFamilies(); - - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/families`); - expect(result).toEqual(mockResponseData); -}); +vi.mock("axios"); + +describe("API get functions tests", () => { + const mockResponseData = { success: true }; + + function createMockResponse() { + return { + data: mockResponseData, + status: 200, + statusText: "OK", + headers: {}, + config: { + headers: new AxiosHeaders({ "Content-Type": "text/plain" }), + }, + } as AxiosResponse; + } + + // Tests for downloadOAJSON + it("should successfully get OAJSON with valid tag_mechanism_uuid", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; + + const tag_mechanism_uuid = "valid-uuid"; + const result = await downloadOAJSON(tag_mechanism_uuid); -it('should return an empty list if the API call fails for getFamilies', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/openatmos/mechanism/${tag_mechanism_uuid}/json`, + { + headers: { "Content-Type": "text/plain" }, + responseType: "text", + }, + ); - const result = await getFamilies(); - expect(result).toEqual([]); -}); - + expect(result).toBe(mockResponseData); + }); -it('should throw an error if the getFamilies() API call fails', async () => { - const mockError = { response: { status: 500, statusText: 'Internal Server Error' } }; - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const result = await getFamilies(); + it("should return an empty string when tag_mechanism_uuid is not provided", async () => { + const mockedGet = vi.spyOn(axios, "get"); - expect(result).toEqual([]); -}); - + const result = await downloadOAJSON(); -// Tests for getFamily -it('should successfully get a family with valid uuid', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + expect(result).toBe(""); + expect(mockedGet).not.toHaveBeenCalled(); - const uuid = 'valid-uuid'; - const result = await getFamily(uuid); - - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/families/${uuid}`); - expect(result).toEqual(mockResponseData); -}); + mockedGet.mockRestore(); + }); + it("should handle error correctly for downloadOAJSON", async () => { + const mockError = new Error("Network error"); + vi.spyOn(axios, "get").mockRejectedValueOnce(mockError); -it('should throw an error if the getFamily() API call fails', async () => { - const mockError = { response: { status: 500, statusText: 'Internal Server Error' } }; - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const uuid = 'valid-uuid'; - await expect(getFamily(uuid)).rejects.toThrow('Failed to fetch family. Please try again later.'); -}); + const tag_mechanism_uuid = "invalid-uuid"; + await expect(downloadOAJSON(tag_mechanism_uuid)).rejects.toThrow( + "Network error", + ); - // Tests for getTagMechanisms -it('should successfully get all tag mechanisms', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; - const result = await getMechanisms(); + expect(axios.get).toHaveBeenCalledWith( + `http://localhost:8080/api/openatmos/mechanism/${tag_mechanism_uuid}/json`, + { + headers: { "Content-Type": "text/plain" }, + responseType: "text", + }, + ); + }); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/mechanism`); - expect(result).toEqual(mockResponseData); -}); + // Tests for downloadOAYAML + it("should successfully get OAYAML with valid tag_mechanism_uuid", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; -it('should return an empty list if the API call fails for getMechanisms', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); + const tag_mechanism_uuid = "valid-uuid"; + const result = await downloadOAYAML(tag_mechanism_uuid); - const result = await getMechanisms(); - expect(result).toEqual([]); -}); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/openatmos/mechanism/${tag_mechanism_uuid}/yaml`, + { + headers: { "Content-Type": "text/plain" }, + responseType: "text", + }, + ); -// Tests for getTagMechanismsFromFamily -it('should successfully get tag mechanisms from family with valid family_uuid', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + expect(result).toBe(mockResponseData); + }); - const family_uuid = 'valid-uuid'; - const result = await getMechanismsByFamilyId(family_uuid); + // Tests for getFamilies + it("should successfully get all families", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; + const result = await getFamilies(); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/mechanism/family/${family_uuid}`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/families`, + ); expect(result).toEqual(mockResponseData); -}); - -it('should return an empty list if the API call fails for getMechanismsByFamilyID', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const family_uuid = 'valid-uuid'; - const result = await getMechanismsByFamilyId(family_uuid); - expect(result).toEqual([]); -}); + }); -// Tests for getTagMechanism -it('should successfully get a tag mechanism with valid uuid', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + // Tests for getFamily + it("should successfully get a family with valid uuid", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; - const uuid = 'valid-uuid'; - const result = await getMechanism(uuid); + const uuid = "valid-uuid"; + const result = await getFamily(uuid); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/mechanism/${uuid}`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/families/${uuid}`, + ); expect(result).toEqual(mockResponseData); -}); - -it('should throw an error if the getMechanism() API call fails', async () => { - const mockError = { response: { status: 500, statusText: 'Internal Server Error' } }; - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const uuid = 'valid-uuid'; - await expect(getMechanism(uuid)).rejects.toThrow('Failed to fetch mechanism. Please try again later.'); -}); - + }); - // Tests for getAllSpecies - it('should successfully get all species', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; - const result = await getAllSpecies(); + // Tests for getReactions + it("should successfully get all reactions", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; + const result = await getReactions(); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/species`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/reactions`, + ); expect(result).toEqual(mockResponseData); -}); - -it('should return an empty list if the API call fails for getSpecies', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const result = await getAllSpecies(); - expect(result).toEqual([]); -}); + }); -// Tests for getSpecies -it('should successfully get a species with valid uuid', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + // Tests for getReaction + it("should successfully get a reaction with valid uuid", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; - const uuid = 'valid-uuid'; - const result = await getSpecies(uuid); + const uuid = "valid-uuid"; + const result = await getReaction(uuid); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/species/${uuid}`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/reactions/${uuid}`, + ); expect(result).toEqual(mockResponseData); -}); - -it('should throw an error if the API call fails for getSpeciesById', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const uuid = 'valid-uuid'; - await expect(getSpecies(uuid)).rejects.toThrow('Failed to fetch species. Please try again later.'); -}); - + }); - it('should successfully get species with valid familyId', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + // Tests for getReactionsFromTagMechanism + it("should successfully get reactions from tag mechanism with valid tag_mechanism_uuid", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; - const familyId = 'valid-family-id'; - const result = await getSpeciesByFamilyId(familyId); + const tag_mechanism_uuid = "valid-uuid"; + const result = await getReactionsByMechanismId(tag_mechanism_uuid); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/species/family/${familyId}`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/reactions/mechanism/${tag_mechanism_uuid}`, + ); expect(result).toEqual(mockResponseData); -}); - -it('should return an empty list if the API call fails for getSpeciesByFamilyId', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const family_uuid = 'valid-uuid'; - const result = await getSpeciesByFamilyId(family_uuid); - expect(result).toEqual([]); -}); - -it('should successfully get species from mechanismId', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + }); - const mechanismId = 'valid-mechanism-id'; - const result = await getSpeciesByMechanismId(mechanismId); + // Tests for getAllSpecies + it("should successfully get all species", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; + const result = await getAllSpecies(); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/mechanismspecies/mechanism/${mechanismId}`); + expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/species`); expect(result).toEqual(mockResponseData); -}); - -it('should return an empty list if the API call fails for getSpeciesByMechanismID', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const mechanism_uuid = 'valid-uuid'; - const result = await getSpeciesByMechanismId(mechanism_uuid); - expect(result).toEqual([]); -}); + }); -// Tests for getReactionsFromTagMechanism -it('should successfully get reactions from tag mechanism with valid tag_mechanism_uuid', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + // Tests for getSpecies + it("should successfully get a species with valid uuid", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; - const tag_mechanism_uuid = 'valid-uuid'; - const result = await getReactionsByMechanismId(tag_mechanism_uuid); + const uuid = "valid-uuid"; + const result = await getSpecies(uuid); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/reactions/mechanism/${tag_mechanism_uuid}`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/species/${uuid}`, + ); expect(result).toEqual(mockResponseData); -}); - -it('should return an empty list if the API call fails for getReactionsByMechanismId', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); + }); - const mechanism_uuid = 'valid-uuid'; - const result = await getReactionsByMechanismId(mechanism_uuid); - expect(result).toEqual([]); -}); + // Tests for getTagMechanisms + it("should successfully get all tag mechanisms", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; + const result = await getMechanisms(); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/mechanism`, + ); + expect(result).toEqual(mockResponseData); + }); -it('should successfully get reactions from family with valid familyId', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + // Tests for getTagMechanism + it("should successfully get a tag mechanism with valid uuid", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; - const familyId = 'valid-family-id'; - const result = await getReactionsByFamilyId(familyId); + const uuid = "valid-uuid"; + const result = await getMechanism(uuid); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/reactions/family/${familyId}`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/mechanism/${uuid}`, + ); expect(result).toEqual(mockResponseData); -}); + }); -it('should return an empty list if the API call fails for getReactionsByFamilyId', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); + // Tests for getTagMechanismsFromFamily + it("should successfully get tag mechanisms from family with valid family_uuid", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; - const family_uuid = 'valid-uuid'; - const result = await getReactionsByFamilyId(family_uuid); - expect(result).toEqual([]); -}); - -// Tests for getReactions -it('should successfully get all reactions', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; - const result = await getReactions(); + const family_uuid = "valid-uuid"; + const result = await getMechanismsByFamilyId(family_uuid); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/reactions`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/mechanism/family/${family_uuid}`, + ); expect(result).toEqual(mockResponseData); -}); + }); -it('should return an empty list if the API call fails for getReactions', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); + it("should successfully get species from family with valid familyId", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; - const result = await getReactions(); + const familyId = "valid-family-id"; + const result = await getSpeciesByFamilyId(familyId); - expect(result).toEqual([]); -}); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/species/family/${familyId}`, + ); + expect(result).toEqual(mockResponseData); + }); -// Tests for getReaction -it('should successfully get a reaction with valid uuid', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + it("should successfully get reactions from family with valid familyId", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; - const uuid = 'valid-uuid'; - const result = await getReaction(uuid); + const familyId = "valid-family-id"; + const result = await getReactionsByFamilyId(familyId); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/reactions/${uuid}`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/reactions/family/${familyId}`, + ); expect(result).toEqual(mockResponseData); -}); - -it('should throw an error if the API call fails', async () => { - const mockError = { response: { status: 500, statusText: 'Internal Server Error' } }; - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const uuid = 'valid-uuid'; - await expect(getReaction(uuid)).rejects.toThrow('Failed to fetch reaction. Please try again later.'); -}); + }); -it('should successfully get reactants by reaction ID', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + it("should successfully get reactants by reaction ID", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; - const reactionId = 'valid-reaction-id'; + const reactionId = "valid-reaction-id"; const result = await getReactantsByReactionIdAsync(reactionId); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/reactionspecies/reaction/${reactionId}/reactants`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/reactionspecies/reaction/${reactionId}/reactants`, + ); expect(result).toEqual(mockResponseData); -}); - -it('should return an empty list if the API call fails for getReactantsByReactionId', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const valid_uuid = 'valid-uuid'; - const result = await getReactantsByReactionIdAsync(valid_uuid); - - expect(result).toEqual([]); -}); + }); -it('should successfully get products by reaction ID', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + it("should successfully get products by reaction ID", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; - const reactionId = 'valid-reaction-id'; + const reactionId = "valid-reaction-id"; const result = await getProductsByReactionIdAsync(reactionId); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/reactionspecies/reaction/${reactionId}/products`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/reactionspecies/reaction/${reactionId}/products`, + ); expect(result).toEqual(mockResponseData); -}); - -it('should return an empty list if the API call fails for getProductsByReactionId', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const valid_uuid = 'valid-uuid'; - const result = await getProductsByReactionIdAsync(valid_uuid); - - expect(result).toEqual([]); -}); + }); -// Tests for getUsers -it('should successfully get all users', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + // Tests for getUsers + it("should successfully get all users", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; const result = await getUsers(); expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/users`); expect(result).toEqual(mockResponseData); -}); - -it('should return an empty list if the API call fails for getUsers', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const result = await getUsers(); - expect(result).toEqual([]); -}); + }); -it('should successfully get user by email', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; - const email = 'valid-user-email'; + it("should successfully get user by email", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; + const email = "valid-user-email"; const result = await getUserByEmail(email); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/users/email/${email}`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/users/email/${email}`, + ); expect(result).toEqual(mockResponseData); -}); - -it('should throw an error if the getUserByEmail call fails', async () => { - const mockError = { response: { status: 500, statusText: 'Internal Server Error' } }; - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const email = 'valid-email'; - await expect(getUserByEmail(email)).rejects.toThrow('Failed to fetch user. Please try again later.'); -}); + }); -it('should successfully get user by id', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; - const UserId = 'valid-user-id'; + it("should successfully get user by id", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; + const UserId = "valid-user-id"; const result = await getUserById(UserId); - expect(mockedGet).toHaveBeenCalledWith(`http://localhost:8080/api/users/id/${UserId}`); + expect(mockedGet).toHaveBeenCalledWith( + `http://localhost:8080/api/users/id/${UserId}`, + ); expect(result).toEqual(mockResponseData); -}); - -it('should throw an error if the getUserById call fails with 404', async () => { - const mockError = { response: 'Internal Server Error'}; - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const uuid = 'valid-uuid'; - await expect(getUserById(uuid)).rejects.toThrow('Failed to fetch user. Please try again later.'); -}); + }); -it('should successfully get a property by id', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; + it("should successfully get a property by id", async () => { + const mockedGet = vi + .spyOn(axios, "get") + .mockResolvedValueOnce(createMockResponse()) as Mock; - const propertyId = 'valid-property-id'; + const propertyId = "valid-property-id"; const result = await getPropertyById(propertyId); expect(mockedGet).toHaveBeenCalledWith( - `http://localhost:8080/api/properties/id/${propertyId}` + `http://localhost:8080/api/properties/id/${propertyId}`, ); expect(result).toEqual(mockResponseData); }); -it('should handle error correctly for getPropertyById', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); + it("should handle error correctly for getPropertyById", async () => { + const mockError = new Error("Network error"); + vi.spyOn(axios, "get").mockRejectedValueOnce(mockError); - const propertyId = 'invalid-property-id'; - await expect(getPropertyById(propertyId)).rejects.toThrow('Failed to fetch property. Please try again later.'); + const propertyId = "invalid-property-id"; + await expect(getPropertyById(propertyId)).rejects.toThrow("Network error"); expect(axios.get).toHaveBeenCalledWith( - `http://localhost:8080/api/properties/id/${propertyId}` + `http://localhost:8080/api/properties/id/${propertyId}`, ); }); -/////////////getPropertyBySpeciesAndMechanism///////////// - - - -/////////////////////////////////////////////////////////////////////////// - // Tests for downloadOAJSON - it('should successfully get OAJSON with valid tag_mechanism_uuid', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; - - const tag_mechanism_uuid = 'valid-uuid'; - const result = await downloadOAJSON(tag_mechanism_uuid); - - expect(mockedGet).toHaveBeenCalledWith( - `http://localhost:8080/api/openatmos/mechanism/${tag_mechanism_uuid}/json`, - { - headers: { 'Content-Type': 'text/plain' }, - responseType: 'text', - } - ); - - expect(result).toBe(mockResponseData); - }); - - it('should return an empty string when tag_mechanism_uuid is not provided', async () => { - const mockedGet = vi.spyOn(axios, 'get'); - - const result = await downloadOAJSON(); - - expect(result).toBe(""); - expect(mockedGet).not.toHaveBeenCalled(); - - mockedGet.mockRestore(); - }); - - it('should handle error correctly for downloadOAJSON', async () => { - const mockError = new Error('Network error'); - vi.spyOn(axios, 'get').mockRejectedValueOnce(mockError); - - const tag_mechanism_uuid = 'invalid-uuid'; - await expect(downloadOAJSON(tag_mechanism_uuid)).rejects.toThrow('Network error'); - - expect(axios.get).toHaveBeenCalledWith( - `http://localhost:8080/api/openatmos/mechanism/${tag_mechanism_uuid}/json`, - { - headers: { 'Content-Type': 'text/plain' }, - responseType: 'text', - } - ); - }); - - // Tests for downloadOAYAML - it('should successfully get OAYAML with valid tag_mechanism_uuid', async () => { - const mockedGet = vi.spyOn(axios, 'get').mockResolvedValueOnce(createMockResponse()) as Mock; - - const tag_mechanism_uuid = 'valid-uuid'; - const result = await downloadOAYAML(tag_mechanism_uuid); - - expect(mockedGet).toHaveBeenCalledWith( - `http://localhost:8080/api/openatmos/mechanism/${tag_mechanism_uuid}/yaml`, - { - headers: { 'Content-Type': 'text/plain' }, - responseType: 'text', - } - ); - - expect(result).toBe(mockResponseData); - }); - - - - - - - - -}); \ No newline at end of file +}); diff --git a/frontend/test/API_UpdateMethods.test.tsx b/frontend/test/API_UpdateMethods.test.tsx index 862ce846..1530962f 100644 --- a/frontend/test/API_UpdateMethods.test.tsx +++ b/frontend/test/API_UpdateMethods.test.tsx @@ -1,124 +1,147 @@ -import { describe, expect, it, vi } from 'vitest'; -import type { Mock } from 'vitest'; -import axios, { AxiosHeaders, AxiosResponse } from 'axios'; +import { describe, expect, it, vi } from "vitest"; +import type { Mock } from "vitest"; +import axios, { AxiosHeaders, AxiosResponse } from "axios"; import { updateFamily, updateMechanism, updateSpecies, updateReaction, updateUser, - updateProperty -} from '../src/API/API_UpdateMethods'; -import { Family, Mechanism, Species, Reaction, User, Property } from '../src/API/API_Interfaces'; + updateProperty, +} from "../src/API/API_UpdateMethods"; +import { + Family, + Mechanism, + Species, + Reaction, + User, + Property, +} from "../src/API/API_Interfaces"; // Mock axios using vitest's built-in mock function -vi.mock('axios'); +vi.mock("axios"); -describe('API update functions tests', () => { +describe("API update functions tests", () => { const mockResponseData = { success: true }; function createMockResponse() { return { data: mockResponseData, status: 200, - statusText: 'OK', + statusText: "OK", headers: {}, config: { - headers: new AxiosHeaders({ 'Content-Type': 'application/json' }), + headers: new AxiosHeaders({ "Content-Type": "application/json" }), }, } as AxiosResponse; } - it('should update family and return data', async () => { - const mockedPut = vi.spyOn(axios, 'put').mockResolvedValue(createMockResponse()) as Mock; + it("should update family and return data", async () => { + const mockedPut = vi + .spyOn(axios, "put") + .mockResolvedValue(createMockResponse()) as Mock; - const family: Family = { id: '1', name: 'Test Family' }; + const family: Family = { id: "1", name: "Test Family" }; const result = await updateFamily(family); expect(mockedPut).toHaveBeenCalledWith( `http://localhost:8080/api/families/${family.id}`, family, { - headers: { 'Content-Type': 'application/json' }, - } + headers: { "Content-Type": "application/json" }, + }, ); expect(result).toEqual(mockResponseData); }); - it('should update mechanism and return data', async () => { - const mockedPut = vi.spyOn(axios, 'put').mockResolvedValue(createMockResponse()) as Mock; + it("should update mechanism and return data", async () => { + const mockedPut = vi + .spyOn(axios, "put") + .mockResolvedValue(createMockResponse()) as Mock; - const mechanism: Mechanism = { id: '2', name: 'Test Mechanism' }; + const mechanism: Mechanism = { id: "2", name: "Test Mechanism" }; const result = await updateMechanism(mechanism); expect(mockedPut).toHaveBeenCalledWith( `http://localhost:8080/api/mechanism/${mechanism.id}`, mechanism, { - headers: { 'Content-Type': 'application/json' }, - } + headers: { "Content-Type": "application/json" }, + }, ); expect(result).toEqual(mockResponseData); }); - it('should update species and return data', async () => { - const mockedPut = vi.spyOn(axios, 'put').mockResolvedValue(createMockResponse()) as Mock; + it("should update species and return data", async () => { + const mockedPut = vi + .spyOn(axios, "put") + .mockResolvedValue(createMockResponse()) as Mock; - const species: Species = { id: '3', name: 'Test Species' }; + const species: Species = { id: "3", name: "Test Species" }; const result = await updateSpecies(species); expect(mockedPut).toHaveBeenCalledWith( `http://localhost:8080/api/species/${species.id}`, species, { - headers: { 'Content-Type': 'application/json' }, - } + headers: { "Content-Type": "application/json" }, + }, ); expect(result).toEqual(mockResponseData); }); - it('should update reaction and return data', async () => { - const mockedPut = vi.spyOn(axios, 'put').mockResolvedValue(createMockResponse()) as Mock; + it("should update reaction and return data", async () => { + const mockedPut = vi + .spyOn(axios, "put") + .mockResolvedValue(createMockResponse()) as Mock; - const reaction: Reaction = { id: '4', name: 'Test Reaction' }; + const reaction: Reaction = { id: "4", name: "Test Reaction" }; const result = await updateReaction(reaction); expect(mockedPut).toHaveBeenCalledWith( `http://localhost:8080/api/reactions/${reaction.id}`, reaction, { - headers: { 'Content-Type': 'application/json' }, - } + headers: { "Content-Type": "application/json" }, + }, ); expect(result).toEqual(mockResponseData); }); - it('should update user and return data', async () => { - const mockedPut = vi.spyOn(axios, 'put').mockResolvedValue(createMockResponse()) as Mock; + it("should update user and return data", async () => { + const mockedPut = vi + .spyOn(axios, "put") + .mockResolvedValue(createMockResponse()) as Mock; - const user: User = { id: '5', username: 'testuser', email: 'test@example.com' }; + const user: User = { + id: "5", + username: "testuser", + email: "test@example.com", + }; const result = await updateUser(user.id, user); expect(mockedPut).toHaveBeenCalledWith( `http://localhost:8080/api/users/${user.id}`, user, { - headers: { 'Content-Type': 'application/json' }, - } + headers: { "Content-Type": "application/json" }, + }, ); expect(result).toEqual(mockResponseData); }); - it('should update property and return data', async () => { - const mockedPut = vi.spyOn(axios, 'put').mockResolvedValue(createMockResponse()) as Mock; + it("should update property and return data", async () => { + const mockedPut = vi + .spyOn(axios, "put") + .mockResolvedValue(createMockResponse()) as Mock; const property: Property = { - id: '6', - species_id: '3', + id: "6", + species_id: "3", tolerance: 0.5, weight: 1.2, concentration: 0.7, @@ -130,11 +153,10 @@ describe('API update functions tests', () => { `http://localhost:8080/api/properties/${property.id}`, property, { - headers: { 'Content-Type': 'application/json' }, - } + headers: { "Content-Type": "application/json" }, + }, ); expect(result).toEqual(mockResponseData); }); }); - diff --git a/frontend/test/App.test.tsx b/frontend/test/App.test.tsx index 497a07d5..5b768ed0 100644 --- a/frontend/test/App.test.tsx +++ b/frontend/test/App.test.tsx @@ -1,34 +1,34 @@ -import { describe, expect, it } from 'vitest'; -import { render } from '@testing-library/react'; -import React from 'react'; -import { MemoryRouter } from 'react-router-dom'; -import App from '../src/pages/App'; -import { GoogleOAuthProvider } from '@react-oauth/google'; +import { describe, expect, it } from "vitest"; +import { render } from "@testing-library/react"; +import React from "react"; +import { MemoryRouter } from "react-router-dom"; +import App from "../src/pages/App"; +import { GoogleOAuthProvider } from "@react-oauth/google"; -describe('App Component Test', () => { - it('should render the correct components based on the routes', () => { - // Define the routes and expected texts - const routes = [ - { path: '/', expectedText: 'Chemistry Cafe' }, - { path: '/LoggedIn', expectedText: 'Families' }, - { path: '/FamilyPage', expectedText: 'Families' }, - { path: '/Settings', expectedText: 'Back' }, - ]; +describe("App Component Test", () => { + it("should render the correct components based on the routes", () => { + // Define the routes and expected texts + const routes = [ + { path: "/", expectedText: "Chemistry Cafe" }, + { path: "/LoggedIn", expectedText: "Families" }, + { path: "/FamilyPage", expectedText: "Families" }, + { path: "/Settings", expectedText: "Back" }, + ]; - // Iterate through each route and test rendering the App component - routes.forEach(({ path, expectedText }) => { - // Render the App component within a MemoryRouter with the current route - const { getByText } = render( - - - - - - ); + // Iterate through each route and test rendering the App component + routes.forEach(({ path, expectedText }) => { + // Render the App component within a MemoryRouter with the current route + const { getByText } = render( + + + + + , + ); - // Assert that the expected text is present in the App component - const element = getByText(expectedText); - expect(element).toBeTruthy(); - }); + // Assert that the expected text is present in the App component + const element = getByText(expectedText); + expect(element).toBeTruthy(); }); + }); }); diff --git a/frontend/test/family.test.tsx b/frontend/test/family.test.tsx index 6516d6f6..30dd4445 100644 --- a/frontend/test/family.test.tsx +++ b/frontend/test/family.test.tsx @@ -1,8 +1,15 @@ -import { describe, expect, it, beforeEach, afterEach, vi } from 'vitest'; -import { render, screen, fireEvent, cleanup, waitFor, within } from '@testing-library/react'; -import React from 'react'; -import FamilyPage from '../src/pages/family'; -import { MemoryRouter, useNavigate } from 'react-router-dom'; +import { describe, expect, it, beforeEach, afterEach, vi } from "vitest"; +import { + render, + screen, + fireEvent, + cleanup, + waitFor, + within, +} from "@testing-library/react"; +import React from "react"; +import FamilyPage from "../src/pages/family"; +import { MemoryRouter, useNavigate } from "react-router-dom"; // // Partially mock react-router-dom // vi.mock('react-router-dom', async (importOriginal) => { @@ -22,7 +29,6 @@ import { MemoryRouter, useNavigate } from 'react-router-dom'; // }; // }); - // describe('LoggedIn Component Test', () => { // let navigateMock; @@ -41,107 +47,104 @@ import { MemoryRouter, useNavigate } from 'react-router-dom'; // afterEach(() => { // cleanup(); // }); - + // it('should open the Drawer when clicking the DensitySmallSharpIcon button', async () => { // // Find the button with the DensitySmallSharpIcon using its data-testid attribute // const iconButton = screen.getByTestId('DensitySmallSharpIcon'); - + // // Simulate a click event on the button to open the Drawer // fireEvent.click(iconButton); - + // // Use waitFor to wait for the Drawer to be present (i.e., `sentinelStart` element should be present) // const sentinelStart = await waitFor(() => screen.getByTestId('sentinelStart')); // expect(sentinelStart).toBeTruthy(); // Confirm that the Drawer is open - + // // Verify the presence of the "Log Out" list item in the Drawer // const logOutOption = await waitFor(() => // screen.getByText('Log Out') // ); // expect(logOutOption).toBeTruthy(); // Confirm that "Log Out" is present in the Drawer // }); - + // it('should navigate to Home when clicking the Home button in the Drawer', async () => { // // Open the Drawer by clicking the DensitySmallSharpIcon button // const iconButton = screen.getByTestId('DensitySmallSharpIcon'); // fireEvent.click(iconButton); - + // // Wait for the Drawer to be present // await waitFor(() => screen.getByTestId('sentinelStart')); - + // // Find the Home button inside the Drawer and simulate a click event // const homeButton = screen.getByText('Home'); // fireEvent.click(homeButton); - + // // Verify that the navigate function was called with the expected path for Home // expect(navigateMock).toHaveBeenCalledWith('/LoggedIn'); // }); - + // it('should navigate to FamilyPage when clicking the Families button in the Drawer', async () => { // // Open the Drawer by clicking the DensitySmallSharpIcon button // const iconButton = screen.getByTestId('DensitySmallSharpIcon'); // fireEvent.click(iconButton); - + // // Wait for the Drawer to be present // await waitFor(() => screen.getByTestId('sentinelStart')); - + // // Locate all elements with role "presentation" // const elementsWithPresentationRole = screen.getAllByRole('presentation'); - + // // Filter the elements to find the one representing the Drawer // const drawerElement = elementsWithPresentationRole.find( // (element) => element.classList.contains('MuiDrawer-root') // ); - + // // Ensure the Drawer element was found // if (!drawerElement) { // throw new Error('Drawer element not found'); // } - + // // Find the Families button inside the Drawer // const drawerFamiliesButton = within(drawerElement).getByText('Families'); - + // // Simulate a click event on the Families button inside the Drawer // fireEvent.click(drawerFamiliesButton); - + // // Verify that the navigate function was called with the expected path for Families in the Drawer // expect(navigateMock).toHaveBeenCalledWith('/FamilyPage'); // }); - - - + // it('should navigate to Log Out when clicking the Log Out button in the Drawer', async () => { // // Open the Drawer by clicking the DensitySmallSharpIcon button // const iconButton = screen.getByTestId('DensitySmallSharpIcon'); // fireEvent.click(iconButton); - + // // Wait for the Drawer to be present // await waitFor(() => screen.getByTestId('sentinelStart')); - + // // Find the Log Out button inside the Drawer and simulate a click event // const logOutButton = screen.getByText('Log Out'); // fireEvent.click(logOutButton); - + // // Verify that the navigate function was called with the expected path for Log Out // expect(navigateMock).toHaveBeenCalledWith('/'); // }); - // }); -describe('Dummy Tests', () => { - it('should always pass test 1', () => { - expect(true).toBe(true); - }); - - it('should always pass test 2', () => { - expect(1 + 1).toBe(2); - }); - - it('should always pass test 3', () => { - expect('dummy').toBe('dummy'); - }); - - it('should always pass test 4', () => { - expect([]).toEqual([]); - }); - }); \ No newline at end of file +describe("Dummy Tests", () => { + it("should always pass test 1", () => { + expect(true).toBe(true); + }); + + it("should always pass test 2", () => { + expect(1 + 1).toBe(2); + }); + + it("should always pass test 3", () => { + expect("dummy").toBe("dummy"); + }); + + it("should always pass test 4", () => { + expect([]).toEqual([]); + }); +}); diff --git a/frontend/test/logIn.test.tsx b/frontend/test/logIn.test.tsx index bef703ae..f0082208 100644 --- a/frontend/test/logIn.test.tsx +++ b/frontend/test/logIn.test.tsx @@ -1,9 +1,15 @@ -import { describe, expect, it, beforeEach, afterEach } from 'vitest'; -import { render, screen, fireEvent, waitFor, cleanup } from '@testing-library/react'; -import React from 'react'; -import LogIn from '../src/pages/logIn'; -import { GoogleOAuthProvider } from '@react-oauth/google'; -import { MemoryRouter } from 'react-router-dom'; +import { describe, expect, it, beforeEach, afterEach } from "vitest"; +import { + render, + screen, + fireEvent, + waitFor, + cleanup, +} from "@testing-library/react"; +import React from "react"; +import LogIn from "../src/pages/logIn"; +import { GoogleOAuthProvider } from "@react-oauth/google"; +import { MemoryRouter } from "react-router-dom"; // describe('LogIn Component Test', () => { // beforeEach(() => { @@ -19,7 +25,7 @@ import { MemoryRouter } from 'react-router-dom'; // afterEach(() => { // cleanup(); // }); - + // it('should render the login button and the guest button', () => { // expect(screen.getByText('Sign in')).toBeTruthy(); // Check presence of the login button // expect(screen.getByText('Continue as Guest')).toBeTruthy(); // Check presence of the guest button @@ -42,20 +48,20 @@ import { MemoryRouter } from 'react-router-dom'; // }); // }); -describe('Dummy Tests', () => { - it('should always pass test 1', () => { - expect(true).toBe(true); - }); - - it('should always pass test 2', () => { - expect(1 + 1).toBe(2); - }); - - it('should always pass test 3', () => { - expect('dummy').toBe('dummy'); - }); - - it('should always pass test 4', () => { - expect([]).toEqual([]); - }); - }); \ No newline at end of file +describe("Dummy Tests", () => { + it("should always pass test 1", () => { + expect(true).toBe(true); + }); + + it("should always pass test 2", () => { + expect(1 + 1).toBe(2); + }); + + it("should always pass test 3", () => { + expect("dummy").toBe("dummy"); + }); + + it("should always pass test 4", () => { + expect([]).toEqual([]); + }); +}); diff --git a/frontend/test/loggedIn.test.tsx b/frontend/test/loggedIn.test.tsx index 1e05b506..99a56b8c 100644 --- a/frontend/test/loggedIn.test.tsx +++ b/frontend/test/loggedIn.test.tsx @@ -1,8 +1,15 @@ -import { describe, expect, it, beforeEach, afterEach, vi } from 'vitest'; -import { render, screen, fireEvent, cleanup, waitFor, within } from '@testing-library/react'; -import React from 'react'; -import LoggedIn from '../src/pages/loggedIn'; -import { MemoryRouter, useNavigate } from 'react-router-dom'; +import { describe, expect, it, beforeEach, afterEach, vi } from "vitest"; +import { + render, + screen, + fireEvent, + cleanup, + waitFor, + within, +} from "@testing-library/react"; +import React from "react"; +import LoggedIn from "../src/pages/loggedIn"; +import { MemoryRouter, useNavigate } from "react-router-dom"; // // Partially mock react-router-dom // vi.mock('react-router-dom', async (importOriginal) => { @@ -22,7 +29,6 @@ import { MemoryRouter, useNavigate } from 'react-router-dom'; // }; // }); - // describe('LoggedIn Component Test', () => { // let navigateMock; @@ -73,102 +79,99 @@ import { MemoryRouter, useNavigate } from 'react-router-dom'; // it('should open the Drawer when clicking the DensitySmallSharpIcon button', async () => { // // Find the button with the DensitySmallSharpIcon using its data-testid attribute // const iconButton = screen.getByTestId('DensitySmallSharpIcon'); - + // // Simulate a click event on the button to open the Drawer // fireEvent.click(iconButton); - + // // Use waitFor to wait for the Drawer to be present (i.e., `sentinelStart` element should be present) // const sentinelStart = await waitFor(() => screen.getByTestId('sentinelStart')); // expect(sentinelStart).toBeTruthy(); // Confirm that the Drawer is open - + // // Verify the presence of the "Log Out" list item in the Drawer // const logOutOption = await waitFor(() => // screen.getByText('Log Out') // ); // expect(logOutOption).toBeTruthy(); // Confirm that "Log Out" is present in the Drawer // }); - + // it('should navigate to Home when clicking the Home button in the Drawer', async () => { // // Open the Drawer by clicking the DensitySmallSharpIcon button // const iconButton = screen.getByTestId('DensitySmallSharpIcon'); // fireEvent.click(iconButton); - + // // Wait for the Drawer to be present // await waitFor(() => screen.getByTestId('sentinelStart')); - + // // Find the Home button inside the Drawer and simulate a click event // const homeButton = screen.getByText('Home'); // fireEvent.click(homeButton); - + // // Verify that the navigate function was called with the expected path for Home // expect(navigateMock).toHaveBeenCalledWith('/LoggedIn'); // }); - + // it('should navigate to FamilyPage when clicking the Families button in the Drawer', async () => { // // Open the Drawer by clicking the DensitySmallSharpIcon button // const iconButton = screen.getByTestId('DensitySmallSharpIcon'); // fireEvent.click(iconButton); - + // // Wait for the Drawer to be present // await waitFor(() => screen.getByTestId('sentinelStart')); - + // // Locate all elements with role "presentation" // const elementsWithPresentationRole = screen.getAllByRole('presentation'); - + // // Filter the elements to find the one representing the Drawer // const drawerElement = elementsWithPresentationRole.find( // (element) => element.classList.contains('MuiDrawer-root') // ); - + // // Ensure the Drawer element was found // if (!drawerElement) { // throw new Error('Drawer element not found'); // } - + // // Find the Families button inside the Drawer // const drawerFamiliesButton = within(drawerElement).getByText('Families'); - + // // Simulate a click event on the Families button inside the Drawer // fireEvent.click(drawerFamiliesButton); - + // // Verify that the navigate function was called with the expected path for Families in the Drawer // expect(navigateMock).toHaveBeenCalledWith('/FamilyPage'); // }); - - - + // it('should navigate to Log Out when clicking the Log Out button in the Drawer', async () => { // // Open the Drawer by clicking the DensitySmallSharpIcon button // const iconButton = screen.getByTestId('DensitySmallSharpIcon'); // fireEvent.click(iconButton); - + // // Wait for the Drawer to be present // await waitFor(() => screen.getByTestId('sentinelStart')); - + // // Find the Log Out button inside the Drawer and simulate a click event // const logOutButton = screen.getByText('Log Out'); // fireEvent.click(logOutButton); - + // // Verify that the navigate function was called with the expected path for Log Out // expect(navigateMock).toHaveBeenCalledWith('/'); // }); - // }); -describe('Dummy Tests', () => { - it('should always pass test 1', () => { - expect(true).toBe(true); - }); - - it('should always pass test 2', () => { - expect(1 + 1).toBe(2); - }); - - it('should always pass test 3', () => { - expect('dummy').toBe('dummy'); - }); - - it('should always pass test 4', () => { - expect([]).toEqual([]); - }); - }); \ No newline at end of file +describe("Dummy Tests", () => { + it("should always pass test 1", () => { + expect(true).toBe(true); + }); + + it("should always pass test 2", () => { + expect(1 + 1).toBe(2); + }); + + it("should always pass test 3", () => { + expect("dummy").toBe("dummy"); + }); + + it("should always pass test 4", () => { + expect([]).toEqual([]); + }); +}); diff --git a/frontend/test/main.test.tsx b/frontend/test/main.test.tsx index 043ffaf7..63a61840 100644 --- a/frontend/test/main.test.tsx +++ b/frontend/test/main.test.tsx @@ -1,15 +1,14 @@ -import React from 'react'; -import { vi, describe, expect, it, beforeEach, afterEach } from 'vitest'; -import { render } from '@testing-library/react'; -import { GoogleOAuthProvider } from '@react-oauth/google'; -import App from '../src/pages/App'; -import { BrowserRouter } from 'react-router-dom'; -import '@testing-library/jest-dom'; - +import React from "react"; +import { vi, describe, expect, it, beforeEach, afterEach } from "vitest"; +import { render } from "@testing-library/react"; +import { GoogleOAuthProvider } from "@react-oauth/google"; +import App from "../src/pages/App"; +import { BrowserRouter } from "react-router-dom"; +import "@testing-library/jest-dom"; // Mock environment variable for OAuth Client ID -const mockClientId = 'dummy-client-id'; -vi.mock('vite', () => ({ +const mockClientId = "dummy-client-id"; +vi.mock("vite", () => ({ import: { meta: { env: { @@ -19,8 +18,8 @@ vi.mock('vite', () => ({ }, })); -describe('Root Component Rendering', () => { - it('renders the App component without crashing', () => { +describe("Root Component Rendering", () => { + it("renders the App component without crashing", () => { const { getByText } = render( @@ -28,7 +27,7 @@ describe('Root Component Rendering', () => { - + , ); // Adjust according to what you expect to be rendered by App initially diff --git a/frontend/test/modals.test.tsx b/frontend/test/modals.test.tsx index a3cb7fd7..61b6b881 100644 --- a/frontend/test/modals.test.tsx +++ b/frontend/test/modals.test.tsx @@ -1,16 +1,16 @@ import { render } from "@testing-library/react"; import { describe, it, vi } from "vitest"; import React from "react"; -import { - CreatePublishModal, - CreateShareModal, - CreateDOIModal, - CreateFamilyModal, - CreateMechanismModal, - CreateSpeciesModal, - CreateReactionModal, - CreateReactantModal, - CreateProductModal +import { + CreatePublishModal, + CreateShareModal, + CreateDOIModal, + CreateFamilyModal, + CreateMechanismModal, + CreateSpeciesModal, + CreateReactionModal, + CreateReactantModal, + CreateProductModal, } from "../src/components/Modals"; describe("Modal components", () => { @@ -29,26 +29,73 @@ describe("Modal components", () => { }); it("renders CreateFamilyModal without errors", () => { - render(); + render( + , + ); }); it("renders CreateMechanismModal without errors", () => { - render(); + render( + , + ); }); it("renders CreateSpeciesModal without errors", () => { - render(); + render( + , + ); }); it("renders CreateReactionModal without errors", () => { - render(); + render( + , + ); }); it("renders CreateReactantModal without errors", () => { - render(); + render( + , + ); }); it("renders CreateProductModal without errors", () => { - render(); + render( + , + ); }); }); diff --git a/frontend/test/rolemanagement.test.tsx b/frontend/test/rolemanagement.test.tsx index 568f7bf4..6a5f9976 100644 --- a/frontend/test/rolemanagement.test.tsx +++ b/frontend/test/rolemanagement.test.tsx @@ -1,57 +1,68 @@ -import React from 'react'; -import { describe, expect, it, beforeEach, afterEach, vi } from 'vitest'; -import { render, screen, waitFor } from '@testing-library/react'; -import RoleManagement from '../src/pages/RoleManagement'; // Updated path to RoleManagement -import { useAuth } from '../src/pages/AuthContext'; -import { getUsers } from '../src/API/API_GetMethods'; -import { updateUser } from '../src/API/API_UpdateMethods'; -import { deleteUser } from '../src/API/API_DeleteMethods'; -import '@testing-library/jest-dom'; -import userEvent from '@testing-library/user-event'; +import React from "react"; +import { describe, expect, it, beforeEach, afterEach, vi } from "vitest"; +import { render, screen, waitFor } from "@testing-library/react"; +import RoleManagement from "../src/pages/RoleManagement"; // Updated path to RoleManagement +import { useAuth } from "../src/pages/AuthContext"; +import { getUsers } from "../src/API/API_GetMethods"; +import { updateUser } from "../src/API/API_UpdateMethods"; +import { deleteUser } from "../src/API/API_DeleteMethods"; +import "@testing-library/jest-dom"; +import userEvent from "@testing-library/user-event"; // Mocking necessary modules -vi.mock('../src/pages/AuthContext', () => ({ +vi.mock("../src/pages/AuthContext", () => ({ useAuth: vi.fn(), })); -vi.mock('../src/API/API_GetMethods', () => ({ +vi.mock("../src/API/API_GetMethods", () => ({ getUsers: vi.fn(), })); -vi.mock('../src/API/API_UpdateMethods', () => ({ +vi.mock("../src/API/API_UpdateMethods", () => ({ updateUser: vi.fn(), })); -vi.mock('../src/API/API_DeleteMethods', () => ({ +vi.mock("../src/API/API_DeleteMethods", () => ({ deleteUser: vi.fn(), })); // Sample data const mockUsers = [ - { id: '1', username: 'JohnDoe', email: 'johndoe@example.com', role: 'admin' }, - { id: '2', username: 'JaneDoe', email: 'janedoe@example.com', role: 'unverified' }, + { id: "1", username: "JohnDoe", email: "johndoe@example.com", role: "admin" }, + { + id: "2", + username: "JaneDoe", + email: "janedoe@example.com", + role: "unverified", + }, ]; -const mockLoggedInUser = { id: '123', username: 'TestUser', role: 'admin' }; +const mockLoggedInUser = { id: "123", username: "TestUser", role: "admin" }; -describe('RoleManagement Component', () => { +describe("RoleManagement Component", () => { beforeEach(() => { - (useAuth as unknown as ReturnType).mockReturnValue({ user: mockLoggedInUser }); - (getUsers as unknown as ReturnType).mockResolvedValue(mockUsers); + (useAuth as unknown as ReturnType).mockReturnValue({ + user: mockLoggedInUser, + }); + (getUsers as unknown as ReturnType).mockResolvedValue( + mockUsers, + ); }); afterEach(() => { vi.clearAllMocks(); }); - it('renders loading state initially', async () => { + it("renders loading state initially", async () => { render(); expect(screen.getByText(/Loading users.../i)).toBeInTheDocument(); await waitFor(() => expect(getUsers).toHaveBeenCalledTimes(1)); }); - it('renders error state if fetching users fails', async () => { - (getUsers as unknown as ReturnType).mockRejectedValueOnce(new Error('Fetch error')); + it("renders error state if fetching users fails", async () => { + (getUsers as unknown as ReturnType).mockRejectedValueOnce( + new Error("Fetch error"), + ); render(); await waitFor(() => { @@ -59,16 +70,16 @@ describe('RoleManagement Component', () => { }); }); - it('renders user data in DataGrid when fetching succeeds', async () => { + it("renders user data in DataGrid when fetching succeeds", async () => { render(); await waitFor(() => { const users = screen.getAllByText(/Doe/i); - expect(users).toHaveLength(4); // Expecting both JohnDoe and JaneDoe to appear + expect(users).toHaveLength(4); // Expecting both JohnDoe and JaneDoe to appear }); }); - it('handles edit mode toggling for a user row', async () => { + it("handles edit mode toggling for a user row", async () => { render(); await waitFor(() => { @@ -86,7 +97,7 @@ describe('RoleManagement Component', () => { // await waitFor(() => expect(updateUser).toHaveBeenCalledTimes(1)); }); - it('handles deleting a user', async () => { + it("handles deleting a user", async () => { render(); await waitFor(() => { @@ -101,7 +112,7 @@ describe('RoleManagement Component', () => { // expect(screen.queryByText(/JaneDoe/i)).not.toBeInTheDocument(); }); - it('displays the toolbar and allows quick filter usage', async () => { + it("displays the toolbar and allows quick filter usage", async () => { render(); await waitFor(() => { diff --git a/frontend/test/settings.test.tsx b/frontend/test/settings.test.tsx index fc004287..0f92a624 100644 --- a/frontend/test/settings.test.tsx +++ b/frontend/test/settings.test.tsx @@ -1,8 +1,8 @@ -import { describe, expect, it } from 'vitest'; -import { render, screen, fireEvent } from '@testing-library/react'; -import { MemoryRouter } from 'react-router-dom'; -import Settings from '../src/pages/settings'; -import { GoogleOAuthProvider } from '@react-oauth/google'; // if needed, depending on your setup +import { describe, expect, it } from "vitest"; +import { render, screen, fireEvent } from "@testing-library/react"; +import { MemoryRouter } from "react-router-dom"; +import Settings from "../src/pages/settings"; +import { GoogleOAuthProvider } from "@react-oauth/google"; // if needed, depending on your setup // describe('Settings Component', () => { // const mockContextValue = { @@ -46,20 +46,20 @@ import { GoogleOAuthProvider } from '@react-oauth/google'; // if needed, dependi // }); // }); -describe('Dummy Tests', () => { - it('should always pass test 1', () => { - expect(true).toBe(true); - }); - - it('should always pass test 2', () => { - expect(1 + 1).toBe(2); - }); - - it('should always pass test 3', () => { - expect('dummy').toBe('dummy'); - }); - - it('should always pass test 4', () => { - expect([]).toEqual([]); - }); - }); \ No newline at end of file +describe("Dummy Tests", () => { + it("should always pass test 1", () => { + expect(true).toBe(true); + }); + + it("should always pass test 2", () => { + expect(1 + 1).toBe(2); + }); + + it("should always pass test 3", () => { + expect("dummy").toBe("dummy"); + }); + + it("should always pass test 4", () => { + expect([]).toEqual([]); + }); +}); diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 5a33944a..9cc50ead 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,7 +1,7 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], -}) +}); diff --git a/frontend/vitest.config.ts b/frontend/vitest.config.ts index 9d787f53..26b4bccf 100644 --- a/frontend/vitest.config.ts +++ b/frontend/vitest.config.ts @@ -1,13 +1,13 @@ -import { defineConfig } from 'vitest/config'; +import { defineConfig } from "vitest/config"; export default defineConfig({ test: { - environment: 'jsdom', // simulates a browser environment for React testing - setupFiles: ['vitest.setup.ts'], // Ensure this file exists and contains necessary global setups + environment: "jsdom", // simulates a browser environment for React testing + setupFiles: ["vitest.setup.ts"], // Ensure this file exists and contains necessary global setups globals: true, // Makes globals like describe, expect, it available globally coverage: { - reporter: ['text','html'], // Generates an HTML report - reportsDirectory: './coverage', // Directory where reports are saved + reporter: ["text", "html"], // Generates an HTML report + reportsDirectory: "./coverage", // Directory where reports are saved all: true, // Ensures all files are included in coverage even if not directly tested }, }, diff --git a/frontend/vitest.setup.ts b/frontend/vitest.setup.ts index 10b10a39..e0188e4d 100644 --- a/frontend/vitest.setup.ts +++ b/frontend/vitest.setup.ts @@ -1,2 +1,2 @@ -import '@testing-library/react'; -import '@testing-library/jest-dom'; +import "@testing-library/react"; +import "@testing-library/jest-dom";