Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rick Mansfield's push/pull trail for Advanced Web Apps Sprint #141

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5c85f67
Rick Mansfield's push/pull trail for Advaned Web Apps Sprint
Aug 20, 2021
12a5866
add TOC to README.md
Aug 20, 2021
8c0e5fc
added Pull Req to Readme.md
Aug 20, 2021
17e400b
Create a CodeGrade submission
Aug 20, 2021
9f3d64d
Loging.js Steps 1 & 2 complete
Aug 20, 2021
6844f26
Login.js Step 4 complete
Aug 20, 2021
b910cb9
Login.js add error state
Aug 20, 2021
73012d6
Login.js Add handleChange event handler
Aug 20, 2021
974ec1b
Login.js Tasks #5-8 complete
Aug 20, 2021
d203e6e
refactor comments as breadcrumbs for later
Aug 20, 2021
8d9432e
Built out fetchColorService.js
Aug 20, 2021
38efa27
fixed typo readme from 'BubblePages' to BubblePage
Aug 20, 2021
e4e50c4
Complete Tasks 1 & 2 for BubblePage.js
Aug 20, 2021
b1b39ab
Add Private route, axiosWithAuth delete & save fn
Aug 20, 2021
66d8d8c
Moved Private route to component folder
Aug 20, 2021
481f15c
Consumbing the API complete
Aug 20, 2021
d6611e4
Refactor <label> to Password in Login.js
Aug 20, 2021
3e613fd
Color.test.js #1 complete/passing
Aug 20, 2021
44c8df0
Color.test.js Test#2 complete/passing
Aug 20, 2021
db30fe5
Color.test.js test #3 complete/passing
Aug 20, 2021
5a90d75
refactor app.js login.js from /bubble to /bubbles
Aug 20, 2021
62c0a4b
refactor BubblePage.js saveEdit to /bubbles
Aug 20, 2021
4ae81d7
All Color.test.js Completed/passing
Aug 20, 2021
2d17fa3
ColorList.test.js #1 & #2 complete/passing
Aug 20, 2021
ac0dac7
All ColorList.test.js passing.
Aug 20, 2021
bfccc19
BubblePage.test.js all test complete/passing
Aug 20, 2021
c657639
Added CodeGrade Proof in assets folder
Aug 20, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 35 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Advanced Web Applications Sprint Challenge

