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