Skip to content

Commit

Permalink
feat: add provider data conversion from document to entity and test i…
Browse files Browse the repository at this point in the history
…n-memory gateway
  • Loading branch information
alexx666 committed Apr 15, 2021
1 parent 6d69468 commit 4771d28
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 31 deletions.
4 changes: 2 additions & 2 deletions src/api/routers/todos/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Router } from "express";

// Gatway Implementations
import InMemoryTodoGateway from "../../../providers/todo-in-memory.gateway";
import V4UuidGenerator from "../../../providers/v4-uuid";
import InMemoryTodoGateway from "../../../providers/todo-in-memory/todo-in-memory.gateway";
import V4UuidGenerator from "../../../providers/uuid/v4-uuid";

// Use Case Implementations
import CreateTodoImpl from "../../../modules/todos/impl/create-todo.impl";
Expand Down
4 changes: 2 additions & 2 deletions src/cli/commands/todos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import DeleteTodoImpl from "../../../modules/todos/impl/delete-todo.impl";
import ListTodosImpl from "../../../modules/todos/impl/list-todos.impl";

// Providers
import RestTodoGateway from "../../../providers/todo-http.gateway";
import V4UuidGenerator from "../../../providers/v4-uuid";
import RestTodoGateway from "../../../providers/todo-http/todo-http.gateway";
import V4UuidGenerator from "../../../providers/uuid/v4-uuid";

// Subcommands
import listCmd from "./list-todos";
Expand Down
2 changes: 1 addition & 1 deletion src/modules/todos/entities/todo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe("[Todo] Test Cases", () => {
}
})

