Merge remote-tracking branch 'origin/sprint-3' into 49-image-feature

This commit is contained in:
Henry Feng 2022-11-29 17:21:55 -08:00
commit 20cdc4ce76
15 changed files with 433 additions and 99 deletions

29
.github/workflows/prettier-linting.yml vendored Normal file
View File

@ -0,0 +1,29 @@
name: Prettier
on:
pull_request:
branches:
- main
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
# Single deploy job since we're just deploying
test:
runs-on: ubuntu-latest
steps:
- name: Install apt updates
run: sudo apt -y update; sudo apt -y upgrade;
- name: Install prerequisites
uses: actions/setup-node@v3
with:
node-version: 18
- name: Checkout
uses: actions/checkout@v3
- name: Install dependencies
run: sudo npm install
- name: Start local http server
run: sudo npm run http-server &
- name: Run tests
run: sudo npm lint-prettier

5
.prettierrc.json Normal file
View File

@ -0,0 +1,5 @@
{
"printWidth": 160,
"tabWidth": 4,
"useTabs": true
}

View File

@ -10,7 +10,6 @@
"lint-css": "stylelint **/*.css", "lint-css": "stylelint **/*.css",
"fix-css": "stylelint --fix **/*.css", "fix-css": "stylelint --fix **/*.css",
"http-server": "http-server source", "http-server": "http-server source",
"js-doc": "jsdoc -d source/docs/ -r source/",
"lint-prettier": "prettier --check .", "lint-prettier": "prettier --check .",
"fix-prettier": "prettier --write ." "fix-prettier": "prettier --write ."
}, },
@ -18,12 +17,11 @@
"eslint": "^8.27.0", "eslint": "^8.27.0",
"htmlhint": "1.1.4", "htmlhint": "1.1.4",
"http-server": "", "http-server": "",
"jsdoc": "^4.0.0",
"mocha": "10", "mocha": "10",
"mock-local-storage": "^1.1.23", "mock-local-storage": "^1.1.23",
"prettier": "2.8.0",
"puppeteer": "^18.2.1", "puppeteer": "^18.2.1",
"stylelint": "14.14.1", "stylelint": "14.14.1",
"stylelint-config-standard": "^29.0.0", "stylelint-config-standard": "^29.0.0"
"prettier": "2.8.0"
} }
} }

View File

