From 078cfb439212dbd2bb62623603c92edeef210fb0 Mon Sep 17 00:00:00 2001 From: Kanishka Bansode <96020697+kb-0311@users.noreply.github.com> Date: Sun, 29 Jan 2023 17:52:26 +0530 Subject: [PATCH] Tests for `src/resolvers/Mutations/addUserImage` (#931) * 100% code coverage for addUserImage * started tests for uploadImage.ts * 100% test coverage for uploadImage.ts --- src/utilities/uploadImage.ts | 4 +- tests/resolvers/Mutation/addUserImage.spec.ts | 178 ++++++++++++----- tests/utilities/uploadImage.spec.ts | 183 ++++++++++++++++++ 3 files changed, 317 insertions(+), 48 deletions(-) create mode 100644 tests/utilities/uploadImage.spec.ts diff --git a/src/utilities/uploadImage.ts b/src/utilities/uploadImage.ts index 6cd2a81fad..9374456959 100644 --- a/src/utilities/uploadImage.ts +++ b/src/utilities/uploadImage.ts @@ -36,7 +36,9 @@ export const uploadImage = async ( const newImagePath = `images/${id}-${filename}`; - if (oldImagePath) { + if (oldImagePath !== null) { + console.log("oldImagePath is not null"); + logger.info("old image should be deleted"); // If user/organization already has an image delete it from the API diff --git a/tests/resolvers/Mutation/addUserImage.spec.ts b/tests/resolvers/Mutation/addUserImage.spec.ts index fd5e5d169d..fd4a50d5a8 100644 --- a/tests/resolvers/Mutation/addUserImage.spec.ts +++ b/tests/resolvers/Mutation/addUserImage.spec.ts @@ -1,28 +1,33 @@ import "dotenv/config"; -import { - // Document, - Types, -} from "mongoose"; -// import { Interface_User, User } from "../../../src/models"; +import { Document, Types } from "mongoose"; +import { Interface_User, User } from "../../../src/models"; import { connect, disconnect } from "../../../src/db"; import { MutationAddUserImageArgs } from "../../../src/types/generatedGraphQLTypes"; import { addUserImage as addUserImageResolver } from "../../../src/resolvers/Mutation/addUserImage"; -import { USER_NOT_FOUND } from "../../../src/constants"; -// import { nanoid } from "nanoid"; -import { beforeAll, afterAll, describe, it, expect } from "vitest"; +import { USER_NOT_FOUND, USER_NOT_FOUND_MESSAGE } from "../../../src/constants"; +import { + beforeAll, + afterAll, + describe, + it, + expect, + afterEach, + vi, +} from "vitest"; +import { nanoid } from "nanoid"; -// let testUser:Interface_User & Document +let testUser: Interface_User & Document; beforeAll(async () => { await connect(); - // testUser = await User.create({ - // email: `email${nanoid().toLowerCase()}@gmail.com`, - // password: "password", - // firstName: "firstName", - // lastName: "lastName", - // appLanguageCode: "en", - // }); + testUser = await User.create({ + email: `email${nanoid().toLowerCase()}@gmail.com`, + password: "password", + firstName: "firstName", + lastName: "lastName", + appLanguageCode: "en", + }); }); afterAll(async () => { @@ -30,6 +35,11 @@ afterAll(async () => { }); describe("resolvers -> Mutation -> addUserImage", () => { + afterEach(() => { + vi.restoreAllMocks(); + vi.doUnmock("../../../src/constants"); + vi.resetModules(); + }); it(`throws NotFoundError if no user exists with _id === context.userId`, async () => { try { const args: MutationAddUserImageArgs = { @@ -45,36 +55,110 @@ describe("resolvers -> Mutation -> addUserImage", () => { expect(error.message).toEqual(USER_NOT_FOUND); } }); + it(`throws NotFoundError if no user exists with _id === context.userId // IN_PRODUCTION=true`, async () => { + const { requestContext } = await import("../../../src/libraries"); + + const spy = vi + .spyOn(requestContext, "translate") + .mockImplementationOnce((message) => `Translated ${message}`); + + try { + const args: MutationAddUserImageArgs = { + file: "", + }; + + const context = { + userId: Types.ObjectId().toString(), + }; - // it(`sets image field to null for organization with _id === args.organizationId - // and returns the updated organization`, async () => { - // await User.updateOne( - // { - // _id: testUser._id, - // }, - // { - // $set: { - // image: 'image', - // }, - // } - // ); - - // const args: MutationAddUserImageArgs = { - // file: '', - // }; - - // const context = { - // userId: testUser._id, - // }; - - // const addUserImagePayload = await addUserImageResolver?.({}, args, context); - - // const updatedTestUser = await User.findOne({ - // _id: testUser._id, - // }).lean(); - - // expect(addUserImagePayload).toEqual(updatedTestUser); - - // expect(addUserImagePayload?.image).toEqual(null); - // }); + vi.doMock("../../../src/constants", async () => { + const actualConstants: object = await vi.importActual( + "../../../src/constants" + ); + return { + ...actualConstants, + IN_PRODUCTION: true, + }; + }); + const { addUserImage: addUserImageResolverUserError } = await import( + "../../../src/resolvers/Mutation/addUserImage" + ); + await addUserImageResolverUserError?.({}, args, context); + } catch (error: any) { + expect(spy).toHaveBeenLastCalledWith(USER_NOT_FOUND_MESSAGE); + expect(error.message).toEqual(`Translated ${USER_NOT_FOUND_MESSAGE}`); + } + }); + it(`When Image is given, updates current user's user object and returns the object when Image is in DB path`, async () => { + const uploadImage = await import("../../../src/utilities"); + + const spy = vi + .spyOn(uploadImage, "uploadImage") + .mockImplementationOnce(async () => { + return { + newImagePath: "newImagePath", + imageAlreadyInDbPath: "imageAlreadyInDbPath", + }; + }); + + const args: MutationAddUserImageArgs = { + file: "newImageFile.png", + }; + + const context = { + userId: testUser._id, + }; + + const { addUserImage: addUserImageResolverUserError } = await import( + "../../../src/resolvers/Mutation/addUserImage" + ); + const addUserImagePayload = await addUserImageResolverUserError?.( + {}, + args, + context + ); + + expect(spy).toHaveBeenCalledTimes(1); + expect(addUserImagePayload).toEqual({ + ...testUser.toObject(), + + image: "imageAlreadyInDbPath", + }); + }); + it(`When Image is given, updates current user's user object and returns the object when Image is not in DB path`, async () => { + const uploadImage = await import("../../../src/utilities"); + + const spy = vi + .spyOn(uploadImage, "uploadImage") + .mockImplementationOnce(async () => { + return { + newImagePath: "newImagePath", + imageAlreadyInDbPath: "", + }; + }); + + const args: MutationAddUserImageArgs = { + file: "newImageFile.png", + }; + + const context = { + userId: testUser._id, + }; + + const { addUserImage: addUserImageResolverUserError } = await import( + "../../../src/resolvers/Mutation/addUserImage" + ); + const addUserImagePayload = await addUserImageResolverUserError?.( + {}, + args, + context + ); + + expect(spy).toHaveBeenCalledTimes(1); + expect(addUserImagePayload).toEqual({ + ...testUser.toObject(), + + image: "newImagePath", + }); + }); }); diff --git a/tests/utilities/uploadImage.spec.ts b/tests/utilities/uploadImage.spec.ts new file mode 100644 index 0000000000..f561de5424 --- /dev/null +++ b/tests/utilities/uploadImage.spec.ts @@ -0,0 +1,183 @@ +require("dotenv").config(); +import { nanoid } from "nanoid"; +import fs from "fs"; +import { + afterAll, + afterEach, + beforeAll, + describe, + expect, + it, + vi, +} from "vitest"; +import { connect, disconnect } from "../../src/db"; +import { Interface_User, User } from "../../src/models"; +import { Document } from "mongoose"; +import path from "path"; + +let testUser: Interface_User & Document; + +beforeAll(async () => { + await connect(); + + testUser = await User.create({ + email: `email${nanoid().toLowerCase()}@gmail.com`, + password: "password", + firstName: "firstName", + lastName: "lastName", + appLanguageCode: "en", + }); + fs.mkdir(path.join(__dirname, "../../src/images"), (err) => { + if (err) { + throw err; + } + }); + const img = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0" + + "NAAAAKElEQVQ4jWNgYGD4Twzu6FhFFGYYNXDUwGFpIAk2E4dHDRw1cDgaCAASFOffhEIO" + + "3gAAAABJRU5ErkJggg=="; + const data = img.replace(/^data:image\/\w+;base64,/, ""); + const buf = Buffer.from(data, "base64"); + await fs.writeFile( + path.join(__dirname, "../../src/images/image.png"), + buf, + (error) => { + if (error) console.log(error); + } + ); +}); + +afterAll(async () => { + fs.unlink(path.join(__dirname, "../../src/images/image.png"), (err) => { + if (err) throw err; + }); + fs.rm( + path.join(__dirname, "../../src/images"), + { recursive: true }, + (err) => { + if (err) { + throw err; + } + } + ); + await disconnect(); +}); + +describe("utilities -> uploadImage", () => { + afterEach(async () => { + vi.resetModules(); + vi.restoreAllMocks(); + }); + + it("should create a new Image", async () => { + const pngImage: any = { + filename: "image.png", + createReadStream: () => { + return fs.createReadStream( + path.join(__dirname, "../../src/images/image.png") + ); + }, + }; + + const imageAlreadyInDbFile = await import( + "../../src/utilities/imageAlreadyInDbCheck" + ); + + const mockedImageAlreadyInDb = vi + .spyOn(imageAlreadyInDbFile, "imageAlreadyInDbCheck") + .mockImplementation( + async (oldImagePath: string | null, newImagePath: string) => { + console.log(oldImagePath, newImagePath); + + return ""; + } + ); + + const { uploadImage } = await import("../../src/utilities/uploadImage"); + + const uploadImagePayload = await uploadImage(pngImage, null); + + const testUserObj = await User.findByIdAndUpdate( + { + _id: testUser.id, + }, + { + $set: { + image: uploadImagePayload.newImagePath, + }, + }, + { + new: true, + } + ).lean(); + + expect(mockedImageAlreadyInDb).toHaveBeenCalledWith( + null, + testUserObj?.image + ); + expect(uploadImagePayload?.newImagePath).toEqual(testUserObj?.image); + }); + + it("should create a new Image when an old Image Path already Exists", async () => { + const pngImage: any = { + filename: "image.png", + createReadStream: () => { + return fs.createReadStream( + path.join(__dirname, "../../src/images/image.png") + ); + }, + }; + + const imageAlreadyInDbFile = await import( + "../../src/utilities/imageAlreadyInDbCheck" + ); + + const mockedImageAlreadyInDb = vi + .spyOn(imageAlreadyInDbFile, "imageAlreadyInDbCheck") + .mockImplementation( + async (oldImagePath: string | null, newImagePath: string) => { + console.log(oldImagePath, newImagePath); + + return newImagePath; + } + ); + + const { uploadImage } = await import("../../src/utilities/uploadImage"); + + const testUserBeforeObj = await User.findById({ + _id: testUser.id, + }); + const oldImagePath = testUserBeforeObj?.image!; + console.log(oldImagePath); + + const deleteDuplicatedImage = await import( + "../../src/utilities/deleteImage" + ); + + const mockedDeleteImage = vi + .spyOn(deleteDuplicatedImage, "deleteImage") + .mockImplementation(async () => {}); + + const uploadImagePayload = await uploadImage(pngImage, oldImagePath); + + const testUserObj = await User.findByIdAndUpdate( + { + _id: testUser.id, + }, + { + $set: { + image: uploadImagePayload.newImagePath, + }, + }, + { + new: true, + } + ).lean(); + expect(mockedDeleteImage).toBeCalledWith(oldImagePath, testUserObj?.image); + expect(mockedImageAlreadyInDb).toHaveBeenCalledWith( + oldImagePath, + testUserObj?.image + ); + expect(uploadImagePayload?.newImagePath).toEqual(testUserObj?.image); + }); +});