it("should throw en error because of a missing ID", () => {
it("should throw en error because of a missing Description", () => {
try {
const _ = new Todo("id", notDefined, new Date())
} catch (error) {
Expand Down
5 changes: 2 additions & 3 deletions src/modules/todos/impl/create-todo.impl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,14 @@ describe("[CreateTodo] Success Cases", () => {
const createTodo: CreateTodoImpl = new CreateTodoImpl(mockSuccessGateway, mockUUIDGenerator);

it("should return a the mocked todo in a valid CreateTodoResponse object", async () => {
expect.assertions(1);

const insufficientRequest: any = { ...request };

delete insufficientRequest.id

const response = await createTodo.execute(insufficientRequest)

expect(response).toEqual({ ...insufficientRequest, id: "generatedId" });
expect.assertions(1);
})
})

Expand All @@ -44,11 +43,11 @@ describe("[CreateTodo] Fail Cases", () => {
const createTodo: CreateTodoImpl = new CreateTodoImpl(mockFailureGateway, mockUUIDGenerator);

it("should return throw an error with the gateways message", async () => {
expect.assertions(1);
try {
await createTodo.execute(request)
} catch (error) {
expect(error.message).toEqual(errorMessage)
expect.assertions(1);
}
})
})
4 changes: 2 additions & 2 deletions src/modules/todos/impl/delete-todo.impl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ describe("[DeleteTodo] Success Cases", () => {
const deleteTodo: DeleteTodoImpl = new DeleteTodoImpl(mockSuccessGateway);

it("should return a the mocked todo in a valid DeleteTodoResponse object", async () => {
expect.assertions(1);

const result = await deleteTodo.execute({ id: randomId })

expect(result).toEqual({ item: todo });
expect.assertions(1);
})
})

Expand All @@ -36,11 +36,11 @@ describe("[DeleteTodo] Fail Cases", () => {
const deleteTodo: DeleteTodoImpl = new DeleteTodoImpl(mockFailureGateway);

it("should return throw an error with the gateways message", async () => {
expect.assertions(1);
try {
await deleteTodo.execute({ id: randomId })
} catch (error) {
expect(error.message).toEqual(errorMessage)
expect.assertions(1);
}
})
})
5 changes: 2 additions & 3 deletions src/modules/todos/impl/list-todos.impl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ describe("[ListTodos] Success Cases", () => {
const listTodos: ListTodosImpl = new ListTodosImpl(mockSuccessGateway);

it("should return a the mocked todo in a valid ListTodosResponse object", async () => {
expect.assertions(1);

const result = await listTodos.execute(request)

expect(result).toEqual({ items: [todo], count: 1 });
expect.assertions(1);
})
})

Expand All @@ -35,11 +34,11 @@ describe("[ListTodos] Fail Cases", () => {
const listTodos: ListTodosImpl = new ListTodosImpl(mockFailureGateway);

it("should return throw an error with the gateways message", async () => {
expect.assertions(1);
try {
await listTodos.execute(request)
} catch (error) {
expect(error.message).toEqual(errorMessage)
expect.assertions(1);
}
})
})
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ClientRequest, IncomingMessage, RequestOptions } from "http";
import { ReadableGateway, WritableGateway } from "../modules/shared/entity.gateway";
import { Todo } from "../modules/todos/entities/todo";
import { ReadableGateway, WritableGateway } from "../../modules/shared/entity.gateway";
import { Todo } from "../../modules/todos/entities/todo";

interface RestListTodoResponse {
count: number;
Expand Down
51 changes: 51 additions & 0 deletions src/providers/todo-in-memory/todo-document.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Todo } from "../../modules/todos/entities/todo";

import TodoDocument from "./todo-document";

const notDefined: any = undefined;
const description = "description";
const todo = new Todo("id", "description", new Date())

describe("[TodoDocument] Test Cases", () => {

it("should create a document successfully", () => {
const document = new TodoDocument("description", new Date().toISOString())
expect(document).toBeDefined()
})

it("should create a document from todo successfully", () => {
const document = TodoDocument.fromTodo(todo)
expect(document.description).toEqual(description)
expect(document.due).toEqual(todo.due.toISOString())
})

it("should convert a document to todo successfully", () => {
const document = TodoDocument.fromTodo(todo)
expect(document.toEntity("id")).toEqual(todo)
})

it("should throw en error because of an undefined Todo", () => {
try {
const _ = TodoDocument.fromTodo(notDefined)
} catch (error) {
expect(error.message).toEqual("ValidationError: No todo provided!")
}
})

it("should throw en error because of a missing Description", () => {
try {
const _ = new TodoDocument(notDefined, new Date().toISOString())
} catch (error) {
expect(error.message).toEqual("ValidationError: Description not provided!")
}
})

it("should throw en error because of a missing Due date", () => {
try {
const _ = new TodoDocument("description", notDefined)
} catch (error) {
expect(error.message).toEqual("ValidationError: Due date not provided!")
}
})

})
18 changes: 18 additions & 0 deletions src/providers/todo-in-memory/todo-document.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Todo } from "../../modules/todos/entities/todo";

export default class TodoDocument {

public static fromTodo(todo: Todo): TodoDocument {
if (!todo) throw new Error("ValidationError: No todo provided!")
return new TodoDocument(todo.description, todo.due.toISOString());
}

constructor(public readonly description: string, public readonly due: string) {
if (!description) throw new Error("ValidationError: Description not provided!")
if (!due) throw new Error("ValidationError: Due date not provided!")
}

public toEntity(id: string): Todo {
return new Todo(id, this.description, new Date(this.due));
}
}
75 changes: 75 additions & 0 deletions src/providers/todo-in-memory/todo-in-memory.gateway.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Todo } from "../../modules/todos/entities/todo";
import TodoDocument from "./todo-document";
import InMemoryTodoGateway from "./todo-in-memory.gateway";

describe("[InMemoryTodoGateway] Initialization", () => {
it("should create an in memory todo gateway without any todos", async () => {
const inMemTodoGW = new InMemoryTodoGateway()
const todos = await inMemTodoGW.find({ limit: 10, skip: 0 })
expect(todos.length).toEqual(0)
expect.assertions(1)
})
})

describe("[InMemoryTodoGateway] Test Cases", () => {

let inMemTodoGW: InMemoryTodoGateway

beforeEach(() => {
const seed = new Map<string, TodoDocument>([
["1", new TodoDocument("first", new Date().toISOString())],
["2", new TodoDocument("second", new Date().toISOString())],
["3", new TodoDocument("third", new Date().toISOString())],
])

inMemTodoGW = new InMemoryTodoGateway(seed);
})

it("should return all items in map as todos", async () => {
const todos = await inMemTodoGW.find({ limit: 10, skip: 0 })
expect(todos.length).toEqual(3)
expect.assertions(1)
})

it("should return second todo", async () => {
expect.assertions(2)
const todos = await inMemTodoGW.find({ limit: 1, skip: 1 })
expect(todos.length).toEqual(1)
expect(todos[0].id).toEqual("2")
})

it("should add a new todo and return it", async () => {
const todo = await inMemTodoGW.save(new Todo("4", "forth", new Date()));
const todos = await inMemTodoGW.find({ limit: 1, skip: 3 })
expect(todos.length).toEqual(1)
expect(todos[0]).toEqual(todo)
expect.assertions(2)
})

it("should throw an error because the todo already exist", async () => {
try {
const _ = await inMemTodoGW.save(new Todo("1", "description", new Date()));
} catch (error) {
expect(error.message).toEqual("Todo already exists!");
expect.assertions(1)
}
})

it("should remove a todo and return its value", async () => {
const todo = await inMemTodoGW.delete("3");
const todos = await inMemTodoGW.find({ limit: 10, skip: 0 })
expect(todos).not.toContain(todo)
expect(todos.length).toEqual(2)
expect.assertions(2)
})

it("should throw an error because the todo does not exist", async () => {
try {
const _ = await inMemTodoGW.delete("4");
} catch (error) {
expect(error.message).toEqual("Todo does not exist!");
expect.assertions(1)
}
})

})
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
import { ReadableGateway, WritableGateway } from "../modules/shared/entity.gateway";
import { Todo } from "../modules/todos/entities/todo";
import { ReadableGateway, WritableGateway } from "../../modules/shared/entity.gateway";
import { Todo } from "../../modules/todos/entities/todo";
import TodoDocument from "./todo-document";

interface FindQuery {
limit: number;
skip: number;
}

interface TodoDocument {
description: string,
due: string;
}

export default class InMemoryTodoGateway implements ReadableGateway<Todo>, WritableGateway<Todo> {

private documents: Map<string, TodoDocument>;

constructor() {
this.documents = new Map<string, TodoDocument>()
}
constructor(private documents: Map<string, TodoDocument> = new Map<string, TodoDocument>()) {}

public async delete(id: string): Promise<Todo> {
if (!this.documents.has(id)) throw new Error("Todo does not exist!");
Expand All @@ -32,7 +24,7 @@ export default class InMemoryTodoGateway implements ReadableGateway<Todo>, Writa
public async save(todo: Todo): Promise<Todo> {
if (this.documents.has(todo.id)) throw new Error("Todo already exists!");

this.documents.set(todo.id, { description: todo.description, due: todo.due.toISOString() });
this.documents.set(todo.id, TodoDocument.fromTodo(todo));

return todo;
}
Expand All @@ -44,6 +36,6 @@ export default class InMemoryTodoGateway implements ReadableGateway<Todo>, Writa

const docs = keys.map(key => this.documents.get(key)!);

return docs.map((d, i) => new Todo(keys[i], d.description, new Date(d.due)))
return docs.map((d, i) => d.toEntity(keys[i]))
}
}
4 changes: 2 additions & 2 deletions src/providers/v4-uuid.ts → src/providers/uuid/v4-uuid.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import UUDIGenerator from "../modules/shared/uuid-generator";
import UUDIGenerator from "../../modules/shared/uuid-generator";

import { v4 } from "uuid";

export default class V4UuidGenerator implements UUDIGenerator {
public generate(): string {
return v4()
}
}
}

0 comments on commit 4771d28

Please sign in to comment.