From c853381493c507b1ff01afca6e7f3e5a7dee735c Mon Sep 17 00:00:00 2001 From: Victor Klawitter Date: Tue, 5 Oct 2021 14:03:21 -0400 Subject: [PATCH 1/6] Added remove from closet --- Server/controllers/mainMethods.ts | 17 +++++++++++++++++ Server/package.json | 3 ++- Server/router.js | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Server/controllers/mainMethods.ts b/Server/controllers/mainMethods.ts index bfc3b79..bae4f3c 100644 --- a/Server/controllers/mainMethods.ts +++ b/Server/controllers/mainMethods.ts @@ -181,6 +181,23 @@ export async function postADQ(ctx : any) { } }; +export async function removeADQ(ctx : any) { + const body = ctx.request.body; + try{ + await db.ADQ.destroy({ + where: { + userPrimaryKey: body.UserId, + itemPrimaryKey: body.ItemId, + } + }) + ctx.status = 201; + }catch(er){ + ctx.body = er; + ctx.status = 404; + } + +} + // Follow Users Method export async function followUser(ctx:any) { diff --git a/Server/package.json b/Server/package.json index 6025c5d..696903e 100644 --- a/Server/package.json +++ b/Server/package.json @@ -31,5 +31,6 @@ "supertest": "^6.1.6", "ts-jest": "^27.0.5", "ts-node": "^10.2.1" - } + }, + "esModuleInterop": true } diff --git a/Server/router.js b/Server/router.js index 84b169f..8a3176f 100644 --- a/Server/router.js +++ b/Server/router.js @@ -24,6 +24,8 @@ router.post('/OneItem', mainMethods.getOneItem); //Done router.get('/adq', mainMethods.getADQ); // Register new adquisition router.post('/adq', mainMethods.postADQ); +//Remove a adquisition +router.delete('/adq', mainMethods.removeADQ); //Get all follows router.get('/follow', mainMethods.getFollows); // Done From c9c950c8e6161586e6fa05c7391b9c312850c8ad Mon Sep 17 00:00:00 2001 From: Victor Klawitter Date: Tue, 5 Oct 2021 14:33:49 -0400 Subject: [PATCH 2/6] Tests: Added test for deleting items from closet --- Server/index.test.ts | 13 ++++++++++++- Server/router.js | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Server/index.test.ts b/Server/index.test.ts index d32cff8..eca2f01 100644 --- a/Server/index.test.ts +++ b/Server/index.test.ts @@ -1107,7 +1107,7 @@ describe('Testing of endpoints on server', () => { request(server) .post('/follow') .send({ - currentUserId: 100, + currentUserId: 6444454848, profileUser: 2, }) .expect(404) @@ -1193,6 +1193,17 @@ describe('Testing of endpoints on server', () => { return done(); }) }) + test('DELETE /adq should remove item from closet', async () => { + const priorToAdd = await request(server).get('/adq') + await request(server).post('/adq').send({UserId: 1, ItemId: 227}) + const afterAdd = await request(server).get('/adq') + await request(server).delete('/adq').send({UserId: 1,ItemId: 227}) + const afterRemove = await request(server).get('/adq') + if(priorToAdd.body.length < afterAdd.body.length && afterAdd.body.length > afterRemove.body.length){ + expect(true).toBe(true); + }else{expect(false).toBe(true)} + + }) test('POST /logout should blacklist the session', async () => { const login = await request(server).post('/login').send({ diff --git a/Server/router.js b/Server/router.js index 8a3176f..a0d875a 100644 --- a/Server/router.js +++ b/Server/router.js @@ -21,9 +21,9 @@ router.post('/items', mainMethods.postItems); //NO LONGER NEEDED router.post('/OneItem', mainMethods.getOneItem); //Done //Get all adquisitions -router.get('/adq', mainMethods.getADQ); +router.get('/adq', mainMethods.getADQ); //done // Register new adquisition -router.post('/adq', mainMethods.postADQ); +router.post('/adq', mainMethods.postADQ); //done //Remove a adquisition router.delete('/adq', mainMethods.removeADQ); From fdfda22596d1266c051b1c8904536b49cdd98bca Mon Sep 17 00:00:00 2001 From: Sean Araujo Date: Tue, 5 Oct 2021 14:35:28 -0400 Subject: [PATCH 3/6] cypress testing for MyCloset --- .../1-getting-started/HomeDash.spec.jsx | 2 - .../1-getting-started/MyCloset.spec.js | 69 +++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 Client/client/cypress/integration/1-getting-started/MyCloset.spec.js diff --git a/Client/client/cypress/integration/1-getting-started/HomeDash.spec.jsx b/Client/client/cypress/integration/1-getting-started/HomeDash.spec.jsx index 8ac51d0..b8e43d0 100644 --- a/Client/client/cypress/integration/1-getting-started/HomeDash.spec.jsx +++ b/Client/client/cypress/integration/1-getting-started/HomeDash.spec.jsx @@ -1,5 +1,3 @@ - - describe('HomeDash Component', () => { it('Should change whats rendered when top nav links are clicked', () => { cy.visit('http://localhost:3000/'); diff --git a/Client/client/cypress/integration/1-getting-started/MyCloset.spec.js b/Client/client/cypress/integration/1-getting-started/MyCloset.spec.js new file mode 100644 index 0000000..4298ebc --- /dev/null +++ b/Client/client/cypress/integration/1-getting-started/MyCloset.spec.js @@ -0,0 +1,69 @@ +describe('HomeDash Component', () => { +it('Should change to MyCloset page when MyCloset button is pressed', () => { + cy.visit('http://localhost:3000/'); + + cy.get('input[name="email"]').type('test@test.com') + cy.get('input[name="password"]').type('test') + + cy.get('button[type="submit"]').click() + + cy.get('nav').within(()=> { + cy.get('h1').contains('Hi test!') + }) + + cy.get('.body').within(() => { + cy.get('.is-info').click() + }) + cy.url().should('include', 'http://localhost:3000/MyCloset') + + }) + + it('Should change whats rendered when top nav links are clicked', () => { + cy.visit('http://localhost:3000/'); + + cy.get('input[name="email"]').type('test@test.com') + cy.get('input[name="password"]').type('test') + + cy.get('button[type="submit"]').click() + + cy.get('nav').within(()=> { + cy.get('h1').contains('Hi test!') + }) + + cy.get('.body').within(() => { + cy.get('.is-info').click() + }) + + cy.get('.categories').within(()=> { + cy.get('li').click({multiple: true, force: true}) + + }) +}) + +it('Should change to ItemDetails Page when a item is clicked', () => { + cy.visit('http://localhost:3000/'); + + cy.get('input[name="email"]').type('test@test.com') + cy.get('input[name="password"]').type('test') + + cy.get('button[type="submit"]').click() + + cy.get('.body').within(() => { + cy.get('.is-info').click() + }) + + cy.get('.categories').within(()=> { + cy.get('li').click({multiple: true, force: true}) + + }) + + cy.get('.pt-2').within(()=> { + cy.get('div').within(() => { + cy.get('img').last().click() + + }) + }) + cy.url().should('include', 'http://localhost:3000/itemDetail') + +}) +}) \ No newline at end of file From fc1c3a833ff6d7a5399372ef54c906ebf520307c Mon Sep 17 00:00:00 2001 From: Sean Araujo Date: Tue, 5 Oct 2021 14:53:15 -0400 Subject: [PATCH 4/6] cypress testing for SearchResults --- .../1-getting-started/SearchResults.spec.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Client/client/cypress/integration/1-getting-started/SearchResults.spec.js diff --git a/Client/client/cypress/integration/1-getting-started/SearchResults.spec.js b/Client/client/cypress/integration/1-getting-started/SearchResults.spec.js new file mode 100644 index 0000000..ae77438 --- /dev/null +++ b/Client/client/cypress/integration/1-getting-started/SearchResults.spec.js @@ -0,0 +1,34 @@ +describe('SearchResults Component', () => { + it('Should change whats rendered when new search terms are typed', () => { + cy.visit('http://localhost:3000/'); + + cy.get('input[name="email"]').type('test@test.com') + cy.get('input[name="password"]').type('test') + + cy.get('button[type="submit"]').click() + + cy.get('.search-bar').type('test') + + cy.get('.search-follow').within(() => { + cy.get('.is-4').contains('test') + }) + }) + it('Should change screen when an item is clicked from the search results', () => { + cy.visit('http://localhost:3000/'); + + cy.get('input[name="email"]').type('test@test.com') + cy.get('input[name="password"]').type('test') + + cy.get('button[type="submit"]').click() + + cy.get('.search-bar').type('shirt') + + cy.get('.search-follow').within(() => { + cy.get('.search-item-box').within(() => { + cy.get('img').last().click({force: true}) + }) + }) + cy.url().should('include', 'http://localhost:3000/itemDetail') + +}) +}) \ No newline at end of file From 706b19cb95eae84bf2d57c02bf7293126f0ca9a4 Mon Sep 17 00:00:00 2001 From: Sean Araujo Date: Tue, 5 Oct 2021 15:02:43 -0400 Subject: [PATCH 5/6] UserCloset cypress testing --- .../1-getting-started/UserCloset.spec.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Client/client/cypress/integration/1-getting-started/UserCloset.spec.js diff --git a/Client/client/cypress/integration/1-getting-started/UserCloset.spec.js b/Client/client/cypress/integration/1-getting-started/UserCloset.spec.js new file mode 100644 index 0000000..5162d85 --- /dev/null +++ b/Client/client/cypress/integration/1-getting-started/UserCloset.spec.js @@ -0,0 +1,21 @@ +describe('UserCloset Component', () => { + it('Should change whats rendered when new search terms are typed', () => { + cy.visit('http://localhost:3000/'); + + cy.get('input[name="email"]').type('test@test.com') + cy.get('input[name="password"]').type('test') + + cy.get('button[type="submit"]').click() + + cy.get('.search-bar').type('test') + + cy.get('.search-follow').within(() => { + cy.get('.is-4').first().click({force: true}) + }) + + cy.url().should('include', 'http://localhost:3000/UserCloset/') + cy.get('.body').within(() => { + cy.get('.mt-5').contains("test's Closet") + }) + }) +}) \ No newline at end of file From ab98ca61b468bb589f6ff3dff6bff30368a45e7a Mon Sep 17 00:00:00 2001 From: Sean Araujo Date: Tue, 5 Oct 2021 16:33:05 -0400 Subject: [PATCH 6/6] Delete items from mycloset and Blacklist logout implemented --- Client/client/src/App.tsx | 3 +- Client/client/src/apiServices.tsx | 29 ++++++++++++++++++- Client/client/src/components/DeleteButton.tsx | 9 ++++++ .../src/components/MyCloset/MyCloset.tsx | 9 +++++- Client/client/src/redux/actions.tsx | 2 +- 5 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 Client/client/src/components/DeleteButton.tsx diff --git a/Client/client/src/App.tsx b/Client/client/src/App.tsx index f83be2b..eb5eff9 100644 --- a/Client/client/src/App.tsx +++ b/Client/client/src/App.tsx @@ -13,7 +13,7 @@ import UserCloset from './components/UserCloset/UserCloset'; import LoginPage from './components/LoginPage/LoginPage'; import actions from './redux/actions'; import { connect } from 'react-redux'; - +import apiService from './apiServices'; import logo from './utils/ClothierLiteCrop.png' import fetchService from './fetchService' @@ -59,6 +59,7 @@ function App({getItems, getUser, user, setSearchVal, searchVal}: props): JSX.Ele const logOut = () => { localStorage.removeItem('accessToken'); + apiService.logout(); setAuthenticated(false); } diff --git a/Client/client/src/apiServices.tsx b/Client/client/src/apiServices.tsx index cb0d0c1..b4b5860 100644 --- a/Client/client/src/apiServices.tsx +++ b/Client/client/src/apiServices.tsx @@ -27,6 +27,15 @@ async login(user:BasicUser) { .then((res) => (res.json())) .catch((err) => console.log(err)) }, +async logout() { + return fetch(`${baseURL}/logout`, { + method: 'POST', + credentials: 'include', + mode: 'cors', + }) + .then((res) => (res.json())) + .catch((err) => console.log(err)); +}, async profile (accessToken:string | number | null, tokenType:any) { return fetch(`${baseURL}/me`, { method: 'GET', @@ -112,7 +121,25 @@ async fetchOneItem (id:string) { .then(response => response.json()) .catch(err => console.log(err)); return result; -} +}, +async deleteItemFromCloset(UserId:number, ItemId:number){ + const res = fetch(baseURL + '/adq', { + method: 'DELETE', + credentials: 'include', + mode: 'cors', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + UserId, + ItemId + }) + }) + .then(response => response.json()) + .catch(err => console.log(err)); + return res; +}, + } diff --git a/Client/client/src/components/DeleteButton.tsx b/Client/client/src/components/DeleteButton.tsx new file mode 100644 index 0000000..939cdb9 --- /dev/null +++ b/Client/client/src/components/DeleteButton.tsx @@ -0,0 +1,9 @@ +import React from 'react' +import apiService from '../apiServices' +const DeleteButton = ({ user, item}:any) => { + return ( + + ) +} + +export default DeleteButton diff --git a/Client/client/src/components/MyCloset/MyCloset.tsx b/Client/client/src/components/MyCloset/MyCloset.tsx index 07778dd..6f21a2d 100644 --- a/Client/client/src/components/MyCloset/MyCloset.tsx +++ b/Client/client/src/components/MyCloset/MyCloset.tsx @@ -8,6 +8,7 @@ import '../../styles/app.css'; import fetchService from '../../fetchService'; import { User, Category } from '../../Interfaces/interfaces' import Categories from '../Categories'; +import DeleteButton from '../DeleteButton'; interface props { @@ -15,10 +16,11 @@ interface props { getUser: Function, getItems: Function searchVal: string + DeleteItemFromCloset: Function } -function MyCloset({user, getUser, getItems, searchVal}: props) : JSX.Element { +function MyCloset({user, getUser, getItems, DeleteItemFromCloset, searchVal}: props) : JSX.Element { const ADQitems = user.ADQs; const userCategories = [...new Set(user.ADQs.map((item) => item.item.category))]; const initialState = userCategories.map(category => {return {category: category, isActive: ''}}) @@ -86,6 +88,7 @@ function MyCloset({user, getUser, getItems, searchVal}: props) : JSX.Element {
n/a +
)} @@ -95,6 +98,7 @@ function MyCloset({user, getUser, getItems, searchVal}: props) : JSX.Element {
n/a +
)} @@ -104,6 +108,7 @@ function MyCloset({user, getUser, getItems, searchVal}: props) : JSX.Element {
n/a +
)} @@ -112,6 +117,7 @@ function MyCloset({user, getUser, getItems, searchVal}: props) : JSX.Element { {filteredItems.slice((quarter*3)).map(item =>
+ n/a
@@ -139,6 +145,7 @@ const mapStateToProps = ({store}:any) => { const mapDispatchToProps = (dispatch:any) => { return { + DeleteItemFromCloset: (action:any) => dispatch(action), getItems: (action:any) => dispatch(action), getUser: (action:any) => dispatch(action), }; diff --git a/Client/client/src/redux/actions.tsx b/Client/client/src/redux/actions.tsx index 40a4b0b..73d32a4 100644 --- a/Client/client/src/redux/actions.tsx +++ b/Client/client/src/redux/actions.tsx @@ -20,7 +20,7 @@ const actions = { setSelectedUser : (user:User) => ({ type: 'setSelectedUser', payload: user - }), + }) }; export default actions; \ No newline at end of file