diff --git a/__tests__/contact.spec.ts b/__tests__/contact.spec.ts index ddc9372..158d40c 100644 --- a/__tests__/contact.spec.ts +++ b/__tests__/contact.spec.ts @@ -3,6 +3,65 @@ import bcrypt from "bcrypt"; import supertest from "supertest"; import { basePath, web } from "../src/application/web"; import logger from "../src/application/logger"; +import { Contact } from "@prisma/client"; + +describe("GET /contact:id", () => { + let token: string = ""; + let createdContact: Contact = {} as Contact; + + beforeAll(async () => { + token = await ContactTestUtil.getToken(); + createdContact = await ContactTestUtil.createContact(); + }); + + afterAll(async () => { + await ContactTestUtil.deleteContact(); + await ContactTestUtil.deleteUser(); + }); + + it ("should return 200 - success getting a contact", async () => { + const res = await supertest(web) + .get(`${basePath}/contact/${createdContact.id}`) + .set('Authorization', `Bearer ${token}`); + + logger.info(res.body); + expect(res.status).toBe(200); + expect(res.body.data.id).toBe(createdContact.id); + expect(res.body.data.first_name).toBe(createdContact.first_name); + expect(res.body.data.last_name).toBe(createdContact.last_name); + expect(res.body.data.email).toBe(createdContact.email); + expect(res.body.data.phone).toBe(createdContact.phone); + }); + + it("should return 404 - invalid contact id", async () => { + const res = await supertest(web) + .get(`${basePath}/contact/test123`) + .set('Authorization', `Bearer ${token}`); + + logger.info(res.body); + expect(res.status).toBe(404); + expect(res.body.errors).toBeDefined(); + }); + + it("should return 404 - contact id doesn't exists", async () => { + const res = await supertest(web) + .get(`${basePath}/contact/10000`) + .set('Authorization', `Bearer ${token}`); + + logger.info(res.body); + expect(res.status).toBe(404); + expect(res.body.errors).toBeDefined(); + }); + + it("should return 401 - empty authorization", async () => { + const res = await supertest(web) + .get(`${basePath}/contact/${createdContact.id}`); + + logger.info(res.body); + expect(res.status).toBe(401); + expect(res.body.errors).toBeDefined(); + }); +}); describe("POST /contact", () => { let token: string = ""; @@ -16,40 +75,33 @@ describe("POST /contact", () => { await ContactTestUtil.deleteUser(); }) - const newContact = { - first_name: "First", - last_name: "Last", - email: "first@last.com", - phone: "08123456789" - } - it("should return 200 - success creating contact", async () => { const res = await supertest(web) .post(`${basePath}/contact`) - .send(newContact) + .send(ContactTestUtil.contact) .set('Authorization', `Bearer ${token}`); logger.info(res.body); expect(res.status).toBe(200); expect(res.body.data.id).toBeGreaterThanOrEqual(1); - expect(res.body.data.first_name).toBe(newContact.first_name); - expect(res.body.data.last_name).toBe(newContact.last_name); - expect(res.body.data.email).toBe(newContact.email); - expect(res.body.data.phone).toBe(newContact.phone); + expect(res.body.data.first_name).toBe(ContactTestUtil.contact.first_name); + expect(res.body.data.last_name).toBe(ContactTestUtil.contact.last_name); + expect(res.body.data.email).toBe(ContactTestUtil.contact.email); + expect(res.body.data.phone).toBe(ContactTestUtil.contact.phone); }); it("should return 200 - success creating contact with emty last_name, email, and phone", async () => { const res = await supertest(web) .post(`${basePath}/contact`) .send({ - first_name: newContact.first_name + first_name: ContactTestUtil.contact.first_name }) .set('Authorization', `Bearer ${token}`); logger.info(res.body); expect(res.status).toBe(200); expect(res.body.data.id).toBeGreaterThanOrEqual(1); - expect(res.body.data.first_name).toBe(newContact.first_name); + expect(res.body.data.first_name).toBe(ContactTestUtil.contact.first_name); expect(res.body.data.last_name).toBe(""); expect(res.body.data.email).toBe(""); expect(res.body.data.phone).toBe(""); @@ -59,8 +111,8 @@ describe("POST /contact", () => { const res = await supertest(web) .post(`${basePath}/contact`) .send({ - first_name: newContact.first_name, - last_name: newContact.last_name, + first_name: ContactTestUtil.contact.first_name, + last_name: ContactTestUtil.contact.last_name, email: "test", }) .set('Authorization', `Bearer ${token}`); @@ -74,8 +126,8 @@ describe("POST /contact", () => { const res = await supertest(web) .post(`${basePath}/contact`) .send({ - first_name: newContact.first_name, - last_name: newContact.last_name, + first_name: ContactTestUtil.contact.first_name, + last_name: ContactTestUtil.contact.last_name, phone: "0123456789012345678901", }) .set('Authorization', `Bearer ${token}`); @@ -84,6 +136,18 @@ describe("POST /contact", () => { expect(res.status).toBe(400); expect(res.body.errors.phone).toBeDefined(); }); + + it("should return 401 - empty authorization", async () => { + const res = await supertest(web) + .post(`${basePath}/contact`) + .send({ + first_name: ContactTestUtil.contact.first_name + }); + + logger.info(res.body); + expect(res.status).toBe(401); + expect(res.body.errors).toBeDefined(); + }); }) class ContactTestUtil { @@ -93,6 +157,13 @@ class ContactTestUtil { password: "password" }; + static contact = { + first_name: "First", + last_name: "Last", + email: "first@last.com", + phone: "08123456789" + } + static async create() { await prisma.user.create({ data: { @@ -120,6 +191,17 @@ class ContactTestUtil { await prisma.user.deleteMany({}); } + static async createContact(): Promise { + const contact = await prisma.contact.create({ + data: { + ...ContactTestUtil.contact, + username: ContactTestUtil.user.username + } + }); + + return contact as Contact; + } + static async deleteContact() { await prisma.contact.deleteMany({}); } diff --git a/docker-compose.yml b/docker-compose.yml index 8987e6d..a05fa83 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,23 +13,23 @@ services: - POSTGRES_PASSWORD=${DB_PASSWORD} networks: - contact_api_network - # contact-api: - # environment: - # - DATABASE_URL=${DATABASE_URL} - # - PORT=${PORT} - # - BASE_URL_PATH=${BASE_URL_PATH} - # - JWT_SECRET=${JWT_SECRET} - # - JWT_EXPIRED_IN_MINUTES=${JWT_EXPIRED_IN_MINUTES} - # build: . - # image: contact-api - # ports: - # - '3000:3000' - # depends_on: - # - db - # volumes: - # - .:/usr/src/node-app - # networks: - # - contact_api_network + contact-api: + environment: + - DATABASE_URL=${DATABASE_URL} + - PORT=${PORT} + - BASE_URL_PATH=${BASE_URL_PATH} + - JWT_SECRET=${JWT_SECRET} + - JWT_EXPIRED_IN_MINUTES=${JWT_EXPIRED_IN_MINUTES} + build: . + image: contact-api + ports: + - '3000:3000' + depends_on: + - db + volumes: + - .:/usr/src/node-app + networks: + - contact_api_network volumes: postgres-db: diff --git a/src/controller/contact.ts b/src/controller/contact.ts index dd7175a..8c23b44 100644 --- a/src/controller/contact.ts +++ b/src/controller/contact.ts @@ -1,9 +1,26 @@ import { Request, Response, NextFunction } from "express"; import ContactService from "../service/contact"; import { ContactRequest } from "../model/contact"; +import { ResponseError } from "../error/response"; export class ContactController { + static async getById(req: Request, res: Response, next: NextFunction) { + try { + if (isNaN(Number(req.params.id))) { + throw new ResponseError(404, "contact doesn't exists") + } + const getRes = await ContactService.findById(res.locals.user.username, Number(req.params.id)); + + res.status(200) + .json({ + data: getRes + }) + } catch (e) { + next(e); + } + } + static async create(req: Request, res: Response, next: NextFunction) { try { const createRes = await ContactService.create(res.locals.user.username, req.body as ContactRequest); diff --git a/src/router/contact.ts b/src/router/contact.ts index c69c7ec..6eebdbd 100644 --- a/src/router/contact.ts +++ b/src/router/contact.ts @@ -5,6 +5,7 @@ import { accessValidation } from "../middleware/accessValidation"; export const getContactRouter = (basePath: string) => { const contactRouter = express.Router(); contactRouter.use(accessValidation); + contactRouter.get(`${basePath}/contact/:id`, ContactController.getById); contactRouter.post(`${basePath}/contact`, ContactController.create); return contactRouter; diff --git a/src/service/contact.ts b/src/service/contact.ts index 47e0759..1d7380e 100644 --- a/src/service/contact.ts +++ b/src/service/contact.ts @@ -1,15 +1,27 @@ import prisma from "../application/database"; +import { ResponseError } from "../error/response"; import { ContactRequest, ContactResponse, toContactResponse } from "../model/contact"; import { ContactValidation } from "../validation/contact"; import { Validation } from "../validation/validation"; export default class ContactService { + static async findById(username: string, id: number): Promise { + const contact = await prisma.contact.findFirstOrThrow({ + where: { + AND: { + username: username, + id: id + } + } + }).catch((e) => { throw new ResponseError(404, "contact doesn't exists") }); + + return toContactResponse(contact); + } + static async create(username: string, req: ContactRequest): Promise { const validatedReq = Validation.validate(ContactValidation.CREATE, req); - console.info(validatedReq); - const contact = await prisma.contact.create({ data: { ...validatedReq,