From 8dd48282ec634322476c40246c88bcb22233c6b8 Mon Sep 17 00:00:00 2001 From: Quentin DI MEO Date: Mon, 19 Aug 2024 23:00:33 +0200 Subject: [PATCH 1/8] [082] adding empty tests page --- front-end/src/App.tsx | 2 + front-end/src/constants/Common.tsx | 2 + front-end/src/pages/Home/Home.css | 39 +------------ front-end/src/pages/Tests/Tests.css | 39 +++++++++++++ front-end/src/pages/Tests/Tests.tsx | 91 +++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 38 deletions(-) create mode 100644 front-end/src/pages/Tests/Tests.css create mode 100644 front-end/src/pages/Tests/Tests.tsx diff --git a/front-end/src/App.tsx b/front-end/src/App.tsx index e9c045c..a54ad10 100644 --- a/front-end/src/App.tsx +++ b/front-end/src/App.tsx @@ -7,6 +7,7 @@ import Home from "./pages/Home/Home"; import Lyrics from "./pages/Lyrics/Lyrics"; import ProcessedImages from "./pages/ProcessedImages/ProcessedImages"; import Redirect from "./pages/Redirect/Redirect"; +import Tests from "./pages/Tests/Tests"; import "./App.css"; @@ -18,6 +19,7 @@ const App = (): JSX.Element => { } /> } /> } /> + } /> } /> } /> diff --git a/front-end/src/constants/Common.tsx b/front-end/src/constants/Common.tsx index 126c122..eb2ec19 100644 --- a/front-end/src/constants/Common.tsx +++ b/front-end/src/constants/Common.tsx @@ -77,6 +77,7 @@ export const TITLE = { PREFIX: "GTFR-CG - ", REDIRECT: "Redirect", + TESTS: "Tests", HOME: "Home", ARTWORK_GENERATION: "Artwork Generation", PROCESSED_IMAGES: "Processed Images", @@ -86,6 +87,7 @@ export const TITLE = { export const PATHS = { redirect: "/redirect", home: "/home", + tests: "/tests", artworkGeneration: "/artwork-generation", processedImages: "/processed-images", lyrics: "/lyrics", diff --git a/front-end/src/pages/Home/Home.css b/front-end/src/pages/Home/Home.css index a1b6996..cab460b 100644 --- a/front-end/src/pages/Home/Home.css +++ b/front-end/src/pages/Home/Home.css @@ -1,39 +1,2 @@ -#home { - div.navbar.home { - width: 50%; - - button { - height: 100px; - width: -webkit-fill-available; - } - } - - .stats-board { - width: 50%; - - margin: 2% auto 0 auto; - padding: 0.75em; - - border: 2px solid #ddd; - border-radius: 1rem; - background-color: #ffffff; - - .stats-entry { - flex-direction: row; - - .stat-title { - width: 60%; - - text-align: center; - font-size: larger; - } - - .stat-text { - margin: auto; - - font-size: 1em; - font-style: italic; - } - } - } +#tests { } diff --git a/front-end/src/pages/Tests/Tests.css b/front-end/src/pages/Tests/Tests.css new file mode 100644 index 0000000..a1b6996 --- /dev/null +++ b/front-end/src/pages/Tests/Tests.css @@ -0,0 +1,39 @@ +#home { + div.navbar.home { + width: 50%; + + button { + height: 100px; + width: -webkit-fill-available; + } + } + + .stats-board { + width: 50%; + + margin: 2% auto 0 auto; + padding: 0.75em; + + border: 2px solid #ddd; + border-radius: 1rem; + background-color: #ffffff; + + .stats-entry { + flex-direction: row; + + .stat-title { + width: 60%; + + text-align: center; + font-size: larger; + } + + .stat-text { + margin: auto; + + font-size: 1em; + font-style: italic; + } + } + } +} diff --git a/front-end/src/pages/Tests/Tests.tsx b/front-end/src/pages/Tests/Tests.tsx new file mode 100644 index 0000000..b54e6c3 --- /dev/null +++ b/front-end/src/pages/Tests/Tests.tsx @@ -0,0 +1,91 @@ +import { JSX, useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; + +import { is2xxSuccessful, sendRequest } from "../../common/Requests"; +import { API, BACKEND_URL, PATHS, TITLE, TOAST, TOAST_TYPE } from "../../constants/Common"; + +import { sendToast } from "../../common/Toast"; +import { Statistics } from "../../common/Types"; +import useTitle from "../../common/UseTitle"; + +import "./Tests.css"; + +const Tests = (): JSX.Element => { + useTitle(TITLE.TESTS); + + const navigate = useNavigate(); + + const [geniusToken, setGeniusToken] = useState(""); + const [stats, setStats] = useState({} as Statistics); + + const fetchStatistics = () => { + sendRequest("GET", BACKEND_URL + API.STATISTICS).then((response) => { + if (!is2xxSuccessful(response.status)) { + sendToast(response.message, TOAST_TYPE.ERROR); + return; + } + + setStats(response.data as Statistics); + }).catch((error) => { + sendToast(error.message, TOAST_TYPE.ERROR); + }); + }; + + const fetchGeniusToken = () => { + sendRequest("GET", BACKEND_URL + API.GENIUS_TOKEN).then((response) => { + if (!is2xxSuccessful(response.status) || response.data.token === "") { + sendToast(response.message, TOAST_TYPE.ERROR, 10); + sendToast(TOAST.ADD_GENIUS_TOKEN, TOAST_TYPE.WARN, 20); + return; + } + + sendToast(TOAST.WELCOME, TOAST_TYPE.SUCCESS, 5); + setGeniusToken(response.data.token); + }).catch((error) => { + sendToast(error.message, TOAST_TYPE.ERROR); + }); + }; + + useEffect(() => { + const fetchAndSetData = () => { + if (!window.location.href.endsWith(PATHS.tests)) { + navigate(PATHS.tests); + return; + } + + const routeKey = location.pathname; + const hasVisited = sessionStorage.getItem(routeKey); + + fetchStatistics(); + + if (!hasVisited) { + fetchGeniusToken(); + sessionStorage.setItem(routeKey, "visited"); + } + }; + + fetchAndSetData(); + }, [navigate]); + + return ( +
+
+ + +
+ +
+ +

Tests

+ +
+
+ + +
+ ); +}; + +export default Tests; \ No newline at end of file From e870ea09bf1febb96d3f93bfa4901f6e41003967 Mon Sep 17 00:00:00 2001 From: Quentin DI MEO Date: Sun, 25 Aug 2024 16:16:17 +0200 Subject: [PATCH 2/8] [082] adding nav button at the bottom of the home page --- front-end/src/pages/Home/Home.css | 47 +++++++++++++++++++++++++++-- front-end/src/pages/Home/Home.tsx | 5 +++ front-end/src/pages/Tests/Tests.css | 39 +----------------------- front-end/src/pages/Tests/Tests.tsx | 2 +- 4 files changed, 52 insertions(+), 41 deletions(-) diff --git a/front-end/src/pages/Home/Home.css b/front-end/src/pages/Home/Home.css index cab460b..effb01f 100644 --- a/front-end/src/pages/Home/Home.css +++ b/front-end/src/pages/Home/Home.css @@ -1,2 +1,45 @@ -#tests { -} +#home { + div.navbar { + &.home { + width: 50%; + + button { + height: 100px; + width: -webkit-fill-available; + } + } + + &.tests { + margin-top: 24px; + } + } + + .stats-board { + width: 50%; + + margin: 2% auto 0 auto; + padding: 0.75em; + + border: 2px solid #ddd; + border-radius: 1rem; + background-color: #ffffff; + + .stats-entry { + flex-direction: row; + + .stat-title { + width: 60%; + + text-align: center; + font-size: larger; + } + + .stat-text { + margin: auto; + + font-size: 1em; + font-style: italic; + } + } + } +} \ No newline at end of file diff --git a/front-end/src/pages/Home/Home.tsx b/front-end/src/pages/Home/Home.tsx index 1b6d6e3..fa99072 100644 --- a/front-end/src/pages/Home/Home.tsx +++ b/front-end/src/pages/Home/Home.tsx @@ -135,6 +135,11 @@ const Home = (): JSX.Element => { +
+ +

Genius Token: '{ geniusToken }'

diff --git a/front-end/src/pages/Tests/Tests.css b/front-end/src/pages/Tests/Tests.css index a1b6996..cab460b 100644 --- a/front-end/src/pages/Tests/Tests.css +++ b/front-end/src/pages/Tests/Tests.css @@ -1,39 +1,2 @@ -#home { - div.navbar.home { - width: 50%; - - button { - height: 100px; - width: -webkit-fill-available; - } - } - - .stats-board { - width: 50%; - - margin: 2% auto 0 auto; - padding: 0.75em; - - border: 2px solid #ddd; - border-radius: 1rem; - background-color: #ffffff; - - .stats-entry { - flex-direction: row; - - .stat-title { - width: 60%; - - text-align: center; - font-size: larger; - } - - .stat-text { - margin: auto; - - font-size: 1em; - font-style: italic; - } - } - } +#tests { } diff --git a/front-end/src/pages/Tests/Tests.tsx b/front-end/src/pages/Tests/Tests.tsx index b54e6c3..abe6264 100644 --- a/front-end/src/pages/Tests/Tests.tsx +++ b/front-end/src/pages/Tests/Tests.tsx @@ -72,7 +72,7 @@ const Tests = (): JSX.Element => {
-
+
From 889ab0fd71cc497c21b69b3c063144e14afe8990 Mon Sep 17 00:00:00 2001 From: Quentin DI MEO Date: Sun, 25 Aug 2024 17:51:22 +0200 Subject: [PATCH 3/8] [082] setting up generic tests board and test components with run button --- front-end/src/pages/Tests/Test.tsx | 29 +++++++ front-end/src/pages/Tests/Tests.css | 25 ++++++ front-end/src/pages/Tests/Tests.tsx | 96 +++++++++++++----------- front-end/src/pages/Tests/TestsBoard.tsx | 20 +++++ 4 files changed, 125 insertions(+), 45 deletions(-) create mode 100644 front-end/src/pages/Tests/Test.tsx create mode 100644 front-end/src/pages/Tests/TestsBoard.tsx diff --git a/front-end/src/pages/Tests/Test.tsx b/front-end/src/pages/Tests/Test.tsx new file mode 100644 index 0000000..26b78a2 --- /dev/null +++ b/front-end/src/pages/Tests/Test.tsx @@ -0,0 +1,29 @@ +import { useState } from "react"; + +export type TestResult = { + successful: boolean; + prompt: string; +}; + +type TestProps = { + title: string; + func: () => TestResult; +}; + +export const Test = (props: TestProps) => { + const { title, func } = props; + + const [result, setResult] = useState(); + + return ( +
+

{title}

+ + { result?.successful && +

{result.prompt}

+ } +
+ ); +} \ No newline at end of file diff --git a/front-end/src/pages/Tests/Tests.css b/front-end/src/pages/Tests/Tests.css index cab460b..4ab1cfe 100644 --- a/front-end/src/pages/Tests/Tests.css +++ b/front-end/src/pages/Tests/Tests.css @@ -1,2 +1,27 @@ #tests { + #page { + width: 80%; + margin: auto; + gap: 16px; + + .column { + width: 100%; + margin: auto; + + .board { + background: #ffffff; + box-shadow: 0 0 10px rgba(0,0,0,0.1); + border: 4px solid #0000001a; + border-radius: 1em; + + .test { + margin: 16px 8px; + + h3 { + width: 100%; + } + } + } + } + } } diff --git a/front-end/src/pages/Tests/Tests.tsx b/front-end/src/pages/Tests/Tests.tsx index abe6264..4bfbd5c 100644 --- a/front-end/src/pages/Tests/Tests.tsx +++ b/front-end/src/pages/Tests/Tests.tsx @@ -1,71 +1,52 @@ -import { JSX, useEffect, useState } from "react"; +import { JSX } from "react"; import { useNavigate } from "react-router-dom"; import { is2xxSuccessful, sendRequest } from "../../common/Requests"; -import { API, BACKEND_URL, PATHS, TITLE, TOAST, TOAST_TYPE } from "../../constants/Common"; +import { API, BACKEND_URL, PATHS, TITLE } from "../../constants/Common"; -import { sendToast } from "../../common/Toast"; -import { Statistics } from "../../common/Types"; import useTitle from "../../common/UseTitle"; +import { TestResult } from "./Test"; import "./Tests.css"; +import { TestsBoard } from "./TestsBoard"; const Tests = (): JSX.Element => { useTitle(TITLE.TESTS); const navigate = useNavigate(); - const [geniusToken, setGeniusToken] = useState(""); - const [stats, setStats] = useState({} as Statistics); + const testStatistics = (): TestResult => { + let result = { successful: false, prompt: "" }; - const fetchStatistics = () => { sendRequest("GET", BACKEND_URL + API.STATISTICS).then((response) => { - if (!is2xxSuccessful(response.status)) { - sendToast(response.message, TOAST_TYPE.ERROR); - return; - } - - setStats(response.data as Statistics); + result = { successful: is2xxSuccessful(response.status), prompt: response.message }; }).catch((error) => { - sendToast(error.message, TOAST_TYPE.ERROR); + result = { successful: false, prompt: error.message }; }); + return result; }; - const fetchGeniusToken = () => { + const testGeniusToken = (): TestResult => { + let result = { successful: false, prompt: "" }; + sendRequest("GET", BACKEND_URL + API.GENIUS_TOKEN).then((response) => { - if (!is2xxSuccessful(response.status) || response.data.token === "") { - sendToast(response.message, TOAST_TYPE.ERROR, 10); - sendToast(TOAST.ADD_GENIUS_TOKEN, TOAST_TYPE.WARN, 20); - return; - } - - sendToast(TOAST.WELCOME, TOAST_TYPE.SUCCESS, 5); - setGeniusToken(response.data.token); + result = { successful: is2xxSuccessful(response.status), prompt: response.message }; }).catch((error) => { - sendToast(error.message, TOAST_TYPE.ERROR); + result = { successful: false, prompt: error.message }; }); + return result; }; - useEffect(() => { - const fetchAndSetData = () => { - if (!window.location.href.endsWith(PATHS.tests)) { - navigate(PATHS.tests); - return; - } - - const routeKey = location.pathname; - const hasVisited = sessionStorage.getItem(routeKey); - - fetchStatistics(); - - if (!hasVisited) { - fetchGeniusToken(); - sessionStorage.setItem(routeKey, "visited"); - } - }; - - fetchAndSetData(); - }, [navigate]); + const boards = { + env_var: { + id: "env-var", + title: "Environment Variables", + tests: [ + { title: "Genius Token", func: testGeniusToken }, + { title: "Statistics", func: testStatistics }, + ], + }, + }; return (
@@ -80,7 +61,32 @@ const Tests = (): JSX.Element => {

Tests

-
+
+
+ + +
+
+ +
+
+
+ +
+
+

External

+
+

Genius Token

+

ééééé

+
+
+ +
+
+ +
+
+
diff --git a/front-end/src/pages/Tests/TestsBoard.tsx b/front-end/src/pages/Tests/TestsBoard.tsx new file mode 100644 index 0000000..4bd0ffb --- /dev/null +++ b/front-end/src/pages/Tests/TestsBoard.tsx @@ -0,0 +1,20 @@ +import { Test, TestResult } from "./Test"; + +type TestsBoardProps = { + id: string; + title: string; + tests: { title: string, func: () => TestResult }[]; +}; + +export const TestsBoard = (props: TestsBoardProps) => { + const { id, title, tests } = props; + + return ( +
+

{title}

+ { tests.map((test) => ( + + ))} +
+ ); +}; \ No newline at end of file From e897e988af22dbcde3fd872e748c0cad081ac210 Mon Sep 17 00:00:00 2001 From: Quentin DI MEO Date: Sun, 1 Sep 2024 23:24:46 +0200 Subject: [PATCH 4/8] [082] reference testing is functional --- front-end/src/pages/Tests/Test.tsx | 25 ++++++++++---- front-end/src/pages/Tests/Tests.css | 2 +- front-end/src/pages/Tests/Tests.tsx | 43 +++++++++++------------- front-end/src/pages/Tests/TestsBoard.tsx | 10 +++--- src/routes/artwork_generation.py | 6 ++-- src/routes/home.py | 4 +-- src/routes/lyrics.py | 2 +- 7 files changed, 51 insertions(+), 41 deletions(-) diff --git a/front-end/src/pages/Tests/Test.tsx b/front-end/src/pages/Tests/Test.tsx index 26b78a2..66cb2ef 100644 --- a/front-end/src/pages/Tests/Test.tsx +++ b/front-end/src/pages/Tests/Test.tsx @@ -1,28 +1,41 @@ import { useState } from "react"; +import { StateSetter } from "../../common/Types"; + export type TestResult = { successful: boolean; prompt: string; + duration?: number; }; -type TestProps = { +export type TestFunc = (setter: StateSetter) => Promise; + +export type TestProps = { title: string; - func: () => TestResult; + func: TestFunc; }; export const Test = (props: TestProps) => { const { title, func } = props; - const [result, setResult] = useState(); + const [result, setResult] = useState({} as TestResult); + const [testIsRunning, setTestIsRunning] = useState(false); + + const runTest = async (func: TestFunc) => { + setResult({} as TestResult); + setTestIsRunning(true); + await func(setResult); + setTestIsRunning(false); + }; return (

{title}

- { result?.successful && -

{result.prompt}

+

{`Test completed in ${result.duration}ms`}

}
); diff --git a/front-end/src/pages/Tests/Tests.css b/front-end/src/pages/Tests/Tests.css index 4ab1cfe..7c6180a 100644 --- a/front-end/src/pages/Tests/Tests.css +++ b/front-end/src/pages/Tests/Tests.css @@ -18,7 +18,7 @@ margin: 16px 8px; h3 { - width: 100%; + width: 30%; } } } diff --git a/front-end/src/pages/Tests/Tests.tsx b/front-end/src/pages/Tests/Tests.tsx index 4bfbd5c..3b0d11b 100644 --- a/front-end/src/pages/Tests/Tests.tsx +++ b/front-end/src/pages/Tests/Tests.tsx @@ -2,43 +2,40 @@ import { JSX } from "react"; import { useNavigate } from "react-router-dom"; import { is2xxSuccessful, sendRequest } from "../../common/Requests"; -import { API, BACKEND_URL, PATHS, TITLE } from "../../constants/Common"; - +import { StateSetter } from "../../common/Types"; import useTitle from "../../common/UseTitle"; +import { API, BACKEND_URL, PATHS, TITLE } from "../../constants/Common"; import { TestResult } from "./Test"; -import "./Tests.css"; import { TestsBoard } from "./TestsBoard"; +import "./Tests.css"; + const Tests = (): JSX.Element => { useTitle(TITLE.TESTS); const navigate = useNavigate(); - const testStatistics = (): TestResult => { - let result = { successful: false, prompt: "" }; - - sendRequest("GET", BACKEND_URL + API.STATISTICS).then((response) => { - result = { successful: is2xxSuccessful(response.status), prompt: response.message }; + const testStatistics = async (setter: StateSetter) => { + const start = Date.now(); + await sendRequest("GET", BACKEND_URL + API.STATISTICS).then((response) => { + setter({ successful: is2xxSuccessful(response.status), prompt: response.message, duration: Date.now() - start }); }).catch((error) => { - result = { successful: false, prompt: error.message }; + setter({ successful: false, prompt: error.message, duration: Date.now() - start }); }); - return result; }; - const testGeniusToken = (): TestResult => { - let result = { successful: false, prompt: "" }; - - sendRequest("GET", BACKEND_URL + API.GENIUS_TOKEN).then((response) => { - result = { successful: is2xxSuccessful(response.status), prompt: response.message }; + const testGeniusToken = async (setter: StateSetter) => { + const start = Date.now(); + await sendRequest("GET", BACKEND_URL + API.GENIUS_TOKEN).then((response) => { + setter({ successful: is2xxSuccessful(response.status), prompt: response.message, duration: Date.now() - start }); }).catch((error) => { - result = { successful: false, prompt: error.message }; + setter({ successful: false, prompt: error.message, duration: Date.now() - start }); }); - return result; }; - const boards = { - env_var: { + const boards = [ + { id: "env-var", title: "Environment Variables", tests: [ @@ -46,7 +43,7 @@ const Tests = (): JSX.Element => { { title: "Statistics", func: testStatistics }, ], }, - }; + ]; return (
@@ -63,7 +60,7 @@ const Tests = (): JSX.Element => {
- + b.id === "env-var"))} />
@@ -72,7 +69,7 @@ const Tests = (): JSX.Element => {
-
+ {/*

External

@@ -86,7 +83,7 @@ const Tests = (): JSX.Element => {
-
+
*/}
diff --git a/front-end/src/pages/Tests/TestsBoard.tsx b/front-end/src/pages/Tests/TestsBoard.tsx index 4bd0ffb..5725770 100644 --- a/front-end/src/pages/Tests/TestsBoard.tsx +++ b/front-end/src/pages/Tests/TestsBoard.tsx @@ -1,9 +1,9 @@ -import { Test, TestResult } from "./Test"; +import { Test, TestProps } from "./Test"; type TestsBoardProps = { - id: string; - title: string; - tests: { title: string, func: () => TestResult }[]; + id?: string; + title?: string; + tests?: TestProps[]; }; export const TestsBoard = (props: TestsBoardProps) => { @@ -12,7 +12,7 @@ export const TestsBoard = (props: TestsBoardProps) => { return (

{title}

- { tests.map((test) => ( + { tests?.map((test) => ( ))}
diff --git a/src/routes/artwork_generation.py b/src/routes/artwork_generation.py index c61f388..9838999 100644 --- a/src/routes/artwork_generation.py +++ b/src/routes/artwork_generation.py @@ -22,7 +22,7 @@ def useItunesImage() -> Response: """ Interprets the fetched iTunes URL and saves the image to the user's folder. :return: [Response] The response to the request. """ - log.debug("POST - Generating artwork using an iTunes image...") + log.log("POST - Generating artwork using an iTunes image...") body = literal_eval(request.get_data(as_text=True)) image_url: Optional[str] = body.get("url") if image_url is None: @@ -60,7 +60,7 @@ def useLocalImage() -> Response: """ Saves the uploaded image to the user's folder. :return: [Response] The response to the request. """ - log.debug("POST - Generating artwork using a local image...") + log.log("POST - Generating artwork using a local image...") if "file" not in request.files: return createApiResponse(const.HttpStatus.BAD_REQUEST.value, const.ERR_NO_FILE) file = request.files["file"] @@ -149,7 +149,7 @@ def useYoutubeThumbnail() -> Response: """ Handles the extraction and processing of a YouTube thumbnail from a given URL. :return: [Response] The response to the request. """ - log.debug("POST - Generating artwork using a YouTube thumbnail...") + log.log("POST - Generating artwork using a YouTube thumbnail...") body = literal_eval(request.get_data(as_text=True)) youtube_url: Optional[str] = body.get("url") if youtube_url is None: diff --git a/src/routes/home.py b/src/routes/home.py index 9c15054..00b3cf6 100644 --- a/src/routes/home.py +++ b/src/routes/home.py @@ -17,7 +17,7 @@ def getGeniusToken() -> Response: """ Returns the Genius API token. :return: [Response] The response to the request. """ - log.debug("GET - Fetching Genius API token...") + log.log("GET - Fetching Genius API token...") token = session.get(const.SessionFields.genius_token.value, "") return createApiResponse(const.HttpStatus.OK.value, "Genius API token fetched successfully.", {"token": token}) @@ -27,6 +27,6 @@ def getStatistics() -> Response: """ Returns the statistics as a JSON object. :return: [Response] The response to the request. """ - log.debug("GET - Fetching statistics...") + log.log("GET - Fetching statistics...") stats = getJsonStatsFromFile() return createApiResponse(const.HttpStatus.OK.value, "Statistics fetched successfully.", stats) diff --git a/src/routes/lyrics.py b/src/routes/lyrics.py index 99c340e..72a1ff0 100644 --- a/src/routes/lyrics.py +++ b/src/routes/lyrics.py @@ -83,7 +83,7 @@ def getGeniusLyrics() -> Response: """ Fetches the lyrics of a song from Genius.com. :return: [Response] The response to the request. """ - log.debug("POST - Fetching lyrics from Genius...") + log.log("POST - Fetching lyrics from Genius...") body = literal_eval(request.get_data(as_text=True)) song_name: Optional[str] = body.get("songName") artist: Optional[str] = body.get("artist") From a778fdf02fd4527e48ca3add7cd8491faad94c2d Mon Sep 17 00:00:00 2001 From: Quentin DI MEO Date: Mon, 2 Sep 2024 00:17:59 +0200 Subject: [PATCH 5/8] [082] quality adjustments on board and test style --- front-end/src/App.css | 10 ++++++++++ front-end/src/pages/Tests/Test.tsx | 17 ++++++++++++----- front-end/src/pages/Tests/Tests.css | 20 ++++++++++++++++++-- front-end/src/pages/Tests/Tests.tsx | 4 ++-- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/front-end/src/App.css b/front-end/src/App.css index f545458..16ecb26 100644 --- a/front-end/src/App.css +++ b/front-end/src/App.css @@ -369,4 +369,14 @@ input[type="file"] { } .bold { font-weight: bold; +} + +.t-green { + color: #007f00; +} +.t-yellow { + color: #7f7f00; +} +.t-red { + color: #7f0000; } \ No newline at end of file diff --git a/front-end/src/pages/Tests/Test.tsx b/front-end/src/pages/Tests/Test.tsx index 66cb2ef..d80afec 100644 --- a/front-end/src/pages/Tests/Test.tsx +++ b/front-end/src/pages/Tests/Test.tsx @@ -1,6 +1,7 @@ import { useState } from "react"; import { StateSetter } from "../../common/Types"; +import { isEmpty } from "../../common/utils/ObjUtils"; export type TestResult = { successful: boolean; @@ -29,13 +30,19 @@ export const Test = (props: TestProps) => { }; return ( -
+

{title}

- + { isEmpty(result) && + + } { result?.successful && -

{`Test completed in ${result.duration}ms`}

+

+ Test completed 
+ {result?.successful ? "successfully" : "with a failure"}
+  in {result?.duration} milliseconds +

}
); diff --git a/front-end/src/pages/Tests/Tests.css b/front-end/src/pages/Tests/Tests.css index 7c6180a..ae1cab1 100644 --- a/front-end/src/pages/Tests/Tests.css +++ b/front-end/src/pages/Tests/Tests.css @@ -13,12 +13,28 @@ box-shadow: 0 0 10px rgba(0,0,0,0.1); border: 4px solid #0000001a; border-radius: 1em; + padding-bottom: 2%; .test { - margin: 16px 8px; + margin: 2% 4%; + gap: 1%; h3 { - width: 30%; + min-width: 42%; + justify-content: center; + } + button { + width: -webkit-fill-available; + } + p { + width: -webkit-fill-available; + font-size: 16px; + text-align: center; + + span { + display: contents; + font-size: inherit; + } } } } diff --git a/front-end/src/pages/Tests/Tests.tsx b/front-end/src/pages/Tests/Tests.tsx index 3b0d11b..db36af9 100644 --- a/front-end/src/pages/Tests/Tests.tsx +++ b/front-end/src/pages/Tests/Tests.tsx @@ -69,7 +69,7 @@ const Tests = (): JSX.Element => {
- {/*
+

External

@@ -83,7 +83,7 @@ const Tests = (): JSX.Element => {
-
*/} +
From d5ab407e4aa3cc99045ea4b4aa9cdce359911b70 Mon Sep 17 00:00:00 2001 From: Quentin DI MEO Date: Mon, 2 Sep 2024 00:56:34 +0200 Subject: [PATCH 6/8] [082] adding snacks test, style adjustments --- front-end/src/pages/Tests/Test.tsx | 9 +++--- front-end/src/pages/Tests/Tests.css | 3 +- front-end/src/pages/Tests/Tests.tsx | 47 +++++++++++++++++++++-------- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/front-end/src/pages/Tests/Test.tsx b/front-end/src/pages/Tests/Test.tsx index d80afec..6a2946d 100644 --- a/front-end/src/pages/Tests/Test.tsx +++ b/front-end/src/pages/Tests/Test.tsx @@ -32,16 +32,15 @@ export const Test = (props: TestProps) => { return (

{title}

- { isEmpty(result) && + { isEmpty(result) ? - } - { result?.successful && + :

- Test completed 
+ Test completed
{result?.successful ? "successfully" : "with a failure"}
-  in {result?.duration} milliseconds + in {result?.duration} milliseconds

}
diff --git a/front-end/src/pages/Tests/Tests.css b/front-end/src/pages/Tests/Tests.css index ae1cab1..8c29ee2 100644 --- a/front-end/src/pages/Tests/Tests.css +++ b/front-end/src/pages/Tests/Tests.css @@ -2,11 +2,12 @@ #page { width: 80%; margin: auto; - gap: 16px; + gap: 1rem; .column { width: 100%; margin: auto; + gap: 1rem; .board { background: #ffffff; diff --git a/front-end/src/pages/Tests/Tests.tsx b/front-end/src/pages/Tests/Tests.tsx index db36af9..33903a8 100644 --- a/front-end/src/pages/Tests/Tests.tsx +++ b/front-end/src/pages/Tests/Tests.tsx @@ -4,11 +4,12 @@ import { useNavigate } from "react-router-dom"; import { is2xxSuccessful, sendRequest } from "../../common/Requests"; import { StateSetter } from "../../common/Types"; import useTitle from "../../common/UseTitle"; -import { API, BACKEND_URL, PATHS, TITLE } from "../../constants/Common"; +import { API, BACKEND_URL, PATHS, TITLE, TOAST_TYPE } from "../../constants/Common"; import { TestResult } from "./Test"; import { TestsBoard } from "./TestsBoard"; +import { dismissToast, sendToast } from "../../common/Toast"; import "./Tests.css"; const Tests = (): JSX.Element => { @@ -16,24 +17,43 @@ const Tests = (): JSX.Element => { const navigate = useNavigate(); - const testStatistics = async (setter: StateSetter) => { + // ENV-VAR + const testGeniusToken = async (setter: StateSetter) => { const start = Date.now(); - await sendRequest("GET", BACKEND_URL + API.STATISTICS).then((response) => { + await sendRequest("GET", BACKEND_URL + API.GENIUS_TOKEN).then((response) => { setter({ successful: is2xxSuccessful(response.status), prompt: response.message, duration: Date.now() - start }); }).catch((error) => { setter({ successful: false, prompt: error.message, duration: Date.now() - start }); }); }; - - const testGeniusToken = async (setter: StateSetter) => { + const testStatistics = async (setter: StateSetter) => { const start = Date.now(); - await sendRequest("GET", BACKEND_URL + API.GENIUS_TOKEN).then((response) => { + await sendRequest("GET", BACKEND_URL + API.STATISTICS).then((response) => { setter({ successful: is2xxSuccessful(response.status), prompt: response.message, duration: Date.now() - start }); }).catch((error) => { setter({ successful: false, prompt: error.message, duration: Date.now() - start }); }); }; + // FRONT-END + const testSnacks = async (setter: StateSetter) => { + const start = Date.now(); + const toastContainer = document.getElementById("toast-container"); + + if (!toastContainer) { + setter({ successful: false, prompt: "Toast container not found", duration: Date.now() - start }); + return; + } + + sendToast("Testing snacks", TOAST_TYPE.INFO); + if (toastContainer.childElementCount === 0) { + setter({ successful: false, prompt: "Snacks not working", duration: Date.now() - start }); + } else { + setter({ successful: true, prompt: "Snacks tested", duration: Date.now() - start }); + dismissToast(toastContainer.lastElementChild as HTMLElement, 0); + } + }; + const boards = [ { id: "env-var", @@ -43,6 +63,13 @@ const Tests = (): JSX.Element => { { title: "Statistics", func: testStatistics }, ], }, + { + id: "front-end", + title: "Front-end Features", + tests: [ + { title: "Snacks", func: testSnacks }, + ], + } ]; return ( @@ -61,10 +88,7 @@ const Tests = (): JSX.Element => {
b.id === "env-var"))} /> - -
-
- + b.id === "front-end"))} />
@@ -80,9 +104,6 @@ const Tests = (): JSX.Element => {
- -
-
From 685d748b3b98a6885023b670a4749ecea8dcee31 Mon Sep 17 00:00:00 2001 From: Quentin DI MEO Date: Mon, 2 Sep 2024 02:00:44 +0200 Subject: [PATCH 7/8] [082] adding api tests, run all button --- front-end/src/pages/Tests/Test.tsx | 9 +-- front-end/src/pages/Tests/Tests.css | 9 +++ front-end/src/pages/Tests/Tests.tsx | 81 +++++++++++++++++------- front-end/src/pages/Tests/TestsBoard.tsx | 4 +- 4 files changed, 75 insertions(+), 28 deletions(-) diff --git a/front-end/src/pages/Tests/Test.tsx b/front-end/src/pages/Tests/Test.tsx index 6a2946d..52ce035 100644 --- a/front-end/src/pages/Tests/Test.tsx +++ b/front-end/src/pages/Tests/Test.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { RefObject, useState } from "react"; import { StateSetter } from "../../common/Types"; import { isEmpty } from "../../common/utils/ObjUtils"; @@ -14,10 +14,11 @@ export type TestFunc = (setter: StateSetter) => Promise; export type TestProps = { title: string; func: TestFunc; + buttonRef: RefObject; }; export const Test = (props: TestProps) => { - const { title, func } = props; + const { title, func, buttonRef } = props; const [result, setResult] = useState({} as TestResult); const [testIsRunning, setTestIsRunning] = useState(false); @@ -33,8 +34,8 @@ export const Test = (props: TestProps) => {

{title}

{ isEmpty(result) ? - :

diff --git a/front-end/src/pages/Tests/Tests.css b/front-end/src/pages/Tests/Tests.css index 8c29ee2..503363a 100644 --- a/front-end/src/pages/Tests/Tests.css +++ b/front-end/src/pages/Tests/Tests.css @@ -1,4 +1,8 @@ #tests { + button[id="run-all"] { + width: 35%; + margin: 0 auto 2% auto + } #page { width: 80%; margin: auto; @@ -16,6 +20,11 @@ border-radius: 1em; padding-bottom: 2%; + .title { + font-size: xx-large; + margin: 1em 0; + } + .test { margin: 2% 4%; gap: 1%; diff --git a/front-end/src/pages/Tests/Tests.tsx b/front-end/src/pages/Tests/Tests.tsx index 33903a8..b29fd43 100644 --- a/front-end/src/pages/Tests/Tests.tsx +++ b/front-end/src/pages/Tests/Tests.tsx @@ -1,20 +1,26 @@ -import { JSX } from "react"; +import { JSX, useRef, useState } from "react"; import { useNavigate } from "react-router-dom"; -import { is2xxSuccessful, sendRequest } from "../../common/Requests"; -import { StateSetter } from "../../common/Types"; +import { is2xxSuccessful, objectToQueryString, sendRequest } from "../../common/Requests"; +import { dismissToast, sendToast } from "../../common/Toast"; +import { ItunesResponse, LyricsResponse, StateSetter } from "../../common/Types"; import useTitle from "../../common/UseTitle"; -import { API, BACKEND_URL, PATHS, TITLE, TOAST_TYPE } from "../../constants/Common"; +import { API, BACKEND_URL, ITUNES_URL, PATHS, TITLE, TOAST_TYPE } from "../../constants/Common"; import { TestResult } from "./Test"; import { TestsBoard } from "./TestsBoard"; -import { dismissToast, sendToast } from "../../common/Toast"; import "./Tests.css"; const Tests = (): JSX.Element => { useTitle(TITLE.TESTS); + const refGeniusToken = useRef(null); + const refStatistics = useRef(null); + const refSnacks = useRef(null); + const refItunes = useRef(null); + const refGenius = useRef(null); + const navigate = useNavigate(); // ENV-VAR @@ -54,24 +60,64 @@ const Tests = (): JSX.Element => { } }; + // API + const testItunes = async (setter: StateSetter) => { + const start = Date.now(); + const data = { term: "hello", country: "US", entity: "album", limit: 10 }; + const queryString = objectToQueryString(data); + + await sendRequest("POST", ITUNES_URL + "/search" + queryString).then((response: ItunesResponse) => { + setter({ successful: response.resultCount > 0, prompt: "iTunes API test successful", duration: Date.now() - start }); + }).catch((error) => { + setter({ successful: false, prompt: error.message, duration: Date.now() - start }); + }); + }; + const testGenius = async (setter: StateSetter) => { + const start = Date.now(); + const body = { artist: "Adele", songName: "Hello" }; + await sendRequest("POST", BACKEND_URL + API.LYRICS.GET_LYRICS, body).then((response: LyricsResponse) => { + setter({ successful: is2xxSuccessful(response.status), prompt: response.message, duration: Date.now() - start }); + }).catch((error) => { + setter({ successful: false, prompt: error.message, duration: Date.now() - start }); + }); + }; + const boards = [ { id: "env-var", title: "Environment Variables", tests: [ - { title: "Genius Token", func: testGeniusToken }, - { title: "Statistics", func: testStatistics }, + { title: "Genius Token", func: testGeniusToken, buttonRef: refGeniusToken }, + { title: "Statistics", func: testStatistics, buttonRef: refStatistics }, ], }, { id: "front-end", - title: "Front-end Features", + title: "Front-End Components", tests: [ - { title: "Snacks", func: testSnacks }, + { title: "Snacks", func: testSnacks, buttonRef: refSnacks }, ], - } + }, + { + id: "api", + title: "API", + tests: [ + { title: "iTunes", func: testItunes, buttonRef: refItunes }, + { title: "Genius Lyrics", func: testGenius, buttonRef: refGenius }, + ], + }, ]; + const [clickedRunAll, setClickedRunAll] = useState(false); + const handleRunAll = () => { + setClickedRunAll(true); + if (refGeniusToken.current) refGeniusToken.current.click(); + if (refStatistics.current) refStatistics.current.click(); + if (refSnacks.current) refSnacks.current.click(); + if (refItunes.current) refItunes.current.click(); + if (refGenius.current) refGenius.current.click(); + }; + return (

@@ -85,25 +131,16 @@ const Tests = (): JSX.Element => {

Tests

+ +
b.id === "env-var"))} /> b.id === "front-end"))} /> -
-
-
-

External

-
-

Genius Token

-

ééééé

-
-
- -
-
+ b.id === "api"))} />
diff --git a/front-end/src/pages/Tests/TestsBoard.tsx b/front-end/src/pages/Tests/TestsBoard.tsx index 5725770..2b097e8 100644 --- a/front-end/src/pages/Tests/TestsBoard.tsx +++ b/front-end/src/pages/Tests/TestsBoard.tsx @@ -11,9 +11,9 @@ export const TestsBoard = (props: TestsBoardProps) => { return (
-

{title}

+

{title}

{ tests?.map((test) => ( - + ))}
); From f5121222e26cc1c702d732144433a31ce6b312f8 Mon Sep 17 00:00:00 2001 From: Quentin DI MEO Date: Mon, 2 Sep 2024 18:10:53 +0200 Subject: [PATCH 8/8] [082] adapting readme consequently --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e1d3868..e2cf214 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ cd front-end/ && npm run dev # will launch the front end of the application - By default, the application runs locally on ports 8000 (back) and 4242 (front). Access it @ [**http://localhost:4242**](http://localhost:4242). - The application features 6 major pages: - [x] **Home**: the main page, where your statistics are displayed and you can navigate to **Artwork Generation** and **Lyrics**. - - [ ] **Tests** *(TBD)*: the unit tests page, to check the application's integrity. + - [x] **Tests** : the unit tests page, to check the application's integrity. - [x] **Artwork Generation**: the page where you can generate artwork from a local file or an iTunes search. - [x] **Processed Images**: the page where you can download a background image and a YouTube thumbnail. - [x] **Lyrics**: the page where you can fetch lyrics from Genius and convert them to lyrics blocks. @@ -139,8 +139,9 @@ cd front-end/ && npm run dev # will launch the front end of the application - documentation strings are added to the codebase - the artwork generation page is reworked to welcome YT section and better UX - the logger system is reinforced to log more actions and be customizable -- ***[1.3.0]** Aug 19 2024*: **Lyrics Fetch** — Project will support lyrics fetching from Genius and their conversion to lyrics blocks. [#089](https://github.com/Thomas-Fernandes/GTFR-CG/pull/89) - - ***[1.3.1]** Aug 19 2024*: The project's front end will be fully migrated to **React Typescript with Vite**. [#088](https://github.com/Thomas-Fernandes/GTFR-CG/pull/88) +- ***[1.3.0]** Aug 19 2024*: **Lyrics Fetch** — Project now supports lyrics fetching from Genius and their conversion to lyrics blocks. [#089](https://github.com/Thomas-Fernandes/GTFR-CG/pull/89) + - ***[1.3.1]** Aug 19 2024*: Project's front end is fully migrated to **React Typescript with Vite**. [#088](https://github.com/Thomas-Fernandes/GTFR-CG/pull/88) + - ***[1.3.2]** Sep ?? 2024*: Project now has a unit test page, better .env handling with a tutorial file. [#???](#card_file_box-changelog) - ***[1.4.0]** Coming later...*: **Lyrics Cards** — Project will support automatic cards generation from text blocks. [#???](#card_file_box-changelog) - ***[1.5.0]** Coming later...*: **Boost!** — Project will see its existing functionalities sharpened. [#???](#card_file_box-changelog) - ***[1.6.0]** Coming later...*: **Koh-Lanta** — Project will be unified in an all-in-one application. [#???](#card_file_box-changelog)