Merge remote-tracking branch 'origin/sprint-2' into allow-for-user-uploaded-images

This commit is contained in:
Henry Feng 2022-11-20 14:40:17 -08:00
commit 131553ddeb
22 changed files with 623 additions and 446 deletions

View File

@ -20,4 +20,4 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: sudo npm install run: sudo npm install
- name: Run tests - name: Run tests
run: sudo npm run lintCSS run: sudo npm run lint-css

View File

@ -20,4 +20,4 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: sudo npm install run: sudo npm install
- name: Run tests - name: Run tests
run: sudo npm run lintHTML run: sudo npm run lint-html

View File

@ -22,4 +22,4 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: sudo npm install run: sudo npm install
- name: Run tests - name: Run tests
run: sudo npm run lint run: sudo npm run lint-js

View File

@ -1,3 +1,4 @@
{ {
"extends": "stylelint-config-standard" "extends": "stylelint-config-standard",
"ignore": ["inside-parens", "param", "value"]
} }

View File

@ -1,2 +1,5 @@
# cse110-fa22-group29 # cse110-fa22-group29
[Team Page Link](https://github.com/cse110-fa22-group29/cse110-fa22-group29/blob/main/admin/team.md) [Team Page Link](https://github.com/cse110-fa22-group29/cse110-fa22-group29/blob/main/admin/team.md)
[Food Journal](https://cse110-fa22-group29.github.io/cse110-fa22-group29/)

View File

@ -31,6 +31,9 @@ So far the features listed below have been completed to some degree:
- Linting (JS) - Linting (JS)
- Implemented: ction triggers on any PR, uses eslint to perform style enforcement on all JS components - Implemented: ction triggers on any PR, uses eslint to perform style enforcement on all JS components
- ToDo: trigger workflow only on certain PRs which relate to JS code - ToDo: trigger workflow only on certain PRs which relate to JS code
- Linting (HTML)
- Implemented: action triggers on any PR, uses HTMLhint to perform style enforcement on all HTML components
- Linting (CSS)
- Implemented: action triggers on any PR, uses Stylelint to perform style enforcement on all CSS components
## Planned Features and Timeline ## Planned Features and Timeline

View File

@ -0,0 +1,47 @@
# Meeting Minutes (11/07/2022)
## Team 29: Hackers1995
## Meeting Topic: First Sprint
Meeting notes for the first sprint
## Attendance
1. Rhea Bhutada
2. George Dubinin
3. Gavyn Ezell
4. Henry Feng
5. Kara Hoagland
6. Marc Reta
7. Sanjit Joseph
8. Daniel Hernandez
9. Arthur Lu
10. Isaac Otero
## Meeting Details
- When: 11/17/2022 at 11:30PM
- Where: Design & Innovation Building
## Agenda:
- ### Old/Unresolved Business
- N/A
- ### New Business
- Second sprint commences!
- Focus on design progress for the project showoff
- Cuisine vs Tag identifiers for reviews (both?)
- localStorage will hold:
- list of active IDs which is updated for very create operation. An ID uniquely identifies a review
- value, "nextId" denoting the index of the next available slot for an Id
- entries for every single review (javascript object)
- a list for every tag that denotes which Ids belong to reviews containing this tag
End2end tests will rely on specific html element names which include the following:
- "create-btn" (located on homepage and used to create a new review)
- "submit-btn" (located on form and used to post review)
- "update-btn" (located on a specific review page)
- "delete-btn" (located on a specific review page)
- "tag-add-btn" (located on the review create form)
- ### Next Meeting's Business
## Decisions Made
-
## End Time
- 11/17/2022 at 1:00PM

View File

@ -0,0 +1,36 @@
# Meeting Minutes (11/20/2022)
## Team 29: Hackers1995
## Meeting Topic: Second Sprint Meeting 3
<what are we working on today>
## Attendance
1. Rhea Bhutada
2. George Dubinin
3. Gavyn Ezell
4. Henry Feng
5. Kara Hoagland
6. Marc Reta
7. Sanjit Joseph
8. Daniel Hernandez
9. Arthur Lu
10. Isaac Otero
## Meeting Details
- When: 11/20/2022 at 1:00PM
- Where: CSE Building Second Floor
## Agenda:
- ### Old/Unresolved Business
- N/A
- ### New Business
- Planning for the Agile Steam Status Video
- *Present the status of your software*
- *Description of current challenges to development*
- *Preview of the next sprint and what to look forward to*
- ### Next Meeting's Business
## Decisions Made
-
## End Time
- 11/20/2022 at 3:00PM

View File

@ -4,10 +4,11 @@
"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-js": "eslint **/*.js",
"fix-style": "eslint --fix **/*.js", "fix-js": "eslint --fix **/*.js",
"lintHTML": "htmlhint '**/*.html'", "lint-html": "htmlhint **/*.html",
"lintCSS": "stylelint '**/*.css'", "lint-css": "stylelint **/*.css",
"fix-css": "stylelint --fix **/*.css",
"http-server": "http-server source" "http-server": "http-server source"
}, },
"devDependencies": { "devDependencies": {

View File

@ -14,42 +14,56 @@
<!-- 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/ReviewCard.css" /> <link rel="stylesheet" href="./static/CreatePage.css" />
<link rel="icon" href="./assets/images/icons/favicon.ico">
<script src="./assets/scripts/CreatePage.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')"> <input type="button" value="Home" id="home-btn" onclick="window.location.assign('./index.html')">
<form id="new-food-entry"> <div class ="Top-Bar">
<fieldset> <img src ="./assets/images/icons/Logo.png" alt="logo" />
<legend>Pic:</legend> <h1> Food Journal </h1>
Choose Input type: <!--
<form id="form">
<input type='search' id="seaching" name="searchBar" placeholder="Search journal...">
<button class="click" type="search">
Search
</button>
</form>
--->
</div>
<div class="journal-form">
<h1>New Entry </h1>
<form id="new-food-entry">
<fieldset>
<legend>Pic:</legend>
Choose Input type:
<select id="select" name="select"> <select id="select" name="select">
<option value="file">File Upload</option> <option value="file">File Upload</option>
<option value="url">From an URL</option> <option value="url">From an URL</option>
</select> </select>
<label for="mealImage" id="source"> <label for="mealImage" id="source">
Source: Source:
<input type="file" accept="image/*" 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:
<input type="text" id="imgAlt" name="imgAlt"> <input type="text" id="imgAlt" name="imgAlt">
</label> </label>
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend> Meal: </legend>
<legend> Meal: </legend> <label for="Meal: ">Meal:
<label for="Meal: ">Meal: <input type="text" id="mealName" name="mealName" required>
<input type="text" id="mealName" name="mealName" required> </label>
</label> <label for="comments">Comments:
<label for="comments">Comments: <br>
<br> <textarea name="comments" id="comments"></textarea>
<textarea name="comments" id="comments"></textarea> </label>
</label> </fieldset>
</fieldset>
<fieldset class="rating"> <fieldset class="rating">
<legend> Rating: </legend> <legend> Rating: </legend>
<input type="radio" id="s5" name="rating" value="5"/> <label for="s5" id="s5-select"> 5 stars </label> <input type="radio" id="s5" name="rating" value="5"/> <label for="s5" id="s5-select"> 5 stars </label>
@ -59,24 +73,25 @@
<input type="radio" id="s1" name="rating" value="1"/> <label for="s1" id="s1-select"> 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>
<legend>Other Info:</legend> <legend>Other Info:</legend>
<label for="restaurant"> <label for="restaurant">
Restaurant: Restaurant:
<input type="text" id="restaurant" name="restaurant" required> <input type="text" id="restaurant" name="restaurant" required>
</label> </label>
<label for="tag-form"> <label for="tag-form">
Tags: Tags:
<input type="text" id="tag-form" name="tag-form"> <input type="text" id="tag-form" name="tag-form">
<div class='tag-container' id="tag-container-form"> <div class='tag-container' id="tag-container-form">
</div> </div>
<button type="button" id="tag-add-btn">Add Tag</button> <button type="button" id="tag-add-btn">Add Tag</button>
</label> </label>
</fieldset>
<button type="submit" id="save-btn" value="Submit">Save Review</button> </fieldset>
</form> <button type="submit" id="save-btn" value="Submit">Save Review</button>
</form>
</div>
</body> </body>
</html> </html>

View File

@ -77,7 +77,7 @@
</label> </label>
</fieldset> </fieldset>
<button type="submit" value="Submit">Add Review</button> <button type="submit" id="save-btn" value="Submit">Add Review</button>
</form> </form>
</body> </body>
</html> </html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,76 @@
import {strict as assert} from "node:assert";
/**
* Fills out a create or update review form
* @param {Object} page the page object which contains the create or update form
* @param {Object} review review data to input into the form
*/
export async function setReviewForm(page, review) {
// Set text fields
await page.$eval("#imgAlt", (el, value) => el.value = value, review.imgAlt);
await page.$eval("#mealName", (el, value) => el.value = value, review.mealName);
await page.$eval("#comments", (el, value) => el.value = value, review.comments);
await page.$eval("#restaurant", (el, value) => el.value = value, review.restaurant);
// Get all tag elements and click them to delete them
let tag_items = await page.$$(".tag");
if(tag_items !== null){
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 < review.tags.length; i++){
await page.$eval("#tag-form", (el, value) => el.value = value, review.tags[i]);
await tag_btn.click();
}
// Select a new rating
let rating_select = await page.$(`#s${review.rating}-select`);
await rating_select.click({delay: 100});
}
/**
* Tests a page or shadowDOM for correct element text, src, or alt values
* @param {Object} root page or shodowDOM to test
* @param {string} prefix prefix character for element IDs
* @param {Object} expected values for eahc element
*/
export async function checkCorrectness(root, prefix, expected){
// Get the review image and check src and alt
let img = await root.$(`#${prefix}-mealImg`);
let imgSrc = await img.getProperty("src");
let imgAlt = await img.getProperty("alt");
// Check src and alt
assert.strictEqual(await imgSrc.jsonValue(), expected.imgSrc);
assert.strictEqual(await imgAlt.jsonValue(), expected.imgAlt);
// Get the title, comment, and restaurant
let title = await root.$(`#${prefix}-mealName`);
let title_text = await title.getProperty("innerText");
let comment = await root.$(`#${prefix}-comments`);
let comment_text = await comment.getProperty("innerText");
let restaurant = await root.$(`#${prefix}-restaurant`);
let restaurant_text = await restaurant.getProperty("innerText");
// Check title, comment, and restaurant
assert.strictEqual(await title_text.jsonValue(), expected.mealName);
assert.strictEqual(await comment_text.jsonValue(), expected.comments);
assert.strictEqual(await restaurant_text.jsonValue(), expected.restaurant);
// Check tags
let tags = await root.$$(".tag");
assert.strictEqual(await tags.length, expected.tags.length);
for(let i = 0; i < expected.tags.length; i++){
let tag_text = await tags[i].getProperty("innerText");
assert.strictEqual(await tag_text.jsonValue(), expected.tags[i]);
}
// Check stars
let stars = await root.$(`#${prefix}-rating`);
let stars_src = await stars.getProperty("src");
assert.strictEqual(await stars_src.jsonValue(), expected.rating);
}

View File

@ -1,7 +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 puppeteer from "puppeteer-core"; import puppeteer from "puppeteer-core";
import { exit } from "node:process"; import {exit} from "node:process";
import {setReviewForm, checkCorrectness} from "./appTestHelpers.js";
describe("test App end to end", async () => { describe("test App end to end", async () => {
@ -17,7 +18,8 @@ describe("test App end to end", async () => {
root = false; root = false;
} }
browser = await puppeteer.launch({args: root ? ['--no-sandbox'] : undefined}); //browser = await puppeteer.launch({headless: false, slowMo: 250, args: root ? ['--no-sandbox'] : undefined});
browser = await puppeteer.launch({args: root ? ["--no-sandbox"] : undefined});
page = await browser.newPage(); page = await browser.newPage();
try{ try{
await page.goto("http://localhost:8080", {timeout: 1000}); await page.goto("http://localhost:8080", {timeout: 1000});
@ -35,346 +37,210 @@ describe("test App end to end", async () => {
}); });
}); });
describe("test create 1 new review", async () => { describe("test CRUD on simple inputs and default image", () => {
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 describe("test create 1 new review", async () => {
await page.$eval("#mealImg", el => el.value = "sample src"); it("create 1 new review", async () => {
await page.$eval("#imgAlt", el => el.value = "sample alt"); // Click the button to create a new review
await page.$eval("#mealName", el => el.value = "sample name"); let create_btn = await page.$("#create-btn");
await page.$eval("#comments", el => el.value = "sample comment"); await create_btn.click();
await page.$eval("#restaurant", el => el.value = "sample restaurant"); await page.waitForNavigation();
// Get the button needed to add new tags // create a new review
let tag_btn = await page.$("#tag-add-btn"); let review = {
for(let i = 0; i < 5; i++){ imgAlt: "sample alt",
await page.$eval("#tag-form", (el, value) => el.value = `tag ${value}`, i); mealName: "sample name",
await tag_btn.click(); comments: "sample comment",
} restaurant: "sample restaurant",
tags: ["tag 0", "tag 1", "tag 2", "tag 3", "tag 4"],
rating: 1
};
await setReviewForm(page, review);
// Select a new rating of 1 star // Click the save button to save updates
let rating_select = await page.$("#s1-select"); let save_btn = await page.$("#save-btn");
await rating_select.click({delay: 100}); await save_btn.click();
await page.waitForNavigation();
});
// Click the save button to save updates it("check details page", async () => {
let save_btn = await page.$("#save-btn"); // check the details page for correctness
await save_btn.click(); let expected = {
await page.waitForNavigation(); imgSrc: "http://localhost:8080/assets/images/icons/plate_with_cutlery.png",
imgAlt: "sample alt",
mealName: "sample name",
comments: "sample comment",
restaurant: "sample restaurant",
tags: ["tag 0", "tag 1", "tag 2", "tag 3", "tag 4"],
rating: "http://localhost:8080/assets/images/icons/1-star.svg"
};
await checkCorrectness(page, "d", expected);
});
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");
let expected = {
imgSrc: "http://localhost:8080/assets/images/icons/plate_with_cutlery.png",
imgAlt: "sample alt",
mealName: "sample name",
comments: "sample comment",
restaurant: "sample restaurant",
tags: ["tag 0", "tag 1", "tag 2", "tag 3", "tag 4"],
rating: "http://localhost:8080/assets/images/icons/1-star.svg"
};
await checkCorrectness(shadowRoot, "a", expected);
});
}); });
it("check details page", async () => { describe("test read 1 review after refresh", async () => {
// Get the review image and check src and alt it("refresh page", async () => {
let img = await page.$("#d-mealImg"); // Reload the page
let imgSrc = await img.getProperty("src"); await page.reload({ waitUntil: ["networkidle0", "domcontentloaded"] });
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 it("check details page", async () => {
let title = await page.$("#d-mealName"); // click review card
let title_text = await title.getProperty("innerText"); let review_card = await page.$("review-card");
let comment = await page.$("#d-comments"); await review_card.click();
let comment_text = await comment.getProperty("innerText"); await page.waitForNavigation();
let restaurant = await page.$("#d-restaurant");
let restaurant_text = await restaurant.getProperty("innerText");
// Check title, comment, and restaurant // check the details page for correctness
assert.strictEqual(await title_text.jsonValue(), "sample name"); let expected = {
assert.strictEqual(await comment_text.jsonValue(), "sample comment"); imgSrc: "http://localhost:8080/assets/images/icons/plate_with_cutlery.png",
assert.strictEqual(await restaurant_text.jsonValue(), "sample restaurant"); imgAlt: "sample alt",
mealName: "sample name",
comments: "sample comment",
restaurant: "sample restaurant",
tags: ["tag 0", "tag 1", "tag 2", "tag 3", "tag 4"],
rating: "http://localhost:8080/assets/images/icons/1-star.svg"
};
await checkCorrectness(page, "d", expected);
});
// Check tags it("check home page", async () => {
let tags = page.$(".tag"); // Click the button to return to the home page
for(let i = 0; i < tags.length; i++){ let home_btn = await page.$("#home-btn");
let tag_text = await tags[i].getProperty("innerText"); home_btn.click();
assert.strictEqual(await tag_text.jsonValue(), `tag -${i}`); await page.waitForNavigation();
}
// Check stars // Get the review card again and get its shadowRoot
let stars = await page.$("#d-rating"); let review_card = await page.$("review-card");
let stars_src = await stars.getProperty("src"); let shadowRoot = await review_card.getProperty("shadowRoot");
assert.strictEqual(await stars_src.jsonValue(), "./assets/images/icons/5-star.svg");
// check the details page for correctness
let expected = {
imgSrc: "http://localhost:8080/assets/images/icons/plate_with_cutlery.png",
imgAlt: "sample alt",
mealName: "sample name",
comments: "sample comment",
restaurant: "sample restaurant",
tags: ["tag 0", "tag 1", "tag 2", "tag 3", "tag 4"],
rating: "http://localhost:8080/assets/images/icons/1-star.svg"
};
await checkCorrectness(shadowRoot, "a", expected);
});
}); });
it("check home page", async () => { describe("test update 1 review", 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 it("update 1 review", async () => {
let review_card = await page.$("review-card");
let shadowRoot = await review_card.getProperty("shadowRoot");
// Get the review image and check src and alt // Get the only review card and click it
let img = await shadowRoot.$("#a-mealImg"); let review_card = await page.$("review-card");
let imgSrc = await img.getProperty("src"); await review_card.click();
let imgAlt = await img.getProperty("alt"); await page.waitForNavigation();
// Check src and alt
assert.strictEqual(await imgSrc.jsonValue(), "sample src");
assert.strictEqual(await imgAlt.jsonValue(), "sample alt");
// Get the title, comment, and restaurant // Click the button to show update form
let title = await shadowRoot.$("#a-mealName"); let update_btn = await page.$("#update-btn");
let title_text = await title.getProperty("innerText"); await update_btn.click();
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 // create a new review
let tags = shadowRoot.$(".tag"); let review = {
for(let i = 0; i < tags.length; i++){ imgAlt: "updated alt",
let tag_text = await tags[i].getProperty("innerText"); mealName: "updated name",
assert.strictEqual(await tag_text.jsonValue(), `tag -${i}`); comments: "updated comment",
} restaurant: "updated restaurant",
tags: ["tag -0", "tag -1", "tag -2", "tag -3", "tag -4", "tag -5"],
rating: 5
};
await setReviewForm(page, review);
// Check stars // Click the save button to save updates
let stars = await shadowRoot.$("#a-rating"); let save_btn = await page.$("#save-btn");
let stars_src = await stars.getProperty("src"); await save_btn.click();
assert.strictEqual(await stars_src.jsonValue(), "./assets/images/icons/5-star.svg"); await page.waitForNavigation();
}); });
});
it("check details page", async () => {
// check the details page for correctness
let expected = {
imgSrc: "http://localhost:8080/assets/images/icons/plate_with_cutlery.png",
imgAlt: "updated alt",
mealName: "updated name",
comments: "updated comment",
restaurant: "updated restaurant",
tags: ["tag -0", "tag -1", "tag -2", "tag -3", "tag -4", "tag -5"],
rating: "http://localhost:8080/assets/images/icons/5-star.svg"
};
await checkCorrectness(page, "d", expected);
});
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");
// check the details page for correctness
let expected = {
imgSrc: "http://localhost:8080/assets/images/icons/plate_with_cutlery.png",
imgAlt: "updated alt",
mealName: "updated name",
comments: "updated comment",
restaurant: "updated restaurant",
tags: ["tag -0", "tag -1", "tag -2", "tag -3", "tag -4", "tag -5"],
rating: "http://localhost:8080/assets/images/icons/5-star.svg"
};
await checkCorrectness(shadowRoot, "a", expected);
});
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 () => { describe("test delete 1 review", async () => {
// click review card it("delete 1 review", async () => {
let review_card = await page.$("review-card"); // Get the only review card and click it
console.log(JSON.stringify(review_card)); let review_card = await page.$("review-card");
await review_card.click(); await review_card.click();
await page.waitForNavigation(); await page.waitForNavigation();
// Get the review image and check src and alt page.on("dialog", async dialog => {
let img = await page.$("#d-mealImg"); console.log(dialog.message());
let imgSrc = await img.getProperty("src"); await dialog.accept();
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 // Get the delete button and click it
let title = await page.$("#d-mealName"); let delete_btn = await page.$("#delete-btn");
let title_text = await title.getProperty("innerText"); await delete_btn.click();
let comment = await page.$("#d-comments"); await page.waitForNavigation();
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 // Check that the card was correctly removed (there should be no remaining cards)
assert.strictEqual(await title_text.jsonValue(), "sample name"); review_card = await page.$("#review-card");
assert.strictEqual(await comment_text.jsonValue(), "sample comment"); assert.strictEqual(review_card, null);
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 () => { after(async () => {

View File

@ -18,12 +18,12 @@ function init() {
* @param {Array<Object>} reviews An array of reviews * @param {Array<Object>} reviews An array of reviews
*/ */
function addReviewsToDocument(reviews) { function addReviewsToDocument(reviews) {
let mainEl = document.querySelector("main"); let box = document.getElementById("review-container");
reviews.forEach(review => { reviews.forEach(review => {
let newReview = document.createElement("review-card"); let newReview = document.createElement("review-card");
newReview.data = review; newReview.data = review;
//TODO: want to append it to whatever the box is in layout //TODO: want to append it to whatever the box is in layout
mainEl.append(newReview); box.append(newReview);
}); });
} }

View File

@ -13,14 +13,39 @@
<!-- 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/ReviewCard.css" /> <link rel="stylesheet" href="./static/homepage.css" />
<script src="assets/scripts/main.js" type="module"></script> <script src="assets/scripts/main.js" type="module"></script>
</head> </head>
<body> <body>
<div class ="Top-Bar">
<img src ="./assets/images/icons/Logo.png" alt="logo" />
<h1 style="font-family:'Lucida Sans'"> Food Journal </h1>
<form id="form">
<input type='search' id="seaching" name="searchBar" placeholder="Search journal...">
<button class="click" type="search">
Search
</button>
</form>
<!--
<form id="form">
<input type='search' id="seaching" name="searchBar" placeholder="Search journal...">
<button class="click" type="search">
Search
</button>
</form>
--->
<main> <main>
<!-- Add Food Entries Here --> <!-- Add Food Entries Here -->
<div class="Review-boxes">
<h2> Recent Reviews </h2>
<img src ="./assets/images/icons/Grouppink.png" alt="CREATE" id="create-btn" onclick="window.location.assign('./CreatePage.html')"></img>
</div>
<div class="Filter-box">
</div>
<div class="review-container" id="review-container"></div>
</main> </main>
<button type="button" id="create-btn"><a href='./CreatePage.html'></a>CREATE</button> <!--<button type="button" id="create-btn"><a href='./CreatePage.html'></a>CREATE</button>-->
</body> </body>
</html> </html>

View File

@ -1,83 +1,84 @@
/* CreatePage.css */ /* CreatePage.css */
* { body{
font-family: sans-serif; background-color: #13323b;
} }
body { h1 {
height: 100%;
width: 100%;
}
fieldset {
border: 2px solid rgb(214 214 214);
box-sizing: border-box;
display: block;
width: max-content;
}
form button {
display: block;
margin-top: 5px;
}
label[for="ingredients"] p {
margin: 0;
}
label[for="numRatings"] {
margin: 10px 0 0;
}
label[for^="rating"] {
padding-right: 10px;
}
label:not([for^="rating"]) {
display: block;
margin-bottom: 5px;
}
main {
column-gap: 10px;
display: flex;
flex-wrap: wrap;
height: auto;
max-width: 660px;
row-gap: 10px;
width: 100%;
}
.tag-container {
display: flex;
flex-flow: row wrap;
}
.tag {
background-color: grey;
border-radius: 7px;
color: white;
padding-right: 7px;
padding-left: 7px;
margin: 3px;
}
.tag::before {
display: inline-block;
content: "x";
height: 15px;
width: 15px;
margin-right: 4px;
text-align: center; text-align: center;
color: white; }
cursor: pointer; .Top-Bar{
margin-top: -8cm;
}
.Top-Bar > img{
position: relative;
top: 7.85cm;
}
.Top-Bar > h1{
position: relative;
top: 2.2cm;
font-size: 3cm;
color: #EAA9BC
}
.Top-Bar > form{
position: relative;
left: 32cm;
} }
.tag:hover::before { .journal-form {
color: red; font-size: 120%;
width: 50%;
display: block;
margin: auto;
color: #ccb3bb;
border: 3px solid rgb(7, 0, 0);
background-color: #b52754;
} }
.danger { .hidden,
background-color: rgb(254 171 171); .rating:not(:checked) > input { /* Hide radio circles while star rating */
border-color: red; 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;
} }

View File

@ -0,0 +1,65 @@
/* homepage.css */
/* Color*/
body{
background-color: #13323b;
}
.Top-Bar{
margin-top: -8cm;
}
.Top-Bar > img{
position: relative;
top: 7.5cm;
}
.Top-Bar > h1{
position: relative;
left: 10.5cm;
top: 2.2cm;
font-size: 3cm;
color: #EAA9BC;
}
.Top-Bar > form{
position: relative;
left: 32cm;
}
.Review-boxes {
position: relative;
}
.Review-boxes > h2 {
position: relative;
left: 10cm;
font-size: 1.5cm;
color: #EAA9BC;
}
.Review-boxes > input {
position: relative;
left: 20.34cm;
top: -3.5cm;
}
.Filter-box{
width:300px;
height:700px;
background: #8D4E62;
position: relative;
left: 29.5cm;
top: -5.5cm;
}
.review-container{
display: flex;
position: relative;
top: -22cm;
left: 5cm;
max-width: 900px;
flex-wrap: wrap;
}
.review-container > div {
background-color: #f1f1f1;
width: 200px;
height: 200px;
margin: 10px;
text-align: center;
line-height: 75px;
font-size: 30px;
}

View File

@ -0,0 +1,19 @@
# Use Stylelint for CSS linting framework
- Status: accept
- Deciders: Arthur Lu, Marc Reta
- Date: 11 / 14 / 22
## Decision Drivers
- Need linting to work with multiple style standards
- Need linting to be fast and informative
## Considered Options
- Stylelint
- Prettier
## Decision Outcome
Chosen Option: Stylelint for its easy installation and unopinionated.

View File

@ -0,0 +1,19 @@
# Use HTMLhint for HTML linting framework
- Status: accept
- Deciders: Arthur Lu, Marc Reta
- Date: 11 / 14 / 22
## Decision Drivers
- Need linting to work with multiple style standards
- Need linting to be fast and informative
## Considered Options
- HTMLhint
- HTML-validate
## Decision Outcome
Chosen Option: HTMLhint for its low configuration complexity.