import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields.constants'; import { TEST_PERSON_1_ID, TEST_PERSON_2_ID, TEST_PERSON_3_ID, TEST_PERSON_4_ID, TEST_PERSON_5_ID, } from 'test/integration/constants/test-person-ids.constants'; import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; import { deleteAllRecords } from 'test/integration/utils/delete-all-records'; describe('GraphQL People Pagination with Composite Field Sorting', () => { beforeAll(async () => { await deleteAllRecords('person'); const testPeople = [ { id: TEST_PERSON_1_ID, firstName: 'Alice', lastName: 'Brown', }, { id: TEST_PERSON_2_ID, firstName: 'Alice', lastName: 'Smith', }, { id: TEST_PERSON_3_ID, firstName: 'Bob', lastName: 'Johnson', }, { id: TEST_PERSON_4_ID, firstName: 'Bob', lastName: 'Williams', }, { id: TEST_PERSON_5_ID, firstName: 'Charlie', lastName: 'Davis', }, ]; for (const person of testPeople) { const graphqlOperation = createOneOperationFactory({ objectMetadataSingularName: 'person', gqlFields: PERSON_GQL_FIELDS, data: { id: person.id, name: { firstName: person.firstName, lastName: person.lastName, }, }, }); await makeGraphqlAPIRequest(graphqlOperation).expect(200); } }); it('should support pagination with fullName composite field in ascending order', async () => { const firstPageOperation = findManyOperationFactory({ objectMetadataSingularName: 'person', objectMetadataPluralName: 'people', gqlFields: PERSON_GQL_FIELDS, orderBy: { name: { firstName: 'AscNullsLast', lastName: 'AscNullsLast', }, }, first: 2, }); const firstPageResponse = await makeGraphqlAPIRequest(firstPageOperation).expect(200); const firstPagePeople = firstPageResponse.body.data.people.edges.map( (edge: any) => edge.node, ); const firstPageCursor = firstPageResponse.body.data.people.pageInfo.endCursor; expect(firstPagePeople).toHaveLength(2); expect(firstPageResponse.body.data.people.pageInfo.hasNextPage).toBe(true); expect(firstPagePeople[0].name.firstName).toBe('Alice'); expect(firstPagePeople[0].name.lastName).toBe('Brown'); expect(firstPagePeople[1].name.firstName).toBe('Alice'); expect(firstPagePeople[1].name.lastName).toBe('Smith'); const secondPageOperation = findManyOperationFactory({ objectMetadataSingularName: 'person', objectMetadataPluralName: 'people', gqlFields: PERSON_GQL_FIELDS, orderBy: { name: { firstName: 'AscNullsLast', lastName: 'AscNullsLast', }, }, first: 2, after: firstPageCursor, }); const secondPageResponse = await makeGraphqlAPIRequest(secondPageOperation).expect(200); const secondPagePeople = secondPageResponse.body.data.people.edges.map( (edge: any) => edge.node, ); expect(secondPagePeople).toHaveLength(2); expect(secondPagePeople[0].name.firstName).toBe('Bob'); expect(secondPagePeople[0].name.lastName).toBe('Johnson'); expect(secondPagePeople[1].name.firstName).toBe('Bob'); expect(secondPagePeople[1].name.lastName).toBe('Williams'); const firstPageIds = firstPagePeople.map((p: { id: string }) => p.id); const secondPageIds = secondPagePeople.map((p: { id: string }) => p.id); const intersection = firstPageIds.filter((id: string) => secondPageIds.includes(id), ); expect(intersection).toHaveLength(0); const thirdPageOperation = findManyOperationFactory({ objectMetadataSingularName: 'person', objectMetadataPluralName: 'people', gqlFields: PERSON_GQL_FIELDS, orderBy: { name: { firstName: 'AscNullsLast', lastName: 'AscNullsLast', }, }, first: 2, after: secondPageResponse.body.data.people.pageInfo.endCursor, }); const thirdPageResponse = await makeGraphqlAPIRequest(thirdPageOperation).expect(200); const thirdPagePeople = thirdPageResponse.body.data.people.edges.map( (edge: any) => edge.node, ); expect(thirdPagePeople).toHaveLength(1); expect(thirdPagePeople[0].name.firstName).toBe('Charlie'); expect(thirdPagePeople[0].name.lastName).toBe('Davis'); expect(thirdPageResponse.body.data.people.pageInfo.hasNextPage).toBe(false); }); it('should support cursor-based pagination with fullName in descending order', async () => { const firstPageOperation = findManyOperationFactory({ objectMetadataSingularName: 'person', objectMetadataPluralName: 'people', gqlFields: PERSON_GQL_FIELDS, orderBy: { name: { firstName: 'DescNullsLast', lastName: 'DescNullsLast', }, }, first: 2, }); const firstPageResponse = await makeGraphqlAPIRequest(firstPageOperation).expect(200); const firstPagePeople = firstPageResponse.body.data.people.edges.map( (edge: any) => edge.node, ); expect(firstPagePeople).toHaveLength(2); expect(firstPagePeople[0].name.firstName).toBe('Charlie'); expect(firstPagePeople[0].name.lastName).toBe('Davis'); expect(firstPagePeople[1].name.firstName).toBe('Bob'); expect(firstPagePeople[1].name.lastName).toBe('Williams'); const secondPageOperation = findManyOperationFactory({ objectMetadataSingularName: 'person', objectMetadataPluralName: 'people', gqlFields: PERSON_GQL_FIELDS, orderBy: { name: { firstName: 'DescNullsLast', lastName: 'DescNullsLast', }, }, first: 2, after: firstPageResponse.body.data.people.pageInfo.endCursor, }); const secondPageResponse = await makeGraphqlAPIRequest(secondPageOperation).expect(200); const secondPagePeople = secondPageResponse.body.data.people.edges.map( (edge: any) => edge.node, ); expect(secondPagePeople).toHaveLength(2); expect(secondPagePeople[0].name.firstName).toBe('Bob'); expect(secondPagePeople[0].name.lastName).toBe('Johnson'); expect(secondPagePeople[1].name.firstName).toBe('Alice'); expect(secondPagePeople[1].name.lastName).toBe('Smith'); }); it('should support backward pagination with fullName composite field in ascending order', async () => { const allPeopleOperation = findManyOperationFactory({ objectMetadataSingularName: 'person', objectMetadataPluralName: 'people', gqlFields: PERSON_GQL_FIELDS, orderBy: { name: { firstName: 'AscNullsLast', lastName: 'AscNullsLast', }, }, }); const allPeopleResponse = await makeGraphqlAPIRequest(allPeopleOperation).expect(200); const allPeople = allPeopleResponse.body.data.people.edges.map( (edge: any) => edge.node, ); const lastPersonCursor = allPeopleResponse.body.data.people.pageInfo.endCursor; const backwardPageOperation = findManyOperationFactory({ objectMetadataSingularName: 'person', objectMetadataPluralName: 'people', gqlFields: PERSON_GQL_FIELDS, orderBy: { name: { firstName: 'AscNullsLast', lastName: 'AscNullsLast', }, }, last: 2, before: lastPersonCursor, }); const backwardPageResponse = await makeGraphqlAPIRequest( backwardPageOperation, ).expect(200); const backwardPagePeople = backwardPageResponse.body.data.people.edges.map( (edge: any) => edge.node, ); expect(backwardPagePeople).toHaveLength(2); expect(backwardPagePeople[0].id).toBe(allPeople.at(-2)?.id); expect(backwardPagePeople[1].id).toBe(allPeople.at(-3)?.id); }); });