mirror of
				https://github.com/cse110-fa22-group29/cse110-fa22-group29.git
				synced 2025-10-31 03:46:50 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/sprint-2' into allow-for-user-uploaded-images
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/js-unittest.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/js-unittest.yml
									
									
									
									
										vendored
									
									
								
							| @@ -23,5 +23,7 @@ jobs: | |||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v3 | ||||||
|       - name: Install dependencies |       - name: Install dependencies | ||||||
|         run: sudo npm install |         run: sudo npm install | ||||||
|  |       - name: Start local http server | ||||||
|  |         run: sudo npm run http-server &  | ||||||
|       - name: Run tests |       - name: Run tests | ||||||
|         run: sudo npm test |         run: sudo npm test | ||||||
							
								
								
									
										33
									
								
								admin/meetings/111622-checkin6.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								admin/meetings/111622-checkin6.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | # Meeting Minutes (11/16/2022) | ||||||
|  | ## Team 29: Hackers1995 | ||||||
|  | ## Meeting Topic: Weekly TA Catchup with Gagan | ||||||
|  | We are meeting with Gagan to discuss Checkpoint 1 and Sprint 2 resolutions. | ||||||
|  |  | ||||||
|  | ## Attendance | ||||||
|  | 1. Rhea Bhutada | ||||||
|  | 2. George Dubinin | ||||||
|  | 3. Gagan Gopalaiah | ||||||
|  | 4. Kara Hoagland | ||||||
|  |  | ||||||
|  | ## Meeting Details | ||||||
|  | - When: 11/16/2022 at 3:30PM | ||||||
|  | - Where: Zoom | ||||||
|  |  | ||||||
|  | ## Agenda: | ||||||
|  |  | ||||||
|  | ## Discussion Points by Gagan | ||||||
|  | - Updated Gagan on Sprint 1 | ||||||
|  |   - looked at Girhub actions | ||||||
|  |   - looked at the published page so far | ||||||
|  |   - discussed retrospective | ||||||
|  | - Upcoming Assignments | ||||||
|  |   - we have to come up with a video on the status of our app | ||||||
|  |   - ramp up the styling part, so u can brag about the design of the app | ||||||
|  |   - this video is supposed to encourage healthy competition | ||||||
|  | - Other Concerns | ||||||
|  |   - JSDocs - not primary concern right now | ||||||
|  |   - GitHub Pages vs. Netlify | ||||||
|  |     - Gagan sees Netlify as more professional and not to difficult to implement | ||||||
|  |  | ||||||
|  | ## End Time | ||||||
|  | - 11/09/2022 at 3:45PM | ||||||
| @@ -4,16 +4,19 @@ | |||||||
|   "type": "module", |   "type": "module", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "test": "mocha --recursive --require mock-local-storage './{,!(node_modules)/**}/*.test.js'", |     "test": "mocha --recursive --require mock-local-storage './{,!(node_modules)/**}/*.test.js'", | ||||||
|     "lint": "eslint '**/*.js'", |     "lint": "eslint **/*.js", | ||||||
|     "fix-style": "eslint --fix **/*.js", |     "fix-style": "eslint --fix **/*.js", | ||||||
|     "lintHTML": "htmlhint '**/*.html'", |     "lintHTML": "htmlhint '**/*.html'", | ||||||
|     "lintCSS": "stylelint '**/*.css'" |     "lintCSS": "stylelint '**/*.css'", | ||||||
|  |     "http-server": "http-server source" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "eslint": "^8.27.0", |     "eslint": "^8.27.0", | ||||||
|     "htmlhint": "1.1.4", |     "htmlhint": "1.1.4", | ||||||
|  |     "http-server": "", | ||||||
|     "mocha": "10", |     "mocha": "10", | ||||||
|     "mock-local-storage": "^1.1.23", |     "mock-local-storage": "^1.1.23", | ||||||
|  |     "puppeteer": "^18.2.1", | ||||||
|     "stylelint": "14.14.1", |     "stylelint": "14.14.1", | ||||||
|     "stylelint-config-standard": "^29.0.0" |     "stylelint-config-standard": "^29.0.0" | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -14,18 +14,24 @@ | |||||||
|   <!-- Main Stylesheets & Scripts --> |   <!-- Main Stylesheets & Scripts --> | ||||||
|   <!-- Temporarily commented out reset.css due to furthur discussion needed on the values of the default config--> |   <!-- Temporarily commented out reset.css due to furthur discussion needed on the values of the default config--> | ||||||
|   <!-- <link rel="stylesheet" href="/static/reset.css" /> --> |   <!-- <link rel="stylesheet" href="/static/reset.css" /> --> | ||||||
|   <link rel="stylesheet" href="./static/CreatePage.css" /> |   <link rel="stylesheet" href="./static/ReviewCard.css" /> | ||||||
|   <script src="assets/scripts/main.js" type="module"></script> |   <script src="./assets/scripts/CreatePage.js" type="module"></script> | ||||||
|  |  | ||||||
| </head> | </head> | ||||||
|  |  | ||||||
| <body> | <body> | ||||||
|  |   <input type="button" value="Home" id="home-btn" onclick="window.location.assign('./index.html')"> | ||||||
|   <form id="new-food-entry"> |   <form id="new-food-entry"> | ||||||
|     <fieldset> |     <fieldset> | ||||||
|       <legend>Pic:</legend> |       <legend>Pic:</legend> | ||||||
|       <label for="mealImage"> |       Choose Input type: | ||||||
|  |       <select id="select" name="select"> | ||||||
|  |         <option value="file">File Upload</option> | ||||||
|  |         <option value="url">From an URL</option> | ||||||
|  |       </select> | ||||||
|  |       <label for="mealImage" id="source"> | ||||||
|         Source: |         Source: | ||||||
|         <input type="text" id="mealImg" name="mealImg"> |         <input type="file" accept="image/*" id="mealImg" name="mealImg"> | ||||||
|       </label> |       </label> | ||||||
|       <label for="image-alt"> |       <label for="image-alt"> | ||||||
|         Alt Text: |         Alt Text: | ||||||
| @@ -46,11 +52,11 @@ | |||||||
|  |  | ||||||
|     <fieldset class="rating"> |     <fieldset class="rating"> | ||||||
|       <legend> Rating: </legend> |       <legend> Rating: </legend> | ||||||
|       <input type="radio" id="s5" name="rating" value="5"/> <label for="s5"> 5 stars </label> |       <input type="radio" id="s5" name="rating" value="5"/> <label for="s5" id="s5-select"> 5 stars </label> | ||||||
|       <input type="radio" id="s4" name="rating" value="4"/> <label for="s4"> 4 stars </label> |       <input type="radio" id="s4" name="rating" value="4"/> <label for="s4" id="s4-select"> 4 stars </label> | ||||||
|       <input type="radio" id="s3" name="rating" value="3"/> <label for="s3"> 3 stars </label> |       <input type="radio" id="s3" name="rating" value="3"/> <label for="s3" id="s3-select"> 3 stars </label> | ||||||
|       <input type="radio" id="s2" name="rating" value="2"/> <label for="s2"> 2 stars </label> |       <input type="radio" id="s2" name="rating" value="2"/> <label for="s2" id="s2-select"> 2 stars </label> | ||||||
|       <input type="radio" id="s1" name="rating" value="1"/> <label for="s1"> 1 star </label> |       <input type="radio" id="s1" name="rating" value="1"/> <label for="s1" id="s1-select"> 1 star </label> | ||||||
|     </fieldset> |     </fieldset> | ||||||
|  |  | ||||||
|     <fieldset> |     <fieldset> | ||||||
| @@ -65,12 +71,11 @@ | |||||||
|         <div class='tag-container' id="tag-container-form"> |         <div class='tag-container' id="tag-container-form"> | ||||||
|  |  | ||||||
|         </div> |         </div> | ||||||
|         <button type="button" id="tagAdd">Add Tag</button> |         <button type="button" id="tag-add-btn">Add Tag</button> | ||||||
|       </label> |       </label> | ||||||
|  |  | ||||||
|     </fieldset> |     </fieldset> | ||||||
|     <button type="submit" value="Submit">Add Review</button> |     <button type="submit" id="save-btn" value="Submit">Save Review</button> | ||||||
|     <button type="button" class="danger">Clear Review Journal</button> |  | ||||||
|   </form> |   </form> | ||||||
| </body> | </body> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,8 +19,9 @@ | |||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
|   <main> |   <main> | ||||||
|     <button type="button" id="update">Update</button> |     <input type="button" value="Home" id="home-btn" onclick="window.location.assign('./index.html')"> | ||||||
|     <button type="button" id="delete" class="danger">Delete</button> |     <button type="button" id="update-btn">Update</button> | ||||||
|  |     <button type="button" id="delete-btn" class="danger">Delete</button> | ||||||
|   </main> |   </main> | ||||||
|     <!----> <form id="update-food-entry" class="hidden"> |     <!----> <form id="update-food-entry" class="hidden"> | ||||||
|       <fieldset> |       <fieldset> | ||||||
| @@ -48,11 +49,11 @@ | |||||||
|        |        | ||||||
|       <fieldset class="rating"> |       <fieldset class="rating"> | ||||||
|         <legend> Rating: </legend> |         <legend> Rating: </legend> | ||||||
|         <input type="radio" id="s5" name="rating" value="5"/> <label for="s5"> 5 stars </label> |         <input type="radio" id="s5" name="rating" value="5"/> <label for="s5" id="s5-select"> 5 stars </label> | ||||||
|         <input type="radio" id="s4" name="rating" value="4"/> <label for="s4"> 4 stars </label> |         <input type="radio" id="s4" name="rating" value="4"/> <label for="s4" id="s4-select"> 4 stars </label> | ||||||
|         <input type="radio" id="s3" name="rating" value="3"/> <label for="s3"> 3 stars </label> |         <input type="radio" id="s3" name="rating" value="3"/> <label for="s3" id="s3-select"> 3 stars </label> | ||||||
|         <input type="radio" id="s2" name="rating" value="2"/> <label for="s2"> 2 stars </label> |         <input type="radio" id="s2" name="rating" value="2"/> <label for="s2" id="s2-select"> 2 stars </label> | ||||||
|         <input type="radio" id="s1" name="rating" value="1"/> <label for="s1"> 1 star </label> |         <input type="radio" id="s1" name="rating" value="1"/> <label for="s1" id="s1-select"> 1 star </label> | ||||||
|       </fieldset> |       </fieldset> | ||||||
|  |  | ||||||
|       <fieldset> |       <fieldset> | ||||||
| @@ -67,7 +68,7 @@ | |||||||
|           <div class='tag-container' id="tag-container-form"> |           <div class='tag-container' id="tag-container-form"> | ||||||
|    |    | ||||||
|           </div> |           </div> | ||||||
|           <button type="button" id="tagAdd">Add Tag</button> |           <button type="button" id="tag-add-btn">Add Tag</button> | ||||||
|         </label> |         </label> | ||||||
|    |    | ||||||
|       </fieldset> |       </fieldset> | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 6.6 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 4.9 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 8.6 KiB | 
							
								
								
									
										106
									
								
								source/assets/scripts/CreatePage.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								source/assets/scripts/CreatePage.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | |||||||
