diff --git a/__mocks__/@tsndr/cloudflare-worker-jwt.ts b/__mocks__/@tsndr/cloudflare-worker-jwt.ts new file mode 100644 index 00000000..d90cca54 --- /dev/null +++ b/__mocks__/@tsndr/cloudflare-worker-jwt.ts @@ -0,0 +1,7 @@ +const mockJwt = { + sign: jest.fn().mockImplementation(() => { + return "SIGNED_JWT"; + }), +}; + +export default mockJwt; diff --git a/package.json b/package.json index c2b1425e..f7b190e9 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "start": "wrangler dev", "test": "echo 'running tests ๐Ÿงช' && jest --coverage && echo 'โœ… All tests passed'", - "test-watch": "jest --watch", + "test-watch": "jest . --watch", "login": "wrangler login", "check": "wrangler whoami", "deploy": "wrangler deploy", diff --git a/src/constants/responses.ts b/src/constants/responses.ts index b6317d9a..676693dd 100644 --- a/src/constants/responses.ts +++ b/src/constants/responses.ts @@ -29,7 +29,10 @@ export const NAME_CHANGED = "User nickname changed successfully"; export const ROLE_REMOVED = "Role Removed successfully"; export const VERIFICATION_STRING = - "Please verify your identity by clicking the link above and granting authorization to the Real Dev Squad. This will allow us to manage your Discord data."; + "Please verify your discord account by clicking the link below ๐Ÿ‘‡"; + +export const VERIFICATION_SUBSTRING = + "By granting authorization, you agree to permit us to manage your server nickname displayed ONLY in the Real Dev Squad server and to sync your joining data with your user account on our platform."; export const ROLE_FETCH_FAILED = "Oops! We are experiencing an issue fetching roles."; diff --git a/src/controllers/verifyCommand.ts b/src/controllers/verifyCommand.ts index 668010f3..93d7a0b2 100644 --- a/src/controllers/verifyCommand.ts +++ b/src/controllers/verifyCommand.ts @@ -1,5 +1,9 @@ import config from "../../config/config"; -import { RETRY_COMMAND, VERIFICATION_STRING } from "../constants/responses"; +import { + RETRY_COMMAND, + VERIFICATION_STRING, + VERIFICATION_SUBSTRING, +} from "../constants/responses"; import { env } from "../typeDefinitions/default.types"; import { discordEphemeralResponse } from "../utils/discordEphemeralResponse"; import { generateUniqueToken } from "../utils/generateUniqueToken"; @@ -24,7 +28,7 @@ export async function verifyCommand( ); if (response?.status === 201 || response?.status === 200) { const verificationSiteURL = config(env).VERIFICATION_SITE_URL; - const message = `${verificationSiteURL}/discord?token=${token}\n${VERIFICATION_STRING}`; + const message = `${VERIFICATION_STRING}\n${verificationSiteURL}/discord?token=${token}\n${VERIFICATION_SUBSTRING}`; return discordEphemeralResponse(message); } else { return discordEphemeralResponse(RETRY_COMMAND); diff --git a/tests/fixtures/fixture.ts b/tests/fixtures/fixture.ts index b051ddf6..ee237192 100644 --- a/tests/fixtures/fixture.ts +++ b/tests/fixtures/fixture.ts @@ -135,3 +135,22 @@ export const rolesMock = [ mentionable: true, }, ]; +export const mockDateNow = 1626512345678; +export const UNIQUE_TOKEN = "UNIQUE_TOKEN"; +export const env = { + BOT_PUBLIC_KEY: "BOT_PUBLIC_KEY", + DISCORD_GUILD_ID: "DISCORD_GUILD_ID", + DISCORD_TOKEN: "SIGNED_JWT", +}; + +export const discordUserData = { + type: "discord", + token: UNIQUE_TOKEN, + attributes: { + discordId: 1, + userAvatar: "https://cdn.discordapp.com/avatars/1/userAvatarHash.jpg", + userName: "userName", + discriminator: "discriminator", + expiry: mockDateNow + 1000 * 60 * 2, + }, +}; diff --git a/tests/unit/handlers/verifyCommand.test.ts b/tests/unit/handlers/verifyCommand.test.ts new file mode 100644 index 00000000..35dc831b --- /dev/null +++ b/tests/unit/handlers/verifyCommand.test.ts @@ -0,0 +1,99 @@ +import { + RETRY_COMMAND, + VERIFICATION_STRING, + VERIFICATION_SUBSTRING, +} from "../../../src/constants/responses"; +import config from "../../../config/config"; +import { + UNIQUE_TOKEN, + discordUserData, + env, + mockDateNow, +} from "../../fixtures/fixture"; + +describe("verifyCommand", () => { + beforeEach(() => { + jest.mock("@tsndr/cloudflare-worker-jwt"); + jest.spyOn(Date, "now").mockReturnValue(mockDateNow); + jest.mock("../../../src/utils/generateUniqueToken", () => ({ + generateUniqueToken: () => Promise.resolve(UNIQUE_TOKEN), + })); + }); + + afterEach(() => { + jest.spyOn(Date, "now").mockRestore(); + }); + + test("should return JSON response when response is ok", async () => { + jest.spyOn(global, "fetch").mockResolvedValueOnce({ + ok: true, + status: 200, + json: jest.fn().mockResolvedValueOnce(discordUserData), + } as unknown as Response); + + const { verifyCommand } = await import( + "../../../src/controllers/verifyCommand" + ); + + const result = await verifyCommand( + 1, + "userAvatarHash", + "userName", + "discriminator", + env + ); + + expect(global.fetch).toHaveBeenCalledWith( + `http://localhost:3000/external-accounts`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${env.DISCORD_TOKEN}`, + }, + body: JSON.stringify(discordUserData), + } + ); + const resultText = await result.text(); + const resultData = JSON.parse(resultText); + + const verificationSiteURL = config(env).VERIFICATION_SITE_URL; + const message = `${VERIFICATION_STRING}\n${verificationSiteURL}/discord?token=${UNIQUE_TOKEN}\n${VERIFICATION_SUBSTRING}`; + expect(resultData.data.content).toEqual(message); + }); + + test("should return INTERNAL_SERVER_ERROR when response is not ok", async () => { + jest.spyOn(global, "fetch").mockResolvedValueOnce({ + ok: true, + status: 400, // ERROR STATUS + json: jest.fn().mockResolvedValueOnce(discordUserData), + } as unknown as Response); + + const { verifyCommand } = await import( + "../../../src/controllers/verifyCommand" + ); + const result = await verifyCommand( + 1233434, + "sjkhdkjashdksjh", + "test user", + "sndbhsbgdj", + env + ); + + expect(global.fetch).toHaveBeenCalledWith( + `http://localhost:3000/external-accounts`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${env.DISCORD_TOKEN}`, + }, + body: JSON.stringify(discordUserData), + } + ); + const resultText = await result.text(); + const resultData = JSON.parse(resultText); + + expect(resultData.data.content).toEqual(RETRY_COMMAND); + }); +});