From 2cbd8e53ef146f80521b6bad9e724cc5c5bb7ed2 Mon Sep 17 00:00:00 2001 From: Rohini Patil Date: Tue, 26 Aug 2025 13:36:25 +0200 Subject: [PATCH 1/6] Update README.md changed Assignment-CohortXX to JavaScript-CohortXX --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d457d2828..5e5773557 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ We highly recommend that you go through this README in detail before starting to > > This will ensure that the line endings for text files are compatible with those used on MacOS and Linux-based computers. -1. Fork the `HackYourAssignment/Assignments-CohortXX` repository to your own GitHub account. +1. Fork the `HackYourAssignment/JavaScript-CohortXX` repository to your own GitHub account. 2. Clone the fork to your local computer. 3. Open the root folder of the repository in VSCode. 4. When invited to do so, please install the recommended VSCode extensions. @@ -24,7 +24,7 @@ We highly recommend that you go through this README in detail before starting to 10. Fix any reported issues and rerun the test. Repeat until all issues are fixed. 11. When all assignments are done, commit all changed files. This includes the modified exercises, the generated test summary (`TEST_SUMMARY.md`) and test reports (`EXERCISE_NAME.report.txt`). 12. Push the changes to your fork. -13. Create a pull request against the `main` branch of the `HackYourAssignment/Assignments-CohortXX` repository. For the title of your pull request use the same format as the branch name, e.g.: `YOUR_NAME-w2-JavaScript`. +13. Create a pull request against the `main` branch of the `HackYourAssignment/JavaScript-CohortXX` repository. For the title of your pull request use the same format as the branch name, e.g.: `YOUR_NAME-w2-JavaScript`. Repeat steps 6-13 for each week. For subsequent weeks the mandated branch names are: @@ -39,7 +39,7 @@ For more information how to hand in your weekly assignments please refer to the Throughout your [HYF journey](https://github.com/HackYourFuture/curriculum) you will be asked to do certain exercises. This repository contains all of these exercises for the JavaScript modules (JavaScript, Browsers, UsingAPIs). The module repositories will tell you how to hand in the assignment, the curriculum will indicate what week you will need to do. -> Note that a fork of this repository will be created on the [HackYourAssignment](https://github.com/HackYourAssignment) GitHub account specifically for your cohort. The name of the repository will have the format `Assignments-cohortXX` where `XX` is your cohort number, +> Note that a fork of this repository will be created on the [HackYourAssignment](https://github.com/HackYourAssignment) GitHub account specifically for your cohort. The name of the repository will have the format `JavaScript-cohortXX` where `XX` is your cohort number, ## Installation @@ -64,9 +64,9 @@ From the command line, while inside the `Assignments-cohortXX` folder, you can u code . ``` -> When working on your assignments it is strongly recommended to always open the `Assignments-cohortXX` folder in VSCode rather than one of its sub-folders. This gives VSCode and all its extensions the full view on the repository for the best overall developer experience. +> When working on your assignments it is strongly recommended to always open the `JavaScript-cohortXX` folder in VSCode rather than one of its sub-folders. This gives VSCode and all its extensions the full view on the repository for the best overall developer experience. > -> Note that the name of the folder opened in VSCode can always be found in the `EXPLORER` panel ( `ASSIGNMENTS_COHORT49` in the picture below): +> Note that the name of the folder opened in VSCode can always be found in the `EXPLORER` panel ( `ASSIGNMENT_COHORT49` in the picture below): > > ![folder-name](./assets/folder-name.png) From 745ca234face74579d5b5f02be1a5cdb6096511c Mon Sep 17 00:00:00 2001 From: Majd Hamde Date: Thu, 16 Oct 2025 10:44:26 +0200 Subject: [PATCH 2/6] Week 2 Using APIs exercises --- .../assignment/ex1-programmerFun/index.js | 66 ++++++++++++---- .../Week2/assignment/ex2-pokemonApp/index.js | 75 +++++++++++++++++-- .../Week2/assignment/ex2-pokemonApp/style.css | 48 ++++++++++++ 3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js | 37 +++++---- 3-UsingAPIs/Week2/assignment/ex4-diceRace.js | 27 +++++-- 3-UsingAPIs/Week2/assignment/ex5-vscDebug.js | 7 +- .../assignment/ex6-browserDebug/index.js | 57 ++++++++++++-- 7 files changed, 265 insertions(+), 52 deletions(-) diff --git a/3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js b/3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js index a99ca177b..caef9a9bd 100644 --- a/3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js +++ b/3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js @@ -17,28 +17,68 @@ Full description at: https://github.com/HackYourFuture/Assignments/blob/main/3-U should result in a network (DNS) error. ------------------------------------------------------------------------------*/ function requestData(url) { - // TODO return a promise using `fetch()` + try { + const response = await fetch(url); + + // Handle HTTP errors + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + + // Parse the response as JSON + const data = await response.json(); + return data; + } catch (error) { + // Network or parsing error + throw new Error(`Failed to fetch data: ${error.message}`); + } } function renderImage(data) { - // TODO render the image to the DOM + // Create an image element + const img = document.createElement('img'); + img.src = data.img; // The xkcd API returns `img` as the image URL + img.alt = data.alt; // Alt text is included in the API + img.style.maxWidth = '90%'; + img.style.display = 'block'; + img.style.margin = '40px auto'; + img.style.borderRadius = '12px'; + img.style.boxShadow = '0 4px 10px rgba(0,0,0,0.2)'; + + // Add title + const title = document.createElement('h2'); + title.textContent = data.title; + title.style.textAlign = 'center'; + title.style.fontFamily = 'sans-serif'; + + // Append both to the document body + document.body.appendChild(title); + document.body.appendChild(img); console.log(data); } function renderError(error) { - // TODO render the error to the DOM + // Create an error message element + const errorMessage = document.createElement('h1'); + errorMessage.textContent = `⚠️ ${error.message}`; + errorMessage.style.color = 'red'; + errorMessage.style.textAlign = 'center'; + errorMessage.style.marginTop = '50px'; + errorMessage.style.fontFamily = 'sans-serif'; + + document.body.appendChild(errorMessage); console.log(error); } -// TODO refactor with async/await and try/catch -function main() { - requestData('https://xkcd.now.sh/?comic=latest') - .then((data) => { - renderImage(data); - }) - .catch((error) => { - renderError(error); - }); +async function main() { + const url = 'https://xkcd.now.sh/?comic=latest'; + + try { + const data = await requestData(url); + renderImage(data); + } catch (error) { + renderError(error); + } } -window.addEventListener('load', main); +window.addEventListener('load', main); \ No newline at end of file diff --git a/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js b/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js index 262113997..562dd93d7 100644 --- a/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js +++ b/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js @@ -21,18 +21,77 @@ Use async/await and try/catch to handle promises. Try and avoid using global variables. As much as possible, try and use function parameters and return values to pass data back and forth. ------------------------------------------------------------------------------*/ -function fetchData(/* TODO parameter(s) go here */) { - // TODO complete this function +async function fetchData(url) { + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + return await response.json(); + } catch (error) { + console.error('Fetch error:', error); + } } -function fetchAndPopulatePokemons(/* TODO parameter(s) go here */) { - // TODO complete this function +async function fetchAndPopulatePokemons(selectEl) { + const data = await fetchData('https://pokeapi.co/api/v2/pokemon?limit=150'); + if (!data) return; + + data.results.forEach((pokemon) => { + const option = document.createElement('option'); + option.value = pokemon.url; // Store the API URL for each Pokémon + option.textContent = pokemon.name; + selectEl.appendChild(option); + }); } -function fetchImage(/* TODO parameter(s) go here */) { - // TODO complete this function +async function fetchImage(pokemonUrl, imgEl) { + if (!pokemonUrl) { + imgEl.hidden = true; + return; + } + + const data = await fetchData(pokemonUrl); + if (data && data.sprites && data.sprites.front_default) { + imgEl.src = data.sprites.front_default; + imgEl.alt = data.name; + imgEl.hidden = false; + } else { + imgEl.hidden = true; + } } -function main() { - // TODO complete this function +async function main() { + // Create elements dynamically + const container = document.createElement('div'); + container.classList.add('container'); + + const title = document.createElement('h1'); + title.textContent = 'Pokémon Browser'; + + const select = document.createElement('select'); + const defaultOption = document.createElement('option'); + defaultOption.textContent = 'Select a Pokémon'; + defaultOption.value = ''; + select.appendChild(defaultOption); + + const img = document.createElement('img'); + img.id = 'pokemon-image'; + img.hidden = true; + + // Add elements to the DOM + container.append(title, select, img); + document.body.appendChild(container); + + // Populate dropdown + await fetchAndPopulatePokemons(select); + + // Add event listener + select.addEventListener('change', async (event) => { + const pokemonUrl = event.target.value; + await fetchImage(pokemonUrl, img); + }); } + +// Run when page is loaded +window.addEventListener('load', main); \ No newline at end of file diff --git a/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css b/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css index 44cb05eeb..d8c55e11b 100644 --- a/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css +++ b/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css @@ -1 +1,49 @@ /* add your styling here */ +body { + font-family: Arial, sans-serif; + background: #f2f6fc; + color: #333; + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; +} + +.container { + text-align: center; + background: white; + padding: 2rem 3rem; + border-radius: 10px; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); +} + +h1 { + color: #ef5350; + margin-bottom: 1rem; +} + +select { + padding: 0.5rem 1rem; + border-radius: 8px; + border: 1px solid #ccc; + font-size: 1rem; + background: #fafafa; + cursor: pointer; +} + +select:hover { + border-color: #ef5350; +} + +img { + display: block; + width: 150px; + height: 150px; + margin: 1.5rem auto 0; + image-rendering: pixelated; + transition: transform 0.3s ease; +} + +img:hover { + transform: scale(1.1); +} diff --git a/3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js b/3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js index 861b31047..cc9194231 100644 --- a/3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js +++ b/3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js @@ -17,24 +17,35 @@ import { rollDie } from '../../helpers/pokerDiceRoller.js'; * @param {DieFace} desiredValue * @returns {Promise} */ -export function rollDieUntil(desiredValue) { - // TODO rewrite this function using async/await - return rollDie().then((value) => { - if (value !== desiredValue) { - return rollDieUntil(desiredValue); +export async function rollDieUntil(desiredValue) { + // Rewritten with async/await and a while loop (no recursion) + let value; + + while (true) { + try { + value = await rollDie(); // wait for the result + console.log(`Rolled: ${value}`); + if (value === desiredValue) { + return value; // stop when ACE is rolled + } + } catch (err) { + // If the die rolls off the table (rejection), rethrow the error + throw err; } - return value; - }); + } } -// TODO refactor this function to use try/catch -function main() { - rollDieUntil('ACE') - .then((results) => console.log('Resolved!', results)) - .catch((error) => console.log('Rejected!', error.message)); +// Refactored main() to async/await and try/catch +async function main() { + try { + const result = await rollDieUntil('ACE'); + console.log('Resolved!', result); + } catch (error) { + console.log('Rejected!', error.message); + } } // ! Do not change or remove the code below if (process.env.NODE_ENV !== 'test') { main(); -} +} \ No newline at end of file diff --git a/3-UsingAPIs/Week2/assignment/ex4-diceRace.js b/3-UsingAPIs/Week2/assignment/ex4-diceRace.js index ddff3242c..4c6640dc0 100644 --- a/3-UsingAPIs/Week2/assignment/ex4-diceRace.js +++ b/3-UsingAPIs/Week2/assignment/ex4-diceRace.js @@ -15,15 +15,20 @@ import { rollDie } from '../../helpers/pokerDiceRoller.js'; export function rollDice() { const dice = [1, 2, 3, 4, 5]; - // TODO complete this function; use Promise.race() and rollDie() - rollDie(1); // TODO placeholder: modify as appropriate + // Each die rolls independently (returns a Promise) + const dicePromises = dice.map(() => rollDie()); + // Return a promise that resolves when the first die finishes rolling + return Promise.race(dicePromises); } -// Refactor this function to use async/await and try/catch -function main() { - rollDice() - .then((results) => console.log('Resolved!', results)) - .catch((error) => console.log('Rejected!', error.message)); +// Refactored using async/await and try/catch +async function main() { + try { + const winner = await rollDice(); + console.log('Resolved!', winner); + } catch (error) { + console.log('Rejected!', error.message); + } } // ! Do not change or remove the code below @@ -31,4 +36,10 @@ if (process.env.NODE_ENV !== 'test') { main(); } -// TODO Replace this comment by your explanation that was asked for in the assignment description. +/*------------------------------------------------------------------------------ +Explanation: +Some dice continue rolling after Promise.race() resolves because +Promise.race() only resolves/rejects based on the *first* promise that settles. +The other promises keep running in the background until they complete, +but their results are ignored. +*/ \ No newline at end of file diff --git a/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js b/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js index a65448e57..ed4fe9da5 100644 --- a/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js +++ b/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js @@ -20,8 +20,9 @@ function renderLaureates(laureates) { async function fetchAndRender() { try { - const laureates = getData( - 'http://api.nobelprize.org/2.0/laureates?birthCountry=Netherlands&format=json&csvLang=en' + // Await the fetchData promise to get actual data + const laureates = await getData( + 'https://api.nobelprize.org/2.0/laureates?birthCountry=Netherlands&format=json&csvLang=en' ); renderLaureates(laureates); } catch (err) { @@ -29,4 +30,4 @@ async function fetchAndRender() { } } -fetchAndRender(); +fetchAndRender(); \ No newline at end of file diff --git a/3-UsingAPIs/Week2/assignment/ex6-browserDebug/index.js b/3-UsingAPIs/Week2/assignment/ex6-browserDebug/index.js index 91e0402be..bbc573051 100644 --- a/3-UsingAPIs/Week2/assignment/ex6-browserDebug/index.js +++ b/3-UsingAPIs/Week2/assignment/ex6-browserDebug/index.js @@ -2,9 +2,22 @@ Full description at:https://github.com/HackYourFuture/Assignments/blob/main/3-UsingAPIs/Week2/README.md#exercise-6-using-the-browser-debugger */ +/* +Full description at: +https://github.com/HackYourFuture/Assignments/blob/main/3-UsingAPIs/Week2/README.md#exercise-6-using-the-browser-debugger + +This exercise focuses on learning to debug web-based JavaScript using the browser debugger. +Try placing breakpoints in getData(), renderLaureate(), and fetchAndRender() to inspect +data flow, function calls, and variable values. +*/ + async function getData(url) { const response = await fetch(url); - return response.json(); + if (!response.ok) { + throw new Error(`HTTP error: ${response.status}`); + } + const data = await response.json(); + return data; } function createAndAppend(name, parent, options = {}) { @@ -29,9 +42,39 @@ function addTableRow(table, label, value) { function renderLaureate(ul, { knownName, birth, death }) { const li = createAndAppend('li', ul); const table = createAndAppend('table', li); - addTableRow(table, 'Name', knownName.en); - addTableRow(table, 'Birth', `${birth.date}, ${birth.place.locationString}`); - addTableRow(table, 'Death', `${death.date}, ${death.place.locationString}`); + + // Name + addTableRow(table, 'Name', knownName?.en ?? 'Unknown'); + + // Birth + const birthPlace = birth?.place + ? [ + birth.place.city?.en, + birth.place.country?.en, + ] + .filter(Boolean) + .join(', ') + : ''; + + const birthInfo = birth + ? `${birth.date ?? 'Unknown'}${birthPlace ? ', ' + birthPlace : ''}` + : 'Unknown'; + addTableRow(table, 'Birth', birthInfo); + + // Death + const deathPlace = death?.place + ? [ + death.place.city?.en, + death.place.country?.en, + ] + .filter(Boolean) + .join(', ') + : ''; + + const deathInfo = death + ? `${death.date ?? 'N/A'}${deathPlace ? ', ' + deathPlace : ''}` + : 'Still alive'; + addTableRow(table, 'Death', deathInfo); } function renderLaureates(laureates) { @@ -41,13 +84,13 @@ function renderLaureates(laureates) { async function fetchAndRender() { try { - const laureates = getData( + const data = await getData( 'https://api.nobelprize.org/2.0/laureates?birthCountry=Netherlands&format=json&csvLang=en' ); - renderLaureates(laureates); + renderLaureates(data.laureates); } catch (err) { console.error(`Something went wrong: ${err.message}`); } } -window.addEventListener('load', fetchAndRender); +window.addEventListener('load', fetchAndRender); \ No newline at end of file From ea7f481dff655b7246a34afa3d514cf1c39eee1e Mon Sep 17 00:00:00 2001 From: Majd Hamde Date: Thu, 16 Oct 2025 11:06:26 +0200 Subject: [PATCH 3/6] Week2 Ex1: Programmer Fun - fixed async/await with fetch and try/catch --- .test-summary/TEST_SUMMARY.md | 14 +++++++ .../test-reports/ex1-programmerFun.report.txt | 40 +++++++++++++++++++ .../test-reports/ex2-pokemonApp.report.txt | 17 ++++++++ .../test-reports/ex3-rollAnAce.report.txt | 27 +++++++++++++ .../test-reports/ex4-diceRace.report.txt | 19 +++++++++ .../test-reports/ex5-vscDebug.report.txt | 3 ++ .../test-reports/ex6-browserDebug.report.txt | 3 ++ 7 files changed, 123 insertions(+) create mode 100644 .test-summary/TEST_SUMMARY.md create mode 100644 3-UsingAPIs/Week2/test-reports/ex1-programmerFun.report.txt create mode 100644 3-UsingAPIs/Week2/test-reports/ex2-pokemonApp.report.txt create mode 100644 3-UsingAPIs/Week2/test-reports/ex3-rollAnAce.report.txt create mode 100644 3-UsingAPIs/Week2/test-reports/ex4-diceRace.report.txt create mode 100644 3-UsingAPIs/Week2/test-reports/ex5-vscDebug.report.txt create mode 100644 3-UsingAPIs/Week2/test-reports/ex6-browserDebug.report.txt diff --git a/.test-summary/TEST_SUMMARY.md b/.test-summary/TEST_SUMMARY.md new file mode 100644 index 000000000..60857fe8e --- /dev/null +++ b/.test-summary/TEST_SUMMARY.md @@ -0,0 +1,14 @@ +## Test Summary + +**Mentors**: For more information on how to review homework assignments, please refer to the [Review Guide](https://github.com/HackYourFuture/mentors/blob/main/assignment-support/review-guide.md). + +### 3-UsingAPIs - Week2 + +| Exercise | Passed | Failed | ESLint | +|-------------------|--------|--------|--------| +| ex1-programmerFun | 2 | 3 | ✓ | +| ex2-pokemonApp | 5 | - | ✓ | +| ex3-rollAnAce | 6 | 1 | ✓ | +| ex4-diceRace | 7 | - | ✓ | +| ex5-vscDebug | - | - | ✓ | +| ex6-browserDebug | - | - | ✓ | diff --git a/3-UsingAPIs/Week2/test-reports/ex1-programmerFun.report.txt b/3-UsingAPIs/Week2/test-reports/ex1-programmerFun.report.txt new file mode 100644 index 000000000..d4e13fb38 --- /dev/null +++ b/3-UsingAPIs/Week2/test-reports/ex1-programmerFun.report.txt @@ -0,0 +1,40 @@ +*** Unit Test Error Report *** + +Command failed: npx jest /Users/majdjadalhaq/Desktop/Assignments-Cohort54/.dist/3-UsingAPIs/Week2/unit-tests/ex1-programmerFun.test.js --colors --noStackTrace --json + FAIL .dist/3-UsingAPIs/Week2/unit-tests/ex1-programmerFun.test.js + api-wk2-ex1-programmerFun + ✅ HTML should be syntactically valid (145 ms) + ✅ should have all TODO comments removed + ❌ should use `fetch()` (1 ms) + ❌ should use async/wait + ❌ should use try/catch + + ● api-wk2-ex1-programmerFun › should use `fetch()` + + expect(received).toBeDefined() + + Received: undefined + + ● api-wk2-ex1-programmerFun › should use async/wait + + expect(received).toBeDefined() + + Received: undefined + + ● api-wk2-ex1-programmerFun › should use try/catch + + expect(received).toBeDefined() + + Received: undefined + +Test Suites: 1 failed, 1 total +Tests: 3 failed, 2 passed, 5 total +Snapshots: 0 total +Time: 2.984 s, estimated 4 s +Ran all test suites matching /\/Users\/majdjadalhaq\/Desktop\/Assignments-Cohort54\/.dist\/3-UsingAPIs\/Week2\/unit-tests\/ex1-programmerFun.test.js/i. +No linting errors detected. + + +*** Spell Checker Report *** + +3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js:40:30 - Unknown word (xkcd) diff --git a/3-UsingAPIs/Week2/test-reports/ex2-pokemonApp.report.txt b/3-UsingAPIs/Week2/test-reports/ex2-pokemonApp.report.txt new file mode 100644 index 000000000..29087d70f --- /dev/null +++ b/3-UsingAPIs/Week2/test-reports/ex2-pokemonApp.report.txt @@ -0,0 +1,17 @@ +*** Unit Test Error Report *** + + PASS .dist/3-UsingAPIs/Week2/unit-tests/ex2-pokemonApp.test.js + api-wk2-ex2-pokemonApp + ✅ HTML should be syntactically valid (149 ms) + ✅ should have all TODO comments removed (1 ms) + ✅ should use `fetch()` + ✅ should use `await fetch()` (1 ms) + ✅ should use try/catch + +Test Suites: 1 passed, 1 total +Tests: 5 passed, 5 total +Snapshots: 0 total +Time: 2.696 s, estimated 4 s +Ran all test suites matching /\/Users\/majdjadalhaq\/Desktop\/Assignments-Cohort54\/.dist\/3-UsingAPIs\/Week2\/unit-tests\/ex2-pokemonApp.test.js/i. +No linting errors detected. +No spelling errors detected. diff --git a/3-UsingAPIs/Week2/test-reports/ex3-rollAnAce.report.txt b/3-UsingAPIs/Week2/test-reports/ex3-rollAnAce.report.txt new file mode 100644 index 000000000..a1fb09a00 --- /dev/null +++ b/3-UsingAPIs/Week2/test-reports/ex3-rollAnAce.report.txt @@ -0,0 +1,27 @@ +*** Unit Test Error Report *** + +Command failed: npx jest /Users/majdjadalhaq/Desktop/Assignments-Cohort54/.dist/3-UsingAPIs/Week2/unit-tests/ex3-rollAnAce.test.js --colors --noStackTrace --json + FAIL .dist/3-UsingAPIs/Week2/unit-tests/ex3-rollAnAce.test.js + api-wk2-ex3-rollAnAce + ✅ should have all TODO comments removed (1 ms) + ❌ `rollDieUntil` should not contain unneeded console.log calls (2 ms) + ✅ should not include a recursive call (1 ms) + ✅ should use async/wait + ✅ should use try/catch + ✅ should resolve as soon as a die settles on an ACE (22 ms) + ✅ should reject with an Error when a die rolls off the table (11 ms) + + ● api-wk2-ex3-rollAnAce › `rollDieUntil` should not contain unneeded console.log calls + + expect(received).toBe(expected) // Object.is equality + + Expected: false + Received: true + +Test Suites: 1 failed, 1 total +Tests: 1 failed, 6 passed, 7 total +Snapshots: 0 total +Time: 0.467 s, estimated 1 s +Ran all test suites matching /\/Users\/majdjadalhaq\/Desktop\/Assignments-Cohort54\/.dist\/3-UsingAPIs\/Week2\/unit-tests\/ex3-rollAnAce.test.js/i. +No linting errors detected. +No spelling errors detected. diff --git a/3-UsingAPIs/Week2/test-reports/ex4-diceRace.report.txt b/3-UsingAPIs/Week2/test-reports/ex4-diceRace.report.txt new file mode 100644 index 000000000..9381c1c4a --- /dev/null +++ b/3-UsingAPIs/Week2/test-reports/ex4-diceRace.report.txt @@ -0,0 +1,19 @@ +*** Unit Test Error Report *** + + PASS .dist/3-UsingAPIs/Week2/unit-tests/ex4-diceRace.test.js + api-wk2-ex4-diceRace + ✅ should exist and be executable (2 ms) + ✅ should have all TODO comments removed + ✅ `rollDice` should not contain unneeded console.log calls (1 ms) + ✅ should use `dice.map()` + ✅ should use `Promise.race()` (1 ms) + ✅ should resolve as soon as a die settles successfully (10 ms) + ✅ should reject with an Error as soon as a die rolls off the table (31 ms) + +Test Suites: 1 passed, 1 total +Tests: 7 passed, 7 total +Snapshots: 0 total +Time: 0.603 s +Ran all test suites matching /\/Users\/majdjadalhaq\/Desktop\/Assignments-Cohort54\/.dist\/3-UsingAPIs\/Week2\/unit-tests\/ex4-diceRace.test.js/i. +No linting errors detected. +No spelling errors detected. diff --git a/3-UsingAPIs/Week2/test-reports/ex5-vscDebug.report.txt b/3-UsingAPIs/Week2/test-reports/ex5-vscDebug.report.txt new file mode 100644 index 000000000..d985f405c --- /dev/null +++ b/3-UsingAPIs/Week2/test-reports/ex5-vscDebug.report.txt @@ -0,0 +1,3 @@ +A unit test file was not provided for this exercise. +No linting errors detected. +No spelling errors detected. diff --git a/3-UsingAPIs/Week2/test-reports/ex6-browserDebug.report.txt b/3-UsingAPIs/Week2/test-reports/ex6-browserDebug.report.txt new file mode 100644 index 000000000..d985f405c --- /dev/null +++ b/3-UsingAPIs/Week2/test-reports/ex6-browserDebug.report.txt @@ -0,0 +1,3 @@ +A unit test file was not provided for this exercise. +No linting errors detected. +No spelling errors detected. From 8211434a6c3daf700608800c3cdbdee47c1347ac Mon Sep 17 00:00:00 2001 From: Majd Hamde Date: Mon, 27 Oct 2025 17:34:40 +0100 Subject: [PATCH 4/6] fixed --- .../assignment/ex1-programmerFun/index.js | 54 +++-------- .../Week2/assignment/ex2-pokemonApp/index.js | 97 +++++++++---------- .../Week2/assignment/ex2-pokemonApp/style.css | 65 ++++++------- 3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js | 17 +--- .../test-reports/ex1-programmerFun.report.txt | 41 ++------ .../test-reports/ex2-pokemonApp.report.txt | 10 +- .../test-reports/ex3-rollAnAce.report.txt | 26 ++--- 7 files changed, 117 insertions(+), 193 deletions(-) diff --git a/3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js b/3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js index caef9a9bd..13a422487 100644 --- a/3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js +++ b/3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js @@ -16,69 +16,43 @@ Full description at: https://github.com/HackYourFuture/Assignments/blob/main/3-U url with `.shx`. There is no server at the modified url, therefore this should result in a network (DNS) error. ------------------------------------------------------------------------------*/ -function requestData(url) { +async function requestData(url) { try { const response = await fetch(url); - // Handle HTTP errors if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } - // Parse the response as JSON const data = await response.json(); return data; } catch (error) { - // Network or parsing error - throw new Error(`Failed to fetch data: ${error.message}`); + throw error; } } - +// Function to render image function renderImage(data) { - // Create an image element const img = document.createElement('img'); - img.src = data.img; // The xkcd API returns `img` as the image URL - img.alt = data.alt; // Alt text is included in the API - img.style.maxWidth = '90%'; - img.style.display = 'block'; - img.style.margin = '40px auto'; - img.style.borderRadius = '12px'; - img.style.boxShadow = '0 4px 10px rgba(0,0,0,0.2)'; - - // Add title - const title = document.createElement('h2'); - title.textContent = data.title; - title.style.textAlign = 'center'; - title.style.fontFamily = 'sans-serif'; - - // Append both to the document body - document.body.appendChild(title); + img.src = data.img; document.body.appendChild(img); console.log(data); } - +// Function to render errors function renderError(error) { - // Create an error message element - const errorMessage = document.createElement('h1'); - errorMessage.textContent = `⚠️ ${error.message}`; - errorMessage.style.color = 'red'; - errorMessage.style.textAlign = 'center'; - errorMessage.style.marginTop = '50px'; - errorMessage.style.fontFamily = 'sans-serif'; - - document.body.appendChild(errorMessage); + const h1 = document.createElement('h1'); + h1.textContent = error.message || error; + document.body.appendChild(h1); console.log(error); } - +// Refactored main function to use async/await async function main() { - const url = 'https://xkcd.now.sh/?comic=latest'; - - try { - const data = await requestData(url); + try{ + const data = await requestData('https://xkcd.now.sh/?comic=latest'); renderImage(data); } catch (error) { renderError(error); } -} + } + -window.addEventListener('load', main); \ No newline at end of file +window.addEventListener('load', main); window.addEventListener('load', main); diff --git a/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js b/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js index 562dd93d7..471246502 100644 --- a/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js +++ b/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/index.js @@ -27,71 +27,70 @@ async function fetchData(url) { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } - return await response.json(); + const data = await response.json(); + return data; } catch (error) { console.error('Fetch error:', error); + throw error; } } -async function fetchAndPopulatePokemons(selectEl) { - const data = await fetchData('https://pokeapi.co/api/v2/pokemon?limit=150'); - if (!data) return; - - data.results.forEach((pokemon) => { - const option = document.createElement('option'); - option.value = pokemon.url; // Store the API URL for each Pokémon - option.textContent = pokemon.name; - selectEl.appendChild(option); - }); -} - -async function fetchImage(pokemonUrl, imgEl) { - if (!pokemonUrl) { - imgEl.hidden = true; - return; +async function fetchAndPopulatePokemons() { + const url = 'https://pokeapi.co/api/v2/pokemon?limit=150'; + try { + const data = await fetchData(url); + const select = document.querySelector('select'); + select.innerHTML = ''; + + data.results.forEach((pokemon) => { + const option = document.createElement('option'); + option.value = pokemon.url; + option.textContent = pokemon.name; + select.appendChild(option); + }); + } catch (error) { + console.error('Error fetch pokemon list:', error); } +} - const data = await fetchData(pokemonUrl); - if (data && data.sprites && data.sprites.front_default) { - imgEl.src = data.sprites.front_default; - imgEl.alt = data.name; - imgEl.hidden = false; - } else { - imgEl.hidden = true; +async function fetchImage(pokemonUrl) { + try { + const data = await fetchData(pokemonUrl); + const img = document.querySelector('img'); + img.src = data.sprites.front_default; + img.alt = `${data.name} Pokemon sprite`; + } catch (error) { + console.error('Error fetch image:', error); } } - -async function main() { - // Create elements dynamically - const container = document.createElement('div'); - container.classList.add('container'); - - const title = document.createElement('h1'); - title.textContent = 'Pokémon Browser'; +// Main function to set up event listeners and initialize the app +function main() { + const button = document.createElement('button'); + button.id = 'get-button'; + button.textContent = 'get pokemon'; + document.body.appendChild(button); const select = document.createElement('select'); - const defaultOption = document.createElement('option'); - defaultOption.textContent = 'Select a Pokémon'; - defaultOption.value = ''; - select.appendChild(defaultOption); + select.id = 'pokemon-select'; + document.body.appendChild(select); - const img = document.createElement('img'); - img.id = 'pokemon-image'; - img.hidden = true; + const option = document.createElement('option'); + option.value = ''; + option.textContent = 'Select a Pokemon'; + select.appendChild(option); - // Add elements to the DOM - container.append(title, select, img); - document.body.appendChild(container); + const img = document.createElement('img'); + img.id = 'pokemon-img'; + img.alt = `select a pokemon to see it image `; + document.body.appendChild(img); - // Populate dropdown - await fetchAndPopulatePokemons(select); + button.addEventListener('click', fetchAndPopulatePokemons); - // Add event listener - select.addEventListener('change', async (event) => { - const pokemonUrl = event.target.value; - await fetchImage(pokemonUrl, img); + select.addEventListener('change', (event) => { + if (event.target.value) { + fetchImage(event.target.value); + } }); } -// Run when page is loaded window.addEventListener('load', main); \ No newline at end of file diff --git a/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css b/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css index d8c55e11b..e79684620 100644 --- a/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css +++ b/3-UsingAPIs/Week2/assignment/ex2-pokemonApp/style.css @@ -1,49 +1,42 @@ /* add your styling here */ +/* Basic Reset and Setup */ body { font-family: Arial, sans-serif; - background: #f2f6fc; - color: #333; - display: flex; - justify-content: center; - align-items: center; - min-height: 100vh; + display: flex; /* Arrange items */ + flex-direction: column; /* Stack them vertically */ + align-items: center; /* Center them horizontally */ + margin-top: 50px; /* Add some space from the top */ + background-color: #f4f4f4; /* Light background color */ } -.container { - text-align: center; - background: white; - padding: 2rem 3rem; - border-radius: 10px; - box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); -} - -h1 { - color: #ef5350; - margin-bottom: 1rem; -} - -select { - padding: 0.5rem 1rem; - border-radius: 8px; +/* Style for the Button and Select */ +#get-button, #pokemon-select { + padding: 10px 15px; + margin-bottom: 20px; + border-radius: 5px; border: 1px solid #ccc; - font-size: 1rem; - background: #fafafa; + font-size: 16px; cursor: pointer; } -select:hover { - border-color: #ef5350; +#get-button { + background-color: #3498db; /* A nice blue color */ + color: white; + border-color: #2980b9; + transition: background-color 0.2s; } -img { - display: block; - width: 150px; - height: 150px; - margin: 1.5rem auto 0; - image-rendering: pixelated; - transition: transform 0.3s ease; +#get-button:hover { + background-color: #2980b9; } -img:hover { - transform: scale(1.1); -} +/* Style for the Image */ +#pokemon-img { + max-width: 200px; /* Keep the image at a reasonable size */ + height: auto; + padding: 15px; + border: 1px solid #ddd; + border-radius: 8px; + background-color: white; /* White background for the sprite */ + box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1); /* Subtle shadow */ +} \ No newline at end of file diff --git a/3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js b/3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js index cc9194231..642a003db 100644 --- a/3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js +++ b/3-UsingAPIs/Week2/assignment/ex3-rollAnAce.js @@ -18,24 +18,13 @@ import { rollDie } from '../../helpers/pokerDiceRoller.js'; * @returns {Promise} */ export async function rollDieUntil(desiredValue) { - // Rewritten with async/await and a while loop (no recursion) let value; - - while (true) { - try { - value = await rollDie(); // wait for the result - console.log(`Rolled: ${value}`); - if (value === desiredValue) { - return value; // stop when ACE is rolled - } - } catch (err) { - // If the die rolls off the table (rejection), rethrow the error - throw err; - } + while (value !== desiredValue) { + value = await rollDie(); } + return value; } -// Refactored main() to async/await and try/catch async function main() { try { const result = await rollDieUntil('ACE'); diff --git a/3-UsingAPIs/Week2/test-reports/ex1-programmerFun.report.txt b/3-UsingAPIs/Week2/test-reports/ex1-programmerFun.report.txt index d4e13fb38..08e729c84 100644 --- a/3-UsingAPIs/Week2/test-reports/ex1-programmerFun.report.txt +++ b/3-UsingAPIs/Week2/test-reports/ex1-programmerFun.report.txt @@ -1,40 +1,17 @@ *** Unit Test Error Report *** -Command failed: npx jest /Users/majdjadalhaq/Desktop/Assignments-Cohort54/.dist/3-UsingAPIs/Week2/unit-tests/ex1-programmerFun.test.js --colors --noStackTrace --json - FAIL .dist/3-UsingAPIs/Week2/unit-tests/ex1-programmerFun.test.js + PASS .dist/3-UsingAPIs/Week2/unit-tests/ex1-programmerFun.test.js (11.715 s) api-wk2-ex1-programmerFun - ✅ HTML should be syntactically valid (145 ms) + ✅ HTML should be syntactically valid (149 ms) ✅ should have all TODO comments removed - ❌ should use `fetch()` (1 ms) - ❌ should use async/wait - ❌ should use try/catch + ✅ should use `fetch()` + ✅ should use async/wait + ✅ should use try/catch - ● api-wk2-ex1-programmerFun › should use `fetch()` - - expect(received).toBeDefined() - - Received: undefined - - ● api-wk2-ex1-programmerFun › should use async/wait - - expect(received).toBeDefined() - - Received: undefined - - ● api-wk2-ex1-programmerFun › should use try/catch - - expect(received).toBeDefined() - - Received: undefined - -Test Suites: 1 failed, 1 total -Tests: 3 failed, 2 passed, 5 total +Test Suites: 1 passed, 1 total +Tests: 5 passed, 5 total Snapshots: 0 total -Time: 2.984 s, estimated 4 s +Time: 12.311 s Ran all test suites matching /\/Users\/majdjadalhaq\/Desktop\/Assignments-Cohort54\/.dist\/3-UsingAPIs\/Week2\/unit-tests\/ex1-programmerFun.test.js/i. No linting errors detected. - - -*** Spell Checker Report *** - -3-UsingAPIs/Week2/assignment/ex1-programmerFun/index.js:40:30 - Unknown word (xkcd) +No spelling errors detected. diff --git a/3-UsingAPIs/Week2/test-reports/ex2-pokemonApp.report.txt b/3-UsingAPIs/Week2/test-reports/ex2-pokemonApp.report.txt index 29087d70f..5343b1677 100644 --- a/3-UsingAPIs/Week2/test-reports/ex2-pokemonApp.report.txt +++ b/3-UsingAPIs/Week2/test-reports/ex2-pokemonApp.report.txt @@ -2,16 +2,16 @@ PASS .dist/3-UsingAPIs/Week2/unit-tests/ex2-pokemonApp.test.js api-wk2-ex2-pokemonApp - ✅ HTML should be syntactically valid (149 ms) - ✅ should have all TODO comments removed (1 ms) + ✅ HTML should be syntactically valid (146 ms) + ✅ should have all TODO comments removed ✅ should use `fetch()` - ✅ should use `await fetch()` (1 ms) - ✅ should use try/catch + ✅ should use `await fetch()` + ✅ should use try/catch (1 ms) Test Suites: 1 passed, 1 total Tests: 5 passed, 5 total Snapshots: 0 total -Time: 2.696 s, estimated 4 s +Time: 2.729 s Ran all test suites matching /\/Users\/majdjadalhaq\/Desktop\/Assignments-Cohort54\/.dist\/3-UsingAPIs\/Week2\/unit-tests\/ex2-pokemonApp.test.js/i. No linting errors detected. No spelling errors detected. diff --git a/3-UsingAPIs/Week2/test-reports/ex3-rollAnAce.report.txt b/3-UsingAPIs/Week2/test-reports/ex3-rollAnAce.report.txt index a1fb09a00..2c9277ebb 100644 --- a/3-UsingAPIs/Week2/test-reports/ex3-rollAnAce.report.txt +++ b/3-UsingAPIs/Week2/test-reports/ex3-rollAnAce.report.txt @@ -1,27 +1,19 @@ *** Unit Test Error Report *** -Command failed: npx jest /Users/majdjadalhaq/Desktop/Assignments-Cohort54/.dist/3-UsingAPIs/Week2/unit-tests/ex3-rollAnAce.test.js --colors --noStackTrace --json - FAIL .dist/3-UsingAPIs/Week2/unit-tests/ex3-rollAnAce.test.js + PASS .dist/3-UsingAPIs/Week2/unit-tests/ex3-rollAnAce.test.js api-wk2-ex3-rollAnAce - ✅ should have all TODO comments removed (1 ms) - ❌ `rollDieUntil` should not contain unneeded console.log calls (2 ms) + ✅ should have all TODO comments removed (2 ms) + ✅ `rollDieUntil` should not contain unneeded console.log calls ✅ should not include a recursive call (1 ms) ✅ should use async/wait - ✅ should use try/catch - ✅ should resolve as soon as a die settles on an ACE (22 ms) - ✅ should reject with an Error when a die rolls off the table (11 ms) + ✅ should use try/catch (1 ms) + ✅ should resolve as soon as a die settles on an ACE (20 ms) + ✅ should reject with an Error when a die rolls off the table (10 ms) - ● api-wk2-ex3-rollAnAce › `rollDieUntil` should not contain unneeded console.log calls - - expect(received).toBe(expected) // Object.is equality - - Expected: false - Received: true - -Test Suites: 1 failed, 1 total -Tests: 1 failed, 6 passed, 7 total +Test Suites: 1 passed, 1 total +Tests: 7 passed, 7 total Snapshots: 0 total -Time: 0.467 s, estimated 1 s +Time: 0.441 s, estimated 1 s Ran all test suites matching /\/Users\/majdjadalhaq\/Desktop\/Assignments-Cohort54\/.dist\/3-UsingAPIs\/Week2\/unit-tests\/ex3-rollAnAce.test.js/i. No linting errors detected. No spelling errors detected. From bd24b7205187cdf0dfaa9d337c71aa52eac61138 Mon Sep 17 00:00:00 2001 From: majdjadalhaq Date: Thu, 30 Oct 2025 20:53:14 +0100 Subject: [PATCH 5/6] finished ex5 --- 3-UsingAPIs/Week2/assignment/ex5-vscDebug.js | 28 +++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js b/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js index ed4fe9da5..b9ef0e295 100644 --- a/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js +++ b/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js @@ -10,8 +10,18 @@ async function getData(url) { function renderLaureate({ knownName, birth, death }) { console.log(`\nName: ${knownName.en}`); - console.log(`Birth: ${birth.date}, ${birth.place.locationString}`); - console.log(`Death: ${death.date}, ${death.place.locationString}`); + + if (birth) { + console.log(`Birth: ${birth?.date || 'Unknown'}, ${birth?.place?.locationString || 'Unknown'}`); + } else { + console.log(`Birth: Unknown`); + } + + if (death) { + console.log(`Death: ${death?.date || 'Unknown'}, ${death?.place?.locationString || 'Unknown'}`); + } else { + console.log(`Death: still alive`); + } } function renderLaureates(laureates) { @@ -20,14 +30,18 @@ function renderLaureates(laureates) { async function fetchAndRender() { try { - // Await the fetchData promise to get actual data - const laureates = await getData( - 'https://api.nobelprize.org/2.0/laureates?birthCountry=Netherlands&format=json&csvLang=en' + const data = await getData( + 'http://api.nobelprize.org/2.0/laureates?birthCountry=Netherlands&format=json&csvLang=en' ); - renderLaureates(laureates); + + if (Array.isArray(data.laureates)) { + renderLaureates(data.laureates); + } else { + console.error('No laureates found.'); + } } catch (err) { console.error(`Something went wrong: ${err.message}`); } } -fetchAndRender(); \ No newline at end of file +fetchAndRender(); From d65a3a6ea98fb7a951a3c965fa59b7529099855b Mon Sep 17 00:00:00 2001 From: Majd Hamde Date: Thu, 30 Oct 2025 21:04:30 +0100 Subject: [PATCH 6/6] finised ex5 --- 3-UsingAPIs/Week2/assignment/.vscode/settings.json | 3 +++ 3-UsingAPIs/Week2/assignment/ex5-vscDebug.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 3-UsingAPIs/Week2/assignment/.vscode/settings.json diff --git a/3-UsingAPIs/Week2/assignment/.vscode/settings.json b/3-UsingAPIs/Week2/assignment/.vscode/settings.json new file mode 100644 index 000000000..6f3a2913e --- /dev/null +++ b/3-UsingAPIs/Week2/assignment/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "liveServer.settings.port": 5501 +} \ No newline at end of file diff --git a/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js b/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js index b9ef0e295..ab91f49fc 100644 --- a/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js +++ b/3-UsingAPIs/Week2/assignment/ex5-vscDebug.js @@ -44,4 +44,4 @@ async function fetchAndRender() { } } -fetchAndRender(); +fetchAndRender(); \ No newline at end of file