|  | import { newReviewToStorage } from "./localStorage.js"; | ||||||
|  |  | ||||||
|  | window.addEventListener("DOMContentLoaded", init); | ||||||
|  |  | ||||||
|  | function init() { | ||||||
|  | 	// get next id | ||||||
|  |  | ||||||
|  | 	// creates the key | ||||||
|  | 	initFormHandler(); | ||||||
|  |      | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function initFormHandler() { | ||||||
|  |  | ||||||
|  | 	//accessing form components | ||||||
|  | 	let tagContainer = document.getElementById("tag-container-form"); | ||||||
|  | 	let form = document.querySelector("form"); | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	* change the input source of the image between local file and URL  | ||||||
|  | 	* depending on user's selection | ||||||
|  | 	*/ | ||||||
|  | 	let select = document.getElementById("select"); | ||||||
|  | 	select.addEventListener("change", function() { | ||||||
|  | 		const input = document.getElementById('source'); | ||||||
|  | 	 | ||||||
|  | 		if (select.value == "file") { | ||||||
|  | 		  input.innerHTML = ` | ||||||
|  | 		  Source: | ||||||
|  | 		  <input type="file" accept="image/*" id="mealImg" name="mealImg"> | ||||||
|  | 		  ` | ||||||
|  | 		} | ||||||
|  | 		//TODO: change to photo taking for sprint 3 | ||||||
|  | 		else { | ||||||
|  | 		  input.innerHTML = ` | ||||||
|  | 		  Source: | ||||||
|  | 		  <input type="text" id="mealImg" name="mealImg"> | ||||||
|  | 		  ` | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	//addressing sourcing image from local file | ||||||
|  | 	let imgDataURL = ""; | ||||||
|  | 	document.getElementById("mealImg").addEventListener("change", function() { | ||||||
|  | 		const reader = new FileReader(); | ||||||
|  | 		 | ||||||
|  | 		//store image data URL after successful image load | ||||||
|  | 		reader.addEventListener("load", ()=>{ | ||||||
|  | 			imgDataURL = reader.result; | ||||||
|  | 		}, false); | ||||||
|  | 		 | ||||||
|  | 		//convert image file into data URL for local storage | ||||||
|  | 		reader.readAsDataURL(document.getElementById("mealImg").files[0]); | ||||||
|  | 	}) | ||||||
|  | 		 | ||||||
|  | 	form.addEventListener("submit", function(e){ | ||||||
|  | 	/* | ||||||
|  |     *  User submits the form for their review. | ||||||
|  |     *  We create reviewCard and put in storage | ||||||
|  |     */ | ||||||
|  | 		e.preventDefault(); | ||||||
|  | 		let formData = new FormData(form); | ||||||
|  | 		let reviewObject = {}; | ||||||
|  | 		for (let [key, value] of formData) { | ||||||
|  | 			console.log(`${key}`); | ||||||
|  | 			console.log(`${value}`); | ||||||
|  | 			if (`${key}` !== "tag-form") { | ||||||
|  | 				reviewObject[`${key}`] = `${value}`; | ||||||
|  | 			} | ||||||
|  | 			if (`${key}` === "mealImg" && select.value == "file") { | ||||||
|  | 				reviewObject["mealImg"] = imgDataURL; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		reviewObject["tags"] = []; | ||||||
|  |  | ||||||
|  | 		let tags = document.querySelectorAll(".tag"); | ||||||
|  | 		for(let i = 0; i < tags.length; i ++) { | ||||||
|  | 			reviewObject["tags"].push(tags[i].innerHTML); | ||||||
|  | 			tagContainer.removeChild(tags[i]); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		let nextReviewId = newReviewToStorage(reviewObject); | ||||||
|  | 		sessionStorage.setItem("currID", JSON.stringify(nextReviewId)); | ||||||
|  |  | ||||||
|  | 		window.location.assign("./ReviewDetails.html"); | ||||||
|  |          | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	let tagAddBtn = document.getElementById("tag-add-btn"); | ||||||
|  | 	tagAddBtn.addEventListener("click", ()=> { | ||||||
|  | 		let tagField = document.getElementById("tag-form"); | ||||||
|  | 		if (tagField.value.length > 0) { | ||||||
|  | 			let tagLabel = document.createElement("label"); | ||||||
|  | 			tagLabel.innerHTML = tagField.value; | ||||||
|  | 			tagLabel.setAttribute("class","tag"); | ||||||
|  | 			tagLabel.addEventListener("click",()=> { | ||||||
|  | 				tagContainer.removeChild(tagLabel); | ||||||
|  | 			}); | ||||||
|  |        | ||||||
|  | 			tagContainer.append(tagLabel); | ||||||
|  | 			tagField.value = ""; | ||||||
|  |  | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -6,7 +6,6 @@ class ReviewCard extends HTMLElement { | |||||||
| 	constructor() { | 	constructor() { | ||||||
| 		super();  | 		super();  | ||||||
|  |  | ||||||
|  |  | ||||||
| 		let shadowEl = this.attachShadow({mode:"open"}); | 		let shadowEl = this.attachShadow({mode:"open"}); | ||||||
|  |  | ||||||
| 		let articleEl = document.createElement("article"); | 		let articleEl = document.createElement("article"); | ||||||
| @@ -88,9 +87,9 @@ class ReviewCard extends HTMLElement { | |||||||
| 		//attach event listener to each recipe-card | 		//attach event listener to each recipe-card | ||||||
| 		this.addEventListener("click", (event) => { | 		this.addEventListener("click", (event) => { | ||||||
| 			console.log(event.target); | 			console.log(event.target); | ||||||
| 			console.log(event.target.data); | 			console.log(event.target.reviewId); | ||||||
| 			//Option 1: sending current data to second html page using localStorage (could also just store index) | 			//Option 1: sending current data to second html page using localStorage (could also just store index) | ||||||
| 			sessionStorage.setItem("current", JSON.stringify(event.target.data)); | 			sessionStorage.setItem("currID", JSON.stringify(event.target.data.reviewID)); | ||||||
| 			window.location.assign("./ReviewDetails.html"); | 			window.location.assign("./ReviewDetails.html"); | ||||||
| 			/* | 			/* | ||||||
|       //Option 2: sending current data to second html page using string query w/ url (currently not storing value) |       //Option 2: sending current data to second html page using string query w/ url (currently not storing value) | ||||||
| @@ -133,12 +132,18 @@ class ReviewCard extends HTMLElement { | |||||||
| 		let articleEl = this.shadowEl.querySelector("article"); | 		let articleEl = this.shadowEl.querySelector("article"); | ||||||
|      |      | ||||||
| 		// setting the article elements for the review card | 		// setting the article elements for the review card | ||||||
|  | 		this.reviewID = data["reviewID"]; | ||||||
|  |  | ||||||
| 		//image setup | 		//image setup | ||||||
| 		let mealImg = document.createElement("img"); | 		let mealImg = document.createElement("img"); | ||||||
| 		mealImg.setAttribute("id", "a-mealImg"); | 		mealImg.setAttribute("id", "a-mealImg"); | ||||||
| 		mealImg.setAttribute("src",data["mealImg"]); |  | ||||||
| 		mealImg.setAttribute("alt",data["imgAlt"]); | 		mealImg.setAttribute("alt",data["imgAlt"]); | ||||||
|  | 		if(data["mealImg"] != ""){ | ||||||
|  | 			mealImg.setAttribute("src",data["mealImg"]); | ||||||
|  | 		} | ||||||
|  | 		else{ | ||||||
|  | 			mealImg.setAttribute("src", "./assets/images/icons/plate_with_cutlery.png"); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		//meal name setup | 		//meal name setup | ||||||
| 		let mealLabel = document.createElement("label"); | 		let mealLabel = document.createElement("label"); | ||||||
| @@ -147,26 +152,6 @@ class ReviewCard extends HTMLElement { | |||||||
| 		mealLabel.innerHTML = data["mealName"]; | 		mealLabel.innerHTML = data["mealName"]; | ||||||
|  |  | ||||||
| 		//restaurant name setup | 		//restaurant name setup | ||||||
| 		/* |  | ||||||
|     //review page link |  | ||||||
|     //giving it functionality to save the review card's info to session storage for loading the review page |  | ||||||
|     let reviewLink = document.createElement('a'); |  | ||||||
|     reviewLink.setAttribute('href','./review.html') |  | ||||||
|     reviewLink.innerHTML = 'review page' |  | ||||||
|     reviewLink.addEventListener('click', () => { |  | ||||||
|       sessionStorage.clear(); |  | ||||||
|       let currReview = { |  | ||||||
|         "imgSrc": data['imgSrc'], |  | ||||||
|         "imgAlt": data['imgAlt'], |  | ||||||
|         "mealName": data['mealName'], |  | ||||||
|         "restaurant": data['restaurant'], |  | ||||||
|         "comments": data['comments'], |  | ||||||
|         "rating": data['rating'], |  | ||||||
|         "tags": data['tags']                 |  | ||||||
|       } |  | ||||||
|       sessionStorage.setItem('currReview', JSON.stringify(currReview)); |  | ||||||
|     }); |  | ||||||
| */ |  | ||||||
| 		let restaurantLabel = document.createElement("label"); | 		let restaurantLabel = document.createElement("label"); | ||||||
| 		restaurantLabel.setAttribute("id", "a-restaurant"); | 		restaurantLabel.setAttribute("id", "a-restaurant"); | ||||||
| 		restaurantLabel.setAttribute("class","restaurant-name"); | 		restaurantLabel.setAttribute("class","restaurant-name"); | ||||||
| @@ -197,14 +182,15 @@ class ReviewCard extends HTMLElement { | |||||||
| 			for (let i = 0; i < data["tags"].length; i++) { | 			for (let i = 0; i < data["tags"].length; i++) { | ||||||
| 				let newTag = document.createElement("label"); | 				let newTag = document.createElement("label"); | ||||||
| 				newTag.setAttribute("class","tag"); | 				newTag.setAttribute("class","tag"); | ||||||
| 				newTag.innerHTML = data["tags"][i] + "   "; | 				newTag.innerHTML = data["tags"][i]; | ||||||
| 				tagContainer.append(newTag); | 				tagContainer.append(newTag); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		//adding final ID to data! | ||||||
|  |  | ||||||
| 		articleEl.append(mealImg); | 		articleEl.append(mealImg); | ||||||
| 		articleEl.append(mealLabel); | 		articleEl.append(mealLabel); | ||||||
| 		//articleEl.append(reviewLink) |  | ||||||
| 		articleEl.append(restaurantLabel); | 		articleEl.append(restaurantLabel); | ||||||
| 		articleEl.append(ratingDiv); | 		articleEl.append(ratingDiv); | ||||||
| 		articleEl.append(tagContainer); | 		articleEl.append(tagContainer); | ||||||
| @@ -237,6 +223,7 @@ class ReviewCard extends HTMLElement { | |||||||
| 		let dataContainer = {}; | 		let dataContainer = {}; | ||||||
|      |      | ||||||
| 		// getting the article elements for the review card | 		// getting the article elements for the review card | ||||||
|  | 		dataContainer["reviewID"] = this.reviewID; | ||||||
|  |  | ||||||
| 		//get image | 		//get image | ||||||
| 		let mealImg = this.shadowEl.getElementById("a-mealImg"); | 		let mealImg = this.shadowEl.getElementById("a-mealImg"); | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| //reviewDetails.js | //reviewDetails.js | ||||||
| import {getReviewsFromStorage, saveReviewsToStorage} from "./localStorage.js"; | import {deleteReviewFromStorage, getReviewFromStorage, updateReviewToStorage} from "./localStorage.js"; | ||||||
|  |  | ||||||
| // Run the init() function when the page has loaded | // Run the init() function when the page has loaded | ||||||
| window.addEventListener("DOMContentLoaded", init); | window.addEventListener("DOMContentLoaded", init); | ||||||
| @@ -10,115 +10,96 @@ function init(){ | |||||||
| } | } | ||||||
|  |  | ||||||
| function setupDelete(){ | function setupDelete(){ | ||||||
| 	let deleteBtn = document.getElementById("delete"); | 	let deleteBtn = document.getElementById("delete-btn"); | ||||||
| 	let reviews = getReviewsFromStorage(); | 	let currID = JSON.parse(sessionStorage.getItem("currID")); | ||||||
| 	let current = JSON.parse(sessionStorage.getItem("current")); |  | ||||||
| 	deleteBtn.addEventListener("click", function(){ | 	deleteBtn.addEventListener("click", function(){ | ||||||
| 		if(window.confirm("Are you sure you want to delete this entry?")){ | 		if(window.confirm("Are you sure you want to delete this entry?")){ | ||||||
| 			//delete function | 			deleteReviewFromStorage(currID); | ||||||
| 			if(current){ | 			sessionStorage.removeItem("currID"); | ||||||
| 				console.log(current); | 			window.location.assign("./index.html"); | ||||||
| 				for(let i = 0; i < reviews.length; i++){ |  | ||||||
| 					console.log(reviews[i]); |  | ||||||
| 					if(reviews[i]["mealName"] == current["mealName"] && reviews[i]["restaurant"] == current["restaurant"]){ |  | ||||||
| 						console.log("match found"); |  | ||||||
| 						reviews.splice(i,1); |  | ||||||
| 						saveReviewsToStorage(reviews); |  | ||||||
| 						sessionStorage.removeItem("current"); |  | ||||||
| 						window.location.assign("./index.html"); |  | ||||||
| 						break; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
|  |  | ||||||
| function setupUpdate(){ | function setupUpdate(){ | ||||||
| 	let updateBtn = document.getElementById("update"); | 	let updateBtn = document.getElementById("update-btn"); | ||||||
| 	let reviews = getReviewsFromStorage(); | 	let currID = JSON.parse(sessionStorage.getItem("currID")); | ||||||
| 	let current = JSON.parse(sessionStorage.getItem("current")); | 	let currReview = getReviewFromStorage(currID); | ||||||
| 	let form = document.getElementById("update-food-entry"); | 	let form = document.getElementById("update-food-entry"); | ||||||
| 	updateBtn.addEventListener("click", function(){ | 	updateBtn.addEventListener("click", function(){ | ||||||
| 		//update function | 		//update function | ||||||
| 		if(current){ |  | ||||||
| 			console.log(current); |  | ||||||
| 			form.style.display = "block"; |  | ||||||
| 			let tagContainer = document.getElementById("tag-container-form"); |  | ||||||
| 			console.log(document.querySelectorAll("#update-food-entry input")); |  | ||||||
|  |  | ||||||
| 			//Set value of each input element to current's values | 		//form.style.display = "block"; | ||||||
| 			document.getElementById("mealImg").defaultValue = current["mealImg"]; | 		form.classList.remove("hidden"); | ||||||
| 			document.getElementById("imgAlt").defaultValue = current["imgAlt"]; | 		let tagContainer = document.getElementById("tag-container-form"); | ||||||
| 			document.getElementById("mealName").defaultValue = current["mealName"]; |  | ||||||
| 			document.getElementById("comments").textContent = current["comments"]; |  | ||||||
| 			document.getElementById("rating-" + `${current["rating"]}`).checked = true; |  | ||||||
| 			document.getElementById("restaurant").defaultValue = current["restaurant"]; |  | ||||||
|  |  | ||||||
| 			if(current["tags"]){ | 		//Set value of each input element to current's values | ||||||
| 				for (let i = 0; i < current["tags"].length; i++) { | 		document.getElementById("mealImg").defaultValue = currReview["mealImg"]; | ||||||
| 					let newTag = document.createElement("label"); | 		document.getElementById("imgAlt").defaultValue = currReview["imgAlt"]; | ||||||
| 					newTag.setAttribute("class","tag"); | 		document.getElementById("mealName").defaultValue = currReview["mealName"]; | ||||||
| 					newTag.innerHTML = current["tags"][i] + "   "; | 		document.getElementById("comments").textContent = currReview["comments"]; | ||||||
| 					newTag.addEventListener("click",()=> { | 		document.getElementById("s" + `${currReview["rating"]}`).checked = true; | ||||||
| 						tagContainer.removeChild(newTag); | 		document.getElementById("restaurant").defaultValue = currReview["restaurant"]; | ||||||
| 					}); |  | ||||||
| 					tagContainer.append(newTag); | 		if(currReview["tags"]){ | ||||||
|  | 			while (tagContainer.firstChild) { | ||||||
|  | 				tagContainer.removeChild(tagContainer.firstChild); | ||||||
|  | 			} | ||||||
|  | 			for (let i = 0; i < currReview["tags"].length; i++) { | ||||||
|  | 				let newTag = document.createElement("label"); | ||||||
|  | 				newTag.setAttribute("class","tag"); | ||||||
|  | 				newTag.innerHTML = currReview["tags"][i]; | ||||||
|  | 				newTag.addEventListener("click",()=> { | ||||||
|  | 					tagContainer.removeChild(newTag); | ||||||
|  | 				}); | ||||||
|  | 				tagContainer.append(newTag); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		//Take formdata values as newData when submit | ||||||
|  | 		form.addEventListener("submit", function(){ | ||||||
|  | 			/* | ||||||
|  | 			*  User submits the form for their review. | ||||||
|  | 			*  We create reviewCard and put in storage | ||||||
|  | 			*/ | ||||||
|  | 			let formData = new FormData(form); | ||||||
|  | 			let newData = {}; | ||||||
|  | 			for (let [key, value] of formData) { | ||||||
|  | 				console.log(`${key}`); | ||||||
|  | 				console.log(`${value}`); | ||||||
|  | 				if (`${key}` !== "tag-form") { | ||||||
|  | 					newData[`${key}`] = `${value}`; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			//Take formdata values as newData when submit | 			newData["tags"] = []; | ||||||
| 			form.addEventListener("submit", function(){ |  | ||||||
| 				/* |  | ||||||
|                 *  User submits the form for their review. |  | ||||||
|                 *  We create reviewCard and put in storage |  | ||||||
|                 */ |  | ||||||
| 				let formData = new FormData(form); |  | ||||||
| 				let newData = {}; |  | ||||||
| 				for (let [key, value] of formData) { |  | ||||||
| 					console.log(`${key}`); |  | ||||||
| 					console.log(`${value}`); |  | ||||||
| 					if (`${key}` !== "tag-form") { |  | ||||||
| 						newData[`${key}`] = `${value}`; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				newData["tags"] = []; |  | ||||||
| 		 | 		 | ||||||
| 				let tags = document.querySelectorAll(".tag"); | 			let tags = document.querySelectorAll(".tag"); | ||||||
| 				for(let i = 0; i < tags.length; i ++) { | 			for(let i = 0; i < tags.length; i ++) { | ||||||
| 					newData["tags"].push(tags[i].innerHTML); | 				newData["tags"].push(tags[i].innerHTML); | ||||||
| 					tagContainer.removeChild(tags[i]); | 				tagContainer.removeChild(tags[i]); | ||||||
| 				} | 			} | ||||||
|  |  | ||||||
| 				for(let i = 0; i < reviews.length; i++){ | 			newData["reviewID"] = currID; | ||||||
| 					console.log(reviews[i]); |  | ||||||
| 					if(reviews[i]["mealName"] == current["mealName"] && reviews[i]["restaurant"] == current["restaurant"]){ |  | ||||||
| 						console.log("match found"); |  | ||||||
| 						reviews.splice(i,1,newData); |  | ||||||
| 						saveReviewsToStorage(reviews); |  | ||||||
| 						sessionStorage.setItem("current", JSON.stringify(newData)); |  | ||||||
| 						break; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				form.style.display = "none"; | 			updateReviewToStorage(currID, newData); | ||||||
|  |  | ||||||
| 			}); | 			form.style.display = "none"; | ||||||
|  |  | ||||||
| 			let tagAddBtn = document.getElementById("tagAdd"); | 		}); | ||||||
| 			tagAddBtn.addEventListener("click", ()=> { |  | ||||||
| 				let tagField = document.getElementById("tag-form"); |  | ||||||
| 				if (tagField.value.length > 0) { |  | ||||||
| 					let tagLabel = document.createElement("label"); |  | ||||||
| 					tagLabel.innerHTML = tagField.value; |  | ||||||
| 					tagLabel.setAttribute("class","tag"); |  | ||||||
| 					tagLabel.addEventListener("click",()=> { |  | ||||||
| 						tagContainer.removeChild(tagLabel); |  | ||||||
| 					}); |  | ||||||
|  |  | ||||||
| 					tagContainer.append(tagLabel); | 		let tagAddBtn = document.getElementById("tag-add-btn"); | ||||||
| 					tagField.value = ""; | 		tagAddBtn.addEventListener("click", ()=> { | ||||||
| 				} | 			let tagField = document.getElementById("tag-form"); | ||||||
| 			}); | 			if (tagField.value.length > 0) { | ||||||
| 		} | 				let tagLabel = document.createElement("label"); | ||||||
|  | 				tagLabel.innerHTML = tagField.value; | ||||||
|  | 				tagLabel.setAttribute("class","tag"); | ||||||
|  | 				tagLabel.addEventListener("click",()=> { | ||||||
|  | 					tagContainer.removeChild(tagLabel); | ||||||
|  | 				}); | ||||||
|  | 			 | ||||||
|  | 				tagContainer.append(tagLabel); | ||||||
|  | 				tagField.value = ""; | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,13 +0,0 @@ | |||||||
| // Run the init() function when the page has loaded |  | ||||||
| window.addEventListener("DOMContentLoaded", init); |  | ||||||
|  |  | ||||||
| function init() { |  | ||||||
| 	let result = sessionStorage.getItem("currReview"); |  | ||||||
|  |  | ||||||
| 	let main = document.querySelector("main"); |  | ||||||
|      |  | ||||||
| 	main.innerHTML = result; |  | ||||||
| 	let p = document.createElement("p"); |  | ||||||
| 	p.innerHTML = JSON.parse(result)["comments"]; |  | ||||||
| 	main.append(p); |  | ||||||
| } |  | ||||||
| @@ -1,19 +1,79 @@ | |||||||
| /** | /** | ||||||
|  * @returns {Array<Object>} An array of reviews found in localStorage |  * Creates a new review to storage and performs related meta tasks | ||||||
|  |  * @param {Object} review to store | ||||||
|  |  * @return {number} ID of the newly added review | ||||||
|  */ |  */ | ||||||
| export function getReviewsFromStorage() { | export function newReviewToStorage(review){ | ||||||
| 	let result = JSON.parse(localStorage.getItem("reviews")); | 	//grabbing the nextID, and putting our review object in storage associated with the ID | ||||||
| 	if (result) { | 	let nextReviewId = JSON.parse(localStorage.getItem("nextID")); | ||||||
| 		return result; | 	review["reviewID"] = nextReviewId; | ||||||
| 	} |  | ||||||
| 	return new Array(0); | 	// set the review entry to the review object | ||||||
|  | 	localStorage.setItem(`review${nextReviewId}`, JSON.stringify(review)); | ||||||
|  | 	 | ||||||
|  | 	//updating our activeIDS list | ||||||
|  | 	let tempIdArr = JSON.parse(localStorage.getItem("activeIDS")); | ||||||
|  | 	tempIdArr.push(nextReviewId); | ||||||
|  | 	localStorage.setItem("activeIDS", JSON.stringify(tempIdArr)); | ||||||
|  | 	 | ||||||
|  | 	//increment nextID for next review creation | ||||||
|  | 	nextReviewId++; | ||||||
|  | 	localStorage.setItem("nextID", JSON.stringify(nextReviewId)); | ||||||
|  |  | ||||||
|  | 	return nextReviewId; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Takes in an array of reviews, converts it to a string, and then |  * Gets a single review by ID from storage | ||||||
|  * saves that string to 'reviews' in localStorage |  * @param {string} ID of the review to get | ||||||
|  * @param {Array<Object>} reviews An array of reviews |  * @returns {Object} review object corresponding to param ID | ||||||
|  */ |  */ | ||||||
| export function saveReviewsToStorage(reviews) { | export function getReviewFromStorage(ID){ | ||||||
| 	localStorage.setItem("reviews", JSON.stringify(reviews)); | 	return JSON.parse(localStorage.getItem(`review${ID}`)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Updates a single review by ID to storage | ||||||
|  |  * @param {string} ID of review to update | ||||||
|  |  * @param {Object} review to store | ||||||
|  |  */ | ||||||
|  | export function updateReviewToStorage(ID, review){ | ||||||
|  | 	// set the review entry with ID to the review object | ||||||
|  | 	localStorage.setItem(`review${ID}`, JSON.stringify(review)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Deletes a review by ID from storage | ||||||
|  |  * @param {string} ID of the review to delete | ||||||
|  |  */ | ||||||
|  | export function deleteReviewFromStorage(ID){ | ||||||
|  | 	let activeIDS = JSON.parse(localStorage.getItem("activeIDS")); | ||||||
|  |  | ||||||
|  | 	for (let i in activeIDS) { | ||||||
|  | 		if (activeIDS[i] == ID) { | ||||||
|  | 			activeIDS.splice(i,1); | ||||||
|  | 			localStorage.setItem("activeIDS", JSON.stringify(activeIDS)); | ||||||
|  | 			localStorage.removeItem(`review${ID}`); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	console.error(`could not find review${ID} in localStorage`); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // legacy function | ||||||
|  | export function getAllReviewsFromStorage() { | ||||||
|  | 	if (!(localStorage.getItem("activeIDS"))) { | ||||||
|  | 		// we wanna init the active ID array and start the nextID count | ||||||
|  | 		localStorage.setItem("activeIDS", JSON.stringify([])); | ||||||
|  | 		localStorage.setItem("nextID",  JSON.stringify(0)); | ||||||
|  | 	} | ||||||
|  | 	//iterate thru activeIDS | ||||||
|  | 	let activeIDS = JSON.parse(localStorage.getItem("activeIDS")); | ||||||
|  | 	let reviews = []; | ||||||
|  | 	for (let i = 0; i < activeIDS.length; i++) { | ||||||
|  | 		let currReview = JSON.parse(localStorage.getItem(`review${activeIDS[i]}`)); | ||||||
|  | 		reviews.push(currReview); | ||||||
|  | 	} | ||||||
|  | 	return reviews; | ||||||
| } | } | ||||||
| @@ -1,48 +1,106 @@ | |||||||
| import {strict as assert} from "node:assert"; | import {strict as assert} from "node:assert"; | ||||||
| import {describe, it, beforeEach} from "mocha"; | import {describe, it, before, after} from "mocha"; | ||||||
| import {saveReviewsToStorage, getReviewsFromStorage} from "./localStorage.js"; | import {newReviewToStorage, getReviewFromStorage, updateReviewToStorage, deleteReviewFromStorage, getAllReviewsFromStorage} from "./localStorage.js"; | ||||||
|  |  | ||||||
| beforeEach(() => { |  | ||||||
| 	localStorage.clear(); |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| describe("test app localStorage interaction", () => { | describe("test app localStorage interaction", () => { | ||||||
| 	it("get after init", () => { | 	 | ||||||
| 		assert.deepEqual(getReviewsFromStorage(), []); | 	before(() => { | ||||||
|  | 		localStorage.clear(); | ||||||
| 	}); | 	}); | ||||||
| 	it("store one then get", () => { |  | ||||||
| 		let reviews = [{ | 	it("test localStorage state after init", () => { | ||||||
|  | 		assert.deepEqual(getAllReviewsFromStorage(), []); | ||||||
|  | 		assert.deepEqual(JSON.parse(localStorage.getItem("activeIDS")), []); | ||||||
|  | 		assert.strictEqual(JSON.parse(localStorage.getItem("nextID")), 0); | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	it("test localStorage state after adding one review", () => { | ||||||
|  | 		let review = { | ||||||
| 			"imgSrc": "sample src", | 			"imgSrc": "sample src", | ||||||
| 			"imgAlt": "sample alt", | 			"imgAlt": "sample alt", | ||||||
| 			"mealName": "sample name", | 			"mealName": "sample name", | ||||||
| 			"restaurant": "sample restaurant", | 			"restaurant": "sample restaurant", | ||||||
| 			"rating": 5, | 			"rating": 5, | ||||||
| 			"tags": ["tag 1", "tag  2", "tag 3"] | 			"tags": ["tag 1", "tag  2", "tag 3"] | ||||||
| 		}]; | 		}; | ||||||
|  |  | ||||||
| 		saveReviewsToStorage(reviews); | 		newReviewToStorage(review); | ||||||
| 		assert.deepEqual(getReviewsFromStorage(), reviews); |  | ||||||
|  | 		review.reviewID = 0; | ||||||
|  |  | ||||||
|  | 		assert.deepEqual(getAllReviewsFromStorage(), [review]); | ||||||
|  | 		assert.deepEqual(getReviewFromStorage(0), review); | ||||||
|  | 		assert.deepEqual(JSON.parse(localStorage.getItem("activeIDS")), [0]); | ||||||
|  | 		assert.strictEqual(JSON.parse(localStorage.getItem("nextID")), 1); | ||||||
| 	}); | 	}); | ||||||
| 	it("repeated store one more and get", () => { |  | ||||||
| 		let reviews = []; |  | ||||||
|  |  | ||||||
| 		assert.deepEqual(getReviewsFromStorage(), reviews); | 	it("test localStorage state during adding 999 reviews", () => { | ||||||
|  | 		let reviews = getAllReviewsFromStorage(); | ||||||
|  | 		let ids = [0]; | ||||||
|  |  | ||||||
|  | 		for(let i = 1; i < 1000; i++){ | ||||||
|  | 			ids.push(i); | ||||||
|  | 			let new_review = { | ||||||
|  | 				"imgSrc": `sample src ${i}`, | ||||||
|  | 				"imgAlt": `sample alt ${i}`, | ||||||
|  | 				"mealName": `sample name ${i}`, | ||||||
|  | 				"restaurant": `sample restaurant ${i}`, | ||||||
|  | 				"rating": i, | ||||||
|  | 				"tags": [`tag ${3*i}`, `tag ${3*i + 1}`, `tag ${3*i + 2}`] | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 			newReviewToStorage(new_review); | ||||||
|  |  | ||||||
|  | 			new_review.reviewID = i; | ||||||
|  | 			reviews.push(new_review); | ||||||
|  |  | ||||||
|  | 			assert.deepEqual(getAllReviewsFromStorage(), reviews); | ||||||
|  | 			assert.deepEqual(getReviewFromStorage(i), new_review); | ||||||
|  | 			assert.deepEqual(JSON.parse(localStorage.getItem("activeIDS")), ids); | ||||||
|  | 			assert.strictEqual(JSON.parse(localStorage.getItem("nextID")), (i+1)); | ||||||
|  | 		} | ||||||
|  | 	}).timeout(5000); | ||||||
|  |  | ||||||
|  | 	it("test localStorage state during updating 1000 reviews", () => { | ||||||
|  | 		let reviews = getAllReviewsFromStorage(); | ||||||
|  | 		let ids = JSON.parse(localStorage.getItem("activeIDS")); | ||||||
|  |  | ||||||
| 		for(let i = 0; i < 1000; i++){ | 		for(let i = 0; i < 1000; i++){ | ||||||
| 			reviews = getReviewsFromStorage(); | 			let new_review = { | ||||||
|  | 				"imgSrc": `updated sample src ${i}`, | ||||||
|  | 				"imgAlt": `updated sample alt ${i}`, | ||||||
|  | 				"mealName": `updated sample name ${i}`, | ||||||
|  | 				"restaurant": `updated sample restaurant ${i}`, | ||||||
|  | 				"rating": i*2+i, | ||||||
|  | 				"tags": [`tag ${3*i}`, `tag ${3*i + 1}`, `tag ${3*i + 2}`] | ||||||
|  | 			}; | ||||||
|  | 			new_review.reviewID = i; | ||||||
|  |  | ||||||
| 			reviews.push( | 			reviews[i] = new_review; | ||||||
| 				{ |  | ||||||
| 					"imgSrc": `sample src ${i}`, | 			updateReviewToStorage(i, new_review); | ||||||
| 					"imgAlt": `sample alt ${i}`, |  | ||||||
| 					"mealName": `sample name ${i}`, | 			assert.deepEqual(getAllReviewsFromStorage(), reviews); | ||||||
| 					"restaurant": `sample restaurant ${i}`, | 			assert.deepEqual(getReviewFromStorage(i), new_review); | ||||||
| 					"rating": i, | 			assert.deepEqual(JSON.parse(localStorage.getItem("activeIDS")), ids); | ||||||
| 					"tags": [`tag ${3*i}`, `tag ${3*i + 1}`, `tag ${3*i + 2}`] | 			assert.strictEqual(JSON.parse(localStorage.getItem("nextID")), 1000); | ||||||
| 				} |  | ||||||
| 			); |  | ||||||
| 			saveReviewsToStorage(reviews); |  | ||||||
| 			assert.deepEqual(getReviewsFromStorage(), reviews); |  | ||||||
| 		} | 		} | ||||||
| 	}).timeout(10000); | 	}).timeout(5000); | ||||||
|  |  | ||||||
|  | 	it("test localStorage state during deleting 1000 reviews", () => { | ||||||
|  | 		let reviews = getAllReviewsFromStorage(); | ||||||
|  | 		let ids = JSON.parse(localStorage.getItem("activeIDS")); | ||||||
|  |  | ||||||
|  | 		for(let i = 999; i >= 0; i--){ | ||||||
|  | 			deleteReviewFromStorage(i); | ||||||
|  | 			ids.pop(); | ||||||
|  | 			reviews.pop(); | ||||||
|  |  | ||||||
|  | 			assert.deepEqual(getAllReviewsFromStorage(), reviews); | ||||||
|  | 			assert.deepEqual(JSON.parse(localStorage.getItem("activeIDS")), ids); | ||||||
|  | 			assert.strictEqual(JSON.parse(localStorage.getItem("nextID")), 1000); | ||||||
|  | 		} | ||||||
|  | 	}).timeout(5000); | ||||||
|  |  | ||||||
|  | 	after(() => {}); | ||||||
| }); | }); | ||||||
|   | |||||||
							
								
								
									
										384
									
								
								source/assets/scripts/main.e2e.test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								source/assets/scripts/main.e2e.test.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,384 @@ | |||||||
|  | import {strict as assert} from "node:assert"; | ||||||
|  | import {describe, it, before, after} from "mocha"; | ||||||
|  | import puppeteer from "puppeteer-core"; | ||||||
|  | import { exit } from "node:process"; | ||||||
|  |  | ||||||
|  | describe("test App end to end", async () => { | ||||||
|  |  | ||||||
|  | 	let browser; | ||||||
|  | 	let page; | ||||||
|  |  | ||||||
|  | 	before(async () => { | ||||||
|  | 		let root; | ||||||
|  | 		try { | ||||||
|  | 			root =  process.getuid() == 0; | ||||||
|  | 		} | ||||||
|  | 		catch (error) { | ||||||
|  | 			root = false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		browser = await puppeteer.launch({args: root ? ['--no-sandbox'] : undefined}); | ||||||
|  | 		page = await browser.newPage(); | ||||||
|  | 		try{ | ||||||
|  | 			await page.goto("http://localhost:8080", {timeout: 1000}); | ||||||
|  | 			await console.log(`✔ connected to localhost webserver as ${root ? "root" : "user"}`); | ||||||
|  | 		} | ||||||
|  | 		catch (error) { | ||||||
|  | 			await console.log("❌ failed to connect to localhost webserver on port 8080"); | ||||||
|  | 			await exit(1); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	describe("test simple properties", async () => { | ||||||
|  | 		it("page should have correct title", async () => { | ||||||
|  | 			assert.strictEqual(await page.title(), "Food Journal"); | ||||||
|  | 		}); | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	describe("test create 1 new review", async () => { | ||||||
|  | 		it("create 1 new review", async () => { | ||||||
|  | 			// Click the button to show update form | ||||||
|  | 			let create_btn = await page.$("#create-btn"); | ||||||
|  | 			await create_btn.click(); | ||||||
|  | 			await page.waitForNavigation(); | ||||||
|  |  | ||||||
|  | 			// Set text fields | ||||||
|  | 			await page.$eval("#mealImg", el => el.value = "sample src"); | ||||||
|  | 			await page.$eval("#imgAlt", el => el.value = "sample alt"); | ||||||
|  | 			await page.$eval("#mealName", el => el.value = "sample name"); | ||||||
|  | 			await page.$eval("#comments", el => el.value = "sample comment"); | ||||||
|  | 			await page.$eval("#restaurant", el => el.value = "sample restaurant"); | ||||||
|  |  | ||||||
|  | 			// Get the button needed to add new tags | ||||||
|  | 			let tag_btn = await page.$("#tag-add-btn"); | ||||||
|  | 			for(let i = 0; i < 5; i++){ | ||||||
|  | 				await page.$eval("#tag-form", (el, value) => el.value = `tag ${value}`, i); | ||||||
|  | 				await tag_btn.click(); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Select a new rating of 1 star | ||||||
|  | 			let rating_select = await page.$("#s1-select"); | ||||||
|  | 			await rating_select.click({delay: 100}); | ||||||
|  |  | ||||||
|  | 			// Click the save button to save updates | ||||||
|  | 			let save_btn = await page.$("#save-btn"); | ||||||
|  | 			await save_btn.click(); | ||||||
|  | 			await page.waitForNavigation(); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		it("check details page", async () => { | ||||||
|  | 			// Get the review image and check src and alt | ||||||
|  | 			let img = await page.$("#d-mealImg"); | ||||||
|  | 			let imgSrc = await img.getProperty("src"); | ||||||
|  | 			let imgAlt = await img.getProperty("alt"); | ||||||
|  | 			// Check src and alt | ||||||
|  | 			assert.strictEqual(await imgSrc.jsonValue(), "sample src"); | ||||||
|  | 			assert.strictEqual(await imgAlt.jsonValue(), "sample alt"); | ||||||
|  |  | ||||||
|  | 			// Get the title, comment, and restaurant | ||||||
|  | 			let title = await page.$("#d-mealName"); | ||||||
|  | 			let title_text = await title.getProperty("innerText"); | ||||||
|  | 			let comment = await page.$("#d-comments"); | ||||||
|  | 			let comment_text = await comment.getProperty("innerText"); | ||||||
|  | 			let restaurant = await page.$("#d-restaurant"); | ||||||
|  | 			let restaurant_text = await restaurant.getProperty("innerText"); | ||||||
|  |  | ||||||
|  | 			// Check title, comment, and restaurant | ||||||
|  | 			assert.strictEqual(await title_text.jsonValue(), "sample name"); | ||||||
|  | 			assert.strictEqual(await comment_text.jsonValue(), "sample comment"); | ||||||
|  | 			assert.strictEqual(await restaurant_text.jsonValue(), "sample restaurant"); | ||||||
|  |  | ||||||
|  | 			// Check tags | ||||||
|  | 			let tags = page.$(".tag"); | ||||||
|  | 			for(let i = 0; i < tags.length; i++){ | ||||||
|  | 				let tag_text = await tags[i].getProperty("innerText"); | ||||||
|  | 				assert.strictEqual(await tag_text.jsonValue(), `tag -${i}`); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Check stars | ||||||
|  | 			let stars = await page.$("#d-rating"); | ||||||
|  | 			let stars_src = await stars.getProperty("src"); | ||||||
|  | 			assert.strictEqual(await stars_src.jsonValue(), "./assets/images/icons/5-star.svg"); | ||||||
|  | 		}); | ||||||
|  | 	 | ||||||
|  | 		it("check home page", async () => { | ||||||
|  | 			// Click the button to return to the home page | ||||||
|  | 			let home_btn = await page.$("#home-btn"); | ||||||
|  | 			home_btn.click(); | ||||||
|  | 			await page.waitForNavigation(); | ||||||
|  |  | ||||||
|  | 			// Get the review card again and get its shadowRoot | ||||||
|  | 			let review_card = await page.$("review-card"); | ||||||
|  | 			let shadowRoot = await review_card.getProperty("shadowRoot"); | ||||||
|  |  | ||||||
|  | 			// Get the review image and check src and alt | ||||||
|  | 			let img = await shadowRoot.$("#a-mealImg"); | ||||||
|  | 			let imgSrc = await img.getProperty("src"); | ||||||
|  | 			let imgAlt = await img.getProperty("alt"); | ||||||
|  | 			// Check src and alt | ||||||
|  | 			assert.strictEqual(await imgSrc.jsonValue(), "sample src"); | ||||||
|  | 			assert.strictEqual(await imgAlt.jsonValue(), "sample alt"); | ||||||
|  |  | ||||||
|  | 			// Get the title, comment, and restaurant | ||||||
|  | 			let title = await shadowRoot.$("#a-mealName"); | ||||||
|  | 			let title_text = await title.getProperty("innerText"); | ||||||
|  | 			let comment = await shadowRoot.$("#a-comments"); | ||||||
|  | 			let comment_text = await comment.getProperty("innerText"); | ||||||
|  | 			let restaurant = await shadowRoot.$("#a-restaurant"); | ||||||
|  | 			let restaurant_text = await restaurant.getProperty("innerText"); | ||||||
|  | 			// Check title, comment, and restaurant | ||||||
|  | 			assert.strictEqual(await title_text.jsonValue(), "sample name"); | ||||||
|  | 			assert.strictEqual(await comment_text.jsonValue(), "sample comment"); | ||||||
|  | 			assert.strictEqual(await restaurant_text.jsonValue(), "sample restaurant"); | ||||||
|  | 			 | ||||||
|  | 			// Check tags | ||||||
|  | 			let tags = shadowRoot.$(".tag"); | ||||||
|  | 			for(let i = 0; i < tags.length; i++){ | ||||||
|  | 				let tag_text = await tags[i].getProperty("innerText"); | ||||||
|  | 				assert.strictEqual(await tag_text.jsonValue(), `tag -${i}`); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Check stars | ||||||
|  | 			let stars = await shadowRoot.$("#a-rating"); | ||||||
|  | 			let stars_src = await stars.getProperty("src"); | ||||||
|  | 			assert.strictEqual(await stars_src.jsonValue(), "./assets/images/icons/5-star.svg"); | ||||||
|  | 		}); | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	describe("test read 1 review after refresh", async () => { | ||||||
|  | 		it("refresh page", async () => { | ||||||
|  | 			// Reload the page | ||||||
|  | 			await page.reload({ waitUntil: ["networkidle0", "domcontentloaded"] }); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		it("check details page", async () => { | ||||||
|  | 			// click review card | ||||||
|  | 			let review_card = await page.$("review-card"); | ||||||
|  | 			console.log(JSON.stringify(review_card)); | ||||||
|  | 			await review_card.click(); | ||||||
|  | 			await page.waitForNavigation(); | ||||||
|  |  | ||||||
|  | 			// Get the review image and check src and alt | ||||||
|  | 			let img = await page.$("#d-mealImg"); | ||||||
|  | 			let imgSrc = await img.getProperty("src"); | ||||||
|  | 			let imgAlt = await img.getProperty("alt"); | ||||||
|  | 			// Check src and alt | ||||||
|  | 			assert.strictEqual(await imgSrc.jsonValue(), "sample src"); | ||||||
|  | 			assert.strictEqual(await imgAlt.jsonValue(), "sample alt"); | ||||||
|  |  | ||||||
|  | 			// Get the title, comment, and restaurant | ||||||
|  | 			let title = await page.$("#d-mealName"); | ||||||
|  | 			let title_text = await title.getProperty("innerText"); | ||||||
|  | 			let comment = await page.$("#d-comments"); | ||||||
|  | 			let comment_text = await comment.getProperty("innerText"); | ||||||
|  | 			let restaurant = await page.$("#d-restaurant"); | ||||||
|  | 			let restaurant_text = await restaurant.getProperty("innerText"); | ||||||
|  |  | ||||||
|  | 			// Check title, comment, and restaurant | ||||||
|  | 			assert.strictEqual(await title_text.jsonValue(), "sample name"); | ||||||
|  | 			assert.strictEqual(await comment_text.jsonValue(), "sample comment"); | ||||||
|  | 			assert.strictEqual(await restaurant_text.jsonValue(), "sample restaurant"); | ||||||
|  |  | ||||||
|  | 			// Check tags | ||||||
|  | 			let tags = page.$(".tag"); | ||||||
|  | 			for(let i = 0; i < tags.length; i++){ | ||||||
|  | 				let tag_text = await tags[i].getProperty("innerText"); | ||||||
|  | 				assert.strictEqual(await tag_text.jsonValue(), `tag -${i}`); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Check stars | ||||||
|  | 			let stars = await page.$("#d-rating"); | ||||||
|  | 			let stars_src = await stars.getProperty("src"); | ||||||
|  | 			assert.strictEqual(await stars_src.jsonValue(), "./assets/images/icons/5-star.svg"); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		it("check home page", async () => { | ||||||
|  | 			// Click the button to return to the home page | ||||||
|  | 			let home_btn = await page.$("#home-btn"); | ||||||
|  | 			home_btn.click(); | ||||||
|  | 			await page.waitForNavigation(); | ||||||
|  |  | ||||||
|  | 			// Get the review card again and get its shadowRoot | ||||||
|  | 			let review_card = await page.$("review-card"); | ||||||
|  | 			let shadowRoot = await review_card.getProperty("shadowRoot"); | ||||||
|  |  | ||||||
|  | 			// Get the review image and check src and alt | ||||||
|  | 			let img = await shadowRoot.$("#a-mealImg"); | ||||||
|  | 			let imgSrc = await img.getProperty("src"); | ||||||
|  | 			let imgAlt = await img.getProperty("alt"); | ||||||
|  | 			// Check src and alt | ||||||
|  | 			assert.strictEqual(await imgSrc.jsonValue(), "sample src"); | ||||||
|  | 			assert.strictEqual(await imgAlt.jsonValue(), "sample alt"); | ||||||
|  |  | ||||||
|  | 			// Get the title, comment, and restaurant | ||||||
|  | 			let title = await shadowRoot.$("#a-mealName"); | ||||||
|  | 			let title_text = await title.getProperty("innerText"); | ||||||
|  | 			let comment = await shadowRoot.$("#a-comments"); | ||||||
|  | 			let comment_text = await comment.getProperty("innerText"); | ||||||
|  | 			let restaurant = await shadowRoot.$("#a-restaurant"); | ||||||
|  | 			let restaurant_text = await restaurant.getProperty("innerText"); | ||||||
|  | 			// Check title, comment, and restaurant | ||||||
|  | 			assert.strictEqual(await title_text.jsonValue(), "sample name"); | ||||||
|  | 			assert.strictEqual(await comment_text.jsonValue(), "sample comment"); | ||||||
|  | 			assert.strictEqual(await restaurant_text.jsonValue(), "sample restaurant"); | ||||||
|  | 			 | ||||||
|  | 			// Check tags | ||||||
|  | 			let tags = shadowRoot.$(".tag"); | ||||||
|  | 			for(let i = 0; i < tags.length; i++){ | ||||||
|  | 				let tag_text = await tags[i].getProperty("innerText"); | ||||||
|  | 				assert.strictEqual(await tag_text.jsonValue(), `tag -${i}`); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Check stars | ||||||
|  | 			let stars = await shadowRoot.$("#a-rating"); | ||||||
|  | 			let stars_src = await stars.getProperty("src"); | ||||||
|  | 			assert.strictEqual(await stars_src.jsonValue(), "./assets/images/icons/5-star.svg"); | ||||||
|  | 		}); | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	describe("test update 1 review", async () => { | ||||||
|  |  | ||||||
|  | 		it("update 1 review", async () => { | ||||||
|  |  | ||||||
|  | 			// Get the only review card and click it | ||||||
|  | 			let review_card = await page.$("review-card"); | ||||||
|  | 			console.log(JSON.stringify(review_card)); | ||||||
|  | 			await review_card.click(); | ||||||
|  | 			await page.waitForNavigation(); | ||||||
|  |  | ||||||
|  | 			// Click the button to show update form | ||||||
|  | 			let update_btn = await page.$("#update-btn"); | ||||||
|  | 			await update_btn.click(); | ||||||
|  |  | ||||||
|  | 			// Set text fields | ||||||
|  | 			await page.$eval("#mealImg", el => el.value = "updated src"); | ||||||
|  | 			await page.$eval("#imgAlt", el => el.value = "updated alt"); | ||||||
|  | 			await page.$eval("#mealName", el => el.value = "updated name"); | ||||||
|  | 			await page.$eval("#comments", el => el.value = "updated comment"); | ||||||
|  | 			await page.$eval("#restaurant", el => el.value = "updated restaurant"); | ||||||
|  |  | ||||||
|  | 			// Get all tag elements and click them to delete them | ||||||
|  | 			let tag_items = await page.$$(".tag"); | ||||||
|  | 			for(let i = 0; i < tag_items.length; i++){ | ||||||
|  | 				await tag_items[i].click(); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Get the button needed to add new tags | ||||||
|  | 			let tag_btn = await page.$("#tag-add-btn"); | ||||||
|  | 			for(let i = 0; i < 5; i++){ | ||||||
|  | 				await page.$eval("#tag-form", (el, value) => el.value = `updated tag -${value}`, i); | ||||||
|  | 				await tag_btn.click(); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			// Select a new rating of 5 stars | ||||||
|  | 			let rating_select = await page.$("#s5-select"); | ||||||
|  | 			await rating_selects.click(); | ||||||
|  |  | ||||||
|  | 			// Click the save button to save updates | ||||||
|  | 			let save_btn = await page.$("#save-btn"); | ||||||
|  | 			await save_btn.click(); | ||||||
|  | 			await page.waitForNavigation(); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		it("check details page", async () => { | ||||||
|  | 			// Get the review image and check src and alt | ||||||
|  | 			let img = await page.$("#d-mealImg"); | ||||||
|  | 			let imgSrc = await img.getProperty("src"); | ||||||
|  | 			let imgAlt = await img.getProperty("alt"); | ||||||
|  | 			// Check src and alt | ||||||
|  | 			assert.strictEqual(await imgSrc.jsonValue(), "updated src"); | ||||||
|  | 			assert.strictEqual(await imgAlt.jsonValue(), "updated alt"); | ||||||
|  |  | ||||||
|  | 			// Get the title, comment, and restaurant | ||||||
|  | 			let title = await page.$("#d-mealName"); | ||||||
|  | 			let title_text = await title.getProperty("innerText"); | ||||||
|  | 			let comment = await page.$("#d-comments"); | ||||||
|  | 			let comment_text = await comment.getProperty("innerText"); | ||||||
|  | 			let restaurant = await page.$("#d-restaurant"); | ||||||
|  | 			let restaurant_text = await restaurant.getProperty("innerText"); | ||||||
|  | 			// Check title, comment, and restaurant | ||||||
|  | 			assert.strictEqual(await title_text.jsonValue(), "updated name"); | ||||||
|  | 			assert.strictEqual(await comment_text.jsonValue(), "updated comment"); | ||||||
|  | 			assert.strictEqual(await restaurant_text.jsonValue(), "updated restaurant"); | ||||||
|  | 			 | ||||||
|  | 			// Check tags | ||||||
|  | 			let tags = page.$(".tag"); | ||||||
|  | 			for(let i = 0; i < tags.length; i++){ | ||||||
|  | 				let tag_text = await tags[i].getProperty("innerText"); | ||||||
|  | 				assert.strictEqual(await tag_text.jsonValue(), `updated tag -${i}`); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Check stars | ||||||
|  | 			let stars = await page.$("#d-rating"); | ||||||
|  | 			let stars_src = await stars.getProperty("src"); | ||||||
|  | 			assert.strictEqual(await stars_src.jsonValue(), "./assets/images/icons/1-star.svg"); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		it("check home page", async () => { | ||||||
|  | 			// Click the button to return to the home page | ||||||
|  | 			let home_btn = await page.$("#home-btn"); | ||||||
|  | 			home_btn.click(); | ||||||
|  | 			await page.waitForNavigation(); | ||||||
|  |  | ||||||
|  | 			// Get the review card again and get its shadowRoot | ||||||
|  | 			let review_card = await page.$("review-card"); | ||||||
|  | 			let shadowRoot = await review_card.getProperty("shadowRoot"); | ||||||
|  |  | ||||||
|  | 			// Get the review image and check src and alt | ||||||
|  | 			let img = await shadowRoot.$("#a-mealImg"); | ||||||
|  | 			let imgSrc = await img.getProperty("src"); | ||||||
|  | 			let imgAlt = await img.getProperty("alt"); | ||||||
|  | 			// Check src and alt | ||||||
|  | 			assert.strictEqual(await imgSrc.jsonValue(), "updated src"); | ||||||
|  | 			assert.strictEqual(await imgAlt.jsonValue(), "updated alt"); | ||||||
|  |  | ||||||
|  | 			// Get the title, comment, and restaurant | ||||||
|  | 			let title = await shadowRoot.$("#a-mealName"); | ||||||
|  | 			let title_text = await title.getProperty("innerText"); | ||||||
|  | 			let comment = await shadowRoot.$("#a-comments"); | ||||||
|  | 			let comment_text = await comment.getProperty("innerText"); | ||||||
|  | 			let restaurant = await shadowRoot.$("#a-restaurant"); | ||||||
|  | 			let restaurant_text = await restaurant.getProperty("innerText"); | ||||||
|  | 			// Check title, comment, and restaurant | ||||||
|  | 			assert.strictEqual(await title_text.jsonValue(), "updated name"); | ||||||
|  | 			assert.strictEqual(await comment_text.jsonValue(), "updated comment"); | ||||||
|  | 			assert.strictEqual(await restaurant_text.jsonValue(), "updated restaurant"); | ||||||
|  | 			 | ||||||
|  | 			// Check tags | ||||||
|  | 			let tags = shadowRoot.$(".tag"); | ||||||
|  | 			for(let i = 0; i < tags.length; i++){ | ||||||
|  | 				let tag_text = await tags[i].getProperty("innerText"); | ||||||
|  | 				assert.strictEqual(await tag_text.jsonValue(), `tag -${i}`); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Check stars | ||||||
|  | 			let stars = await shadowRoot.$("#a-rating"); | ||||||
|  | 			let stars_src = await stars.getProperty("src"); | ||||||
|  | 			assert.strictEqual(await stars_src.jsonValue(), "./assets/images/icons/1-star.svg"); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	describe("test delete 1 review", () => { | ||||||
|  | 		it("delete 1 review", async () => { | ||||||
|  | 			// Get the only review card and click it | ||||||
|  | 			let review_card = await page.$("review-card"); | ||||||
|  | 			await review_card.click(); | ||||||
|  | 			await page.waitForNavigation(); | ||||||
|  |  | ||||||
|  | 			// Get the delete button and click it | ||||||
|  | 			let delete_btn = await page.$("#delete-btn"); | ||||||
|  | 			await delete_btn.click(); | ||||||
|  | 			await page.waitForNavigation(); | ||||||
|  |  | ||||||
|  | 			// Check that the card was correctly removed (there should be no remaining cards) | ||||||
|  | 			review_card = await page.$("#review-card"); | ||||||
|  | 			assert.strictEqual(review_card, null); | ||||||
|  | 		}); | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	after(async () => { | ||||||
|  | 		await page.close(); | ||||||
|  | 		await browser.close(); | ||||||
|  | 	}); | ||||||
|  | }); | ||||||
| @@ -1,18 +1,19 @@ | |||||||
| // main.js | // main.js | ||||||
| import {getReviewsFromStorage, saveReviewsToStorage} from "./localStorage.js"; | import {getAllReviewsFromStorage} from "./localStorage.js"; | ||||||
|  |  | ||||||
| // Run the init() function when the page has loaded | // Run the init() function when the page has loaded | ||||||
| window.addEventListener("DOMContentLoaded", init); | window.addEventListener("DOMContentLoaded", init); | ||||||
|  |  | ||||||
| function init() { | function init() { | ||||||
| 	// Get the reviews from localStorage | 	// Get the reviews from localStorage | ||||||
| 	let reviews = getReviewsFromStorage(); | 	let reviews = getAllReviewsFromStorage(); | ||||||
| 	// Add each reviews to the <main> element | 	// Add each reviews to the <main> element | ||||||
| 	addReviewsToDocument(reviews); | 	addReviewsToDocument(reviews); | ||||||
| 	// Add the event listeners to the form elements | 	// Add the event listeners to the form elements | ||||||
| 	initFormHandler(); | 	initFormHandler(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @param {Array<Object>} reviews An array of reviews |  * @param {Array<Object>} reviews An array of reviews | ||||||
|  */ |  */ | ||||||
| @@ -33,129 +34,9 @@ function addReviewsToDocument(reviews) { | |||||||
|  */ |  */ | ||||||
| function initFormHandler() { | function initFormHandler() { | ||||||
|  |  | ||||||
| 	/* |  | ||||||
| 	//btn to create form (could be its own function?) | 	//btn to create form (could be its own function?) | ||||||
| 	let createBtn = document.getElementById("create"); | 	let createBtn = document.getElementById("create-btn"); | ||||||
| 	createBtn.addEventListener("click", function(){ | 	createBtn.addEventListener("click", function(){ | ||||||
| 		window.location.assign("./CreatePage.html"); | 		window.location.assign("./CreatePage.html"); | ||||||
| 	});*/ |  | ||||||
|  |  | ||||||
| 	//accessing form components |  | ||||||
| 	let tagContainer = document.getElementById("tag-container-form"); |  | ||||||
| 	let form = document.querySelector("form"); |  | ||||||
|  |  | ||||||
| 	/* |  | ||||||
| 	* change the input source of the image between local file and URL  |  | ||||||
| 	* depending on user's selection |  | ||||||
| 	*/ |  | ||||||
| 	let select = document.getElementById("select"); |  | ||||||
| 	select.addEventListener("change", function() { |  | ||||||
| 		const input = document.getElementById('source'); |  | ||||||
| 	 |  | ||||||
| 		if (select.value == "file") { |  | ||||||
| 		  input.innerHTML = ` |  | ||||||
| 		  Source: |  | ||||||
| 		  <input type="file" id="mealImg" name="mealImg"> |  | ||||||
| 		  ` |  | ||||||
| 		} |  | ||||||
| 		else { |  | ||||||
| 		  input.innerHTML = ` |  | ||||||
| 		  Source: |  | ||||||
| 		  <input type="text" id="mealImg" name="mealImg"> |  | ||||||
| 		  ` |  | ||||||
| 		} |  | ||||||
| 	}); | 	}); | ||||||
|  |  | ||||||
| 	//addressing sourcing image from local file |  | ||||||
| 	let imgDataURL = ""; |  | ||||||
| 	document.getElementById("mealImg").addEventListener("change", function() { |  | ||||||
| 		const reader = new FileReader(); |  | ||||||
| 		 |  | ||||||
| 		//store image data URL after successful image load |  | ||||||
| 		reader.addEventListener("load", ()=>{ |  | ||||||
| 			imgDataURL = reader.result; |  | ||||||
| 		}, false); |  | ||||||
| 		 |  | ||||||
| 		//convert image file into data URL for local storage |  | ||||||
| 		reader.readAsDataURL(document.getElementById("mealImg").files[0]); |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|    |  | ||||||
| 	form.addEventListener("submit", function(){ |  | ||||||
| 	/* |  | ||||||
|     *  User submits the form for their review. |  | ||||||
|     *  We create reviewCard and put in storage |  | ||||||
|     */ |  | ||||||
| 		let formData = new FormData(form); |  | ||||||
| 		let reviewObject = {}; |  | ||||||
|  |  | ||||||
| 		for (let [key, value] of formData) { |  | ||||||
| 			console.log(`${key}`); |  | ||||||
| 			console.log(`${value}`); |  | ||||||
| 			if (`${key}` !== "tag-form") { |  | ||||||
| 				reviewObject[`${key}`] = `${value}`; |  | ||||||
| 			} |  | ||||||
| 			if (`${key}` === "mealImg" && select.value == "file") { |  | ||||||
| 				reviewObject["mealImg"] = imgDataURL; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		reviewObject["tags"] = []; |  | ||||||
|  |  | ||||||
| 		let tags = document.querySelectorAll(".tag"); |  | ||||||
| 		for(let i = 0; i < tags.length; i ++) { |  | ||||||
| 			reviewObject["tags"].push(tags[i].innerHTML); |  | ||||||
| 			tagContainer.removeChild(tags[i]); |  | ||||||
| 		} |  | ||||||
|      |  | ||||||
|  |  | ||||||
| 		let newReview = document.createElement("review-card"); |  | ||||||
| 		newReview.data = reviewObject; |  | ||||||
|  |  | ||||||
| 		//TODO: want to append it to whatever the box is in layout  |  | ||||||
| 		let mainEl = document.querySelector("main"); |  | ||||||
| 		mainEl.append(newReview); |  | ||||||
|  |  | ||||||
| 		let storedReviews = getReviewsFromStorage(); |  | ||||||
| 		storedReviews.push(reviewObject); |  | ||||||
| 		saveReviewsToStorage(storedReviews); |  | ||||||
| 		document.getElementById("new-food-entry").reset(); |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	// DEV-MODE: for testing purposes  |  | ||||||
| 	let clearBtn = document.querySelector(".danger"); |  | ||||||
| 	clearBtn.addEventListener("click", function() { |  | ||||||
| 		localStorage.clear(); |  | ||||||
| 		let mainEl = document.querySelector("main"); |  | ||||||
| 		while (mainEl.firstChild) { |  | ||||||
| 			mainEl.removeChild(mainEl.firstChild); |  | ||||||
| 		} |  | ||||||
| 		let deleteTags = document.querySelectorAll(".tag"); |  | ||||||
| 		for(let i = 0; i < deleteTags.length; i ++) { |  | ||||||
| 			tagContainer.removeChild(deleteTags[i]); |  | ||||||
| 		} |  | ||||||
|      |  | ||||||
| 		//clears reviews AS WELL as resets form |  | ||||||
| 		document.getElementById("new-food-entry").reset(); |  | ||||||
|       |  | ||||||
|       |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	let tagAddBtn = document.getElementById("tagAdd"); |  | ||||||
| 	tagAddBtn.addEventListener("click", ()=> { |  | ||||||
| 		let tagField = document.getElementById("tag-form"); |  | ||||||
| 		if (tagField.value.length > 0) { |  | ||||||
| 			let tagLabel = document.createElement("label"); |  | ||||||
| 			tagLabel.innerHTML = tagField.value; |  | ||||||
| 			tagLabel.setAttribute("class","tag"); |  | ||||||
| 			tagLabel.addEventListener("click",()=> { |  | ||||||
| 				tagContainer.removeChild(tagLabel); |  | ||||||
| 			}); |  | ||||||
|        |  | ||||||
| 			tagContainer.append(tagLabel); |  | ||||||
| 			tagField.value = ""; |  | ||||||
|  |  | ||||||
| 		} |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,62 +21,6 @@ | |||||||
|   <main> |   <main> | ||||||
|     <!-- Add Food Entries Here --> |     <!-- Add Food Entries Here --> | ||||||
|   </main> |   </main> | ||||||
|   <!--<button type="button" id="create">CREATE</button>--> |   <button type="button" id="create-btn"><a href='./CreatePage.html'></a>CREATE</button> | ||||||
|   <!----> <form id="new-food-entry"> |  | ||||||
|     <fieldset> |  | ||||||
|       <legend>Pic:</legend> |  | ||||||
|       Choose Input type: |  | ||||||
|       <select id="select" name="select"> |  | ||||||
|         <option value="file">File Upload</option> |  | ||||||
|         <option value="url">From an URL</option> |  | ||||||
|       </select> |  | ||||||
|       <label for="mealImage" id="source"> |  | ||||||
|         Source: |  | ||||||
|         <input type="file" id="mealImg" name="mealImg"> |  | ||||||
|       </label> |  | ||||||
|       <label for="image-alt"> |  | ||||||
|         Alt Text: |  | ||||||
|         <input type="text" id="imgAlt" name="imgAlt"> |  | ||||||
|       </label> |  | ||||||
|     </fieldset> |  | ||||||
|     <fieldset> |  | ||||||
|       <legend> Meal: </legend> |  | ||||||
|       <label for="Meal: ">Meal: |  | ||||||
|         <input type="text" id="mealName" name="mealName" required> |  | ||||||
|       </label> |  | ||||||
|       <label for="comments">Comments:  |  | ||||||
|         <br> |  | ||||||
|         <textarea name="comments" id="comments"></textarea> |  | ||||||
|       </label> |  | ||||||
|     </fieldset> |  | ||||||
|      |  | ||||||
|     <fieldset class="rating"> |  | ||||||
|       <legend> Rating: </legend> |  | ||||||
|       <input type="radio" id="s5" name="rating" value="5"/> <label for="s5"> 5 stars </label> |  | ||||||
|       <input type="radio" id="s4" name="rating" value="4"/> <label for="s4"> 4 stars </label> |  | ||||||
|       <input type="radio" id="s3" name="rating" value="3"/> <label for="s3"> 3 stars </label> |  | ||||||
|       <input type="radio" id="s2" name="rating" value="2"/> <label for="s2"> 2 stars </label> |  | ||||||
|       <input type="radio" id="s1" name="rating" value="1"/> <label for="s1"> 1 star </label> |  | ||||||
|     </fieldset> |  | ||||||
|  |  | ||||||
|     <fieldset> |  | ||||||
|       <legend>Other Info:</legend> |  | ||||||
|       <label for="restaurant"> |  | ||||||
|         Restaurant: |  | ||||||
|         <input type="text" id="restaurant" name="restaurant" required> |  | ||||||
|       </label> |  | ||||||
|       <label for="tag-form"> |  | ||||||
|         Tags: |  | ||||||
|         <input type="text" id="tag-form" name="tag-form"> |  | ||||||
|         <div class='tag-container' id="tag-container-form"> |  | ||||||
|  |  | ||||||
|         </div> |  | ||||||
|         <button type="button" id="tagAdd">Add Tag</button> |  | ||||||
|       </label> |  | ||||||
|  |  | ||||||
|     </fieldset> |  | ||||||
|     <button type="submit" value="Submit">Add Review</button> |  | ||||||
|     <button type="button" class="danger">Clear Review Journal</button> |  | ||||||
|   </form> <!----> |  | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
|   | |||||||
| @@ -1,16 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="en"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8" /> |  | ||||||
|     <meta http-equiv="X-UA-Compatible" content="IE=edge" /> |  | ||||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |  | ||||||
|     <title>Food Journal</title> |  | ||||||
|      |  | ||||||
|     <script src="assets/scripts/reviewpage.js" type="module"></script> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
|     <h1>Current Review:</h1> |  | ||||||
|     <main> |  | ||||||
|     </main> |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| [ |  | ||||||
|    { |  | ||||||
|       "imgSrc": "https://cdn.vox-cdn.com/thumbor/Cj5J-5WqSCjlC2tWCOXEB536CJY=/0x0:1810x1182/1200x800/filters:focal(761x447:1049x735)/cdn.vox-cdn.com/uploads/chorus_image/image/69422966/Tacos_Lined_Up.0.png", |  | ||||||
|       "imgAlt": "tacos pic", |  | ||||||
|       "mealName": "Birria Tacos", |  | ||||||
|       "restaurant": "Mike's Red Tacos", |  | ||||||
|       "rating": 5, |  | ||||||
|       "tags": ["delicious", "#worthit","omg"] |  | ||||||
|    }, |  | ||||||
|    { |  | ||||||
|       "imgSrc": "https://www.redwormcomposting.com/images/worm-burrito.JPG", |  | ||||||
|       "imgAlt": "wolftown pic", |  | ||||||
|       "mealName": "Carnitas Burrito", |  | ||||||
|       "restaurant": "Wolftown UCSD", |  | ||||||
|       "rating": 0, |  | ||||||
|       "tags": ["gross", "why","no"] |  | ||||||
|  |  | ||||||
|    } |  | ||||||
| ] |  | ||||||
| @@ -81,3 +81,50 @@ main { | |||||||
|   background-color: rgb(254 171 171); |   background-color: rgb(254 171 171); | ||||||
|   border-color: red; |   border-color: red; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .hidden, | ||||||
|  | .rating:not(:checked) > input { /* Hide radio circles while star rating */ | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Unchecked stars */ | ||||||
|  | .rating:not(:checked) > label { | ||||||
|  |   /* Make stars line up sideways and not vertically */ | ||||||
|  |   float: right; | ||||||
|  |  | ||||||
|  |   /* Hide label text */ | ||||||
|  |   width: 1em; | ||||||
|  |   overflow: hidden; | ||||||
|  |   white-space: nowrap; | ||||||
|  |  | ||||||
|  |   /* Star default color and size */ | ||||||
|  |   font-size: 200%; | ||||||
|  |   line-height: 1.2; | ||||||
|  |   color: #b3b3cc; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .rating > label:active { | ||||||
|  |   position: relative; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .rating:not(:checked) > label::before { | ||||||
|  |   content: "★"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Checked star color */ | ||||||
|  | .rating > input:checked ~ label { | ||||||
|  |   color: #ffbf00; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .rating:not(:checked) > label:hover, | ||||||
|  | .rating:not(:checked) > label:hover ~ label { | ||||||
|  |   color: orangered; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .rating > input:checked + label:hover, | ||||||
|  | .rating > input:checked ~ label:hover, | ||||||
|  | .rating > input:checked + label:hover ~ label, | ||||||
|  | .rating > input:checked ~ label:hover ~ label, | ||||||
|  | .rating > label:hover ~ input:checked ~ label { | ||||||
|  |   color: orangered; | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								specs/adrs/111622-e2etesting-puppeteer.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								specs/adrs/111622-e2etesting-puppeteer.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | # Use puppeteer for JS unit testing framework | ||||||
|  |  | ||||||
|  | - Status: accept | ||||||
|  | - Deciders: Arthur Lu, Marc Reta | ||||||
|  | - Date: 11 / 16 / 22 | ||||||
|  |  | ||||||
|  | ## Decision Drivers | ||||||
|  |  | ||||||
|  | - Need end to end testing framework which runs headlessly and quickly | ||||||
|  | - Framework should integrate well with Mocha, the existing unit testing framework | ||||||
|  | - Framework should be easy to implement end to end tests with | ||||||
|  |  | ||||||
|  | ## Considered Options | ||||||
|  | - puppeteer | ||||||
|  | - selenium-webdriver | ||||||
|  |  | ||||||
|  | ## Decision Outcome | ||||||
|  |  | ||||||
|  | Chosen Option: Puppeteer for its ease of use with mocha.  | ||||||
		Reference in New Issue
	
	Block a user