From cc19871c5538f107e6aee802c19f07aa02a616ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tormod=20Nyg=C3=A5rd?= <tormodny@stud.ntnu.no> Date: Wed, 24 Feb 2021 12:32:36 +0100 Subject: [PATCH 1/2] Issue: Filter by category and test fixes (#27) --- .../post-details.component.spec.ts | 14 +++- .../post-form/post-form.component.spec.ts | 12 +++- .../posts/post-list/post-list.component.html | 5 ++ .../post-list/post-list.component.spec.ts | 3 +- .../posts/post-list/post-list.component.ts | 30 +++++++- client/src/app/posts/post.service.spec.ts | 71 +++++++++++++++++++ client/src/app/posts/post.service.ts | 37 +++++++++- .../user-login-form.component.spec.ts | 3 +- .../user-registration-form.component.spec.ts | 3 +- .../tests/postController.test.ts | 6 +- .../tests/userController.test.ts | 6 +- 11 files changed, 177 insertions(+), 13 deletions(-) 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 42603d5..dd08767 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 @@ -3,6 +3,8 @@ 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 { SharedModule } from 'src/app/shared/shared.module'; +import { PostListComponent } from '../post-list/post-list.component'; import { PostService } from '../post.service'; import { PostDetailsComponent } from './post-details.component'; @@ -39,7 +41,13 @@ describe('PostDetailsComponent', () => { await TestBed.configureTestingModule({ declarations: [ PostDetailsComponent ], - imports: [ HttpClientTestingModule, RouterTestingModule ], + imports: [ + HttpClientTestingModule, + SharedModule, + RouterTestingModule.withRoutes([ + { path: 'annonse', component: PostListComponent} + ]) + ], providers: [ { provide: ActivatedRoute, useValue: { snapshot: {params: {id: 5}}}}, { provide: PostService, useValue: mockPostService } @@ -60,6 +68,8 @@ describe('PostDetailsComponent', () => { it('should get post with id from url parameter', async () => { // Waits for ngOnInit and checks that we get post + expect(component.post).not.toBeNull(); + fixture.whenStable().then(() => { expect(mockPostService.getPost).toHaveBeenCalledWith(5); expect(component.post).toEqual(new Post({ @@ -77,6 +87,8 @@ describe('PostDetailsComponent', () => { it('should delete post with id', async () => { // Waits for ngOnInit and checks that we can delete post + expect(component.post).not.toBeNull(); + fixture.whenStable().then(() => { component.deletePost(); expect(mockPostService.deletePost).toHaveBeenCalledWith(5); 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 ac94cf7..b16d0c1 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 @@ -5,6 +5,7 @@ import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { Category } from 'src/app/models/category.model'; import { SharedModule } from 'src/app/shared/shared.module'; +import { PostListComponent } from '../post-list/post-list.component'; import { PostService } from '../post.service'; import { PostFormComponent } from './post-form.component'; @@ -39,7 +40,14 @@ describe('PostFormComponent', () => { await TestBed.configureTestingModule({ declarations: [ PostFormComponent ], - imports: [ HttpClientTestingModule, RouterTestingModule, FormsModule, SharedModule ], + imports: [ + HttpClientTestingModule, + FormsModule, + SharedModule, + RouterTestingModule.withRoutes([ + { path: 'annonse', component: PostListComponent} + ]) + ], providers: [ { provide: PostService, useValue: mockPostService } ] }) .compileComponents(); @@ -118,6 +126,7 @@ describe('PostFormComponent', () => { it('should delete post with id', async () => { component.id = 5; + expect(component.id).toBe(5); // Waits for ngOnInit and checks that we can delete post fixture.whenStable().then(() => { @@ -128,6 +137,7 @@ describe('PostFormComponent', () => { it('should not delete new post', async () => { // Waits for ngOnInit and checks that we can delete post + expect(component.id).toBe(0); fixture.whenStable().then(() => { component.deletePost(); expect(mockPostService.deletePost).not.toHaveBeenCalledWith(5); diff --git a/client/src/app/posts/post-list/post-list.component.html b/client/src/app/posts/post-list/post-list.component.html index 49aa9a1..728cdee 100644 --- a/client/src/app/posts/post-list/post-list.component.html +++ b/client/src/app/posts/post-list/post-list.component.html @@ -1,3 +1,8 @@ <div> + <app-select [(inputModel)]="selectedCategory" (change)="filterCategory()"> + <option value="0" selected>Ingen kategori</option> + <option *ngFor="let category of categories" [value]="category.getCategoryId">{{category.getName}}</option> + </app-select> + <app-post-thumbnail *ngFor="let post of allPosts" [post]="post"></app-post-thumbnail> </div> 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 464c09f..c7ac545 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,5 +1,6 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { SharedModule } from 'src/app/shared/shared.module'; import { PostListComponent } from './post-list.component'; @@ -10,7 +11,7 @@ describe('PostListComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ PostListComponent ], - imports: [ HttpClientTestingModule ] + imports: [ HttpClientTestingModule, SharedModule ] }) .compileComponents(); }); diff --git a/client/src/app/posts/post-list/post-list.component.ts b/client/src/app/posts/post-list/post-list.component.ts index 2bd3302..3910d07 100644 --- a/client/src/app/posts/post-list/post-list.component.ts +++ b/client/src/app/posts/post-list/post-list.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit } from '@angular/core'; +import { Category } from 'src/app/models/category.model'; import { Post } from 'src/app/models/post.model'; import { PostService } from '../post.service'; @@ -9,11 +10,25 @@ import { PostService } from '../post.service'; }) export class PostListComponent implements OnInit { - allPosts: Array<Post> = [] + allPosts: Array<Post> = []; + categories: Array<Category> = []; + + selectedCategory: number; constructor(private postService: PostService) { } ngOnInit(): void { + // Gets all categories from database and displays them in dropdown + this.postService.getAllCategories().then(categories => { + this.categories = categories; + }).catch(error => { + console.log(error); + }); + + this.getPosts(); + } + + getPosts() { // Gets all posts from database, and displays them this.postService.getAllPosts().then(posts => { this.allPosts = posts; @@ -22,4 +37,17 @@ export class PostListComponent implements OnInit { }); } + filterCategory() { + if (this.selectedCategory > 0) { + // Gets all posts by selected category + this.postService.getPostsByCategory(this.selectedCategory).then(posts => { + this.allPosts = posts; + }).catch(error => { + console.log(error); + }); + } else { + this.getPosts(); + } + } + } diff --git a/client/src/app/posts/post.service.spec.ts b/client/src/app/posts/post.service.spec.ts index eaf3678..5242cf4 100644 --- a/client/src/app/posts/post.service.spec.ts +++ b/client/src/app/posts/post.service.spec.ts @@ -260,5 +260,76 @@ describe('PostService', () => { req.error(new ErrorEvent("400")); }); }); + + describe('getPostsByCategory', () => { + it('should get posts by category', () => { + // Gets posts by category and checks values + service.getPostsByCategory(2).then(posts => { + for (let i = 0; i < posts.length; i++) { + expect(posts[i].getId).toBe(i + 1); + expect(posts[i].getTitle).toBe("Test" + (i + 1)); + expect(posts[i].getCategory).toBe(2); + } + }).catch(error => { + fail(); + }); + + // Mocks and checks HTTP request + const req = httpMock.expectOne("api/post/?categoryid=2"); + expect(req.request.method).toBe("GET"); + req.flush({ + data: [{ + id: 1, + title: "Test1", + description: "TestDescription", + timestamp: 23947298234, + owner: "user", + imageUrl: null, + price: 49, + categoryid: 2 + }, { + id: 2, + title: "Test2", + description: "TestDescription", + timestamp: 23453246527, + owner: "user", + imageUrl: null, + price: 159, + categoryid: 2 + }] + }); + }); + + it('should reject on invalid post', () => { + // Gets invalid post, should go to catch + service.getPostsByCategory(52).then(posts => { + fail(); + }).catch(error => {}); + + // Mocks and checks HTTP request + const req = httpMock.expectOne("api/post/?categoryid=52"); + expect(req.request.method).toBe("GET"); + req.flush({ + data: [{ + id: 0, + title: "Test", + description: "TestDescription", + timestamp: 23947298 + }] + }); + }); + + it('should reject on http error', () => { + // Gets HTTP error instead of post, should catch + service.getPostsByCategory(35).then(post => { + fail(); + }).catch(error => {}); + + // Mocks and checks HTTP request + const req = httpMock.expectOne("api/post/?categoryid=35"); + expect(req.request.method).toBe("GET"); + req.error(new ErrorEvent("400")); + }); + }); }); diff --git a/client/src/app/posts/post.service.ts b/client/src/app/posts/post.service.ts index 3a09b53..be13c64 100644 --- a/client/src/app/posts/post.service.ts +++ b/client/src/app/posts/post.service.ts @@ -27,7 +27,7 @@ export class PostService { for (let post of data.data) { outputPosts.push(new Post(post)); - if (post.getId == 0) { + if (!post.id || post.id == 0) { reject("Could not deserialize Post"); return; } @@ -196,5 +196,40 @@ export class PostService { private update_post(id: number, post: Post) { return this.http.put(this.postUrl + id, post.serialize()); + } + + /** + * Get all posts in database by specified category. + */ + getPostsByCategory(categoryId: number): Promise<Array<Post>> { + return new Promise<Array<Post>>( + (resolve, reject) => { + this.get_posts_by_category(categoryId).subscribe((data: any) => { + try { + let outputPosts = []; + for (let post of data.data) { + outputPosts.push(new Post(post)); + + if (!post.id || post.id == 0) { + reject("Could not deserialize Post"); + return; + } + } + + resolve(outputPosts); + } catch (err: any) { + reject(err); + } + }, + (err: any) => { + console.log(err.message); + reject(err); + }); + } + ); + } + + private get_posts_by_category(categoryId: number) { + return this.http.get(this.postUrl, {params: {categoryid: String(categoryId)}}); } } diff --git a/client/src/app/users/user-login-form/user-login-form.component.spec.ts b/client/src/app/users/user-login-form/user-login-form.component.spec.ts index e680f03..0371849 100644 --- a/client/src/app/users/user-login-form/user-login-form.component.spec.ts +++ b/client/src/app/users/user-login-form/user-login-form.component.spec.ts @@ -1,6 +1,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; +import { SharedModule } from 'src/app/shared/shared.module'; import { UserLoginFormComponent } from './user-login-form.component'; @@ -11,7 +12,7 @@ describe('UserLoginFormComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ UserLoginFormComponent ], - imports: [ HttpClientTestingModule, RouterTestingModule ] + imports: [ HttpClientTestingModule, RouterTestingModule, SharedModule ] }) .compileComponents(); }); diff --git a/client/src/app/users/user-registration-form/user-registration-form.component.spec.ts b/client/src/app/users/user-registration-form/user-registration-form.component.spec.ts index cc0d628..fba63e1 100644 --- a/client/src/app/users/user-registration-form/user-registration-form.component.spec.ts +++ b/client/src/app/users/user-registration-form/user-registration-form.component.spec.ts @@ -1,6 +1,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; +import { SharedModule } from 'src/app/shared/shared.module'; import { UserRegistrationFormComponent } from './user-registration-form.component'; @@ -11,7 +12,7 @@ describe('UserRegistrationFormComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ UserRegistrationFormComponent ], - imports: [ HttpClientTestingModule, RouterTestingModule ] + imports: [ HttpClientTestingModule, RouterTestingModule, SharedModule ] }) .compileComponents(); }); diff --git a/server/src/controllers/postController/tests/postController.test.ts b/server/src/controllers/postController/tests/postController.test.ts index 265b2c0..c54df53 100644 --- a/server/src/controllers/postController/tests/postController.test.ts +++ b/server/src/controllers/postController/tests/postController.test.ts @@ -22,14 +22,14 @@ describe("Test postController", () => { const result = await request(app).get("/api/post/1").send(); expect(result.status).toBe(200); - expect(result.body.data[0]?.title).toBe("test"); + expect(result.body.data[0]?.title).toBe("Skrik"); }); - it('Request /api/post/?categoryid=1 should return datas with categoryname = "Antikviteter og Kunst"', async () => { + it('Request /api/post/?categoryid=1 should return datas with categoryid = 1', async () => { const result = await request(app).get("/api/post/1").send(); expect(result.status).toBe(200); - expect(result.body.data[0]?.name).toBe("Antikviteter og Kunst"); + expect(result.body.data[0]?.categoryid).toBe(1); }); }); diff --git a/server/src/controllers/userController/tests/userController.test.ts b/server/src/controllers/userController/tests/userController.test.ts index 000014a..a2bed03 100644 --- a/server/src/controllers/userController/tests/userController.test.ts +++ b/server/src/controllers/userController/tests/userController.test.ts @@ -10,7 +10,7 @@ describe('Test userController', () => { console.log("...Test ending"); }); - it('Request /api/category should return request of 200!', async () => { + it('Request /api/user should return request of 200!', async () => { const result = await request(app) .get('/api/user') .send() @@ -18,8 +18,8 @@ describe('Test userController', () => { expect(result.status).toBe(200); }); - it('Request /api/category/1 should return data with name "zorg"!', async () => { - const result = await request(app).get('/api/user/1').send(); + it('Request /api/user/1 should return data with name "zorg"!', async () => { + const result = await request(app).get('/api/user').send(); expect(result.status).toBe(200); expect(result.body.data[0]?.username).toBe('zorg'); -- GitLab From 7ce67a606401c61dbfcef0e5a93d28bac3ab6b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tormod=20Nyg=C3=A5rd?= <tormodny@stud.ntnu.no> Date: Thu, 25 Feb 2021 11:44:53 +0100 Subject: [PATCH 2/2] Issue: Added price to post-details (#27) --- .../src/app/posts/post-details/post-details.component.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 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 381d486..ba28431 100644 --- a/client/src/app/posts/post-details/post-details.component.html +++ b/client/src/app/posts/post-details/post-details.component.html @@ -1,9 +1,10 @@ -<h3>Tittel: {{post.getTitle}}</h3> +<h2>{{post.getTitle}}</h2> <img [src]="post.getImageUrl"> -<p>Beskrivelse: {{post.getDescription}}</p> +<h4>{{post.getPrice}} kr</h4> +<p>{{post.getDescription}}</p> <br> -<p>Publiseringstidspunkt: {{post.getTimestamp}}</p> +<p>Publisert: {{post.getTimestamp}}</p> <p>Eier: {{post.getOwner}}</p> <app-button text="Rediger annonse" (click)="editPost()"></app-button> -- GitLab