From b0acc61de20d1fc414082a8e8f5809d027a69ab3 Mon Sep 17 00:00:00 2001 From: tejaskh3 Date: Wed, 1 May 2024 21:38:45 +0530 Subject: [PATCH 1/5] add taskTitle field to /task/update API --- src/controllers/taskUpdatesHandler.ts | 13 +++- src/typeDefinitions/taskUpdate.d.ts | 1 + src/utils/sendTaskUpdates.ts | 3 +- tests/unit/handlers/taskUpdateHandler.test.ts | 5 +- tests/unit/utils/sendTasksUpdates.test.ts | 68 +++++++++++++++---- 5 files changed, 73 insertions(+), 17 deletions(-) diff --git a/src/controllers/taskUpdatesHandler.ts b/src/controllers/taskUpdatesHandler.ts index a87593eb..8656ec74 100644 --- a/src/controllers/taskUpdatesHandler.ts +++ b/src/controllers/taskUpdatesHandler.ts @@ -14,8 +14,17 @@ export const sendTaskUpdatesHandler = async (request: IRequest, env: env) => { try { await verifyNodejsBackendAuthToken(authHeader, env); const updates: TaskUpdates = await request.json(); - const { completed, planned, blockers, userName, taskId } = updates.content; - await sendTaskUpdate(completed, planned, blockers, userName, taskId, env); + const { completed, planned, blockers, userName, taskId, taskTitle } = + updates.content; + await sendTaskUpdate( + completed, + planned, + blockers, + userName, + taskId, + taskTitle, + env + ); return new JSONResponse( "Task update sent on Discord's tracking-updates channel." ); diff --git a/src/typeDefinitions/taskUpdate.d.ts b/src/typeDefinitions/taskUpdate.d.ts index b12b2977..a03c8919 100644 --- a/src/typeDefinitions/taskUpdate.d.ts +++ b/src/typeDefinitions/taskUpdate.d.ts @@ -5,5 +5,6 @@ export interface TaskUpdates { blockers: string; userName: string; taskId: string; + taskTitle: string; }; } diff --git a/src/utils/sendTaskUpdates.ts b/src/utils/sendTaskUpdates.ts index 10502a2e..33d5180a 100644 --- a/src/utils/sendTaskUpdates.ts +++ b/src/utils/sendTaskUpdates.ts @@ -7,11 +7,12 @@ export async function sendTaskUpdate( blockers: string, userName: string, taskId: string, + taskTitle: string, env: env ): Promise { const taskUrl = config(env).RDS_STATUS_SITE_URL + `/tasks/${taskId}`; const formattedString = - `${userName} added an update to their task: <${taskUrl}>\n` + + `**${userName}** added an update to their task: [${taskTitle}](<${taskUrl}>)\n` + `\n**Completed**\n${completed}\n\n` + `**Planned**\n${planned}\n\n` + `**Blockers**\n${blockers}`; diff --git a/tests/unit/handlers/taskUpdateHandler.test.ts b/tests/unit/handlers/taskUpdateHandler.test.ts index f8954d51..5b78bbcd 100644 --- a/tests/unit/handlers/taskUpdateHandler.test.ts +++ b/tests/unit/handlers/taskUpdateHandler.test.ts @@ -21,6 +21,7 @@ describe("sendTaskUpdatesHandler", () => { blockers: "NA", userName: "12345678910", taskId: "79wMEIek990", + taskTitle: "Hyperlink as task Title", }, }; afterEach(() => { @@ -28,13 +29,15 @@ describe("sendTaskUpdatesHandler", () => { }); it("sendTaskUpdate function should return undefined after successfully sending the message", async () => { - const { completed, planned, blockers, userName, taskId } = mockData.content; + const { completed, planned, blockers, userName, taskId, taskTitle } = + mockData.content; const response = await sendTaskUpdate( completed, planned, blockers, userName, taskId, + taskTitle, mockEnv ); expect(response).toBe(undefined); diff --git a/tests/unit/utils/sendTasksUpdates.test.ts b/tests/unit/utils/sendTasksUpdates.test.ts index 1ddfbb4d..7d282584 100644 --- a/tests/unit/utils/sendTasksUpdates.test.ts +++ b/tests/unit/utils/sendTasksUpdates.test.ts @@ -9,6 +9,7 @@ describe("sendTaskUpdate function", () => { const blockers = "No blockers"; const userName = "Tejas"; const taskId = "69nduIn210"; + const taskTitle = "Hyperlink as task title"; const taskUrl = config(mockEnv).RDS_STATUS_SITE_URL + `/tasks/${taskId}`; const assertFetchCall = (url: string, bodyObj: any, mockEnv: any) => { expect(global.fetch).toHaveBeenCalledWith(url, { @@ -28,7 +29,7 @@ describe("sendTaskUpdate function", () => { test("should send the task update to discord tracking channel when all fields are present", async () => { const url = config(mockEnv).TRACKING_CHANNEL_URL; const formattedString = - `${userName} added an update to their task: <${taskUrl}>\n` + + `**${userName}** added an update to their task: [${taskTitle}](<${taskUrl}>)\n` + `\n**Completed**\n${completed}\n\n` + `**Planned**\n${planned}\n\n` + `**Blockers**\n${blockers}`; @@ -46,6 +47,7 @@ describe("sendTaskUpdate function", () => { blockers, userName, taskId, + taskTitle, mockEnv ); @@ -55,7 +57,7 @@ describe("sendTaskUpdate function", () => { test("should send the task update to discord tracking channel when only completed is present", async () => { const url = config(mockEnv).TRACKING_CHANNEL_URL; const formattedString = - `${userName} added an update to their task: <${taskUrl}>\n` + + `**${userName}** added an update to their task: [${taskTitle}](<${taskUrl}>)\n` + `\n**Completed**\n${completed}\n\n` + `**Planned**\n\n\n` + `**Blockers**\n`; @@ -67,7 +69,15 @@ describe("sendTaskUpdate function", () => { .spyOn(global, "fetch") .mockImplementation(() => Promise.resolve(new JSONResponse(""))); - await sendTaskUpdate(completed, "", "", userName, taskId, mockEnv); + await sendTaskUpdate( + completed, + "", + "", + userName, + taskId, + taskTitle, + mockEnv + ); assertFetchCall(url, bodyObj, mockEnv); }); @@ -75,7 +85,7 @@ describe("sendTaskUpdate function", () => { test("should send the task update to discord tracking channel when only planned is present", async () => { const url = config(mockEnv).TRACKING_CHANNEL_URL; const formattedString = - `${userName} added an update to their task: <${taskUrl}>\n` + + `**${userName}** added an update to their task: [${taskTitle}](<${taskUrl}>)\n` + `\n**Completed**\n\n\n` + `**Planned**\n${planned}\n\n` + `**Blockers**\n`; @@ -87,7 +97,7 @@ describe("sendTaskUpdate function", () => { .spyOn(global, "fetch") .mockImplementation(() => Promise.resolve(new JSONResponse(""))); - await sendTaskUpdate("", planned, "", userName, taskId, mockEnv); + await sendTaskUpdate("", planned, "", userName, taskId, taskTitle, mockEnv); assertFetchCall(url, bodyObj, mockEnv); }); @@ -95,7 +105,7 @@ describe("sendTaskUpdate function", () => { test("should send the task update to discord tracking channel when only blockers is present", async () => { const url = config(mockEnv).TRACKING_CHANNEL_URL; const formattedString = - `${userName} added an update to their task: <${taskUrl}>\n` + + `**${userName}** added an update to their task: [${taskTitle}](<${taskUrl}>)\n` + `\n**Completed**\n\n\n` + `**Planned**\n\n\n` + `**Blockers**\n${blockers}`; @@ -107,7 +117,15 @@ describe("sendTaskUpdate function", () => { .spyOn(global, "fetch") .mockImplementation(() => Promise.resolve(new JSONResponse(""))); - await sendTaskUpdate("", "", blockers, userName, taskId, mockEnv); + await sendTaskUpdate( + "", + "", + blockers, + userName, + taskId, + taskTitle, + mockEnv + ); assertFetchCall(url, bodyObj, mockEnv); }); @@ -115,7 +133,7 @@ describe("sendTaskUpdate function", () => { test("should send the task update to discord tracking channel when only completed and planned are present", async () => { const url = config(mockEnv).TRACKING_CHANNEL_URL; const formattedString = - `${userName} added an update to their task: <${taskUrl}>\n` + + `**${userName}** added an update to their task: [${taskTitle}](<${taskUrl}>)\n` + `\n**Completed**\n${completed}\n\n` + `**Planned**\n${planned}\n\n` + `**Blockers**\n`; @@ -127,7 +145,15 @@ describe("sendTaskUpdate function", () => { .spyOn(global, "fetch") .mockImplementation(() => Promise.resolve(new JSONResponse(""))); - await sendTaskUpdate(completed, planned, "", userName, taskId, mockEnv); + await sendTaskUpdate( + completed, + planned, + "", + userName, + taskId, + taskTitle, + mockEnv + ); assertFetchCall(url, bodyObj, mockEnv); }); @@ -135,7 +161,7 @@ describe("sendTaskUpdate function", () => { test("should send the task update to discord tracking channel when only completed and blockers are present", async () => { const url = config(mockEnv).TRACKING_CHANNEL_URL; const formattedString = - `${userName} added an update to their task: <${taskUrl}>\n` + + `**${userName}** added an update to their task: [${taskTitle}](<${taskUrl}>)\n` + `\n**Completed**\n${completed}\n\n` + `**Planned**\n\n\n` + `**Blockers**\n${blockers}`; @@ -147,7 +173,15 @@ describe("sendTaskUpdate function", () => { .spyOn(global, "fetch") .mockImplementation(() => Promise.resolve(new JSONResponse(""))); - await sendTaskUpdate(completed, "", blockers, userName, taskId, mockEnv); + await sendTaskUpdate( + completed, + "", + blockers, + userName, + taskId, + taskTitle, + mockEnv + ); assertFetchCall(url, bodyObj, mockEnv); }); @@ -155,7 +189,7 @@ describe("sendTaskUpdate function", () => { test("should send the task update to discord tracking channel when only planned and blockers are present", async () => { const url = config(mockEnv).TRACKING_CHANNEL_URL; const formattedString = - `${userName} added an update to their task: <${taskUrl}>\n` + + `**${userName}** added an update to their task: [${taskTitle}](<${taskUrl}>)\n` + `\n**Completed**\n\n\n` + `**Planned**\n${planned}\n\n` + `**Blockers**\n${blockers}`; @@ -167,7 +201,15 @@ describe("sendTaskUpdate function", () => { .spyOn(global, "fetch") .mockImplementation(() => Promise.resolve(new JSONResponse(""))); - await sendTaskUpdate("", planned, blockers, userName, taskId, mockEnv); + await sendTaskUpdate( + "", + planned, + blockers, + userName, + taskId, + taskTitle, + mockEnv + ); assertFetchCall(url, bodyObj, mockEnv); }); From 0a0d4c3e953620b6a4b7a2aa42bbcef70f76320e Mon Sep 17 00:00:00 2001 From: tejaskh3 Date: Wed, 1 May 2024 23:51:17 +0530 Subject: [PATCH 2/5] feat:add test case for sendTaskUpdate util --- tests/unit/utils/sendTasksUpdates.test.ts | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/unit/utils/sendTasksUpdates.test.ts b/tests/unit/utils/sendTasksUpdates.test.ts index 7d282584..6ffb6c08 100644 --- a/tests/unit/utils/sendTasksUpdates.test.ts +++ b/tests/unit/utils/sendTasksUpdates.test.ts @@ -25,6 +25,37 @@ describe("sendTaskUpdate function", () => { afterEach(() => { jest.clearAllMocks(); }); + test("should throw an error if response status is not OK", async () => { + const url = config(mockEnv).TRACKING_CHANNEL_URL; + const formattedString = + `**${userName}** added an update to their task: [${taskTitle}](<${taskUrl}>)\n` + + `\n**Completed**\n${completed}\n\n` + + `**Planned**\n${planned}\n\n` + + `**Blockers**\n${blockers}`; + const bodyObj = { + content: formattedString, + }; + + jest + .spyOn(global, "fetch") + .mockResolvedValueOnce( + new JSONResponse("", { status: 400, statusText: "Bad Request" }) + ); + + await expect( + sendTaskUpdate( + completed, + planned, + blockers, + userName, + taskId, + taskTitle, + mockEnv + ) + ).rejects.toThrowError("Failed to send task update: 400 - Bad Request"); + + assertFetchCall(url, bodyObj, mockEnv); + }); test("should send the task update to discord tracking channel when all fields are present", async () => { const url = config(mockEnv).TRACKING_CHANNEL_URL; From 46ad62616dd2553933e1a9e03885348fa9f1787d Mon Sep 17 00:00:00 2001 From: tejaskh3 Date: Thu, 2 May 2024 01:22:04 +0530 Subject: [PATCH 3/5] feat: add test cases to taskUpdateHandler --- tests/unit/handlers/taskUpdateHandler.test.ts | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tests/unit/handlers/taskUpdateHandler.test.ts b/tests/unit/handlers/taskUpdateHandler.test.ts index 5b78bbcd..cd8e0d4a 100644 --- a/tests/unit/handlers/taskUpdateHandler.test.ts +++ b/tests/unit/handlers/taskUpdateHandler.test.ts @@ -2,7 +2,7 @@ import { sendTaskUpdatesHandler } from "../../../src/controllers/taskUpdatesHand import JSONResponse from "../../../src/utils/JsonResponse"; import * as response from "../../../src/constants/responses"; import { sendTaskUpdate } from "../../../src/utils/sendTaskUpdates"; - +import * as responseConstants from "../../../src/constants/responses"; import { generateDummyRequestObject } from "../../fixtures/fixture"; jest.mock("../../../src/utils/verifyAuthToken", () => ({ @@ -11,7 +11,6 @@ jest.mock("../../../src/utils/verifyAuthToken", () => ({ jest.mock("../../../src/utils/sendTaskUpdates", () => ({ sendTaskUpdate: jest.fn().mockResolvedValue(undefined), })); - describe("sendTaskUpdatesHandler", () => { const mockEnv = { DISCORD_TOKEN: "mockToken" }; const mockData = { @@ -27,7 +26,6 @@ describe("sendTaskUpdatesHandler", () => { afterEach(() => { jest.clearAllMocks(); }); - it("sendTaskUpdate function should return undefined after successfully sending the message", async () => { const { completed, planned, blockers, userName, taskId, taskTitle } = mockData.content; @@ -53,4 +51,22 @@ describe("sendTaskUpdatesHandler", () => { expect(result.status).toBe(401); expect(jsonResponse).toEqual(response.UNAUTHORIZED); }); + it("should return success response if task update is sent successfully", async () => { + const mockRequest = generateDummyRequestObject({ + url: "/task/update", + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer dummyToken", + }, + }); + mockRequest.json = jest.fn().mockResolvedValue(mockData); + const result: JSONResponse = await sendTaskUpdatesHandler( + mockRequest, + mockEnv + ); + expect(result.status).toBe(200); + const res: JSONResponse = await result.json(); + expect(res).toBe("Task update sent on Discord's tracking-updates channel."); + }); }); From cad3f65c7270beba6992b373ad9b4bf26f399614 Mon Sep 17 00:00:00 2001 From: tejaskh3 Date: Sun, 5 May 2024 12:18:06 +0530 Subject: [PATCH 4/5] refactor: add message in constant responses --- src/constants/responses.ts | 2 ++ src/controllers/taskUpdatesHandler.ts | 4 +--- tests/unit/handlers/taskUpdateHandler.test.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/constants/responses.ts b/src/constants/responses.ts index 44007852..bff6a2c0 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -77,3 +77,5 @@ export const INVALID_TOKEN_FORMAT = "Invalid Authentication header format. Expected 'Bearer '"; export const AUTHENTICATION_ERROR = "Invalid Authentication token"; +export const TASK_UPDATE_SENT_MESSAGE = + "Task update sent on Discord's tracking-updates channel."; diff --git a/src/controllers/taskUpdatesHandler.ts b/src/controllers/taskUpdatesHandler.ts index 8656ec74..a509d80a 100644 --- a/src/controllers/taskUpdatesHandler.ts +++ b/src/controllers/taskUpdatesHandler.ts @@ -25,9 +25,7 @@ export const sendTaskUpdatesHandler = async (request: IRequest, env: env) => { taskTitle, env ); - return new JSONResponse( - "Task update sent on Discord's tracking-updates channel." - ); + return new JSONResponse(response.TASK_UPDATE_SENT_MESSAGE); } catch (error: any) { return new JSONResponse({ res: response.INTERNAL_SERVER_ERROR, diff --git a/tests/unit/handlers/taskUpdateHandler.test.ts b/tests/unit/handlers/taskUpdateHandler.test.ts index cd8e0d4a..f6cff2de 100644 --- a/tests/unit/handlers/taskUpdateHandler.test.ts +++ b/tests/unit/handlers/taskUpdateHandler.test.ts @@ -67,6 +67,6 @@ describe("sendTaskUpdatesHandler", () => { ); expect(result.status).toBe(200); const res: JSONResponse = await result.json(); - expect(res).toBe("Task update sent on Discord's tracking-updates channel."); + expect(res).toBe(response.TASK_UPDATE_SENT_MESSAGE); }); }); From fed9581a186c08c08cc08fa4d48bdbbf671bb88f Mon Sep 17 00:00:00 2001 From: tejaskh3 Date: Sun, 5 May 2024 12:22:00 +0530 Subject: [PATCH 5/5] remove: extra line --- tests/unit/handlers/taskUpdateHandler.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/handlers/taskUpdateHandler.test.ts b/tests/unit/handlers/taskUpdateHandler.test.ts index f6cff2de..eb61f89a 100644 --- a/tests/unit/handlers/taskUpdateHandler.test.ts +++ b/tests/unit/handlers/taskUpdateHandler.test.ts @@ -2,7 +2,6 @@ import { sendTaskUpdatesHandler } from "../../../src/controllers/taskUpdatesHand import JSONResponse from "../../../src/utils/JsonResponse"; import * as response from "../../../src/constants/responses"; import { sendTaskUpdate } from "../../../src/utils/sendTaskUpdates"; -import * as responseConstants from "../../../src/constants/responses"; import { generateDummyRequestObject } from "../../fixtures/fixture"; jest.mock("../../../src/utils/verifyAuthToken", () => ({