@ -32,13 +32,13 @@
<div class="journal-form" id="review-details"> <div class="journal-form" id="review-details">
<form> <form>
<fieldset class = "meal-name"> <fieldset class = "meal-name">
<h1 id="d-mealName" style="font-family: Century Gothic;"></h1> <h1 id="d-meal-name" style="font-family: Century Gothic;"></h1>
<h1 id="d-restaurant" style="font-family: Century Gothic; font-size: 30px;"></h1> <h1 id="d-restaurant" style="font-family: Century Gothic; font-size: 30px;"></h1>
</fieldset> </fieldset>
<fieldset class = "meal-pics"> <fieldset class = "meal-pics">
<!-- image source --> <!-- image source -->
<img width=40% height=40% id="d-mealImg" style="margin-left: auto; margin-right: auto; display: block;"/> <img width=40% height=40% id="d-meal-img" style="margin-left: auto; margin-right: auto; display: block;"/>
</fieldset> </fieldset>
<fieldset class = "stars-and-comments" style="text-align: center;"> <fieldset class = "stars-and-comments" style="text-align: center;">
@ -55,9 +55,9 @@
<!---Navigation Buttons--> <!---Navigation Buttons-->
<div style="display: flex; justify-content: center;"> <div style="display: flex; justify-content: center;">
<img src="./assets/images/home_button_for_interface.png" style="margin: 20px 10px 20px 10px;" id="home-btn" onclick="window.location.assign('./index.html')" height="50" width="50"/> <img src="./assets/images/home_button_for_interface.png" style="margin: 20px 10px 20px 10px;" id="home-btn" title="Home Page" onclick="window.location.assign('./index.html')" height="50" width="50"/>
<img src ="./assets/images/edit_button_for_interface.png" style="margin: 20px 10px 20px 10px;" id="update-btn" height="50" width="50"/> <img src ="./assets/images/edit_button_for_interface.png" style="margin: 20px 10px 20px 10px;" id="update-btn" title="Edit Review" height="50" width="50"/>
<img src ="./assets/images/delete_icon_for_interface.png" style="margin: 20px 10px 20px 10px;" id="delete-btn" class="danger" height="50" width="50"/> <img src ="./assets/images/delete_icon_for_interface.png" style="margin: 20px 10px 20px 10px;" id="delete-btn" title="Delete Review" class="danger" height="50" width="50"/>
</div> </div>
</main> </main>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 KiB

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -6,9 +6,7 @@ window.addEventListener("DOMContentLoaded", init);
* Delegates the functionality for creating review cards. * Delegates the functionality for creating review cards.
*/ */
function init() { function init() {
initFormHandler(); initFormHandler();
} }
/** /**
@ -104,24 +102,29 @@ function initFormHandler() {
// Event listener for tag functionality // Event listener for tag functionality
let tagAddBtn = document.getElementById("tag-add-btn"); let tagAddBtn = document.getElementById("tag-add-btn");
//Set used to track tags and ensure no duplicates
let tagSet = new Set();
tagAddBtn.addEventListener("click", ()=> { tagAddBtn.addEventListener("click", ()=> {
let tagField = document.getElementById("tag-form"); let tagField = document.getElementById("tag-form");
// If there is a tag, it'll display the tag // If there is a tag, it'll display the tag
if (tagField.value.length > 0) { if (tagField.value.length > 0) {
let tagSetVal = tagField.value.toLowerCase();
if (!tagSet.has(tagSetVal)){
let tagLabel = document.createElement("label"); let tagLabel = document.createElement("label");
tagLabel.innerHTML = tagField.value; tagLabel.innerHTML = tagField.value;
tagLabel.setAttribute("class","tag"); tagLabel.setAttribute("class","tag");
tagSet.add(tagField.value.toLowerCase());
// Allows for user to delete the tag
tagLabel.addEventListener("click",()=> { tagLabel.addEventListener("click",()=> {
tagContainer.removeChild(tagLabel); tagContainer.removeChild(tagLabel);
tagSet.delete(tagField.value.toLowerCase());
}); });
// Adds the tag
tagContainer.append(tagLabel); tagContainer.append(tagLabel);
} else {
window.alert("No duplicate tags allowed");
}
tagField.value = ""; tagField.value = "";
} }
}); });

View File

@ -31,18 +31,15 @@ class ReviewCard extends HTMLElement {
align-items: center; align-items: center;
border: 2px solid rgb(31, 41, 32); border: 2px solid rgb(31, 41, 32);
border-radius: 8px; border-radius: 8px;
display: grid;
grid-template-rows: 118px 56px 14px 18px 15px 36px;
height: auto; height: auto;
row-gap: 5px; row-gap: 5px;
padding: 0 16px 16px 16px; padding: 0 16px 16px 16px;
width: 178px; width: 200px;
margin: 8px 8px 8px 8px; margin: 8px 8px 8px 8px;
} }
div.rating { div.rating {
align-items: center; align-items: center;
column-gap: 5px;
display: flex; display: flex;
} }
@ -50,30 +47,30 @@ class ReviewCard extends HTMLElement {
height: auto; height: auto;
display: inline-block; display: inline-block;
object-fit: scale-down; object-fit: scale-down;
width: 78px;
} }
article>img { article>img {
border-top-left-radius: 6px; border-top-left-radius: 6px;
border-top-right-radius: 6px; border-top-right-radius: 6px;
height: 119px; height: 120px;
object-fit: cover; object-fit: cover;
margin-left: -16px; margin-left: -16px;
margin-right: -16px;
width: calc(100% + 32px); width: calc(100% + 32px);
} }
.meal-name-div {
height: 54px;
overflow: hidden;
}
label.restaurant-name { label.restaurant-name {
color: black !important; color: black !important;
} }
label.meal-name { label.meal-name {
display: -webkit-box; font-size: 24px;
font-size: 16px;
height: 36px; height: 36px;
line-height: 18px;
overflow: hidden;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
} }
label:not(.meal-name), label:not(.meal-name),
@ -83,20 +80,27 @@ class ReviewCard extends HTMLElement {
font-size: 12px; font-size: 12px;
} }
.tag-container { .tag-container-div {
margin-top: 20px; margin-top: 20px;
height: 100px;
overflow: hidden;
}
.tag-container {
display: flex; display: flex;
flex-flow: row wrap; flex-flow: row wrap;
height: fit-content;
} }
.a-tag { .a-tag {
background-color:#94da97; background-color:#94da97;
border-radius: 7px; border-radius: 6px;
color: #94da97; color: #94da97;
padding-right: 7px; padding: 0px 6px 2px 6px;
padding-left: 7px; margin: 2px 2px 2px 2px;
margin: 3px;
font-weight: bold; font-weight: bold;
overflow: hidden;
height: 14px;
} }
`; `;
articleEl.append(styleEl); articleEl.append(styleEl);
@ -149,15 +153,18 @@ class ReviewCard extends HTMLElement {
mealImg.setAttribute("alt","Meal Photo Corrupted"); mealImg.setAttribute("alt","Meal Photo Corrupted");
mealImg.setAttribute("src",data["mealImg"]); mealImg.setAttribute("src",data["mealImg"]);
mealImg.addEventListener("error", function(e) { mealImg.addEventListener("error", function(e) {
mealImg.setAttribute("src", "./assets/images/plate_with_cutlery.png"); mealImg.setAttribute("src", "./assets/images/default_plate.png");
e.onerror = null; e.onerror = null;
}); });
// Meal name setup //meal name setup
let meallabelDiv = document.createElement("div");
meallabelDiv.setAttribute("class", "meal-name-div");
let mealLabel = document.createElement("label"); let mealLabel = document.createElement("label");
mealLabel.setAttribute("id", "a-mealName"); mealLabel.setAttribute("id", "a-mealName");
mealLabel.setAttribute("class","meal-name"); mealLabel.setAttribute("class","meal-name");
mealLabel.innerHTML = data["mealName"]; mealLabel.innerHTML = data["mealName"];
meallabelDiv.append(mealLabel);
// Restaurant name setup // Restaurant name setup
let restaurantLabel = document.createElement("label"); let restaurantLabel = document.createElement("label");
@ -181,7 +188,9 @@ class ReviewCard extends HTMLElement {
starsImg.setAttribute("num", data["rating"]); starsImg.setAttribute("num", data["rating"]);
ratingDiv.append(starsImg); ratingDiv.append(starsImg);
// Tags setup //added tags
let tagContainerDiv = document.createElement("div");
tagContainerDiv.setAttribute("class", "tag-container-div");
let tagContainer = document.createElement("div"); let tagContainer = document.createElement("div");
tagContainer.setAttribute("class", "tag-container"); tagContainer.setAttribute("class", "tag-container");
tagContainer.setAttribute("id", "a-tags"); tagContainer.setAttribute("id", "a-tags");
@ -196,13 +205,14 @@ class ReviewCard extends HTMLElement {
tagContainer.append(newTag); tagContainer.append(newTag);
} }
} }
tagContainerDiv.append(tagContainer);
// Setting all the data to the review card // Setting all the data to the review card
articleEl.append(mealImg); articleEl.append(mealImg);
articleEl.append(mealLabel); articleEl.append(meallabelDiv);
articleEl.append(restaurantLabel); articleEl.append(restaurantLabel);
articleEl.append(ratingDiv); articleEl.append(ratingDiv);
articleEl.append(tagContainer); articleEl.append(tagContainerDiv);
articleEl.append(comments); articleEl.append(comments);

View File

@ -13,20 +13,23 @@ function init(){
setupUpdate(); setupUpdate();
} }
/**
* Populates the relevant data to the details from local storage review
*/
function setupInfo(){ function setupInfo(){
let currID = JSON.parse(sessionStorage.getItem("currID")); let currID = JSON.parse(sessionStorage.getItem("currID"));
let currReview = getReviewFromStorage(currID); let currReview = getReviewFromStorage(currID);
//meal image //meal image
let mealImg = document.getElementById("d-mealImg"); let mealImg = document.getElementById("d-meal-img");
mealImg.setAttribute("src",currReview["mealImg"]); mealImg.setAttribute("src",currReview["mealImg"]);
mealImg.addEventListener("error", function(e) { mealImg.addEventListener("error", function(e) {
mealImg.setAttribute("src", "./assets/images/plate_with_cutlery.png"); mealImg.setAttribute("src", "./assets/images/default_plate.png");
e.onerror = null; e.onerror = null;
}); });
//meal name //meal name
let mealLabel = document.getElementById("d-mealName"); let mealLabel = document.getElementById("d-meal-name");
mealLabel.innerHTML = currReview["mealName"]; mealLabel.innerHTML = currReview["mealName"];
//restaurant name //restaurant name
@ -55,7 +58,7 @@ function setupInfo(){
} }
/** /**
* Sets up delete button to delete reveiw from storage and switch to homepage. * Sets up delete button to delete review from storage and switch to homepage
*/ */
function setupDelete(){ function setupDelete(){
let deleteBtn = document.getElementById("delete-btn"); let deleteBtn = document.getElementById("delete-btn");
@ -70,7 +73,7 @@ function setupDelete(){
} }
/** /**
* Sets up update button to reveal form and update info in storage and the current page. * Sets up update button to reveal form and update info in storage and the current page
*/ */
function setupUpdate(){ function setupUpdate(){
let updateBtn = document.getElementById("update-btn"); let updateBtn = document.getElementById("update-btn");
@ -92,16 +95,22 @@ function setupUpdate(){
document.getElementById("s" + `${currReview["rating"]}`).checked = true; document.getElementById("s" + `${currReview["rating"]}`).checked = true;
document.getElementById("restaurant").defaultValue = currReview["restaurant"]; document.getElementById("restaurant").defaultValue = currReview["restaurant"];
//Set used to track tags and ensure no duplicates
let tagSet = new Set();
if(currReview["tags"]){ if(currReview["tags"]){
while (tagContainer.firstChild) { while (tagContainer.firstChild) {
tagContainer.removeChild(tagContainer.firstChild); tagContainer.removeChild(tagContainer.firstChild);
} }
let tagSetVal = currReview["tags"][i].toLowerCase()
for (let i = 0; i < currReview["tags"].length; i++) { for (let i = 0; i < currReview["tags"].length; i++) {
tagSet.add(tagSetVal);
let newTag = document.createElement("label"); let newTag = document.createElement("label");
newTag.setAttribute("class","tag"); newTag.setAttribute("class","tag");
newTag.innerHTML = currReview["tags"][i]; newTag.innerHTML = currReview["tags"][i];
newTag.addEventListener("click",()=> { newTag.addEventListener("click",()=> {
tagContainer.removeChild(newTag); tagContainer.removeChild(newTag);
tagSet.delete(tagSetVal);
}); });
tagContainer.append(newTag); tagContainer.append(newTag);
} }
@ -148,11 +157,13 @@ function setupUpdate(){
//Take formdata values as newData when submit //Take formdata values as newData when submit
form.addEventListener("submit", function(){ form.addEventListener("submit", function(){
//We create reviewCard datea, replace it in in storage, and update tags /*
* User submits the form for their review.
* We create reviewCard data, replace in storage, and update tags
*/
let formData = new FormData(form); let formData = new FormData(form);
let newData = {}; let newData = {};
//iterate through formData and add to newData
// Iterate through formData an add to newData
for (let [key, value] of formData) { for (let [key, value] of formData) {
console.log(`${key}`); console.log(`${key}`);
console.log(`${value}`); console.log(`${value}`);
@ -183,19 +194,26 @@ function setupUpdate(){
}); });
// Adding tag to form functionality //adding tag to form functionality
let tagAddBtn = document.getElementById("tag-add-btn"); let tagAddBtn = document.getElementById("tag-add-btn");
tagAddBtn.addEventListener("click", ()=> { tagAddBtn.addEventListener("click", ()=> {
let tagField = document.getElementById("tag-form"); let tagField = document.getElementById("tag-form");
if (tagField.value.length > 0) { if (tagField.value.length > 0) {
let tagSetVal = tagField.value.toLowerCase();
if (!tagSet.has(tagSetVal)){
let tagLabel = document.createElement("label"); let tagLabel = document.createElement("label");
tagLabel.innerHTML = tagField.value; tagLabel.innerHTML = tagField.value;
tagLabel.setAttribute("class","tag"); tagLabel.setAttribute("class","tag");
tagSet.add(tagSetVal);
tagLabel.addEventListener("click",()=> { tagLabel.addEventListener("click",()=> {
tagContainer.removeChild(tagLabel); tagContainer.removeChild(tagLabel);
tagSet.delete(tagSetVal);
}); });
tagContainer.append(tagLabel); tagContainer.append(tagLabel);
} else {
window.alert("No duplicate tags allowed");
}
tagField.value = ""; tagField.value = "";
} }
}); });

View File

@ -11,6 +11,9 @@ export function newReviewToStorage(review){
// set the review entry to the review object // set the review entry to the review object
localStorage.setItem(`review${nextReviewId}`, JSON.stringify(review)); localStorage.setItem(`review${nextReviewId}`, JSON.stringify(review));
// adding to the tag keys
addTagsToStorage(nextReviewId, review["tags"]);
//updating our activeIDS list //updating our activeIDS list
let tempIdArr = JSON.parse(localStorage.getItem("activeIDS")); let tempIdArr = JSON.parse(localStorage.getItem("activeIDS"));
tempIdArr.push(nextReviewId); tempIdArr.push(nextReviewId);
@ -37,6 +40,14 @@ export function getReviewFromStorage(ID){
* @param {Object} review to store * @param {Object} review to store
*/ */
export function updateReviewToStorage(ID, review){ export function updateReviewToStorage(ID, review){
let oldReview = JSON.parse(localStorage.getItem(`review${ID}`));
//Get diff of tags and update storage
let deletedTags = oldReview["tags"].filter(x => !review["tags"].includes(x));
let addedTags = review["tags"].filter(x => !oldReview["tags"].includes(x));
deleteTagsFromStorage(ID, deletedTags);
addTagsToStorage(ID, addedTags);
// set the review entry with ID to the review object // set the review entry with ID to the review object
localStorage.setItem(`review${ID}`, JSON.stringify(review)); localStorage.setItem(`review${ID}`, JSON.stringify(review));
} }
@ -52,6 +63,8 @@ export function deleteReviewFromStorage(ID){
if (activeIDS[i] == ID) { if (activeIDS[i] == ID) {
activeIDS.splice(i,1); activeIDS.splice(i,1);
localStorage.setItem("activeIDS", JSON.stringify(activeIDS)); localStorage.setItem("activeIDS", JSON.stringify(activeIDS));
let currReview = JSON.parse(localStorage.getItem(`review${ID}`));
deleteTagsFromStorage(ID, currReview["tags"]);
localStorage.removeItem(`review${ID}`); localStorage.removeItem(`review${ID}`);
return; return;
} }
@ -60,6 +73,65 @@ export function deleteReviewFromStorage(ID){
console.error(`could not find review${ID} in localStorage`); console.error(`could not find review${ID} in localStorage`);
} }
/**
* Delete ID from the specified tags' storage
* @param {string} ID to delete from lists
* @param {string[]} deletedTags to modify storage of
*/
function deleteTagsFromStorage(ID, deletedTags) {
for(let i in deletedTags){
//get local storage of each tag and remove id from tag list
let tagName = "!"+ deletedTags[i].toLowerCase();
let tagArr = JSON.parse(localStorage.getItem(tagName));
for(let j in tagArr){
if(tagArr[j] == ID){
tagArr.splice(j,1);
break;
}
}
if(tagArr.length != 0){
localStorage.setItem(tagName, JSON.stringify(tagArr));
} else {
localStorage.removeItem(tagName);
}
}
}
/**
* Add ID from the specified tags' storage
* @param {string} ID to add to lists
* @param {string[]} addedTags to modify storage of
*/
function addTagsToStorage(ID, addedTags) {
for(let i in addedTags){
let tagName = "!" + addedTags[i].toLowerCase();
let tagArr = JSON.parse(localStorage.getItem(tagName));
if(!tagArr){
tagArr = [];
}
tagArr.push(ID);
localStorage.setItem(tagName, JSON.stringify(tagArr));
}
}
/**
* 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) {
}
// legacy function // legacy function
export function getAllReviewsFromStorage() { export function getAllReviewsFromStorage() {
if (!(localStorage.getItem("activeIDS"))) { if (!(localStorage.getItem("activeIDS"))) {

View File

@ -1,8 +1,8 @@
import {strict as assert} from "node:assert"; import {strict as assert} from "node:assert";
import {describe, it, before, after} from "mocha"; 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(() => { before(() => {
localStorage.clear(); localStorage.clear();
@ -47,9 +47,7 @@ describe("test app localStorage interaction", () => {
"tags": [`tag ${3*i}`, `tag ${3*i + 1}`, `tag ${3*i + 2}`] "tags": [`tag ${3*i}`, `tag ${3*i + 1}`, `tag ${3*i + 2}`]
}; };
newReviewToStorage(new_review); new_review.reviewID = newReviewToStorage(new_review);
new_review.reviewID = i;
reviews.push(new_review); reviews.push(new_review);
assert.deepEqual(getAllReviewsFromStorage(), reviews); assert.deepEqual(getAllReviewsFromStorage(), reviews);
@ -99,5 +97,204 @@ describe("test app localStorage interaction", () => {
} }
}).timeout(5000); }).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(() => {}); after(() => {});
}); });

View File

@ -1,7 +1,6 @@
import {strict as assert} from "node:assert"; import {strict as assert} from "node:assert";
import {describe, it, before, after} from "mocha"; import {describe, it, before, after} from "mocha";
import puppeteer from "puppeteer-core"; import puppeteer from "puppeteer-core";
import {exit} from "node:process";
import {setReviewForm, checkCorrectness} from "./appTestHelpers.js"; import {setReviewForm, checkCorrectness} from "./appTestHelpers.js";
describe("test App end to end", async () => { describe("test App end to end", async () => {
@ -27,7 +26,6 @@ describe("test App end to end", async () => {
} }
catch (error) { catch (error) {
await console.log("❌ failed to connect to localhost webserver on port 8080"); await console.log("❌ failed to connect to localhost webserver on port 8080");
await exit(1);
} }
}); });
@ -65,7 +63,7 @@ describe("test App end to end", async () => {
it("check details page", async () => { it("check details page", async () => {
// check the details page for correctness // check the details page for correctness
let expected = { let expected = {
imgSrc: "http://localhost:8080/assets/images/plate_with_cutlery.png", imgSrc: "http://localhost:8080/assets/images/default_plate.png",
mealName: "sample name", mealName: "sample name",
comments: "sample comment", comments: "sample comment",
restaurant: "sample restaurant", restaurant: "sample restaurant",
@ -86,7 +84,7 @@ describe("test App end to end", async () => {
let shadowRoot = await review_card.getProperty("shadowRoot"); let shadowRoot = await review_card.getProperty("shadowRoot");
let expected = { let expected = {
imgSrc: "http://localhost:8080/assets/images/plate_with_cutlery.png", imgSrc: "http://localhost:8080/assets/images/default_plate.png",
mealName: "sample name", mealName: "sample name",
comments: "sample comment", comments: "sample comment",
restaurant: "sample restaurant", restaurant: "sample restaurant",
@ -111,7 +109,7 @@ describe("test App end to end", async () => {
// check the details page for correctness // check the details page for correctness
let expected = { let expected = {
imgSrc: "http://localhost:8080/assets/images/plate_with_cutlery.png", imgSrc: "http://localhost:8080/assets/images/default_plate.png",
mealName: "sample name", mealName: "sample name",
comments: "sample comment", comments: "sample comment",
restaurant: "sample restaurant", restaurant: "sample restaurant",
@ -133,7 +131,7 @@ describe("test App end to end", async () => {
// check the details page for correctness // check the details page for correctness
let expected = { let expected = {
imgSrc: "http://localhost:8080/assets/images/plate_with_cutlery.png", imgSrc: "http://localhost:8080/assets/images/default_plate.png",
mealName: "sample name", mealName: "sample name",
comments: "sample comment", comments: "sample comment",
restaurant: "sample restaurant", restaurant: "sample restaurant",
@ -176,7 +174,7 @@ describe("test App end to end", async () => {
it("check details page", async () => { it("check details page", async () => {
// check the details page for correctness // check the details page for correctness
let expected = { let expected = {
imgSrc: "http://localhost:8080/assets/images/plate_with_cutlery.png", imgSrc: "http://localhost:8080/assets/images/default_plate.png",
mealName: "updated name", mealName: "updated name",
comments: "updated comment", comments: "updated comment",
restaurant: "updated restaurant", restaurant: "updated restaurant",
@ -198,7 +196,7 @@ describe("test App end to end", async () => {
// check the details page for correctness // check the details page for correctness
let expected = { let expected = {
imgSrc: "http://localhost:8080/assets/images/plate_with_cutlery.png", imgSrc: "http://localhost:8080/assets/images/default_plate.png",
mealName: "updated name", mealName: "updated name",
comments: "updated comment", comments: "updated comment",
restaurant: "updated restaurant", restaurant: "updated restaurant",

View File

@ -1,4 +1,3 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@ -39,7 +38,7 @@
</form> </form>
</div> </div>
<div class="center-display"> <div class="center-display">
<img src ="./assets/images/Grouppink.png" alt="CREATE" style="opacity: 100%;" id="create-btn" onclick="window.location.assign('./CreatePage.html')"/> <img src ="./assets/images/Grouppink.png" alt="CREATE" style="opacity: 100%;" id="create-btn" title="Add an entry!" onclick="window.location.assign('./CreatePage.html')"/>
<h2 id="recent-reviews-text"> Recent Reviews </h2> <h2 id="recent-reviews-text"> Recent Reviews </h2>
<img src ="./assets/images/Grouppink.png" style="opacity:0;"/> <img src ="./assets/images/Grouppink.png" style="opacity:0;"/>

View File

@ -19,6 +19,11 @@
background-color: #f7dfd5; background-color: #f7dfd5;
} }
#d-meal-img {
border: 2px solid rgb(31 41 32);
border-radius: 8px;
}
fieldset { fieldset {
border: none; border: none;
} }