Skip to content

Commit ef0eda4

Browse files
gikfDario-DCnaomi-lgbt
authored
fix(curriculum): improve Bookmark Manager tests (freeCodeCamp#57636)
Co-authored-by: Dario-DC <[email protected]> Co-authored-by: Naomi <[email protected]>
1 parent c603dab commit ef0eda4

File tree

1 file changed

+101
-15
lines changed

1 file changed

+101
-15
lines changed

curriculum/challenges/english/25-front-end-development/lab-bookmark-manager-app/66def5467aee701733aaf8cc.md

Lines changed: 101 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Fulfill the user stories below and get all the tests to pass to complete the lab
1414

1515
**User Stories:**
1616

17-
1. You should have a `getBookmarks` function that returns the `bookmarks` array stored in the local storage. If the `bookmarks` key has not been set yet, the `getBookmarks` function should return an empty array.
17+
1. You should have a `getBookmarks` function that returns the `bookmarks` array stored in the local storage. If the `bookmarks` key has not been set yet, or it doesn't contain a valid array with bookmarks, the `getBookmarks` function should return an empty array.
1818
1. The `bookmarks` key stored in the local storage should be an array of bookmark objects. Each bookmark object should have three keys: `name`, `category`, and `url`.
1919
1. You should have a function named `displayOrCloseForm` that toggles the `hidden` class on `#main-section` and `#form-section`.
2020
1. When you click `#add-bookmark-button`, you should update the inner text of `.category-name` to be the value of the selected option from `#category-dropdown` and call `displayOrCloseForm` to display the form section and hide the main section.
@@ -24,10 +24,10 @@ Fulfill the user stories below and get all the tests to pass to complete the lab
2424
1. You should have a function named `displayOrHideCategory` that toggles the `hidden` class on `#main-section` and `#bookmark-list-section`.
2525
1. When you click `#view-category-button`, you should update the inner text of `.category-name` to be the value of the selected option from `#category-dropdown`, modify the inner HTML of `#category-list` according to the user stories below, and call the `displayOrHideCategory` function.
2626
1. If none of the bookmarks in local storage have the category, you should set the inner HTML of the `#category-list` to a `p` element with the text `No Bookmarks Found`.
27-
1. If one or more bookmarks in local storage have the selected category you should add a radio button with `id` and `value` attributes set to the bookmark name to the `#category-list`'s inner HTML for each of those bookmarks.
27+
1. If one or more bookmarks in local storage have the selected category, you should add a radio button with `id` and `value` attributes, and set to the bookmark name to the `#category-list`'s inner HTML for each of those bookmarks. Additionally, each radio button should have the same `name` attribute.
2828
1. Each radio button should have a corresponding label containing an anchor element with the bookmark name and the `href` attribute set to the bookmark URL.
29-
1. When you click `#close-list-button`, you should run your function to hide the `#bookmark-list-section` and display the main section.
30-
1. When you click `#delete-bookmark-button`, you should delete the bookmark corresponding to the selected radio button from the local storage and update the displayed bookmark list.
29+
1. When you click the `#close-list-button`, you should run your function to hide the `#bookmark-list-section` and display the main section.
30+
1. When you click the `#delete-bookmark-button`, you should delete the bookmark corresponding to the selected radio button and appropriate category from the local storage and update the displayed bookmark list.
3131

3232
# --hints--
3333

@@ -69,6 +69,24 @@ try {
6969
}
7070
```
7171

72+
When the `bookmarks` key in the `localStorage` does not contain a valid array of bookmark objects, the `getBookmarks` function should return an empty array.
73+
74+
```js
75+
try {
76+
localStorage.setItem("bookmarks", 'invalid');
77+
const arrayFromInvalidValue = getBookmarks();
78+
assert.isArray(arrayFromInvalidValue);
79+
assert.isEmpty(arrayFromInvalidValue);
80+
81+
localStorage.setItem("bookmarks", JSON.stringify([{name: "example1", category: "news", notUrl: "example1.com"}]));
82+
const arrayFromInvalidArray = getBookmarks();
83+
assert.isArray(arrayFromInvalidArray)
84+
assert.isEmpty(arrayFromInvalidArray)
85+
} finally {
86+
resetLocalStorage();
87+
}
88+
```
89+
7290
You should have a function named `displayOrCloseForm`.
7391

7492
```js
@@ -201,7 +219,7 @@ try {
201219
}
202220
```
203221

204-
When you click `#view-category-button`, you should modify `#category-list`'s inner HTML by adding a radio button having the `id` and `value` attributes set to the bookmark name for each bookmark in the selected category.
222+
When you click the `#view-category-button`, you should modify the `#category-list` element's inner HTML by adding a radio button. The radio button should have the `id` and `value` attributes set to the bookmark name for each bookmark in the selected category. Additionally, each radio button should have the same `name` attribute.
205223

206224
```js
207225
try {
@@ -214,6 +232,8 @@ try {
214232
assert.strictEqual(bookmarksDisplayed[0].value, "example1");
215233
assert.strictEqual(bookmarksDisplayed[1].id, "example4");
216234
assert.strictEqual(bookmarksDisplayed[1].value, "example4");
235+
assert.isOk(bookmarksDisplayed[0].name)
236+
assert.strictEqual(bookmarksDisplayed[0].name, bookmarksDisplayed[1].name);
217237
} finally {
218238
resetLocalStorage();
219239
}
@@ -262,7 +282,49 @@ closeListButtonTest.dispatchEvent(new Event("click"));
262282
assert.strictEqual(getHidden("bookmark list"), "bookmark list");
263283
```
264284

265-
When you click `#delete-bookmark-button`, you should delete the bookmark corresponding to the selected radio button from the local storage and update the displayed bookmark list.
285+
When you click the `#close-list-button` and then open any category, the `#category-list` should contain only data relevant for the selected category, without duplicating entries.
286+
287+
```js
288+
setLocalStorage();
289+
try {
290+
categoryDropdownTest.value = "miscellaneous";
291+
viewCategoryButtonTest.dispatchEvent(new Event("click"));
292+
const categoryList = document.getElementById("category-list").innerHTML;
293+
assert.strictEqual(categoryList, "<p>No Bookmarks Found</p>");
294+
295+
closeListButtonTest.dispatchEvent(new Event("click"));
296+
categoryDropdownTest.value = "news";
297+
viewCategoryButtonTest.dispatchEvent(new Event("click"));
298+
299+
const newsBookmarks = document.querySelectorAll('#category-list input[type="radio"]');
300+
assert.lengthOf(newsBookmarks, 2);
301+
assert.strictEqual(newsBookmarks[0].id, "example1");
302+
assert.strictEqual(newsBookmarks[0].value, "example1");
303+
assert.strictEqual(newsBookmarks[1].id, "example4");
304+
assert.strictEqual(newsBookmarks[1].value, "example4");
305+
306+
closeListButtonTest.dispatchEvent(new Event("click"));
307+
categoryDropdownTest.value = "work";
308+
viewCategoryButtonTest.dispatchEvent(new Event("click"));
309+
310+
const workBookmarks = document.querySelectorAll('#category-list input[type="radio"]');
311+
assert.lengthOf(workBookmarks, 1);
312+
assert.strictEqual(workBookmarks[0].id, "example3");
313+
assert.strictEqual(workBookmarks[0].value, "example3");
314+
315+
categoryDropdownTest.value = "miscellaneous";
316+
viewCategoryButtonTest.dispatchEvent(new Event("click"));
317+
318+
const paragraphs = document.querySelectorAll("#category-list p");
319+
assert.lengthOf(paragraphs, 1);
320+
assert.strictEqual(paragraphs[0].innerText, "No Bookmarks Found");
321+
} finally {
322+
resetLocalStorage();
323+
clearCategoryList();
324+
}
325+
```
326+
327+
When you click the `#delete-bookmark-button`, you should delete the bookmark corresponding to the selected radio button and appropriate category from the local storage and update the displayed bookmark list.
266328

267329
```js
268330
setLocalStorage();
@@ -281,7 +343,17 @@ try {
281343
assert.strictEqual(bookmarkLabelsDisplayed[0].htmlFor, "example4");
282344
const expected = [{name: "example2", category: "entertainment", url: "example2.com"}, {name: "example3", category: "work", url: "example3.com"}, {name: "example4", category: "news", url: "example4.com"}];
283345
assert.deepEqual(getBookmarks(), expected);
284-
346+
347+
localStorage.setItem("bookmarks", JSON.stringify([{name: "duplicated-name", category: "news", url: "example1.com"}, {name: "duplicated-name", category: "entertainment", url: "example2.com"}]));
348+
349+
categoryDropdownTest.value = "entertainment";
350+
viewCategoryButtonTest.dispatchEvent(new Event("click"));
351+
const radioForDuplicate = document.querySelector('#category-list input[type="radio"]');
352+
radioForDuplicate.checked = true;
353+
354+
deleteBookmarkButtonTest.dispatchEvent(new Event("click"));
355+
356+
assert.deepEqual(getBookmarks(), [{name: "duplicated-name", category: "news", url: "example1.com"}])
285357
} finally {
286358
resetLocalStorage();
287359
}
@@ -529,7 +601,26 @@ const addBookmarkButtonForm = document.getElementById("add-bookmark-button-form"
529601
const categoryList = document.getElementById("category-list");
530602
const closeListButton = document.getElementById("close-list-button");
531603
const deleteBookmarkButton = document.getElementById("delete-bookmark-button");
532-
const getBookmarks = () => JSON.parse(localStorage.getItem("bookmarks")) || [];
604+
605+
const getBookmarks = () => {
606+
try {
607+
const parsed = JSON.parse(localStorage.getItem("bookmarks"));
608+
if (
609+
Array.isArray(parsed) &&
610+
parsed.every(
611+
(item) =>
612+
item.hasOwnProperty("category") &&
613+
item.hasOwnProperty("name") &&
614+
item.hasOwnProperty("url"),
615+
)
616+
) {
617+
return parsed;
618+
}
619+
return [];
620+
} catch {
621+
return [];
622+
}
623+
};
533624

534625
const displayOrCloseForm = () => {
535626
mainSection.classList.toggle("hidden");
@@ -570,12 +661,7 @@ const displayOrHideCategory = () => {
570661
const fillBookmarkList = () => {
571662
categoryHeading[1].innerText = categoryDropdown.value.charAt(0).toUpperCase()
572663
+ categoryDropdown.value.slice(1);
573-
const bookmarksToDisplay = getBookmarks().filter((i) => {
574-
if (i.category === categoryDropdown.value) {
575-
return true
576-
}
577-
return false
578-
});
664+
const bookmarksToDisplay = getBookmarks().filter((i) => i.category === categoryDropdown.value);
579665
if (bookmarksToDisplay.length) {
580666
categoryList.innerHTML = '';
581667
for (const bookmark of bookmarksToDisplay) {
@@ -604,7 +690,7 @@ const deleteBookmark = () => {
604690
for (const radioBookmark of radioBookmarks) {
605691
if (radioBookmark.checked) {
606692
const bookmarks = getBookmarks();
607-
const indexToRemove = bookmarks.findIndex(i => i.name == radioBookmark.value);
693+
const indexToRemove = bookmarks.findIndex(i => i.name == radioBookmark.value && i.category === categoryDropdown.value);
608694
bookmarks.splice(indexToRemove, 1);
609695
localStorage.setItem("bookmarks", JSON.stringify(bookmarks));
610696
return

0 commit comments

Comments
 (0)