diff --git a/source/ReviewDetails.html b/source/ReviewDetails.html index e87bd28..3e71c32 100644 --- a/source/ReviewDetails.html +++ b/source/ReviewDetails.html @@ -32,13 +32,13 @@
-

+

- +
diff --git a/source/assets/scripts/ReviewCard.js b/source/assets/scripts/ReviewCard.js index ba3388c..3d4c97c 100644 --- a/source/assets/scripts/ReviewCard.js +++ b/source/assets/scripts/ReviewCard.js @@ -31,18 +31,15 @@ class ReviewCard extends HTMLElement { align-items: center; border: 2px solid rgb(31, 41, 32); border-radius: 8px; - display: grid; - grid-template-rows: 118px 56px 14px 18px 15px 36px; height: auto; row-gap: 5px; padding: 0 16px 16px 16px; - width: 178px; + width: 200px; margin: 8px 8px 8px 8px; } div.rating { align-items: center; - column-gap: 5px; display: flex; } @@ -50,30 +47,30 @@ class ReviewCard extends HTMLElement { height: auto; display: inline-block; object-fit: scale-down; - width: 78px; } article>img { border-top-left-radius: 6px; border-top-right-radius: 6px; - height: 119px; + height: 120px; object-fit: cover; margin-left: -16px; + margin-right: -16px; width: calc(100% + 32px); } + + .meal-name-div { + height: 54px; + overflow: hidden; + } label.restaurant-name { color: black !important; } label.meal-name { - display: -webkit-box; - font-size: 16px; + font-size: 24px; height: 36px; - line-height: 18px; - overflow: hidden; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; } label:not(.meal-name), @@ -83,20 +80,27 @@ class ReviewCard extends HTMLElement { font-size: 12px; } - .tag-container { + .tag-container-div { margin-top: 20px; + height: 100px; + overflow: hidden; + } + + .tag-container { display: flex; flex-flow: row wrap; + height: fit-content; } .a-tag { background-color:#94da97; - border-radius: 7px; + border-radius: 6px; color: #94da97; - padding-right: 7px; - padding-left: 7px; - margin: 3px; + padding: 0px 6px 2px 6px; + margin: 2px 2px 2px 2px; font-weight: bold; + overflow: hidden; + height: 14px; } `; articleEl.append(styleEl); @@ -162,10 +166,13 @@ class ReviewCard extends HTMLElement { }); //meal name setup + let meallabelDiv = document.createElement("div"); + meallabelDiv.setAttribute("class", "meal-name-div"); let mealLabel = document.createElement("label"); mealLabel.setAttribute("id", "a-mealName"); mealLabel.setAttribute("class","meal-name"); mealLabel.innerHTML = data["mealName"]; + meallabelDiv.append(mealLabel); //restaurant name setup let restaurantLabel = document.createElement("label"); @@ -190,6 +197,8 @@ class ReviewCard extends HTMLElement { ratingDiv.append(starsImg); //added tags + let tagContainerDiv = document.createElement("div"); + tagContainerDiv.setAttribute("class", "tag-container-div"); let tagContainer = document.createElement("div"); tagContainer.setAttribute("class", "tag-container"); tagContainer.setAttribute("id", "a-tags"); @@ -202,14 +211,15 @@ class ReviewCard extends HTMLElement { tagContainer.append(newTag); } } + tagContainerDiv.append(tagContainer); //adding final ID to data! articleEl.append(mealImg); - articleEl.append(mealLabel); + articleEl.append(meallabelDiv); articleEl.append(restaurantLabel); articleEl.append(ratingDiv); - articleEl.append(tagContainer); + articleEl.append(tagContainerDiv); articleEl.append(comments); diff --git a/source/assets/scripts/ReviewDetails.js b/source/assets/scripts/ReviewDetails.js index 89483c2..7f22679 100644 --- a/source/assets/scripts/ReviewDetails.js +++ b/source/assets/scripts/ReviewDetails.js @@ -18,7 +18,7 @@ function setupInfo(){ let currReview = getReviewFromStorage(currID); //meal image - let mealImg = document.getElementById("d-mealImg"); + let mealImg = document.getElementById("d-meal-img"); mealImg.setAttribute("src",currReview["mealImg"]); mealImg.addEventListener("error", function(e) { mealImg.setAttribute("src", "./assets/images/default_plate.png"); @@ -26,7 +26,7 @@ function setupInfo(){ }); //meal name - let mealLabel = document.getElementById("d-mealName"); + let mealLabel = document.getElementById("d-meal-name"); mealLabel.innerHTML = currReview["mealName"]; //restaurant name diff --git a/source/assets/scripts/localStorage.js b/source/assets/scripts/localStorage.js index 2aaf914..545f6d5 100644 --- a/source/assets/scripts/localStorage.js +++ b/source/assets/scripts/localStorage.js @@ -128,4 +128,22 @@ export function getAllReviewsFromStorage() { reviews.push(currReview); } return reviews; +} + +/** + * Returns the top n reviews by ID. If there are less than n reviews, returns the most possible. + * @param {number} n number of reviews to return + * @returns {Object} list of n reviews that are the top rated + */ +export function getTopReviewsFromStorage(n) { + +} + +/** + * Returns all reviews which contain the same tag specified. + * @param {string} tag to filter by + * @returns {Object} list of reviews that all contain the specified tag + */ +export function getReviewsByTag(tag) { + } \ No newline at end of file diff --git a/source/assets/scripts/localStorage.test.js b/source/assets/scripts/localStorage.test.js index b74087d..3330ba0 100644 --- a/source/assets/scripts/localStorage.test.js +++ b/source/assets/scripts/localStorage.test.js @@ -1,8 +1,8 @@ import {strict as assert} from "node:assert"; import {describe, it, before, after} from "mocha"; -import {newReviewToStorage, getReviewFromStorage, updateReviewToStorage, deleteReviewFromStorage, getAllReviewsFromStorage} from "./localStorage.js"; +import {newReviewToStorage, getReviewFromStorage, updateReviewToStorage, deleteReviewFromStorage, getAllReviewsFromStorage, getTopReviewsFromStorage, getReviewsByTag} from "./localStorage.js"; -describe("test app localStorage interaction", () => { +describe("test CRUD localStorage interaction", () => { before(() => { localStorage.clear(); @@ -47,9 +47,7 @@ describe("test app localStorage interaction", () => { "tags": [`tag ${3*i}`, `tag ${3*i + 1}`, `tag ${3*i + 2}`] }; - newReviewToStorage(new_review); - - new_review.reviewID = i; + new_review.reviewID = newReviewToStorage(new_review); reviews.push(new_review); assert.deepEqual(getAllReviewsFromStorage(), reviews); @@ -99,5 +97,204 @@ describe("test app localStorage interaction", () => { } }).timeout(5000); + it("test localStorage state after all deletes", () => { + assert.deepEqual(getAllReviewsFromStorage(), []); + }); + after(() => {}); }); + +describe("test sort/filter localStorage interaction", () => { + + before(() => { + localStorage.clear(); + }); + + it("add sample data for sort and filter", () => { + for(let i = 0; i < 100; i++){ + let review = { + "imgSrc": `sample src ${i}`, + "mealName": `sample name ${i}`, + "restaurant": `sample restaurant ${i}`, + "rating": i, + "tags": [`tag ${i%3}`, `tag ${i < 50}`, "tag x"] + }; + + newReviewToStorage(review); + } + }); + + it("test getTopReviewsFromStorage end behavior after create", () =>{ + for(let i = 0; i <= 100; i++){ + let top_reviews = getTopReviewsFromStorage(i); + for(let j = 0; j < i; j++){ + assert.strictEqual(top_reviews[j].rating, 99 - j); + assert.strictEqual(top_reviews[j].reviewID, 99 - j); + } + } + }); + + it("test getReviewsByTag end behavior after create", () => { + let specific_tagged_reviews = []; + + specific_tagged_reviews = getReviewsByTag("tag 0"); + assert.strictEqual(specific_tagged_reviews.length, 34); + for(let i = 0; i < specific_tagged_reviews.length; i++){ + assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 0"), true); + assert.strictEqual(specific_tagged_reviews[i].reviewID % 3, 0); + } + + specific_tagged_reviews = getReviewsByTag("tag 1"); + assert.strictEqual(specific_tagged_reviews.length, 33); + for(let i = 0; i < specific_tagged_reviews.length; i++){ + assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 1"), true); + assert.strictEqual(specific_tagged_reviews[i].reviewID % 3, 1); + } + + specific_tagged_reviews = getReviewsByTag("tag 2"); + assert.strictEqual(specific_tagged_reviews.length, 33); + for(let i = 0; i < specific_tagged_reviews.length; i++){ + assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 2"), true); + assert.strictEqual(specific_tagged_reviews[i].reviewID % 3, 2); + } + + specific_tagged_reviews = getReviewsByTag("tag true"); + assert.strictEqual(specific_tagged_reviews.length, 50); + for(let i = 0; i < specific_tagged_reviews.length; i++){ + assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag true"), true); + assert.strictEqual(specific_tagged_reviews[i].reviewID < 50, true); + } + + specific_tagged_reviews = getReviewsByTag("tag false"); + assert.strictEqual(specific_tagged_reviews.length, 50); + for(let i = 0; i < specific_tagged_reviews.length; i++){ + assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag false"), true); + assert.strictEqual(specific_tagged_reviews[i].reviewID >= 50, true); + } + + specific_tagged_reviews = getReviewsByTag("tag x"); + assert.strictEqual(specific_tagged_reviews.length, 100); + + specific_tagged_reviews = getReviewsByTag("tag y"); + assert.deepEqual(specific_tagged_reviews, []); + }); + + it("update sample data for sort and filter", () => { + for(let i = 0; i < 100; i++){ + let new_review = { + "imgSrc": `sample src ${i}`, + "mealName": `sample name ${i}`, + "restaurant": `sample restaurant ${i}`, + "rating": 99-i, + "tags": [`tag ${i%4}`, `tag ${i < 37}`, "tag y"] + }; + + updateReviewToStorage(i, new_review); + } + }); + + it("test getTopReviewsFromStorage end behavior after create", () =>{ + for(let i = 0; i <= 100; i++){ + let top_reviews = getTopReviewsFromStorage(i); + for(let j = 0; j < i; j++){ + assert.strictEqual(top_reviews[j].rating, 99 - j); + assert.strictEqual(top_reviews[j].reviewID, j); + } + } + }); + + it("test getReviewsByTag end behavior after update", () => { + let specific_tagged_reviews = []; + + specific_tagged_reviews = getReviewsByTag("tag 0"); + assert.strictEqual(specific_tagged_reviews.length, 25); + for(let i = 0; i < specific_tagged_reviews.length; i++){ + assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 0"), true); + assert.strictEqual(specific_tagged_reviews[i].reviewID % 4, 0); + } + + specific_tagged_reviews = getReviewsByTag("tag 1"); + assert.strictEqual(specific_tagged_reviews.length, 25); + for(let i = 0; i < specific_tagged_reviews.length; i++){ + assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 1"), true); + assert.strictEqual(specific_tagged_reviews[i].reviewID % 4, 1); + } + + specific_tagged_reviews = getReviewsByTag("tag 2"); + assert.strictEqual(specific_tagged_reviews.length, 25); + for(let i = 0; i < specific_tagged_reviews.length; i++){ + assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 2"), true); + assert.strictEqual(specific_tagged_reviews[i].reviewID % 4, 2); + } + + specific_tagged_reviews = getReviewsByTag("tag 3"); + assert.strictEqual(specific_tagged_reviews.length, 25); + for(let i = 0; i < specific_tagged_reviews.length; i++){ + assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag 3"), true); + assert.strictEqual(specific_tagged_reviews[i].reviewID % 4, 3); + } + + specific_tagged_reviews = getReviewsByTag("tag true"); + assert.strictEqual(specific_tagged_reviews.length, 37); + for(let i = 0; i < specific_tagged_reviews.length; i++){ + assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag true"), true); + assert.strictEqual(specific_tagged_reviews[i].reviewID < 37, true); + } + + specific_tagged_reviews = getReviewsByTag("tag false"); + assert.strictEqual(specific_tagged_reviews.length, 63); + for(let i = 0; i < specific_tagged_reviews.length; i++){ + assert.strictEqual(specific_tagged_reviews[i].tags.includes("tag false"), true); + assert.strictEqual(specific_tagged_reviews[i].reviewID >= 37, true); + } + + specific_tagged_reviews = getReviewsByTag("tag x"); + assert.deepEqual(specific_tagged_reviews, []); + + specific_tagged_reviews = getReviewsByTag("tag y"); + assert.strictEqual(specific_tagged_reviews.length, 100); + }); + + it("delete all sample data for sort and filter", () => { + for(let i = 0; i < 100; i++){ + deleteReviewFromStorage(i); + } + }); + + it("test getTopReviewsFromStorage end behavior after delete", () =>{ + for(let i = 0; i <= 100; i++){ + let top_reviews = getTopReviewsFromStorage(i); + assert.deepEqual(top_reviews, []); + } + }); + + it("test getReviewsByTag end behavior after delete", () => { + let specific_tagged_reviews = []; + + specific_tagged_reviews = getReviewsByTag("tag 0"); + assert.deepEqual(specific_tagged_reviews, []); + + specific_tagged_reviews = getReviewsByTag("tag 1"); + assert.deepEqual(specific_tagged_reviews, []); + + specific_tagged_reviews = getReviewsByTag("tag 2"); + assert.deepEqual(specific_tagged_reviews, []); + + specific_tagged_reviews = getReviewsByTag("tag 3"); + assert.deepEqual(specific_tagged_reviews, []); + + specific_tagged_reviews = getReviewsByTag("tag true"); + assert.deepEqual(specific_tagged_reviews, []); + + specific_tagged_reviews = getReviewsByTag("tag false"); + assert.deepEqual(specific_tagged_reviews, []); + + specific_tagged_reviews = getReviewsByTag("tag x"); + assert.deepEqual(specific_tagged_reviews, []); + + specific_tagged_reviews = getReviewsByTag("tag y"); + assert.deepEqual(specific_tagged_reviews, []); + }); + + after(() => {}); +}); \ No newline at end of file diff --git a/source/assets/scripts/main.e2e.test.js b/source/assets/scripts/main.e2e.test.js index 2d9ba59..240e309 100644 --- a/source/assets/scripts/main.e2e.test.js +++ b/source/assets/scripts/main.e2e.test.js @@ -1,7 +1,6 @@ import {strict as assert} from "node:assert"; import {describe, it, before, after} from "mocha"; import puppeteer from "puppeteer-core"; -import {exit} from "node:process"; import {setReviewForm, checkCorrectness} from "./appTestHelpers.js"; describe("test App end to end", async () => { @@ -27,7 +26,6 @@ describe("test App end to end", async () => { } catch (error) { await console.log("❌ failed to connect to localhost webserver on port 8080"); - await exit(1); } }); diff --git a/source/index.html b/source/index.html index 08a45b3..d1f5cd2 100644 --- a/source/index.html +++ b/source/index.html @@ -1,4 +1,3 @@ - diff --git a/source/static/Form.css b/source/static/Form.css index 41fbd68..584826a 100644 --- a/source/static/Form.css +++ b/source/static/Form.css @@ -19,7 +19,7 @@ background-color: #f7dfd5; } -#d-mealImg { +#d-meal-img { border: 2px solid rgb(31 41 32); border-radius: 8px; }