From 5851c2d6cc91197cde08ec54665b41d6297264ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tormod=20Nyg=C3=A5rd?= <tormodny@stud.ntnu.no> Date: Thu, 18 Feb 2021 14:40:27 +0100 Subject: [PATCH] Issue: Post can be deleted (#10) --- .../post-details/post-details.component.html | 2 + .../post-details.component.spec.ts | 62 ++++++++++++++++++- .../post-details/post-details.component.ts | 28 ++++++--- .../post-form/post-form.component.spec.ts | 2 +- .../post-list/post-list.component.spec.ts | 4 +- .../post-thumbnail.component.spec.ts | 4 +- client/src/app/posts/post.service.spec.ts | 32 ++++++++++ client/src/app/posts/post.service.ts | 25 ++++++++ .../src/controllers/postController/index.ts | 8 +-- 9 files changed, 149 insertions(+), 18 deletions(-) diff --git a/client/src/app/posts/post-details/post-details.component.html b/client/src/app/posts/post-details/post-details.component.html index 82d2c97..2a00591 100644 --- a/client/src/app/posts/post-details/post-details.component.html +++ b/client/src/app/posts/post-details/post-details.component.html @@ -5,3 +5,5 @@ <br> <p>Publiseringstidspunkt: {{post.getTimestamp}}</p> <p>Eier: {{post.getOwner}}</p> + +<app-button text="Slett annonse" (click)="deletePost()"></app-button> diff --git a/client/src/app/posts/post-details/post-details.component.spec.ts b/client/src/app/posts/post-details/post-details.component.spec.ts index 90f92b9..42603d5 100644 --- a/client/src/app/posts/post-details/post-details.component.spec.ts +++ b/client/src/app/posts/post-details/post-details.component.spec.ts @@ -1,14 +1,49 @@ +import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { Post } from 'src/app/models/post.model'; +import { PostService } from '../post.service'; import { PostDetailsComponent } from './post-details.component'; describe('PostDetailsComponent', () => { let component: PostDetailsComponent; let fixture: ComponentFixture<PostDetailsComponent>; + let mockPostService; beforeEach(async () => { + // PostService mock setup + mockPostService = jasmine.createSpyObj(['getPost', 'deletePost']); + mockPostService.getPost.and.returnValue( + new Promise<Post>( + (resolve) => { + resolve(new Post({ + id: 5, + title: "Test", + description: "TestDescription", + timestamp: 23947298, + owner: "user", + imageUrl: null, + price: 49, + categoryid: 2 + })); + }) + ); + mockPostService.deletePost.and.returnValue( + new Promise<any>( + (resolve) => { + resolve({data: []}) + }) + ); + await TestBed.configureTestingModule({ - declarations: [ PostDetailsComponent ] + declarations: [ PostDetailsComponent ], + imports: [ HttpClientTestingModule, RouterTestingModule ], + providers: [ + { provide: ActivatedRoute, useValue: { snapshot: {params: {id: 5}}}}, + { provide: PostService, useValue: mockPostService } + ] }) .compileComponents(); }); @@ -22,4 +57,29 @@ describe('PostDetailsComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + it('should get post with id from url parameter', async () => { + // Waits for ngOnInit and checks that we get post + fixture.whenStable().then(() => { + expect(mockPostService.getPost).toHaveBeenCalledWith(5); + expect(component.post).toEqual(new Post({ + id: 5, + title: "Test", + description: "TestDescription", + timestamp: 23947298, + owner: "user", + imageUrl: null, + price: 49, + categoryid: 2 + })); + }); + }); + + it('should delete post with id', async () => { + // Waits for ngOnInit and checks that we can delete post + fixture.whenStable().then(() => { + component.deletePost(); + expect(mockPostService.deletePost).toHaveBeenCalledWith(5); + }); + }); }); diff --git a/client/src/app/posts/post-details/post-details.component.ts b/client/src/app/posts/post-details/post-details.component.ts index 72dd9a8..e8517a7 100644 --- a/client/src/app/posts/post-details/post-details.component.ts +++ b/client/src/app/posts/post-details/post-details.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { Post } from 'src/app/models/post.model'; import { PostService } from '../post.service'; -import { ActivatedRoute } from '@angular/router' +import { ActivatedRoute, Router } from '@angular/router' @Component({ selector: 'app-post-details', @@ -12,19 +12,27 @@ export class PostDetailsComponent implements OnInit { post: Post = new Post(); - constructor(private postService: PostService, private activatedRoute: ActivatedRoute) { } + constructor(private postService: PostService, private activatedRoute: ActivatedRoute, private router: Router) { } ngOnInit(): void { // Gets id parameter from URL - this.activatedRoute.params.subscribe(params => { - const id = params["id"]; + const id = this.activatedRoute.snapshot.params["id"]; - // Gets Post with id from database - this.postService.getPost(id).then(post => { - this.post = post; - }).catch(error => { - console.log(error); - }); + // Gets Post with id from database + this.postService.getPost(id).then(post => { + this.post = post; + }).catch(error => { + console.log(error); + }); + } + + deletePost() { + // Deletes post in database and navigates to post list + this.postService.deletePost(this.post.getId).then(data => { + console.log("Successfully deleted post: " + this.post.getId); + this.router.navigateByUrl("/annonse"); + }).catch(error => { + console.log(error); }); } } diff --git a/client/src/app/posts/post-form/post-form.component.spec.ts b/client/src/app/posts/post-form/post-form.component.spec.ts index 31c4d5b..355179e 100644 --- a/client/src/app/posts/post-form/post-form.component.spec.ts +++ b/client/src/app/posts/post-form/post-form.component.spec.ts @@ -1,5 +1,5 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; diff --git a/client/src/app/posts/post-list/post-list.component.spec.ts b/client/src/app/posts/post-list/post-list.component.spec.ts index 2d39c24..464c09f 100644 --- a/client/src/app/posts/post-list/post-list.component.spec.ts +++ b/client/src/app/posts/post-list/post-list.component.spec.ts @@ -1,3 +1,4 @@ +import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PostListComponent } from './post-list.component'; @@ -8,7 +9,8 @@ describe('PostListComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ PostListComponent ] + declarations: [ PostListComponent ], + imports: [ HttpClientTestingModule ] }) .compileComponents(); }); diff --git a/client/src/app/posts/post-thumbnail/post-thumbnail.component.spec.ts b/client/src/app/posts/post-thumbnail/post-thumbnail.component.spec.ts index ea7282d..04d5c00 100644 --- a/client/src/app/posts/post-thumbnail/post-thumbnail.component.spec.ts +++ b/client/src/app/posts/post-thumbnail/post-thumbnail.component.spec.ts @@ -1,4 +1,5 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; import { PostThumbnailComponent } from './post-thumbnail.component'; @@ -8,7 +9,8 @@ describe('PostThumbnailComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ PostThumbnailComponent ] + declarations: [ PostThumbnailComponent ], + imports: [ RouterTestingModule ] }) .compileComponents(); }); diff --git a/client/src/app/posts/post.service.spec.ts b/client/src/app/posts/post.service.spec.ts index 0439fbe..144bdc0 100644 --- a/client/src/app/posts/post.service.spec.ts +++ b/client/src/app/posts/post.service.spec.ts @@ -176,5 +176,37 @@ describe('PostService', () => { req.error(new ErrorEvent("400")); }); }); + + describe('deletePost', () => { + it('should delete post', () => { + + // Deletes post with id = 2 + service.deletePost(2) + .then(data => {}) + .catch(error => { + fail(); + }); + + // Mocks and checks HTTP request + const req = httpMock.expectOne("api/post/2"); + expect(req.request.method).toBe("DELETE"); + req.flush({ + data: [] + }); + }); + + it('should reject on http error', () => { + + // Deletes post with id = 5, should catch HTTP error + service.deletePost(5).then(data => { + fail(); + }).catch(error => {}); + + // Mocks and checks HTTP request + const req = httpMock.expectOne("api/post/5"); + expect(req.request.method).toBe("DELETE"); + req.error(new ErrorEvent("400")); + }); + }); }); diff --git a/client/src/app/posts/post.service.ts b/client/src/app/posts/post.service.ts index e289495..0ef4e10 100644 --- a/client/src/app/posts/post.service.ts +++ b/client/src/app/posts/post.service.ts @@ -138,4 +138,29 @@ export class PostService { private get_all_categories() { return this.http.get(this.categoryUrl); } + + /** + * Delete post in database by id. + */ + deletePost(id: number): Promise<any> { + return new Promise<any>( + (resolve, reject) => { + this.delete_post(id).subscribe((data: any) => { + try { + resolve(data); + } catch (err: any) { + reject(err); + } + }, + (err: any) => { + console.log(err.message); + reject(err); + }); + } + ); + } + + private delete_post(id: number) { + return this.http.delete(this.postUrl + id); + } } diff --git a/server/src/controllers/postController/index.ts b/server/src/controllers/postController/index.ts index ed5a95f..f9c4eb3 100644 --- a/server/src/controllers/postController/index.ts +++ b/server/src/controllers/postController/index.ts @@ -16,7 +16,7 @@ router.route("/").post(async (request: Request, response: Response) => { description, timestamp, owner, - category, + categoryid, imageUrl, } = request.body; try { @@ -25,12 +25,12 @@ router.route("/").post(async (request: Request, response: Response) => { description: description, timestamp: timestamp, owner: owner, - category: category, + categoryid: categoryid, imageUrl: imageUrl, }; if (Object.values(post).filter((p) => p == undefined).length > 0) return response.status(500).send("Error"); - const input = `INSERT INTO post(title, description, timestamp, owner, category, imageUrl) VALUES (?,?,?,?,?,?)`; + const input = `INSERT INTO post(title, description, timestamp, owner, categoryid, imageUrl) VALUES (?,?,?,?,?,?)`; return response.status(200).json(await query(input, Object.values(post))); } catch (error) { return response.status(400).send("Bad Request"); @@ -85,7 +85,7 @@ router.route("/:id").delete(async (request: Request, response: Response) => { try { response .status(200) - .json(await query("SELECT * FROM post WHERE id=?;", [postId])); + .json(await query("DELETE FROM post WHERE id=?;", [postId])); } catch (error) { response.status(400).send("Bad Request"); } -- GitLab