Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for 100% coverage of src/resolvers/User/posts.ts #2417

Merged
166 changes: 160 additions & 6 deletions tests/resolvers/User/post.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Replace with the correct path

import { GraphQLError } from "graphql";
import type mongoose from "mongoose";
import { Types } from "mongoose";
Expand Down Expand Up @@ -26,6 +27,7 @@ let MONGOOSE_INSTANCE: typeof mongoose;
let testUser: TestUserType;
let testPost: TestPostType;
let testPost2: TestPostType;
let testPost3: TestPostType;
let testOrganization: TestOrganizationType;

beforeAll(async () => {
Expand All @@ -41,6 +43,12 @@ beforeAll(async () => {
organization: testOrganization?._id,
pinned: false,
});
testPost3 = await Post.create({
text: `text${nanoid().toLowerCase()}`,
creatorId: testUser?._id,
organization: testOrganization?._id,
pinned: false,
});
});

afterAll(async () => {
Expand All @@ -55,23 +63,23 @@ describe("resolvers -> User -> post", () => {
await postResolver?.(parent, {}, {});
} catch (error) {
if (error instanceof GraphQLError) {
expect(error.extensions.code).toEqual("INVALID_ARGUMENTS");
expect(error.extensions?.code).toEqual("INVALID_ARGUMENTS");
expect(
(error.extensions.errors as DefaultGraphQLArgumentError[]).length,
(error.extensions?.errors as DefaultGraphQLArgumentError[]).length,
).toBeGreaterThan(0);
}
}
});

it(`returns the expected connection object`, async () => {
const parent = testUser as InterfaceUser;
const connection = await postResolver?.(
parent,
{
first: 2,
first: 3,
},
{},
);
console.log(connection, testPost2?._id, testPost?._id);
const totalCount = await Post.find({
creatorId: testUser?._id,
}).countDocuments();
Expand All @@ -81,18 +89,107 @@ describe("resolvers -> User -> post", () => {
// Check individual properties
// console.log(connection?.edges[0]);
expect((connection?.edges[0] as unknown as PostEdge).cursor).toEqual(
testPost2?._id.toString(),
testPost3?._id.toString(),
);
expect((connection?.edges[1] as unknown as PostEdge).cursor).toEqual(
testPost2?._id.toString(),
);
expect((connection?.edges[2] as unknown as PostEdge).cursor).toEqual(
testPost?._id.toString(),
);
expect(connection?.pageInfo.endCursor).toEqual(testPost?._id.toString());
expect(connection?.pageInfo.hasNextPage).toBe(false);
expect(connection?.pageInfo.hasPreviousPage).toBe(false);
expect(connection?.pageInfo.startCursor).toEqual(testPost2?._id.toString());
expect(connection?.pageInfo.startCursor).toEqual(testPost3?._id.toString());
expect(connection?.totalCount).toEqual(totalCount);
});

it("returns an empty connection object if no posts are found", async () => {
await Post.deleteMany({ creatorId: testUser?._id });
const parent = testUser as InterfaceUser;
const connection = await postResolver?.(parent, { first: 2 }, {});

expect(connection?.edges).toHaveLength(0);
expect(connection?.totalCount).toEqual(0);
expect(connection?.pageInfo.endCursor).toBeNull();
expect(connection?.pageInfo.startCursor).toBeNull();
expect(connection?.pageInfo.hasNextPage).toBe(false);
expect(connection?.pageInfo.hasPreviousPage).toBe(false);
});

it("handles different pagination arguments correctly", async () => {
// Recreate posts for pagination testing
testPost = await Post.create({
text: `text${nanoid().toLowerCase()}`,
creatorId: testUser?._id,
organization: testOrganization?._id,
pinned: false,
});
testPost2 = await Post.create({
text: `text${nanoid().toLowerCase()}`,
creatorId: testUser?._id,
organization: testOrganization?._id,
pinned: false,
});
testPost3 = await Post.create({
text: `text${nanoid().toLowerCase()}`,
creatorId: testUser?._id,
organization: testOrganization?._id,
pinned: false,
});

const parent = testUser as InterfaceUser;

const connectionFirst = await postResolver?.(parent, { first: 1 }, {});
expect(connectionFirst?.edges).toHaveLength(1);
expect(connectionFirst?.pageInfo.hasNextPage).toBe(true);
expect(connectionFirst?.pageInfo.hasPreviousPage).toBe(false);

const connectionLast = await postResolver?.(parent, { last: 1 }, {});
expect(connectionLast?.edges).toHaveLength(1);
expect(connectionLast?.pageInfo.hasNextPage).toBe(false);
expect(connectionLast?.pageInfo.hasPreviousPage).toBe(true);
});

it("throws an error for invalid cursor value", async () => {
const parent = testUser as InterfaceUser;
const args = { after: "invalidCursor", first: 10 };
await expect(postResolver?.(parent, args, {})).rejects.toThrow();
});

it("handles valid cursor value", async () => {
const parent = testUser as InterfaceUser;
const args = { after: testPost2?._id.toString(), first: 10 };
const connection = await postResolver?.(parent, args, {});
expect(connection).toBeDefined();
expect(connection?.edges.length).toBeGreaterThan(0);

const allPostIds = [testPost, testPost2, testPost3].map((post) =>
post?._id.toString(),
);

const returnedCursor = (connection?.edges[0] as unknown as PostEdge).cursor;
expect(allPostIds).toContain(returnedCursor);
expect(returnedCursor).not.toEqual(testPost2?._id.toString());
});
});

it("handles missing cursor value gracefully", async () => {
const parent = testUser as InterfaceUser;
const args = { first: 10 };
const connection = await postResolver?.(parent, args, {});
expect(connection).toBeDefined();
expect(connection?.edges.length).toBeGreaterThan(0);
});

it("handles cursor value with pagination arguments", async () => {
const parent = testUser as InterfaceUser;
const args = { after: testPost?._id.toString(), first: 2 };
const connection = await postResolver?.(parent, args, {});
expect(connection).toBeDefined();
expect(connection?.edges.length).toBeLessThanOrEqual(2);
});

describe("parseCursor function", () => {
it("returns failure state if argument cursorValue is an invalid cursor", async () => {
const result = await parseCursor({
Expand Down Expand Up @@ -121,4 +218,61 @@ describe("parseCursor function", () => {
expect(result.parsedCursor).toEqual(testPost?._id.toString());
}
});

it("returns failure state if creatorId is invalid", async () => {
const result = await parseCursor({
cursorName: "after",
cursorPath: ["after"],
cursorValue: testPost?._id.toString() as string,
creatorId: new Types.ObjectId().toString(),
});

expect(result.isSuccessful).toEqual(false);
if (result.isSuccessful === false) {
expect(result.errors.length).toBeGreaterThan(0);
}
});

it("handles empty string cursor value", async () => {
try {
await parseCursor({
cursorName: "after",
cursorPath: ["after"],
cursorValue: "",
creatorId: testUser?._id.toString() as string,
});
} catch (error) {
expect(error).toBeDefined();
expect((error as Error).message).toContain("Cast to ObjectId failed");
}
});

it("handles invalid ObjectId string as cursor value", async () => {
try {
await parseCursor({
cursorName: "after",
cursorPath: ["after"],
cursorValue: "invalidObjectId",
creatorId: testUser?._id.toString() as string,
});
} catch (error) {
expect(error).toBeDefined();
expect((error as Error).message).toContain("Cast to ObjectId failed");
}
});

it("handles non-existent ObjectId as cursor value", async () => {
const nonExistentId = new Types.ObjectId().toString();
const result = await parseCursor({
cursorName: "after",
cursorPath: ["after"],
cursorValue: nonExistentId,
creatorId: testUser?._id.toString() as string,
});

expect(result.isSuccessful).toEqual(false);
if (result.isSuccessful === false) {
expect(result.errors.length).toBeGreaterThan(0);
}
});
});
Loading