- [Advanced Web Applications Sprint Challenge](#advanced-web-applications-sprint-challenge)
- [Overview](#overview)
- [Introduction](#introduction)
- [Instructions](#instructions)
- [Task 1: Project Setup](#task-1-project-setup)
- [Task 2: CodeGrade Setup](#task-2-codegrade-setup)
- [Task 3: Project Requirements](#task-3-project-requirements)
- [Authentication](#authentication)
- [Consuming the API](#consuming-the-api)
- [Testing](#testing)
- [Reference Materials](#reference-materials)
- [API Documentation](#api-documentation)
- [Hex Color Examples](#hex-color-examples)
- [Submission format](#submission-format)
- [Interview Questions](#interview-questions)
- [Rick Mansfield's push/pull trail for Advanced Web Apps Sprint](#rick-mansfields-pushpull-trail-for-advanced-web-apps-sprint)

## Overview

**Read these instructions carefully. Understand exactly what is expected _before_ starting this Sprint Challenge.**

This challenge allows you to practice the concepts and techniques learned over the past sprint and apply them in a concrete project. This sprint explored **advanced web applications**. During this sprint, you studied **React testing, client-side auth, HTTP methods, and Vercel**.
Expand Down Expand Up @@ -48,21 +67,24 @@ Your finished project must include all of the following requirements. **Unlike o
* [ ] Build in functionality that would allow an error to be displayed in the provided p tag if either the username or password is incorrect.
* [ ] **Make sure your error p tag has an id="error" attribute attached. Codegrade autotests will fail without them.**
* [ ] Construct an http request that retrieves an auth token from the server when the username `Lambda` and the password `School` is passed into the request.
* [ ] Save the token to localStorage.
* [ ] Build a `axiosWithAuth` module within the helpers folder to create an instance of axios with the authentication header.
* [ ] Build a `PrivateRoute` component within the components folder and use it to protect the route that renders the `BubblesPage` component.
* [ ] In `App.js`, build the backend to the logout button. When pressed, send an http request to the logout endpoint and remove the authentication token from localStorage. Use window.location.href to redirect to the login page.
* [x] Save the token to localStorage.
* [x] Build a `axiosWithAuth` module within the helpers folder to create an instance of axios with the authentication header.
* [x] Build a `PrivateRoute` component within the components folder and use it to protect the route that renders the `BubblesPage` component.
* [x] In `App.js`, build the backend to the logout button. When pressed, send an http request to the logout endpoint and remove the authentication token from localStorage. Use window.location.href to redirect to the login page.

#### Consuming the API
> *Add in the http requests and state changes needed to connect our api to the web application. Consider the effect of authentication on your api requests.*

* [ ] In `services/fetchColorServices.js`, build out fetchColorService function to make a GET request to fetch the color data for your bubbles.
* [ ] When `BubblePages` mounts, call fetchColorServices and save it's result in state.
* [ ] In `BubblePage.js`, complete `saveEdit`, and `deleteColor` functions to make API requests for to editing and delete data.
* [ ] Watch and enjoy as your app responds to updates in the data. Check out `Bubbles.js` to see how this is built.
* [x] In `services/fetchColorServices.js`, build out fetchColorService function to make a GET request to fetch the color data for your bubbles.
* [x] When `BubblePage` mounts, call fetchColorServices and save it's result in state.
* [x] In `BubblePage.js`, complete `saveEdit`, and `deleteColor` functions to make API requests for to editing and delete data.
* [x] Watch and enjoy as your app responds to updates in the data. Check out `Bubbles.js` to see how this is built.

#### Testing
* [ ] Finish the test in `Color.test.js`, `ColorList.test.js`, `BubblePage.test.js`. You will need to use rerendering, function mocking and spies in order to complete.
* [ ] * [ ] Note to self ... I used this data
![res.data for colors](src\assets\Capture1.JPG)
view in readme.md preview mode to see pic

**Notes:**
* You are welcome to create additional files but **do not move or rename existing files** or folders.
Expand Down Expand Up @@ -100,4 +122,8 @@ Be prepared to demonstrate your understanding of this week's concepts by answeri
1. Explain what a token is used for.
2. What steps can you take in your web apps to keep your data secure?
3. Describe how web servers work.
4. Which HTTP methods can be mapped to the CRUD acronym that we use when interfacing with APIs/Servers.
4. Which HTTP methods can be mapped to the CRUD acronym that we use when interfacing with APIs/Servers.

## Rick Mansfield's push/pull trail for Advanced Web Apps Sprint

- [Link for convenience](https://github.com/LambdaSchool/web-sprint-challenge-advanced-web-applications/pull/141)
21 changes: 18 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
import React, { useState } from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import PrivateRoute from './components/PrivateRoute';
import BubblePage from './components/BubblePage';

import Login from "./components/Login";
import "./styles.scss";

//3A Build the logout button to call the logout endpoint, remove the localStorage Item and redirect to the login page.
const logout = () => {
localStorage.removeItem("token");
window.location.href = "login";
}
function App() {
return (
<Router>
<div className="App">
<header>
Color Picker Sprint Challenge
<a data-testid="logoutButton" href="#">logout</a>
{/* //3b. Build the logout button to call the logout endpoint, remove the localStorage Item and redirect to the login page. */}
<a data-testid="logoutButton" href="/" onClick={logout}>logout</a>
</header>
<Switch>
{/* //2. Render BubblePage as a PrivateRoute */}
<PrivateRoute exact path="/bubbles" component={BubblePage} />
{/* //1. Add in two routes that link to the Login Component, one for the default path '/' and one for the '/login'. */}
<Route path="/login" component={Login} />
<Route exact path="/" component={Login} />
</Switch>
</div>
</Router>
);
Expand Down
Binary file added src/assets/Capture1.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/cg1.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/cg2.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/cg3.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/cg4.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/terminal-1.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 19 additions & 1 deletion src/components/BubblePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,37 @@ import React, { useEffect, useState } from "react";
import Bubbles from "./Bubbles";
import ColorList from "./ColorList";
import fetchColorService from '../services/fetchColorService';
import axiosWithAuth from "../helpers/axiosWithAuth";
import editColorService from "../services/saveEditService";
import deleteColorService from "../services/deleteColorService";

const BubblePage = () => {
const BubblePage = (props) => {
const [colors, setColors] = useState([]);
const [editing, setEditing] = useState(false);

//1. When the component mounts, make an axios call to retrieve all color data and push to state.useEffect
useEffect(()=>{
axiosWithAuth()
fetchColorService(setColors);
},[editing]);//inserted "editing to prevent memory leak"

const toggleEdit = (value) => {
setEditing(value);
};

//2. Complete toggleEdit, saveEdit, deleteColor and functions

const saveEdit = (editColor) => {
editColorService(editColor);
fetchColorService(setColors);
props.history.push('/bubbles');
toggleEdit(false)
};

const deleteColor = (colorToDelete) => {
console.log('colorToDelete Obj in BubblePage.js', colorToDelete);
deleteColorService(colorToDelete.id);
fetchColorService(setColors);
};

return (
Expand Down
28 changes: 23 additions & 5 deletions src/components/BubblePage.test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
import React from 'react';
import MutationObserver from 'mutationobserver-shim';

import { render, screen} from "@testing-library/react";
import { render, screen, waitFor} from "@testing-library/react";
import BubblePage from './BubblePage';
import ColorList from './ColorList';

const testColors = [
{code: {hex: "##ffebcd"},
color: "blanchedalmond",
id: 8},
{code: {hex: "#6093ca"},
color: "blue",
id: 9},
{code: {hex: "#ff000"},
color: "red",
id: 10}
];

test("Renders without errors", ()=> {

render(<BubblePage />)
});

test("Renders appropriate number of colors passed in through mock", async ()=> {
//Keep in mind that our service is called on mount for this component.
});
const mockColorsFunc = jest.fn(() => { return (testColors) });
render(<ColorList colors={mockColorsFunc()} />);

await waitFor(()=>{
const correctColorsReturned = screen.getAllByTestId(/color/i);
expect(correctColorsReturned).toHaveLength(3);
})
});
79 changes: 77 additions & 2 deletions src/components/Color.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,90 @@ import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import Color from './Color';

//I inpspected the res.data to see the needed syntax/structure.See my pic of this data in readme.md preview mode under testing. I created a TOC Table of Contents for easy reference.
test("Renders without errors with blank color passed into component", () => {
render(
<Color
color={{
code: { hex: "" },
color: "",
id: 0,
}}
/>
);
});

test("Renders the color passed into component", () => {
});
//Arrange - Usually Render/const/screen to prep for Action step
render(
<Color
color={{
code: { hex: "99ddbc" },
color: "limegreen",
id: 1,
}}
/>
);
//Act - Usually const/screen for something
let testColor = screen.getByText(/limegreen/i)
//Assert - What's "expected"
expect(testColor).toBeInTheDocument();

});
test("Executes handleDelete and toggleEdit property when the 'x' icon is clicked", () => {
//Arrange - Usually Render/const/screen to prep for Action step (review Day 1 (Monday) testing Display.test.js)
const mockToggleFunc = jest.fn();
const mockDeleteFunc = jest.fn();
render(
<Color
color={{
code: { hex: "" },
color: "",
id: 1,
}}
deleteColor={mockDeleteFunc}
toggleEdit={mockToggleFunc}
/>
);
let theXToDelete = screen.getByText(/x/i);//it says "icon" on line 39 but it's a text letter "x".

//Act - Usually doing something to what you just const/screened/arranged
userEvent.click(theXToDelete);

//Assert - What's "expected"
expect(mockToggleFunc).toHaveBeenCalled();
expect(mockDeleteFunc).toHaveBeenCalled();
expect(mockDeleteFunc.mock.calls).toHaveLength(1);
expect(mockToggleFunc.mock.calls).toHaveLength(1);
});

test("Executes setEditColor and toggleEdit property when color div is clicked", () => {
//Arrange - Usually Render/const/screen to prep for Action step
const mocksetEditColorFunc = jest.fn();
const mockToggleEditFunc = jest.fn();

render(
<Color
color={{
code: { hex: "" },
color: "",
id: 1,
}}
setEditColor={mocksetEditColorFunc}
toggleEdit={mockToggleEditFunc}
/>
);
let theColorDiv = screen.getByTestId(/color/i);
// let theEditMenu = screen.findByTestId(/edit_menu/i)

//Act - Usually doing something to what you just const/screened/arranged
userEvent.click(theColorDiv);

// //Assert - What's "expected"
expect(mockToggleEditFunc).toHaveBeenCalled();
// // expect(mockToggleEditFunc).toHaveLength(1);
// // expect(theEditMenu).toBeTruthy();
expect(mocksetEditColorFunc).toHaveBeenCalled();
// expect(mocksetEditColorFunc).toHaveLength(1);

});
44 changes: 40 additions & 4 deletions src/components/ColorList.test.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,50 @@
import React from 'react';
import MutationObserver from 'mutationobserver-shim';

import { render, screen} from "@testing-library/react";
import ColorList from './ColorList';
import ColorList from './ColorList'

const testColors = [
{code: {hex: "##ffebcd"},
color: "blanchedalmond",
id: 8},
{code: {hex: "#6093ca"},
color: "blue",
id: 9},
{code: {hex: "#ff000"},
color: "red",
id: 10}
];

test("Renders an empty list of colors without errors", () => {
render(<ColorList colors={[]} />)
});

test("Renders a list of colors without errors", () => {
render(<ColorList colors={testColors} />)
});


test("Renders the EditForm when editing = true and does not render EditForm when editing = false", () => {
});
// //Arrange - Usually Render/const/screen to prep for Action step
const { rerender } = render(<ColorList colors={testColors} editing={true} />)
// //See/inspect DOM for variable name choices.
const editColorLegend = screen.getByText(/edit color/i);
const labelForColorName = screen.getByText(/color name/i);
const labelForColorHex = screen.getByText(/hex code/i);

// //Act - Usually doing something to what you just const/screened/arranged
// //in this case the form should be true and therefore all the above would be present.So not additional actions are needed after editing = true which I've set above in line


// //Assert - What's "expected" from the actions taken
expect(editColorLegend).toBeInTheDocument()
expect(labelForColorName).toBeInTheDocument();
expect(labelForColorHex ).toBeInTheDocument();

// //ReArrange for "falsey" conditions- Usually Render/const/screen to prep for Action step
rerender(<ColorList colors={testColors} editing={false} />);
// // //Act - Usually doing something to what you just const/screened/arranged
// // //Assert - What's "expected" from the actions taken
expect(editColorLegend).not.toBeInTheDocument();
expect(labelForColorName).not.toBeInTheDocument();
expect(labelForColorHex).not.toBeInTheDocument();
});
Loading