From 0290a960aefca498305f504258e4e0ca6784b591 Mon Sep 17 00:00:00 2001 From: fossx229 Date: Sun, 25 Feb 2018 16:53:49 -0600 Subject: [PATCH] Make tests for the client issue #9 --Refactor todo-list.component.spec.ts and todo-list-service.spec.ts -Kyle --- .../src/app/todos/todo-list.component.spec.ts | 159 ++++++++++++++++++ .../src/app/todos/todo-list.service.spec.ts | 103 ++++++++++++ client/src/app/todos/todo-list.service.ts | 2 +- .../java/umm3601/todo/TodoRequestHandler.java | 4 +- 4 files changed, 265 insertions(+), 3 deletions(-) create mode 100644 client/src/app/todos/todo-list.component.spec.ts create mode 100644 client/src/app/todos/todo-list.service.spec.ts diff --git a/client/src/app/todos/todo-list.component.spec.ts b/client/src/app/todos/todo-list.component.spec.ts new file mode 100644 index 0000000..2352e04 --- /dev/null +++ b/client/src/app/todos/todo-list.component.spec.ts @@ -0,0 +1,159 @@ +import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {Todo} from './todo'; +import {TodoListComponent} from './todo-list.component'; +import {TodoListService} from './todo-list.service'; +import {Observable} from 'rxjs'; +import {FormsModule} from '@angular/forms'; +import {CustomModule} from '../custom.module'; +import {MATERIAL_COMPATIBILITY_MODE} from '@angular/material'; + + + +describe('Todo list', () => { + + let todoList: TodoListComponent; + let fixture: ComponentFixture; + + let todoListServiceStub: { + getTodos: () => Observable + }; + + beforeEach(() => { + // stub UserService for test purposes + todoListServiceStub = { + getTodos: () => Observable.of([ + { + _id: 'Blanche_id', + owner: 'Blanche', + status: 'false', + body: 'Nisi eiusmod aliqua velit quis occaecat excepteur.', + category: 'homework' + }, + { + _id: 'Workman_id', + owner: 'Workman', + status: 'false', + body: 'In sunt ex non tempor cillum commodo amet incididunt anim qui commodo quis. Cillum non labore ex sint esse.', + category: 'homework' + }, + { + _id: 'Fry_id', + owner: 'Fry', + status: 'true', + body: 'Laborum incididunt nisi eiusmod aliquaut in ad. Commodo adipisicing sin.', + category: 'video games' + } + ]) + }; + + TestBed.configureTestingModule({ + imports: [CustomModule], + declarations: [TodoListComponent], + // providers: [ UserListService ] // NO! Don't provide the real service! + // Provide a test-double instead + providers: [{provide: TodoListService, useValue: todoListServiceStub}, + {provide: MATERIAL_COMPATIBILITY_MODE, useValue: true}] + }); + }); + + beforeEach(async(() => { + TestBed.compileComponents().then(() => { + fixture = TestBed.createComponent(TodoListComponent); + todoList = fixture.componentInstance; + fixture.detectChanges(); + }); + })); + + it('contains all the users', () => { + expect(todoList.todos.length).toBe(3); + }); + + it('contains a todo with an owner named "Fry"', () => { + expect(todoList.todos.some((todo: Todo) => todo.owner === 'Fry')).toBe(true); + }); + + it('contains a todo with an owner named "Workman"', () => { + expect(todoList.todos.some((todo: Todo) => todo.owner === 'Workman')).toBe(true); + }); + + it("doesn't contain a todo with an owner named 'Santa'", () => { + expect(todoList.todos.some((todo: Todo) => todo.owner === 'Santa')).toBe(false); + }); + + it("has two todos that have a catergory called 'homework'", () => { + expect(todoList.todos.filter((todo: Todo) => todo.category === 'homework').length).toBe(2); + }); + + it("todo list filters by owner", () => { + expect(todoList.filteredTodos.length).toBe(3); + todoList.todoOwner = "a"; + let a : Observable = todoList.refreshTodos(); + a.do(x => Observable.of(x)) + .subscribe(x => + { + expect(todoList.filteredTodos.length).toBe(2); + }); + }); + + it('Todolist filters by category', () => { + expect(todoList.filteredTodos.length).toBe(3); + todoList.todoCategory = 'homework'; + let a : Observable = todoList.refreshTodos(); + a.do(x => Observable.of(x)) + .subscribe(x => + { + expect(todoList.filteredTodos.length).toBe(2); + }); + }); + + it('todo list filters by owner and category', () => { + expect(todoList.filteredTodos.length).toBe(3); + todoList.todoCategory = 'homework'; + todoList.todoOwner = 'Blanche'; + let a : Observable = todoList.refreshTodos(); + a.do(x => Observable.of(x)) + .subscribe(x => + { + expect(todoList.filteredTodos.length).toBe(1); + }); + }); + +}); + +describe("Misbehaving Todo List", () => { + let todoList: TodoListComponent; + let fixture: ComponentFixture; + + let todoListServiceStub: { + getTodos: () => Observable + }; + + beforeEach(() => { + // stub UserService for test purposes + todoListServiceStub = { + getTodos: () => Observable.create(observer => { + observer.error("Error-prone observable"); + }) + }; + + TestBed.configureTestingModule({ + imports: [FormsModule, CustomModule], + declarations: [TodoListComponent], + providers: [{provide: TodoListService, useValue: todoListServiceStub}, + {provide: MATERIAL_COMPATIBILITY_MODE, useValue: true}] + }) + }); + + beforeEach(async(() => { + TestBed.compileComponents().then(() => { + fixture = TestBed.createComponent(TodoListComponent); + todoList = fixture.componentInstance; + fixture.detectChanges(); + }); + })); + + it("generates an error if we don't set up a UserListService", () => { + // Since the observer throws an error, we don't expect users to be defined. + expect(todoList.todos).toBeUndefined(); + }); +}); diff --git a/client/src/app/todos/todo-list.service.spec.ts b/client/src/app/todos/todo-list.service.spec.ts new file mode 100644 index 0000000..6b007e6 --- /dev/null +++ b/client/src/app/todos/todo-list.service.spec.ts @@ -0,0 +1,103 @@ +import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; +import {TestBed} from '@angular/core/testing'; +import {HttpClient} from '@angular/common/http'; + +import {Todo} from './todo'; +import {TodoListService} from './todo-list.service'; + +describe('Todo list service: ', () => { + // A small collection of test todos + const testTodos: Todo[] = [ + { + _id: 'Blanche_id', + owner: 'Blanche', + status: 'false', + body: 'Nisi eiusmod aliqua velit quis occaecat excepteur.', + category: 'homework' + }, + { + _id: 'Workman_id', + owner: 'Workman', + status: 'false', + body: 'In sunt ex non tempor cillum commodo amet incididunt anim qui commodo quis. Cillum non labore ex sint esse.', + category: 'homework' + }, + { + _id: 'Fry_id', + owner: 'Fry', + status: 'true', + body: 'Laborum incididunt nisi eiusmod aliquaut in ad. Commodo adipisicing sin.', + category: 'video games' + } + ]; + const mTodos: Todo[] = testTodos.filter(todo => + todo.category.toLowerCase().indexOf('m') !== -1 + ); + let todoListService: TodoListService; + // These are used to mock the HTTP requests so that we (a) don't have to + // have the server running and (b) we can check exactly which HTTP + // requests were made to ensure that we're making the correct requests. + let httpClient: HttpClient; + let httpTestingController: HttpTestingController; + + beforeEach(() => { + // Set up the mock handling of the HTTP requests + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] + }); + httpClient = TestBed.get(HttpClient); + httpTestingController = TestBed.get(HttpTestingController); + // Construct an instance of the service with the mock + // HTTP client. + todoListService = new TodoListService(httpClient); + }); + + afterEach(() => { + // After every test, assert that there are no more pending requests. + httpTestingController.verify(); + }); + + it('getTodos() calls api/todos', () => { + // Assert that the todos we get from this call to getTodos() + // should be our set of test Todos. Because we're subscribing + // to the result of getTodos(), this won't actually get + // checked until the mocked HTTP request "returns" a response. + // This happens when we call req.flush(testTodos) a few lines + // down. + todoListService.getTodos().subscribe( + todos => expect(todos).toBe(testTodos) + ); + + // Specify that (exactly) one request will be made to the specified URL. + const req = httpTestingController.expectOne(todoListService.baseUrl); + // Check that the request made to that URL was a GET request. + expect(req.request.method).toEqual('GET'); + // Specify the content of the response to that request. This + // triggers the subscribe above, which leads to that check + // actually being performed. + req.flush(testTodos); + }); + + it('getTodos(todoCategory) adds appropriate param string to called URL', () => { + todoListService.getTodos("m").subscribe( + todos => expect(todos).toEqual(mTodos) + ); + + const req = httpTestingController.expectOne(todoListService.baseUrl + '?category=m&'); + expect(req.request.method).toEqual('GET'); + req.flush(mTodos); + }); + + it('getTodoById() calls api/todos/id', () => { + const targetTodo: Todo = testTodos[1]; + const targetId: string = targetTodo._id; + todoListService.getTodoById(targetId).subscribe( + todo => expect(todo).toBe(targetTodo) + ); + + const expectedUrl: string = todoListService.baseUrl + '/' + targetId; + const req = httpTestingController.expectOne(expectedUrl); + expect(req.request.method).toEqual('GET'); + req.flush(targetTodo); + }); +}); diff --git a/client/src/app/todos/todo-list.service.ts b/client/src/app/todos/todo-list.service.ts index 07f7fe0..a980b9a 100644 --- a/client/src/app/todos/todo-list.service.ts +++ b/client/src/app/todos/todo-list.service.ts @@ -9,7 +9,7 @@ import {environment} from "../../environments/environment"; @Injectable() export class TodoListService { - readonly baseUrl: string = environment.API_URL + "todos"; + readonly baseUrl: string = environment.API_URL + 'todos'; private todoUrl: string = this.baseUrl; constructor(private http: HttpClient) { diff --git a/server/src/main/java/umm3601/todo/TodoRequestHandler.java b/server/src/main/java/umm3601/todo/TodoRequestHandler.java index aeb4862..c2b419f 100644 --- a/server/src/main/java/umm3601/todo/TodoRequestHandler.java +++ b/server/src/main/java/umm3601/todo/TodoRequestHandler.java @@ -51,12 +51,12 @@ public String getTodoJSON(Request req, Response res) { - /**Method called from Server when the 'api/users' endpoint is received. + /**Method called from Server when the 'api/todos' endpoint is received. * This handles the request received and the response * that will be sent back. *@param req the HTTP request * @param res the HTTP response - * @return an array of users in JSON formatted String + * @return an array of todos in JSON formatted String */ public String getTodos(Request req, Response res) {