diff --git a/packages/twenty-server/test/integration/graphql/suites/all-people-resolvers.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/all-people-resolvers.integration-spec.ts new file mode 100644 index 000000000000..e5a5ce5c7cd3 --- /dev/null +++ b/packages/twenty-server/test/integration/graphql/suites/all-people-resolvers.integration-spec.ts @@ -0,0 +1,416 @@ +import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util'; +import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; +import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util'; +import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util'; +import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util'; +import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util'; +import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util'; +import { findOneOperationFactory } from 'test/integration/graphql/utils/find-one-operation-factory.util'; +import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util'; +import { updateOneOperationFactory } from 'test/integration/graphql/utils/update-one-operation-factory.util'; +import { generateRecordName } from 'test/integration/utils/generate-record-name'; + +const PERSON_1_ID = '777a8457-eb2d-40ac-a707-551b615b6987'; +const PERSON_2_ID = '777a8457-eb2d-40ac-a707-551b615b6988'; +const PERSON_3_ID = '777a8457-eb2d-40ac-a707-551b615b6989'; + +const PERSON_GQL_FIELDS = ` + id + city + jobTitle + avatarUrl + intro + searchVector + name { + firstName + lastName + } + createdAt + deletedAt +`; + +describe('people resolvers (integration)', () => { + it('1. should create and return people', async () => { + const personCity1 = generateRecordName(PERSON_1_ID); + const personCity2 = generateRecordName(PERSON_2_ID); + const graphqlOperation = createManyOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + gqlFields: PERSON_GQL_FIELDS, + data: [ + { + id: PERSON_1_ID, + city: personCity1, + }, + { + id: PERSON_2_ID, + city: personCity2, + }, + ], + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.createPeople).toHaveLength(2); + + response.body.data.createPeople.forEach((person) => { + expect(person).toHaveProperty('city'); + expect([personCity1, personCity2]).toContain(person.city); + + expect(person).toHaveProperty('id'); + expect(person).toHaveProperty('jobTitle'); + expect(person).toHaveProperty('avatarUrl'); + expect(person).toHaveProperty('intro'); + expect(person).toHaveProperty('searchVector'); + expect(person).toHaveProperty('name'); + expect(person).toHaveProperty('createdAt'); + expect(person).toHaveProperty('deletedAt'); + }); + }); + + it('1b. should create and return one person', async () => { + const personCity3 = generateRecordName(PERSON_3_ID); + + const graphqlOperation = createOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + data: { + id: PERSON_3_ID, + city: personCity3, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const createdPerson = response.body.data.createPerson; + + expect(createdPerson).toHaveProperty('city'); + expect(createdPerson.city).toEqual(personCity3); + + expect(createdPerson).toHaveProperty('id'); + expect(createdPerson).toHaveProperty('jobTitle'); + expect(createdPerson).toHaveProperty('avatarUrl'); + expect(createdPerson).toHaveProperty('intro'); + expect(createdPerson).toHaveProperty('searchVector'); + expect(createdPerson).toHaveProperty('name'); + expect(createdPerson).toHaveProperty('createdAt'); + expect(createdPerson).toHaveProperty('deletedAt'); + }); + + it('2. should find many people', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + gqlFields: PERSON_GQL_FIELDS, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const data = response.body.data.people; + + expect(data).toBeDefined(); + expect(Array.isArray(data.edges)).toBe(true); + + const edges = data.edges; + + if (edges.length > 0) { + const person = edges[0].node; + + expect(person).toHaveProperty('id'); + expect(person).toHaveProperty('jobTitle'); + expect(person).toHaveProperty('avatarUrl'); + expect(person).toHaveProperty('intro'); + expect(person).toHaveProperty('searchVector'); + expect(person).toHaveProperty('name'); + expect(person).toHaveProperty('createdAt'); + expect(person).toHaveProperty('deletedAt'); + } + }); + + it('2b. should find one person', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + filter: { + id: { + eq: PERSON_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const person = response.body.data.person; + + expect(person).toHaveProperty('city'); + + expect(person).toHaveProperty('id'); + expect(person).toHaveProperty('jobTitle'); + expect(person).toHaveProperty('avatarUrl'); + expect(person).toHaveProperty('intro'); + expect(person).toHaveProperty('searchVector'); + expect(person).toHaveProperty('name'); + expect(person).toHaveProperty('createdAt'); + expect(person).toHaveProperty('deletedAt'); + }); + + it('3. should update many people', async () => { + const graphqlOperation = updateManyOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + gqlFields: PERSON_GQL_FIELDS, + data: { + city: 'Updated City', + }, + filter: { + id: { + in: [PERSON_1_ID, PERSON_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedPeople = response.body.data.updatePeople; + + expect(updatedPeople).toHaveLength(2); + + updatedPeople.forEach((person) => { + expect(person.city).toEqual('Updated City'); + }); + }); + + it('3b. should update one person', async () => { + const graphqlOperation = updateOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + data: { + city: 'New City', + }, + recordId: PERSON_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedPerson = response.body.data.updatePerson; + + expect(updatedPerson.city).toEqual('New City'); + }); + + it('4. should find many people with updated city', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + gqlFields: PERSON_GQL_FIELDS, + filter: { + city: { + eq: 'Updated City', + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.people.edges).toHaveLength(2); + }); + + it('4b. should find one person with updated city', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + filter: { + city: { + eq: 'New City', + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.person.city).toEqual('New City'); + }); + + it('5. should delete many people', async () => { + const graphqlOperation = deleteManyOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + gqlFields: PERSON_GQL_FIELDS, + filter: { + id: { + in: [PERSON_1_ID, PERSON_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const deletePeople = response.body.data.deletePeople; + + expect(deletePeople).toHaveLength(2); + + deletePeople.forEach((person) => { + expect(person.deletedAt).toBeTruthy(); + }); + }); + + it('5b. should delete one person', async () => { + const graphqlOperation = deleteOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + recordId: PERSON_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.deletePerson.deletedAt).toBeTruthy(); + }); + + it('6. should not find many people anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + gqlFields: PERSON_GQL_FIELDS, + filter: { + id: { + in: [PERSON_1_ID, PERSON_2_ID], + }, + }, + }); + + const findPeopleResponse = await makeGraphqlAPIRequest(graphqlOperation); + + expect(findPeopleResponse.body.data.people.edges).toHaveLength(0); + }); + + it('6b. should not find one person anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + filter: { + id: { + eq: PERSON_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.person).toBeNull(); + }); + + it('7. should find many deleted people with deletedAt filter', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + gqlFields: PERSON_GQL_FIELDS, + filter: { + id: { + in: [PERSON_1_ID, PERSON_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.people.edges).toHaveLength(2); + }); + + it('7b. should find one deleted person with deletedAt filter', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + filter: { + id: { + eq: PERSON_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.person.id).toEqual(PERSON_3_ID); + }); + + it('8. should destroy many people', async () => { + const graphqlOperation = destroyManyOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + gqlFields: PERSON_GQL_FIELDS, + filter: { + id: { + in: [PERSON_1_ID, PERSON_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.destroyPeople).toHaveLength(2); + }); + + it('8b. should destroy one person', async () => { + const graphqlOperation = destroyOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + recordId: PERSON_3_ID, + }); + + const destroyPeopleResponse = await makeGraphqlAPIRequest(graphqlOperation); + + expect(destroyPeopleResponse.body.data.destroyPerson).toBeTruthy(); + }); + + it('9. should not find many people anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + gqlFields: PERSON_GQL_FIELDS, + filter: { + id: { + in: [PERSON_1_ID, PERSON_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.people.edges).toHaveLength(0); + }); + + it('9b. should not find one person anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'person', + gqlFields: PERSON_GQL_FIELDS, + filter: { + id: { + eq: PERSON_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.person).toBeNull(); + }); +}); diff --git a/packages/twenty-server/test/integration/graphql/suites/all-task-targets-resolvers.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/all-task-targets-resolvers.integration-spec.ts new file mode 100644 index 000000000000..9cf1b93f4d86 --- /dev/null +++ b/packages/twenty-server/test/integration/graphql/suites/all-task-targets-resolvers.integration-spec.ts @@ -0,0 +1,444 @@ +import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util'; +import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; +import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util'; +import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util'; +import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util'; +import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util'; +import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util'; +import { findOneOperationFactory } from 'test/integration/graphql/utils/find-one-operation-factory.util'; +import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util'; +import { updateOneOperationFactory } from 'test/integration/graphql/utils/update-one-operation-factory.util'; +import { generateRecordName } from 'test/integration/utils/generate-record-name'; + +const TASK_TARGET_1_ID = '777a8457-eb2d-40ac-a707-551b615b6987'; +const TASK_TARGET_2_ID = '777a8457-eb2d-40ac-a707-551b615b6988'; +const TASK_TARGET_3_ID = '777a8457-eb2d-40ac-a707-551b615b6989'; +const PERSON_1_ID = '777a8457-eb2d-40ac-a707-441b615b6989'; +const PERSON_2_ID = '777a8457-eb2d-40ac-a707-331b615b6989'; +const TASK_TARGET_GQL_FIELDS = ` + id + createdAt + deletedAt + rocketId + personId + companyId + opportunityId + person{ + id + } +`; + +describe('taskTargets resolvers (integration)', () => { + beforeAll(async () => { + const personName1 = generateRecordName(PERSON_1_ID); + const personName2 = generateRecordName(PERSON_2_ID); + const graphqlOperation = createManyOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + gqlFields: `id`, + data: [ + { + id: PERSON_1_ID, + name: { + firstName: personName1, + lastName: personName1, + }, + }, + { + id: PERSON_2_ID, + name: { + firstName: personName2, + lastName: personName2, + }, + }, + ], + }); + + await makeGraphqlAPIRequest(graphqlOperation); + }); + + afterAll(async () => { + const graphqlOperation = destroyManyOperationFactory({ + objectMetadataSingularName: 'person', + objectMetadataPluralName: 'people', + gqlFields: `id`, + filter: { + id: { + in: [PERSON_1_ID, PERSON_2_ID], + }, + }, + }); + + await makeGraphqlAPIRequest(graphqlOperation); + }); + it('1. should create and return taskTargets', async () => { + const graphqlOperation = createManyOperationFactory({ + objectMetadataSingularName: 'taskTarget', + objectMetadataPluralName: 'taskTargets', + gqlFields: TASK_TARGET_GQL_FIELDS, + data: [ + { + id: TASK_TARGET_1_ID, + }, + { + id: TASK_TARGET_2_ID, + }, + ], + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.createTaskTargets).toHaveLength(2); + + response.body.data.createTaskTargets.forEach((taskTarget) => { + expect(taskTarget).toHaveProperty('id'); + expect(taskTarget).toHaveProperty('createdAt'); + expect(taskTarget).toHaveProperty('deletedAt'); + expect(taskTarget).toHaveProperty('rocketId'); + expect(taskTarget).toHaveProperty('personId'); + expect(taskTarget).toHaveProperty('companyId'); + expect(taskTarget).toHaveProperty('opportunityId'); + expect(taskTarget).toHaveProperty('person'); + }); + }); + + it('1b. should create and return one taskTarget', async () => { + const graphqlOperation = createOneOperationFactory({ + objectMetadataSingularName: 'taskTarget', + gqlFields: TASK_TARGET_GQL_FIELDS, + data: { + id: TASK_TARGET_3_ID, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const createdTaskTarget = response.body.data.createTaskTarget; + + expect(createdTaskTarget).toHaveProperty('id'); + expect(createdTaskTarget).toHaveProperty('createdAt'); + expect(createdTaskTarget).toHaveProperty('deletedAt'); + expect(createdTaskTarget).toHaveProperty('rocketId'); + expect(createdTaskTarget).toHaveProperty('personId'); + expect(createdTaskTarget).toHaveProperty('companyId'); + expect(createdTaskTarget).toHaveProperty('opportunityId'); + expect(createdTaskTarget).toHaveProperty('person'); + }); + + it('2. should find many taskTargets', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'taskTarget', + objectMetadataPluralName: 'taskTargets', + gqlFields: TASK_TARGET_GQL_FIELDS, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const data = response.body.data.taskTargets; + + expect(data).toBeDefined(); + expect(Array.isArray(data.edges)).toBe(true); + + const edges = data.edges; + + if (edges.length > 0) { + const taskTarget = edges[0].node; + + expect(taskTarget).toHaveProperty('id'); + expect(taskTarget).toHaveProperty('createdAt'); + expect(taskTarget).toHaveProperty('deletedAt'); + expect(taskTarget).toHaveProperty('rocketId'); + expect(taskTarget).toHaveProperty('personId'); + expect(taskTarget).toHaveProperty('companyId'); + expect(taskTarget).toHaveProperty('opportunityId'); + expect(taskTarget).toHaveProperty('person'); + } + }); + + it('2b. should find one taskTarget', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'taskTarget', + gqlFields: TASK_TARGET_GQL_FIELDS, + filter: { + id: { + eq: TASK_TARGET_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const taskTarget = response.body.data.taskTarget; + + expect(taskTarget).toHaveProperty('id'); + expect(taskTarget).toHaveProperty('createdAt'); + expect(taskTarget).toHaveProperty('deletedAt'); + expect(taskTarget).toHaveProperty('rocketId'); + expect(taskTarget).toHaveProperty('personId'); + expect(taskTarget).toHaveProperty('companyId'); + expect(taskTarget).toHaveProperty('opportunityId'); + expect(taskTarget).toHaveProperty('person'); + }); + + it('3. should update many taskTargets', async () => { + const graphqlOperation = updateManyOperationFactory({ + objectMetadataSingularName: 'taskTarget', + objectMetadataPluralName: 'taskTargets', + gqlFields: TASK_TARGET_GQL_FIELDS, + data: { + personId: PERSON_1_ID, + }, + filter: { + id: { + in: [TASK_TARGET_1_ID, TASK_TARGET_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedTaskTargets = response.body.data.updateTaskTargets; + + expect(updatedTaskTargets).toHaveLength(2); + + updatedTaskTargets.forEach((taskTarget) => { + expect(taskTarget.person.id).toEqual(PERSON_1_ID); + }); + }); + + it('3b. should update one taskTarget', async () => { + const graphqlOperation = updateOneOperationFactory({ + objectMetadataSingularName: 'taskTarget', + gqlFields: TASK_TARGET_GQL_FIELDS, + data: { + personId: PERSON_2_ID, + }, + recordId: TASK_TARGET_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedTaskTarget = response.body.data.updateTaskTarget; + + expect(updatedTaskTarget.person.id).toEqual(PERSON_2_ID); + }); + + it('4. should find many taskTargets with updated personId', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'taskTarget', + objectMetadataPluralName: 'taskTargets', + gqlFields: TASK_TARGET_GQL_FIELDS, + filter: { + personId: { + eq: PERSON_1_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.taskTargets.edges).toHaveLength(2); + }); + + it('4b. should find one taskTarget with updated personId', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'taskTarget', + gqlFields: TASK_TARGET_GQL_FIELDS, + filter: { + personId: { + eq: PERSON_2_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.taskTarget.person.id).toEqual(PERSON_2_ID); + }); + + it('5. should delete many taskTargets', async () => { + const graphqlOperation = deleteManyOperationFactory({ + objectMetadataSingularName: 'taskTarget', + objectMetadataPluralName: 'taskTargets', + gqlFields: TASK_TARGET_GQL_FIELDS, + filter: { + id: { + in: [TASK_TARGET_1_ID, TASK_TARGET_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const deleteTaskTargets = response.body.data.deleteTaskTargets; + + expect(deleteTaskTargets).toHaveLength(2); + + deleteTaskTargets.forEach((taskTarget) => { + expect(taskTarget.deletedAt).toBeTruthy(); + }); + }); + + it('5b. should delete one taskTarget', async () => { + const graphqlOperation = deleteOneOperationFactory({ + objectMetadataSingularName: 'taskTarget', + gqlFields: TASK_TARGET_GQL_FIELDS, + recordId: TASK_TARGET_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.deleteTaskTarget.deletedAt).toBeTruthy(); + }); + + it('6. should not find many taskTargets anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'taskTarget', + objectMetadataPluralName: 'taskTargets', + gqlFields: TASK_TARGET_GQL_FIELDS, + filter: { + id: { + in: [TASK_TARGET_1_ID, TASK_TARGET_2_ID], + }, + }, + }); + + const findTaskTargetsResponse = + await makeGraphqlAPIRequest(graphqlOperation); + + expect(findTaskTargetsResponse.body.data.taskTargets.edges).toHaveLength(0); + }); + + it('6b. should not find one taskTarget anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'taskTarget', + gqlFields: TASK_TARGET_GQL_FIELDS, + filter: { + id: { + eq: TASK_TARGET_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.taskTarget).toBeNull(); + }); + + it('7. should find many deleted taskTargets with deletedAt filter', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'taskTarget', + objectMetadataPluralName: 'taskTargets', + gqlFields: TASK_TARGET_GQL_FIELDS, + filter: { + id: { + in: [TASK_TARGET_1_ID, TASK_TARGET_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.taskTargets.edges).toHaveLength(2); + }); + + it('7b. should find one deleted taskTarget with deletedAt filter', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'taskTarget', + gqlFields: TASK_TARGET_GQL_FIELDS, + filter: { + id: { + eq: TASK_TARGET_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.taskTarget.id).toEqual(TASK_TARGET_3_ID); + }); + + it('8. should destroy many taskTargets', async () => { + const graphqlOperation = destroyManyOperationFactory({ + objectMetadataSingularName: 'taskTarget', + objectMetadataPluralName: 'taskTargets', + gqlFields: TASK_TARGET_GQL_FIELDS, + filter: { + id: { + in: [TASK_TARGET_1_ID, TASK_TARGET_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.destroyTaskTargets).toHaveLength(2); + }); + + it('8b. should destroy one taskTarget', async () => { + const graphqlOperation = destroyOneOperationFactory({ + objectMetadataSingularName: 'taskTarget', + gqlFields: TASK_TARGET_GQL_FIELDS, + recordId: TASK_TARGET_3_ID, + }); + + const destroyTaskTargetsResponse = + await makeGraphqlAPIRequest(graphqlOperation); + + expect(destroyTaskTargetsResponse.body.data.destroyTaskTarget).toBeTruthy(); + }); + + it('9. should not find many taskTargets anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'taskTarget', + objectMetadataPluralName: 'taskTargets', + gqlFields: TASK_TARGET_GQL_FIELDS, + filter: { + id: { + in: [TASK_TARGET_1_ID, TASK_TARGET_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.taskTargets.edges).toHaveLength(0); + }); + + it('9b. should not find one taskTarget anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'taskTarget', + gqlFields: TASK_TARGET_GQL_FIELDS, + filter: { + id: { + eq: TASK_TARGET_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.taskTarget).toBeNull(); + }); +}); diff --git a/packages/twenty-server/test/integration/graphql/suites/all-tasks-resolvers.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/all-tasks-resolvers.integration-spec.ts new file mode 100644 index 000000000000..f2c5261e9856 --- /dev/null +++ b/packages/twenty-server/test/integration/graphql/suites/all-tasks-resolvers.integration-spec.ts @@ -0,0 +1,403 @@ +import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util'; +import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; +import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util'; +import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util'; +import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util'; +import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util'; +import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util'; +import { findOneOperationFactory } from 'test/integration/graphql/utils/find-one-operation-factory.util'; +import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util'; +import { updateOneOperationFactory } from 'test/integration/graphql/utils/update-one-operation-factory.util'; +import { generateRecordName } from 'test/integration/utils/generate-record-name'; + +const TASK_1_ID = '777a8457-eb2d-40ac-a707-551b615b6987'; +const TASK_2_ID = '777a8457-eb2d-40ac-a707-551b615b6988'; +const TASK_3_ID = '777a8457-eb2d-40ac-a707-551b615b6989'; + +const TASK_GQL_FIELDS = ` + id + title + createdAt + updatedAt + deletedAt + body + position +`; + +describe('tasks resolvers (integration)', () => { + it('1. should create and return tasks', async () => { + const taskTitle1 = generateRecordName(TASK_1_ID); + const taskTitle2 = generateRecordName(TASK_2_ID); + const graphqlOperation = createManyOperationFactory({ + objectMetadataSingularName: 'task', + objectMetadataPluralName: 'tasks', + gqlFields: TASK_GQL_FIELDS, + data: [ + { + id: TASK_1_ID, + title: taskTitle1, + }, + { + id: TASK_2_ID, + title: taskTitle2, + }, + ], + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.createTasks).toHaveLength(2); + + response.body.data.createTasks.forEach((task) => { + expect(task).toHaveProperty('title'); + expect([taskTitle1, taskTitle2]).toContain(task.title); + + expect(task).toHaveProperty('id'); + expect(task).toHaveProperty('createdAt'); + expect(task).toHaveProperty('updatedAt'); + expect(task).toHaveProperty('deletedAt'); + expect(task).toHaveProperty('body'); + expect(task).toHaveProperty('position'); + }); + }); + + it('1b. should create and return one task', async () => { + const taskTitle3 = generateRecordName(TASK_3_ID); + + const graphqlOperation = createOneOperationFactory({ + objectMetadataSingularName: 'task', + gqlFields: TASK_GQL_FIELDS, + data: { + id: TASK_3_ID, + title: taskTitle3, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const createdTask = response.body.data.createTask; + + expect(createdTask).toHaveProperty('title'); + expect(createdTask.title).toEqual(taskTitle3); + + expect(createdTask).toHaveProperty('id'); + expect(createdTask).toHaveProperty('createdAt'); + expect(createdTask).toHaveProperty('updatedAt'); + expect(createdTask).toHaveProperty('deletedAt'); + expect(createdTask).toHaveProperty('body'); + expect(createdTask).toHaveProperty('position'); + }); + + it('2. should find many tasks', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'task', + objectMetadataPluralName: 'tasks', + gqlFields: TASK_GQL_FIELDS, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const data = response.body.data.tasks; + + expect(data).toBeDefined(); + expect(Array.isArray(data.edges)).toBe(true); + + const edges = data.edges; + + if (edges.length > 0) { + const task = edges[0].node; + + expect(task).toHaveProperty('id'); + expect(task).toHaveProperty('createdAt'); + expect(task).toHaveProperty('updatedAt'); + expect(task).toHaveProperty('deletedAt'); + expect(task).toHaveProperty('body'); + expect(task).toHaveProperty('position'); + } + }); + + it('2b. should find one task', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'task', + gqlFields: TASK_GQL_FIELDS, + filter: { + id: { + eq: TASK_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const task = response.body.data.task; + + expect(task).toHaveProperty('title'); + + expect(task).toHaveProperty('id'); + expect(task).toHaveProperty('createdAt'); + expect(task).toHaveProperty('updatedAt'); + expect(task).toHaveProperty('deletedAt'); + expect(task).toHaveProperty('body'); + expect(task).toHaveProperty('position'); + }); + + it('3. should update many tasks', async () => { + const graphqlOperation = updateManyOperationFactory({ + objectMetadataSingularName: 'task', + objectMetadataPluralName: 'tasks', + gqlFields: TASK_GQL_FIELDS, + data: { + title: 'Updated Title', + }, + filter: { + id: { + in: [TASK_1_ID, TASK_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedTasks = response.body.data.updateTasks; + + expect(updatedTasks).toHaveLength(2); + + updatedTasks.forEach((task) => { + expect(task.title).toEqual('Updated Title'); + }); + }); + + it('3b. should update one task', async () => { + const graphqlOperation = updateOneOperationFactory({ + objectMetadataSingularName: 'task', + gqlFields: TASK_GQL_FIELDS, + data: { + title: 'New Title', + }, + recordId: TASK_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedTask = response.body.data.updateTask; + + expect(updatedTask.title).toEqual('New Title'); + }); + + it('4. should find many tasks with updated title', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'task', + objectMetadataPluralName: 'tasks', + gqlFields: TASK_GQL_FIELDS, + filter: { + title: { + eq: 'Updated Title', + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.tasks.edges).toHaveLength(2); + }); + + it('4b. should find one task with updated title', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'task', + gqlFields: TASK_GQL_FIELDS, + filter: { + title: { + eq: 'New Title', + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.task.title).toEqual('New Title'); + }); + + it('5. should delete many tasks', async () => { + const graphqlOperation = deleteManyOperationFactory({ + objectMetadataSingularName: 'task', + objectMetadataPluralName: 'tasks', + gqlFields: TASK_GQL_FIELDS, + filter: { + id: { + in: [TASK_1_ID, TASK_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const deleteTasks = response.body.data.deleteTasks; + + expect(deleteTasks).toHaveLength(2); + + deleteTasks.forEach((task) => { + expect(task.deletedAt).toBeTruthy(); + }); + }); + + it('5b. should delete one task', async () => { + const graphqlOperation = deleteOneOperationFactory({ + objectMetadataSingularName: 'task', + gqlFields: TASK_GQL_FIELDS, + recordId: TASK_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.deleteTask.deletedAt).toBeTruthy(); + }); + + it('6. should not find many tasks anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'task', + objectMetadataPluralName: 'tasks', + gqlFields: TASK_GQL_FIELDS, + filter: { + id: { + in: [TASK_1_ID, TASK_2_ID], + }, + }, + }); + + const findTasksResponse = await makeGraphqlAPIRequest(graphqlOperation); + + expect(findTasksResponse.body.data.tasks.edges).toHaveLength(0); + }); + + it('6b. should not find one task anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'task', + gqlFields: TASK_GQL_FIELDS, + filter: { + id: { + eq: TASK_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.task).toBeNull(); + }); + + it('7. should find many deleted tasks with deletedAt filter', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'task', + objectMetadataPluralName: 'tasks', + gqlFields: TASK_GQL_FIELDS, + filter: { + id: { + in: [TASK_1_ID, TASK_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.tasks.edges).toHaveLength(2); + }); + + it('7b. should find one deleted task with deletedAt filter', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'task', + gqlFields: TASK_GQL_FIELDS, + filter: { + id: { + eq: TASK_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.task.id).toEqual(TASK_3_ID); + }); + + it('8. should destroy many tasks', async () => { + const graphqlOperation = destroyManyOperationFactory({ + objectMetadataSingularName: 'task', + objectMetadataPluralName: 'tasks', + gqlFields: TASK_GQL_FIELDS, + filter: { + id: { + in: [TASK_1_ID, TASK_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.destroyTasks).toHaveLength(2); + }); + + it('8b. should destroy one task', async () => { + const graphqlOperation = destroyOneOperationFactory({ + objectMetadataSingularName: 'task', + gqlFields: TASK_GQL_FIELDS, + recordId: TASK_3_ID, + }); + + const destroyTasksResponse = await makeGraphqlAPIRequest(graphqlOperation); + + expect(destroyTasksResponse.body.data.destroyTask).toBeTruthy(); + }); + + it('9. should not find many tasks anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'task', + objectMetadataPluralName: 'tasks', + gqlFields: TASK_GQL_FIELDS, + filter: { + id: { + in: [TASK_1_ID, TASK_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.tasks.edges).toHaveLength(0); + }); + + it('9b. should not find one task anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'task', + gqlFields: TASK_GQL_FIELDS, + filter: { + id: { + eq: TASK_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.task).toBeNull(); + }); +}); diff --git a/packages/twenty-server/test/integration/graphql/suites/all-timeline-activities.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/all-timeline-activities.integration-spec.ts new file mode 100644 index 000000000000..38a468ec7ce3 --- /dev/null +++ b/packages/twenty-server/test/integration/graphql/suites/all-timeline-activities.integration-spec.ts @@ -0,0 +1,477 @@ +import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util'; +import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; +import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util'; +import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util'; +import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util'; +import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util'; +import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util'; +import { findOneOperationFactory } from 'test/integration/graphql/utils/find-one-operation-factory.util'; +import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util'; +import { updateOneOperationFactory } from 'test/integration/graphql/utils/update-one-operation-factory.util'; +import { generateRecordName } from 'test/integration/utils/generate-record-name'; + +const TIMELINE_ACTIVITY_1_ID = '777a8457-eb2d-40ac-a707-551b615b6987'; +const TIMELINE_ACTIVITY_2_ID = '777a8457-eb2d-40ac-a707-551b615b6988'; +const TIMELINE_ACTIVITY_3_ID = '777a8457-eb2d-40ac-a707-551b615b6989'; + +const TIMELINE_ACTIVITY_GQL_FIELDS = ` + id + happensAt + name + properties + linkedRecordCachedName + linkedRecordId + linkedObjectMetadataId + createdAt + updatedAt + deletedAt + workspaceMemberId + personId + companyId + opportunityId + noteId + taskId + workflowId + workflowVersionId + workflowRunId + rocketId +`; + +describe('timelineActivities resolvers (integration)', () => { + it('1. should create and return timelineActivities', async () => { + const timelineActivityName1 = generateRecordName(TIMELINE_ACTIVITY_1_ID); + const timelineActivityName2 = generateRecordName(TIMELINE_ACTIVITY_2_ID); + + const graphqlOperation = createManyOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + objectMetadataPluralName: 'timelineActivities', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + data: [ + { + id: TIMELINE_ACTIVITY_1_ID, + name: timelineActivityName1, + }, + { + id: TIMELINE_ACTIVITY_2_ID, + name: timelineActivityName2, + }, + ], + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.createTimelineActivities).toHaveLength(2); + + response.body.data.createTimelineActivities.forEach((timelineActivity) => { + expect(timelineActivity).toHaveProperty('name'); + expect([timelineActivityName1, timelineActivityName2]).toContain( + timelineActivity.name, + ); + expect(timelineActivity).toHaveProperty('id'); + expect(timelineActivity).toHaveProperty('happensAt'); + expect(timelineActivity).toHaveProperty('properties'); + expect(timelineActivity).toHaveProperty('linkedRecordCachedName'); + expect(timelineActivity).toHaveProperty('linkedRecordId'); + expect(timelineActivity).toHaveProperty('linkedObjectMetadataId'); + expect(timelineActivity).toHaveProperty('createdAt'); + expect(timelineActivity).toHaveProperty('updatedAt'); + expect(timelineActivity).toHaveProperty('deletedAt'); + expect(timelineActivity).toHaveProperty('workspaceMemberId'); + expect(timelineActivity).toHaveProperty('personId'); + expect(timelineActivity).toHaveProperty('companyId'); + expect(timelineActivity).toHaveProperty('opportunityId'); + expect(timelineActivity).toHaveProperty('noteId'); + expect(timelineActivity).toHaveProperty('taskId'); + expect(timelineActivity).toHaveProperty('workflowId'); + expect(timelineActivity).toHaveProperty('workflowVersionId'); + expect(timelineActivity).toHaveProperty('workflowRunId'); + expect(timelineActivity).toHaveProperty('rocketId'); + }); + }); + + it('1b. should create and return one timelineActivity', async () => { + const timelineActivityName = generateRecordName(TIMELINE_ACTIVITY_3_ID); + + const graphqlOperation = createOneOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + data: { + id: TIMELINE_ACTIVITY_3_ID, + name: timelineActivityName, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const createdTimelineActivity = response.body.data.createTimelineActivity; + + expect(createdTimelineActivity).toHaveProperty('name'); + expect(createdTimelineActivity.name).toEqual(timelineActivityName); + expect(createdTimelineActivity).toHaveProperty('id'); + expect(createdTimelineActivity).toHaveProperty('happensAt'); + expect(createdTimelineActivity).toHaveProperty('properties'); + expect(createdTimelineActivity).toHaveProperty('linkedRecordCachedName'); + expect(createdTimelineActivity).toHaveProperty('linkedRecordId'); + expect(createdTimelineActivity).toHaveProperty('linkedObjectMetadataId'); + expect(createdTimelineActivity).toHaveProperty('createdAt'); + expect(createdTimelineActivity).toHaveProperty('updatedAt'); + expect(createdTimelineActivity).toHaveProperty('deletedAt'); + expect(createdTimelineActivity).toHaveProperty('workspaceMemberId'); + expect(createdTimelineActivity).toHaveProperty('personId'); + expect(createdTimelineActivity).toHaveProperty('companyId'); + expect(createdTimelineActivity).toHaveProperty('opportunityId'); + expect(createdTimelineActivity).toHaveProperty('noteId'); + expect(createdTimelineActivity).toHaveProperty('taskId'); + expect(createdTimelineActivity).toHaveProperty('workflowId'); + expect(createdTimelineActivity).toHaveProperty('workflowVersionId'); + expect(createdTimelineActivity).toHaveProperty('workflowRunId'); + expect(createdTimelineActivity).toHaveProperty('rocketId'); + }); + + it('2. should find many timelineActivities', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + objectMetadataPluralName: 'timelineActivities', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const data = response.body.data.timelineActivities; + + expect(data).toBeDefined(); + expect(Array.isArray(data.edges)).toBe(true); + + if (data.edges.length > 0) { + const timelineActivities = data.edges[0].node; + + expect(timelineActivities).toHaveProperty('happensAt'); + expect(timelineActivities).toHaveProperty('name'); + expect(timelineActivities).toHaveProperty('properties'); + expect(timelineActivities).toHaveProperty('linkedRecordCachedName'); + expect(timelineActivities).toHaveProperty('linkedRecordId'); + expect(timelineActivities).toHaveProperty('linkedObjectMetadataId'); + expect(timelineActivities).toHaveProperty('id'); + expect(timelineActivities).toHaveProperty('createdAt'); + expect(timelineActivities).toHaveProperty('updatedAt'); + expect(timelineActivities).toHaveProperty('deletedAt'); + expect(timelineActivities).toHaveProperty('workspaceMemberId'); + expect(timelineActivities).toHaveProperty('personId'); + expect(timelineActivities).toHaveProperty('companyId'); + expect(timelineActivities).toHaveProperty('opportunityId'); + expect(timelineActivities).toHaveProperty('noteId'); + expect(timelineActivities).toHaveProperty('taskId'); + expect(timelineActivities).toHaveProperty('workflowId'); + expect(timelineActivities).toHaveProperty('workflowVersionId'); + expect(timelineActivities).toHaveProperty('workflowRunId'); + expect(timelineActivities).toHaveProperty('rocketId'); + } + }); + + it('2b. should find one timelineActivity', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + filter: { + id: { + eq: TIMELINE_ACTIVITY_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const timelineActivity = response.body.data.timelineActivity; + + expect(timelineActivity).toHaveProperty('happensAt'); + expect(timelineActivity).toHaveProperty('name'); + expect(timelineActivity).toHaveProperty('properties'); + expect(timelineActivity).toHaveProperty('linkedRecordCachedName'); + expect(timelineActivity).toHaveProperty('linkedRecordId'); + expect(timelineActivity).toHaveProperty('linkedObjectMetadataId'); + expect(timelineActivity).toHaveProperty('id'); + expect(timelineActivity).toHaveProperty('createdAt'); + expect(timelineActivity).toHaveProperty('updatedAt'); + expect(timelineActivity).toHaveProperty('deletedAt'); + expect(timelineActivity).toHaveProperty('workspaceMemberId'); + expect(timelineActivity).toHaveProperty('personId'); + expect(timelineActivity).toHaveProperty('companyId'); + expect(timelineActivity).toHaveProperty('opportunityId'); + expect(timelineActivity).toHaveProperty('noteId'); + expect(timelineActivity).toHaveProperty('taskId'); + expect(timelineActivity).toHaveProperty('workflowId'); + expect(timelineActivity).toHaveProperty('workflowVersionId'); + expect(timelineActivity).toHaveProperty('workflowRunId'); + expect(timelineActivity).toHaveProperty('rocketId'); + }); + + it('3. should update many timelineActivities', async () => { + const graphqlOperation = updateManyOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + objectMetadataPluralName: 'timelineActivities', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + data: { + name: 'Updated Name', + }, + filter: { + id: { + in: [TIMELINE_ACTIVITY_1_ID, TIMELINE_ACTIVITY_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedTimelineActivities = + response.body.data.updateTimelineActivities; + + expect(updatedTimelineActivities).toHaveLength(2); + + updatedTimelineActivities.forEach((timelineActivity) => { + expect(timelineActivity.name).toEqual('Updated Name'); + }); + }); + + it('3b. should update one timelineActivity', async () => { + const graphqlOperation = updateOneOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + data: { + name: 'New Name', + }, + recordId: TIMELINE_ACTIVITY_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedTimelineActivity = response.body.data.updateTimelineActivity; + + expect(updatedTimelineActivity.name).toEqual('New Name'); + }); + + it('4. should find many timelineActivities with updated name', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + objectMetadataPluralName: 'timelineActivities', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + filter: { + name: { + eq: 'Updated Name', + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.timelineActivities.edges).toHaveLength(2); + }); + + it('4b. should find one timelineActivity with updated name', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + filter: { + name: { + eq: 'New Name', + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.timelineActivity.name).toEqual('New Name'); + }); + + it('5. should delete many timelineActivities', async () => { + const graphqlOperation = deleteManyOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + objectMetadataPluralName: 'timelineActivities', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + filter: { + id: { + in: [TIMELINE_ACTIVITY_1_ID, TIMELINE_ACTIVITY_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const deletedTimelineActivities = + response.body.data.deleteTimelineActivities; + + expect(deletedTimelineActivities).toHaveLength(2); + + deletedTimelineActivities.forEach((timelineActivity) => { + expect(timelineActivity.deletedAt).toBeTruthy(); + }); + }); + + it('5b. should delete one timelineActivity', async () => { + const graphqlOperation = deleteOneOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + recordId: TIMELINE_ACTIVITY_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.deleteTimelineActivity.deletedAt).toBeTruthy(); + }); + + it('6. should not find many timelineActivities anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + objectMetadataPluralName: 'timelineActivities', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + filter: { + id: { + in: [TIMELINE_ACTIVITY_1_ID, TIMELINE_ACTIVITY_2_ID], + }, + }, + }); + + const findTimelineActivitiesResponse = + await makeGraphqlAPIRequest(graphqlOperation); + + expect( + findTimelineActivitiesResponse.body.data.timelineActivities.edges, + ).toHaveLength(0); + }); + + it('6b. should not find one timelineActivity anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + filter: { + id: { + eq: TIMELINE_ACTIVITY_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.timelineActivity).toBeNull(); + }); + + it('7. should find many deleted timelineActivities with deletedAt filter', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + objectMetadataPluralName: 'timelineActivities', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + filter: { + id: { + in: [TIMELINE_ACTIVITY_1_ID, TIMELINE_ACTIVITY_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.timelineActivities.edges).toHaveLength(2); + }); + + it('7b. should find one deleted timelineActivity with deletedAt filter', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + filter: { + id: { + eq: TIMELINE_ACTIVITY_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.timelineActivity.id).toEqual( + TIMELINE_ACTIVITY_3_ID, + ); + }); + + it('8. should destroy many timelineActivities', async () => { + const graphqlOperation = destroyManyOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + objectMetadataPluralName: 'timelineActivities', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + filter: { + id: { + in: [TIMELINE_ACTIVITY_1_ID, TIMELINE_ACTIVITY_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.destroyTimelineActivities).toHaveLength(2); + }); + + it('8b. should destroy one timelineActivity', async () => { + const graphqlOperation = destroyOneOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + recordId: TIMELINE_ACTIVITY_3_ID, + }); + + const destroyTimelineActivityResponse = + await makeGraphqlAPIRequest(graphqlOperation); + + expect( + destroyTimelineActivityResponse.body.data.destroyTimelineActivity, + ).toBeTruthy(); + }); + + it('9. should not find many timelineActivities anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + objectMetadataPluralName: 'timelineActivities', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + filter: { + id: { + in: [TIMELINE_ACTIVITY_1_ID, TIMELINE_ACTIVITY_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.timelineActivities.edges).toHaveLength(0); + }); + + it('9b. should not find one timelineActivity anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'timelineActivity', + gqlFields: TIMELINE_ACTIVITY_GQL_FIELDS, + filter: { + id: { + eq: TIMELINE_ACTIVITY_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.timelineActivity).toBeNull(); + }); +}); diff --git a/packages/twenty-server/test/integration/graphql/suites/all-view-fields.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/all-view-fields.integration-spec.ts new file mode 100644 index 000000000000..168bad0376b9 --- /dev/null +++ b/packages/twenty-server/test/integration/graphql/suites/all-view-fields.integration-spec.ts @@ -0,0 +1,407 @@ +import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util'; +import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; +import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util'; +import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util'; +import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util'; +import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util'; +import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util'; +import { findOneOperationFactory } from 'test/integration/graphql/utils/find-one-operation-factory.util'; +import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util'; +import { updateOneOperationFactory } from 'test/integration/graphql/utils/update-one-operation-factory.util'; + +const VIEW_FIELD_1_ID = '777a8457-eb2d-40ac-a707-551b615b6987'; +const VIEW_FIELD_2_ID = '777a8457-eb2d-40ac-a707-551b615b6988'; +const VIEW_FIELD_3_ID = '777a8457-eb2d-40ac-a707-551b615b6989'; +const FIELD_METADATA_ID = '20202020-0c28-43d8-8ba5-3659924d3489'; + +const VIEW_FIELD_GQL_FIELDS = ` + id + fieldMetadataId + isVisible + size + position + createdAt + updatedAt + deletedAt + viewId +`; + +describe('viewFields resolvers (integration)', () => { + it('1. should create and return viewFields', async () => { + const graphqlOperation = createManyOperationFactory({ + objectMetadataSingularName: 'viewField', + objectMetadataPluralName: 'viewFields', + gqlFields: VIEW_FIELD_GQL_FIELDS, + data: [ + { + id: VIEW_FIELD_1_ID, + fieldMetadataId: FIELD_METADATA_ID, + }, + { + id: VIEW_FIELD_2_ID, + fieldMetadataId: FIELD_METADATA_ID, + }, + ], + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.createViewFields).toHaveLength(2); + + response.body.data.createViewFields.forEach((viewField) => { + expect(viewField).toHaveProperty('fieldMetadataId'); + expect(viewField.fieldMetadataId).toEqual(FIELD_METADATA_ID); + expect(viewField).toHaveProperty('id'); + expect(viewField).toHaveProperty('isVisible'); + expect(viewField).toHaveProperty('size'); + expect(viewField).toHaveProperty('position'); + expect(viewField).toHaveProperty('createdAt'); + expect(viewField).toHaveProperty('updatedAt'); + expect(viewField).toHaveProperty('deletedAt'); + expect(viewField).toHaveProperty('viewId'); + }); + }); + + it('1b. should create and return one viewField', async () => { + const graphqlOperation = createOneOperationFactory({ + objectMetadataSingularName: 'viewField', + gqlFields: VIEW_FIELD_GQL_FIELDS, + data: { + id: VIEW_FIELD_3_ID, + fieldMetadataId: FIELD_METADATA_ID, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const createdViewField = response.body.data.createViewField; + + expect(createdViewField).toHaveProperty('fieldMetadataId'); + expect(createdViewField.fieldMetadataId).toEqual(FIELD_METADATA_ID); + expect(createdViewField).toHaveProperty('id'); + expect(createdViewField).toHaveProperty('isVisible'); + expect(createdViewField).toHaveProperty('size'); + expect(createdViewField).toHaveProperty('position'); + expect(createdViewField).toHaveProperty('createdAt'); + expect(createdViewField).toHaveProperty('updatedAt'); + expect(createdViewField).toHaveProperty('deletedAt'); + expect(createdViewField).toHaveProperty('viewId'); + }); + + it('2. should find many viewFields', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewField', + objectMetadataPluralName: 'viewFields', + gqlFields: VIEW_FIELD_GQL_FIELDS, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const data = response.body.data.viewFields; + + expect(data).toBeDefined(); + expect(Array.isArray(data.edges)).toBe(true); + + if (data.edges.length > 0) { + const viewFields = data.edges[0].node; + + expect(viewFields).toHaveProperty('fieldMetadataId'); + expect(viewFields).toHaveProperty('isVisible'); + expect(viewFields).toHaveProperty('size'); + expect(viewFields).toHaveProperty('position'); + expect(viewFields).toHaveProperty('id'); + expect(viewFields).toHaveProperty('createdAt'); + expect(viewFields).toHaveProperty('updatedAt'); + expect(viewFields).toHaveProperty('deletedAt'); + expect(viewFields).toHaveProperty('viewId'); + } + }); + + it('2b. should find one viewField', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewField', + gqlFields: VIEW_FIELD_GQL_FIELDS, + filter: { + id: { + eq: VIEW_FIELD_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const viewField = response.body.data.viewField; + + expect(viewField).toHaveProperty('fieldMetadataId'); + expect(viewField).toHaveProperty('isVisible'); + expect(viewField).toHaveProperty('size'); + expect(viewField).toHaveProperty('position'); + expect(viewField).toHaveProperty('id'); + expect(viewField).toHaveProperty('createdAt'); + expect(viewField).toHaveProperty('updatedAt'); + expect(viewField).toHaveProperty('deletedAt'); + expect(viewField).toHaveProperty('viewId'); + }); + + it('3. should update many viewFields', async () => { + const graphqlOperation = updateManyOperationFactory({ + objectMetadataSingularName: 'viewField', + objectMetadataPluralName: 'viewFields', + gqlFields: VIEW_FIELD_GQL_FIELDS, + data: { + isVisible: false, + }, + filter: { + id: { + in: [VIEW_FIELD_1_ID, VIEW_FIELD_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedViewFields = response.body.data.updateViewFields; + + expect(updatedViewFields).toHaveLength(2); + + updatedViewFields.forEach((viewField) => { + expect(viewField.isVisible).toEqual(false); + }); + }); + + it('3b. should update one viewField', async () => { + const graphqlOperation = updateOneOperationFactory({ + objectMetadataSingularName: 'viewField', + gqlFields: VIEW_FIELD_GQL_FIELDS, + data: { + isVisible: true, + }, + recordId: VIEW_FIELD_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedViewField = response.body.data.updateViewField; + + expect(updatedViewField.isVisible).toEqual(true); + }); + + it('4. should find many viewFields with updated visibility', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewField', + objectMetadataPluralName: 'viewFields', + gqlFields: VIEW_FIELD_GQL_FIELDS, + filter: { + isVisible: { + eq: false, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewFields.edges).toHaveLength(2); + }); + + it('4b. should find one viewField with updated visibility', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewField', + gqlFields: VIEW_FIELD_GQL_FIELDS, + filter: { + isVisible: { + eq: true, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewField.isVisible).toEqual(true); + }); + + it('5. should delete many viewFields', async () => { + const graphqlOperation = deleteManyOperationFactory({ + objectMetadataSingularName: 'viewField', + objectMetadataPluralName: 'viewFields', + gqlFields: VIEW_FIELD_GQL_FIELDS, + filter: { + id: { + in: [VIEW_FIELD_1_ID, VIEW_FIELD_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const deletedViewFields = response.body.data.deleteViewFields; + + expect(deletedViewFields).toHaveLength(2); + + deletedViewFields.forEach((viewField) => { + expect(viewField.deletedAt).toBeTruthy(); + }); + }); + + it('5b. should delete one viewField', async () => { + const graphqlOperation = deleteOneOperationFactory({ + objectMetadataSingularName: 'viewField', + gqlFields: VIEW_FIELD_GQL_FIELDS, + recordId: VIEW_FIELD_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.deleteViewField.deletedAt).toBeTruthy(); + }); + + it('6. should not find many viewFields anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewField', + objectMetadataPluralName: 'viewFields', + gqlFields: VIEW_FIELD_GQL_FIELDS, + filter: { + id: { + in: [VIEW_FIELD_1_ID, VIEW_FIELD_2_ID], + }, + }, + }); + + const findViewFieldsResponse = + await makeGraphqlAPIRequest(graphqlOperation); + + expect(findViewFieldsResponse.body.data.viewFields.edges).toHaveLength(0); + }); + + it('6b. should not find one viewField anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewField', + gqlFields: VIEW_FIELD_GQL_FIELDS, + filter: { + id: { + eq: VIEW_FIELD_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewField).toBeNull(); + }); + + it('7. should find many deleted viewFields with deletedAt filter', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewField', + objectMetadataPluralName: 'viewFields', + gqlFields: VIEW_FIELD_GQL_FIELDS, + filter: { + id: { + in: [VIEW_FIELD_1_ID, VIEW_FIELD_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewFields.edges).toHaveLength(2); + }); + + it('7b. should find one deleted viewField with deletedAt filter', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewField', + gqlFields: VIEW_FIELD_GQL_FIELDS, + filter: { + id: { + eq: VIEW_FIELD_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewField.id).toEqual(VIEW_FIELD_3_ID); + }); + + it('8. should destroy many viewFields', async () => { + const graphqlOperation = destroyManyOperationFactory({ + objectMetadataSingularName: 'viewField', + objectMetadataPluralName: 'viewFields', + gqlFields: VIEW_FIELD_GQL_FIELDS, + filter: { + id: { + in: [VIEW_FIELD_1_ID, VIEW_FIELD_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.destroyViewFields).toHaveLength(2); + }); + + it('8b. should destroy one viewField', async () => { + const graphqlOperation = destroyOneOperationFactory({ + objectMetadataSingularName: 'viewField', + gqlFields: VIEW_FIELD_GQL_FIELDS, + recordId: VIEW_FIELD_3_ID, + }); + + const destroyViewFieldResponse = + await makeGraphqlAPIRequest(graphqlOperation); + + expect(destroyViewFieldResponse.body.data.destroyViewField).toBeTruthy(); + }); + + it('9. should not find many viewFields anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewField', + objectMetadataPluralName: 'viewFields', + gqlFields: VIEW_FIELD_GQL_FIELDS, + filter: { + id: { + in: [VIEW_FIELD_1_ID, VIEW_FIELD_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewFields.edges).toHaveLength(0); + }); + + it('9b. should not find one viewField anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewField', + gqlFields: VIEW_FIELD_GQL_FIELDS, + filter: { + id: { + eq: VIEW_FIELD_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewField).toBeNull(); + }); +}); diff --git a/packages/twenty-server/test/integration/graphql/suites/all-view-filters.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/all-view-filters.integration-spec.ts new file mode 100644 index 000000000000..e55c654aafae --- /dev/null +++ b/packages/twenty-server/test/integration/graphql/suites/all-view-filters.integration-spec.ts @@ -0,0 +1,407 @@ +import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util'; +import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; +import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util'; +import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util'; +import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util'; +import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util'; +import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util'; +import { findOneOperationFactory } from 'test/integration/graphql/utils/find-one-operation-factory.util'; +import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util'; +import { updateOneOperationFactory } from 'test/integration/graphql/utils/update-one-operation-factory.util'; + +const VIEW_FILTER_1_ID = '777a8457-eb2d-40ac-a707-551b615b6987'; +const VIEW_FILTER_2_ID = '777a8457-eb2d-40ac-a707-551b615b6988'; +const VIEW_FILTER_3_ID = '777a8457-eb2d-40ac-a707-551b615b6989'; +const FIELD_METADATA_ID = '20202020-0c28-43d8-8ba5-3659924d3489'; + +const VIEW_FILTER_FIELDS = ` + id + fieldMetadataId + operand + value + displayValue + createdAt + updatedAt + deletedAt + viewId +`; + +describe('viewFilters resolvers (integration)', () => { + it('1. should create and return viewFilters', async () => { + const graphqlOperation = createManyOperationFactory({ + objectMetadataSingularName: 'viewFilter', + objectMetadataPluralName: 'viewFilters', + gqlFields: VIEW_FILTER_FIELDS, + data: [ + { + id: VIEW_FILTER_1_ID, + fieldMetadataId: FIELD_METADATA_ID, + }, + { + id: VIEW_FILTER_2_ID, + fieldMetadataId: FIELD_METADATA_ID, + }, + ], + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.createViewFilters).toHaveLength(2); + + response.body.data.createViewFilters.forEach((viewFilter) => { + expect(viewFilter).toHaveProperty('fieldMetadataId'); + expect(viewFilter.fieldMetadataId).toEqual(FIELD_METADATA_ID); + expect(viewFilter).toHaveProperty('id'); + expect(viewFilter).toHaveProperty('operand'); + expect(viewFilter).toHaveProperty('value'); + expect(viewFilter).toHaveProperty('displayValue'); + expect(viewFilter).toHaveProperty('createdAt'); + expect(viewFilter).toHaveProperty('updatedAt'); + expect(viewFilter).toHaveProperty('deletedAt'); + expect(viewFilter).toHaveProperty('viewId'); + }); + }); + + it('1b. should create and return one viewFilter', async () => { + const graphqlOperation = createOneOperationFactory({ + objectMetadataSingularName: 'viewFilter', + gqlFields: VIEW_FILTER_FIELDS, + data: { + id: VIEW_FILTER_3_ID, + fieldMetadataId: FIELD_METADATA_ID, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const createdViewFilter = response.body.data.createViewFilter; + + expect(createdViewFilter).toHaveProperty('fieldMetadataId'); + expect(createdViewFilter.fieldMetadataId).toEqual(FIELD_METADATA_ID); + expect(createdViewFilter).toHaveProperty('id'); + expect(createdViewFilter).toHaveProperty('operand'); + expect(createdViewFilter).toHaveProperty('value'); + expect(createdViewFilter).toHaveProperty('displayValue'); + expect(createdViewFilter).toHaveProperty('createdAt'); + expect(createdViewFilter).toHaveProperty('updatedAt'); + expect(createdViewFilter).toHaveProperty('deletedAt'); + expect(createdViewFilter).toHaveProperty('viewId'); + }); + + it('2. should find many viewFilters', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewFilter', + objectMetadataPluralName: 'viewFilters', + gqlFields: VIEW_FILTER_FIELDS, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const data = response.body.data.viewFilters; + + expect(data).toBeDefined(); + expect(Array.isArray(data.edges)).toBe(true); + + if (data.edges.length > 0) { + const viewFilters = data.edges[0].node; + + expect(viewFilters).toHaveProperty('fieldMetadataId'); + expect(viewFilters).toHaveProperty('operand'); + expect(viewFilters).toHaveProperty('value'); + expect(viewFilters).toHaveProperty('displayValue'); + expect(viewFilters).toHaveProperty('id'); + expect(viewFilters).toHaveProperty('createdAt'); + expect(viewFilters).toHaveProperty('updatedAt'); + expect(viewFilters).toHaveProperty('deletedAt'); + expect(viewFilters).toHaveProperty('viewId'); + } + }); + + it('2b. should find one viewFilter', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewFilter', + gqlFields: VIEW_FILTER_FIELDS, + filter: { + id: { + eq: VIEW_FILTER_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const viewFilter = response.body.data.viewFilter; + + expect(viewFilter).toHaveProperty('fieldMetadataId'); + expect(viewFilter).toHaveProperty('operand'); + expect(viewFilter).toHaveProperty('value'); + expect(viewFilter).toHaveProperty('displayValue'); + expect(viewFilter).toHaveProperty('id'); + expect(viewFilter).toHaveProperty('createdAt'); + expect(viewFilter).toHaveProperty('updatedAt'); + expect(viewFilter).toHaveProperty('deletedAt'); + expect(viewFilter).toHaveProperty('viewId'); + }); + + it('3. should update many viewFilters', async () => { + const graphqlOperation = updateManyOperationFactory({ + objectMetadataSingularName: 'viewFilter', + objectMetadataPluralName: 'viewFilters', + gqlFields: VIEW_FILTER_FIELDS, + data: { + operand: 'Updated Operand', + }, + filter: { + id: { + in: [VIEW_FILTER_1_ID, VIEW_FILTER_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedViewFilters = response.body.data.updateViewFilters; + + expect(updatedViewFilters).toHaveLength(2); + + updatedViewFilters.forEach((viewFilter) => { + expect(viewFilter.operand).toEqual('Updated Operand'); + }); + }); + + it('3b. should update one viewFilter', async () => { + const graphqlOperation = updateOneOperationFactory({ + objectMetadataSingularName: 'viewFilter', + gqlFields: VIEW_FILTER_FIELDS, + data: { + operand: 'Updated Operand 3', + }, + recordId: VIEW_FILTER_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedViewFilter = response.body.data.updateViewFilter; + + expect(updatedViewFilter.operand).toEqual('Updated Operand 3'); + }); + + it('4. should find many viewFilters with updated operand', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewFilter', + objectMetadataPluralName: 'viewFilters', + gqlFields: VIEW_FILTER_FIELDS, + filter: { + operand: { + eq: 'Updated Operand', + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewFilters.edges).toHaveLength(2); + }); + + it('4b. should find one viewFilter with updated operand', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewFilter', + gqlFields: VIEW_FILTER_FIELDS, + filter: { + operand: { + eq: 'Updated Operand 3', + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewFilter.operand).toEqual('Updated Operand 3'); + }); + + it('5. should delete many viewFilters', async () => { + const graphqlOperation = deleteManyOperationFactory({ + objectMetadataSingularName: 'viewFilter', + objectMetadataPluralName: 'viewFilters', + gqlFields: VIEW_FILTER_FIELDS, + filter: { + id: { + in: [VIEW_FILTER_1_ID, VIEW_FILTER_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const deletedViewFilters = response.body.data.deleteViewFilters; + + expect(deletedViewFilters).toHaveLength(2); + + deletedViewFilters.forEach((viewFilter) => { + expect(viewFilter.deletedAt).toBeTruthy(); + }); + }); + + it('5b. should delete one viewFilter', async () => { + const graphqlOperation = deleteOneOperationFactory({ + objectMetadataSingularName: 'viewFilter', + gqlFields: VIEW_FILTER_FIELDS, + recordId: VIEW_FILTER_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.deleteViewFilter.deletedAt).toBeTruthy(); + }); + + it('6. should not find many viewFilters anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewFilter', + objectMetadataPluralName: 'viewFilters', + gqlFields: VIEW_FILTER_FIELDS, + filter: { + id: { + in: [VIEW_FILTER_1_ID, VIEW_FILTER_2_ID], + }, + }, + }); + + const findViewFiltersResponse = + await makeGraphqlAPIRequest(graphqlOperation); + + expect(findViewFiltersResponse.body.data.viewFilters.edges).toHaveLength(0); + }); + + it('6b. should not find one viewFilter anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewFilter', + gqlFields: VIEW_FILTER_FIELDS, + filter: { + id: { + eq: VIEW_FILTER_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewFilter).toBeNull(); + }); + + it('7. should find many deleted viewFilters with deletedAt filter', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewFilter', + objectMetadataPluralName: 'viewFilters', + gqlFields: VIEW_FILTER_FIELDS, + filter: { + id: { + in: [VIEW_FILTER_1_ID, VIEW_FILTER_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewFilters.edges).toHaveLength(2); + }); + + it('7b. should find one deleted viewFilter with deletedAt filter', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewFilter', + gqlFields: VIEW_FILTER_FIELDS, + filter: { + id: { + eq: VIEW_FILTER_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewFilter.id).toEqual(VIEW_FILTER_3_ID); + }); + + it('8. should destroy many viewFilters', async () => { + const graphqlOperation = destroyManyOperationFactory({ + objectMetadataSingularName: 'viewFilter', + objectMetadataPluralName: 'viewFilters', + gqlFields: VIEW_FILTER_FIELDS, + filter: { + id: { + in: [VIEW_FILTER_1_ID, VIEW_FILTER_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.destroyViewFilters).toHaveLength(2); + }); + + it('8b. should destroy one viewFilter', async () => { + const graphqlOperation = destroyOneOperationFactory({ + objectMetadataSingularName: 'viewFilter', + gqlFields: VIEW_FILTER_FIELDS, + recordId: VIEW_FILTER_3_ID, + }); + + const destroyViewFilterResponse = + await makeGraphqlAPIRequest(graphqlOperation); + + expect(destroyViewFilterResponse.body.data.destroyViewFilter).toBeTruthy(); + }); + + it('9. should not find many viewFilters anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewFilter', + objectMetadataPluralName: 'viewFilters', + gqlFields: VIEW_FILTER_FIELDS, + filter: { + id: { + in: [VIEW_FILTER_1_ID, VIEW_FILTER_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewFilters.edges).toHaveLength(0); + }); + + it('9b. should not find one viewFilter anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewFilter', + gqlFields: VIEW_FILTER_FIELDS, + filter: { + id: { + eq: VIEW_FILTER_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewFilter).toBeNull(); + }); +}); diff --git a/packages/twenty-server/test/integration/graphql/suites/all-view-sorts.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/all-view-sorts.integration-spec.ts new file mode 100644 index 000000000000..0a3830e1ed28 --- /dev/null +++ b/packages/twenty-server/test/integration/graphql/suites/all-view-sorts.integration-spec.ts @@ -0,0 +1,399 @@ +import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util'; +import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; +import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util'; +import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util'; +import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util'; +import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util'; +import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util'; +import { findOneOperationFactory } from 'test/integration/graphql/utils/find-one-operation-factory.util'; +import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util'; +import { updateOneOperationFactory } from 'test/integration/graphql/utils/update-one-operation-factory.util'; + +const VIEW_SORT_1_ID = '777a8457-eb2d-40ac-a707-551b615b6987'; +const VIEW_SORT_2_ID = '777a8457-eb2d-40ac-a707-551b615b6988'; +const VIEW_SORT_3_ID = '777a8457-eb2d-40ac-a707-551b615b6989'; +const FIELD_METADATA_ID = '20202020-0c28-43d8-8ba5-3659924d3489'; + +const VIEW_SORT_GQL_FIELDS = ` + id + fieldMetadataId + direction + createdAt + updatedAt + deletedAt + viewId +`; + +describe('viewSorts resolvers (integration)', () => { + it('1. should create and return viewSorts', async () => { + const graphqlOperation = createManyOperationFactory({ + objectMetadataSingularName: 'viewSort', + objectMetadataPluralName: 'viewSorts', + gqlFields: VIEW_SORT_GQL_FIELDS, + data: [ + { + id: VIEW_SORT_1_ID, + fieldMetadataId: FIELD_METADATA_ID, + direction: 'ASC', + }, + { + id: VIEW_SORT_2_ID, + fieldMetadataId: FIELD_METADATA_ID, + direction: 'DESC', + }, + ], + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.createViewSorts).toHaveLength(2); + + response.body.data.createViewSorts.forEach((viewSort) => { + expect(viewSort).toHaveProperty('fieldMetadataId'); + expect(viewSort.fieldMetadataId).toEqual(FIELD_METADATA_ID); + expect(viewSort).toHaveProperty('direction'); + expect(viewSort).toHaveProperty('id'); + expect(viewSort).toHaveProperty('createdAt'); + expect(viewSort).toHaveProperty('updatedAt'); + expect(viewSort).toHaveProperty('deletedAt'); + expect(viewSort).toHaveProperty('viewId'); + }); + }); + + it('1b. should create and return one viewSort', async () => { + const graphqlOperation = createOneOperationFactory({ + objectMetadataSingularName: 'viewSort', + gqlFields: VIEW_SORT_GQL_FIELDS, + data: { + id: VIEW_SORT_3_ID, + fieldMetadataId: FIELD_METADATA_ID, + direction: 'ASC', + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const createdViewSort = response.body.data.createViewSort; + + expect(createdViewSort).toHaveProperty('fieldMetadataId'); + expect(createdViewSort.fieldMetadataId).toEqual(FIELD_METADATA_ID); + expect(createdViewSort).toHaveProperty('direction'); + expect(createdViewSort).toHaveProperty('id'); + expect(createdViewSort).toHaveProperty('createdAt'); + expect(createdViewSort).toHaveProperty('updatedAt'); + expect(createdViewSort).toHaveProperty('deletedAt'); + expect(createdViewSort).toHaveProperty('viewId'); + }); + + it('2. should find many viewSorts', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewSort', + objectMetadataPluralName: 'viewSorts', + gqlFields: VIEW_SORT_GQL_FIELDS, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const data = response.body.data.viewSorts; + + expect(data).toBeDefined(); + expect(Array.isArray(data.edges)).toBe(true); + + if (data.edges.length > 0) { + const viewSorts = data.edges[0].node; + + expect(viewSorts).toHaveProperty('fieldMetadataId'); + expect(viewSorts).toHaveProperty('direction'); + expect(viewSorts).toHaveProperty('id'); + expect(viewSorts).toHaveProperty('createdAt'); + expect(viewSorts).toHaveProperty('updatedAt'); + expect(viewSorts).toHaveProperty('deletedAt'); + expect(viewSorts).toHaveProperty('viewId'); + } + }); + + it('2b. should find one viewSort', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewSort', + gqlFields: VIEW_SORT_GQL_FIELDS, + filter: { + id: { + eq: VIEW_SORT_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const viewSort = response.body.data.viewSort; + + expect(viewSort).toHaveProperty('fieldMetadataId'); + expect(viewSort).toHaveProperty('direction'); + expect(viewSort).toHaveProperty('id'); + expect(viewSort).toHaveProperty('createdAt'); + expect(viewSort).toHaveProperty('updatedAt'); + expect(viewSort).toHaveProperty('deletedAt'); + expect(viewSort).toHaveProperty('viewId'); + }); + + it('3. should update many viewSorts', async () => { + const graphqlOperation = updateManyOperationFactory({ + objectMetadataSingularName: 'viewSort', + objectMetadataPluralName: 'viewSorts', + gqlFields: VIEW_SORT_GQL_FIELDS, + data: { + direction: 'DESC', + }, + filter: { + id: { + in: [VIEW_SORT_1_ID, VIEW_SORT_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedViewSorts = response.body.data.updateViewSorts; + + expect(updatedViewSorts).toHaveLength(2); + + updatedViewSorts.forEach((viewSort) => { + expect(viewSort.direction).toEqual('DESC'); + }); + }); + + it('3b. should update one viewSort', async () => { + const graphqlOperation = updateOneOperationFactory({ + objectMetadataSingularName: 'viewSort', + gqlFields: VIEW_SORT_GQL_FIELDS, + data: { + direction: 'ASC', + }, + recordId: VIEW_SORT_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedViewSort = response.body.data.updateViewSort; + + expect(updatedViewSort.direction).toEqual('ASC'); + }); + + it('4. should find many viewSorts with updated direction', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewSort', + objectMetadataPluralName: 'viewSorts', + gqlFields: VIEW_SORT_GQL_FIELDS, + filter: { + direction: { + eq: 'DESC', + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewSorts.edges).toHaveLength(2); + }); + + it('4b. should find one viewSort with updated direction', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewSort', + gqlFields: VIEW_SORT_GQL_FIELDS, + filter: { + direction: { + eq: 'ASC', + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewSort.direction).toEqual('ASC'); + }); + + it('5. should delete many viewSorts', async () => { + const graphqlOperation = deleteManyOperationFactory({ + objectMetadataSingularName: 'viewSort', + objectMetadataPluralName: 'viewSorts', + gqlFields: VIEW_SORT_GQL_FIELDS, + filter: { + id: { + in: [VIEW_SORT_1_ID, VIEW_SORT_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const deletedViewSorts = response.body.data.deleteViewSorts; + + expect(deletedViewSorts).toHaveLength(2); + + deletedViewSorts.forEach((viewSort) => { + expect(viewSort.deletedAt).toBeTruthy(); + }); + }); + + it('5b. should delete one viewSort', async () => { + const graphqlOperation = deleteOneOperationFactory({ + objectMetadataSingularName: 'viewSort', + gqlFields: VIEW_SORT_GQL_FIELDS, + recordId: VIEW_SORT_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.deleteViewSort.deletedAt).toBeTruthy(); + }); + + it('6. should not find many viewSorts anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewSort', + objectMetadataPluralName: 'viewSorts', + gqlFields: VIEW_SORT_GQL_FIELDS, + filter: { + id: { + in: [VIEW_SORT_1_ID, VIEW_SORT_2_ID], + }, + }, + }); + + const findViewSortsResponse = await makeGraphqlAPIRequest(graphqlOperation); + + expect(findViewSortsResponse.body.data.viewSorts.edges).toHaveLength(0); + }); + + it('6b. should not find one viewSort anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewSort', + gqlFields: VIEW_SORT_GQL_FIELDS, + filter: { + id: { + eq: VIEW_SORT_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewSort).toBeNull(); + }); + + it('7. should find many deleted viewSorts with deletedAt filter', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewSort', + objectMetadataPluralName: 'viewSorts', + gqlFields: VIEW_SORT_GQL_FIELDS, + filter: { + id: { + in: [VIEW_SORT_1_ID, VIEW_SORT_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewSorts.edges).toHaveLength(2); + }); + + it('7b. should find one deleted viewSort with deletedAt filter', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewSort', + gqlFields: VIEW_SORT_GQL_FIELDS, + filter: { + id: { + eq: VIEW_SORT_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewSort.id).toEqual(VIEW_SORT_3_ID); + }); + + it('8. should destroy many viewSorts', async () => { + const graphqlOperation = destroyManyOperationFactory({ + objectMetadataSingularName: 'viewSort', + objectMetadataPluralName: 'viewSorts', + gqlFields: VIEW_SORT_GQL_FIELDS, + filter: { + id: { + in: [VIEW_SORT_1_ID, VIEW_SORT_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.destroyViewSorts).toHaveLength(2); + }); + + it('8b. should destroy one viewSort', async () => { + const graphqlOperation = destroyOneOperationFactory({ + objectMetadataSingularName: 'viewSort', + gqlFields: VIEW_SORT_GQL_FIELDS, + recordId: VIEW_SORT_3_ID, + }); + + const destroyViewSortResponse = + await makeGraphqlAPIRequest(graphqlOperation); + + expect(destroyViewSortResponse.body.data.destroyViewSort).toBeTruthy(); + }); + + it('9. should not find many viewSorts anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'viewSort', + objectMetadataPluralName: 'viewSorts', + gqlFields: VIEW_SORT_GQL_FIELDS, + filter: { + id: { + in: [VIEW_SORT_1_ID, VIEW_SORT_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewSorts.edges).toHaveLength(0); + }); + + it('9b. should not find one viewSort anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'viewSort', + gqlFields: VIEW_SORT_GQL_FIELDS, + filter: { + id: { + eq: VIEW_SORT_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.viewSort).toBeNull(); + }); +}); diff --git a/packages/twenty-server/test/integration/graphql/suites/all-views.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/all-views.integration-spec.ts new file mode 100644 index 000000000000..4caa88084f8d --- /dev/null +++ b/packages/twenty-server/test/integration/graphql/suites/all-views.integration-spec.ts @@ -0,0 +1,429 @@ +import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util'; +import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; +import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util'; +import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util'; +import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util'; +import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util'; +import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util'; +import { findOneOperationFactory } from 'test/integration/graphql/utils/find-one-operation-factory.util'; +import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util'; +import { updateOneOperationFactory } from 'test/integration/graphql/utils/update-one-operation-factory.util'; +import { generateRecordName } from 'test/integration/utils/generate-record-name'; + +const VIEW_1_ID = '777a8457-eb2d-40ac-a707-551b615b6987'; +const VIEW_2_ID = '777a8457-eb2d-40ac-a707-551b615b6988'; +const VIEW_3_ID = '777a8457-eb2d-40ac-a707-551b615b6989'; +const OBJECT_METADATA_ID = '20202020-b374-4779-a561-80086cb2e17f'; + +const VIEW_GQL_FIELDS = ` + id + name + objectMetadataId + type + key + icon + kanbanFieldMetadataId + position + isCompact + createdAt + updatedAt + deletedAt +`; + +describe('views resolvers (integration)', () => { + it('1. should create and return views', async () => { + const viewName1 = generateRecordName(VIEW_1_ID); + const viewName2 = generateRecordName(VIEW_2_ID); + + const graphqlOperation = createManyOperationFactory({ + objectMetadataSingularName: 'view', + objectMetadataPluralName: 'views', + gqlFields: VIEW_GQL_FIELDS, + data: [ + { + id: VIEW_1_ID, + name: viewName1, + objectMetadataId: OBJECT_METADATA_ID, + }, + { + id: VIEW_2_ID, + name: viewName2, + objectMetadataId: OBJECT_METADATA_ID, + }, + ], + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.createViews).toHaveLength(2); + + response.body.data.createViews.forEach((view) => { + expect(view).toHaveProperty('name'); + expect([viewName1, viewName2]).toContain(view.name); + expect(view).toHaveProperty('id'); + expect(view).toHaveProperty('objectMetadataId'); + expect(view).toHaveProperty('type'); + expect(view).toHaveProperty('key'); + expect(view).toHaveProperty('icon'); + expect(view).toHaveProperty('kanbanFieldMetadataId'); + expect(view).toHaveProperty('position'); + expect(view).toHaveProperty('isCompact'); + expect(view).toHaveProperty('createdAt'); + expect(view).toHaveProperty('updatedAt'); + expect(view).toHaveProperty('deletedAt'); + }); + }); + + it('1b. should create and return one view', async () => { + const viewName = generateRecordName(VIEW_3_ID); + + const graphqlOperation = createOneOperationFactory({ + objectMetadataSingularName: 'view', + gqlFields: VIEW_GQL_FIELDS, + data: { + id: VIEW_3_ID, + name: viewName, + objectMetadataId: OBJECT_METADATA_ID, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const createdView = response.body.data.createView; + + expect(createdView).toHaveProperty('name'); + expect(createdView.name).toEqual(viewName); + expect(createdView).toHaveProperty('id'); + expect(createdView).toHaveProperty('objectMetadataId'); + expect(createdView).toHaveProperty('type'); + expect(createdView).toHaveProperty('key'); + expect(createdView).toHaveProperty('icon'); + expect(createdView).toHaveProperty('kanbanFieldMetadataId'); + expect(createdView).toHaveProperty('position'); + expect(createdView).toHaveProperty('isCompact'); + expect(createdView).toHaveProperty('createdAt'); + expect(createdView).toHaveProperty('updatedAt'); + expect(createdView).toHaveProperty('deletedAt'); + }); + + it('2. should find many views', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'view', + objectMetadataPluralName: 'views', + gqlFields: VIEW_GQL_FIELDS, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const data = response.body.data.views; + + expect(data).toBeDefined(); + expect(Array.isArray(data.edges)).toBe(true); + + if (data.edges.length > 0) { + const views = data.edges[0].node; + + expect(views).toHaveProperty('name'); + expect(views).toHaveProperty('objectMetadataId'); + expect(views).toHaveProperty('type'); + expect(views).toHaveProperty('key'); + expect(views).toHaveProperty('icon'); + expect(views).toHaveProperty('kanbanFieldMetadataId'); + expect(views).toHaveProperty('position'); + expect(views).toHaveProperty('isCompact'); + expect(views).toHaveProperty('id'); + expect(views).toHaveProperty('createdAt'); + expect(views).toHaveProperty('updatedAt'); + expect(views).toHaveProperty('deletedAt'); + } + }); + + it('2b. should find one view', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'view', + gqlFields: VIEW_GQL_FIELDS, + filter: { + id: { + eq: VIEW_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const view = response.body.data.view; + + expect(view).toHaveProperty('name'); + expect(view).toHaveProperty('objectMetadataId'); + expect(view).toHaveProperty('type'); + expect(view).toHaveProperty('key'); + expect(view).toHaveProperty('icon'); + expect(view).toHaveProperty('kanbanFieldMetadataId'); + expect(view).toHaveProperty('position'); + expect(view).toHaveProperty('isCompact'); + expect(view).toHaveProperty('id'); + expect(view).toHaveProperty('createdAt'); + expect(view).toHaveProperty('updatedAt'); + expect(view).toHaveProperty('deletedAt'); + }); + + it('3. should update many views', async () => { + const graphqlOperation = updateManyOperationFactory({ + objectMetadataSingularName: 'view', + objectMetadataPluralName: 'views', + gqlFields: VIEW_GQL_FIELDS, + data: { + isCompact: true, + }, + filter: { + id: { + in: [VIEW_1_ID, VIEW_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedViews = response.body.data.updateViews; + + expect(updatedViews).toHaveLength(2); + + updatedViews.forEach((view) => { + expect(view.isCompact).toEqual(true); + }); + }); + + it('3b. should update one view', async () => { + const graphqlOperation = updateOneOperationFactory({ + objectMetadataSingularName: 'view', + gqlFields: VIEW_GQL_FIELDS, + data: { + isCompact: false, + }, + recordId: VIEW_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedView = response.body.data.updateView; + + expect(updatedView.isCompact).toEqual(false); + }); + + it('4. should find many views with updated isCompact', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'view', + objectMetadataPluralName: 'views', + gqlFields: VIEW_GQL_FIELDS, + filter: { + isCompact: { + eq: true, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.views.edges).toHaveLength(2); + }); + + it('4b. should find one view with updated isCompact', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'view', + gqlFields: VIEW_GQL_FIELDS, + filter: { + isCompact: { + eq: false, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.view.isCompact).toEqual(false); + }); + + it('5. should delete many views', async () => { + const graphqlOperation = deleteManyOperationFactory({ + objectMetadataSingularName: 'view', + objectMetadataPluralName: 'views', + gqlFields: VIEW_GQL_FIELDS, + filter: { + id: { + in: [VIEW_1_ID, VIEW_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const deletedViews = response.body.data.deleteViews; + + expect(deletedViews).toHaveLength(2); + + deletedViews.forEach((view) => { + expect(view.deletedAt).toBeTruthy(); + }); + }); + + it('5b. should delete one view', async () => { + const graphqlOperation = deleteOneOperationFactory({ + objectMetadataSingularName: 'view', + gqlFields: VIEW_GQL_FIELDS, + recordId: VIEW_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.deleteView.deletedAt).toBeTruthy(); + }); + + it('6. should not find many views anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'view', + objectMetadataPluralName: 'views', + gqlFields: VIEW_GQL_FIELDS, + filter: { + id: { + in: [VIEW_1_ID, VIEW_2_ID], + }, + }, + }); + + const findViewsResponse = await makeGraphqlAPIRequest(graphqlOperation); + + expect(findViewsResponse.body.data.views.edges).toHaveLength(0); + }); + + it('6b. should not find one view anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'view', + gqlFields: VIEW_GQL_FIELDS, + filter: { + id: { + eq: VIEW_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.view).toBeNull(); + }); + + it('7. should find many deleted views with deletedAt filter', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'view', + objectMetadataPluralName: 'views', + gqlFields: VIEW_GQL_FIELDS, + filter: { + id: { + in: [VIEW_1_ID, VIEW_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.views.edges).toHaveLength(2); + }); + + it('7b. should find one deleted view with deletedAt filter', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'view', + gqlFields: VIEW_GQL_FIELDS, + filter: { + id: { + eq: VIEW_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.view.id).toEqual(VIEW_3_ID); + }); + + it('8. should destroy many views', async () => { + const graphqlOperation = destroyManyOperationFactory({ + objectMetadataSingularName: 'view', + objectMetadataPluralName: 'views', + gqlFields: VIEW_GQL_FIELDS, + filter: { + id: { + in: [VIEW_1_ID, VIEW_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.destroyViews).toHaveLength(2); + }); + + it('8b. should destroy one view', async () => { + const graphqlOperation = destroyOneOperationFactory({ + objectMetadataSingularName: 'view', + gqlFields: VIEW_GQL_FIELDS, + recordId: VIEW_3_ID, + }); + + const destroyViewResponse = await makeGraphqlAPIRequest(graphqlOperation); + + expect(destroyViewResponse.body.data.destroyView).toBeTruthy(); + }); + + it('9. should not find many views anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'view', + objectMetadataPluralName: 'views', + gqlFields: VIEW_GQL_FIELDS, + filter: { + id: { + in: [VIEW_1_ID, VIEW_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.views.edges).toHaveLength(0); + }); + + it('9b. should not find one view anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'view', + gqlFields: VIEW_GQL_FIELDS, + filter: { + id: { + eq: VIEW_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.view).toBeNull(); + }); +}); diff --git a/packages/twenty-server/test/integration/graphql/suites/all-webhooks.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/all-webhooks.integration-spec.ts new file mode 100644 index 000000000000..7de793dbd8ee --- /dev/null +++ b/packages/twenty-server/test/integration/graphql/suites/all-webhooks.integration-spec.ts @@ -0,0 +1,403 @@ +import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util'; +import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; +import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util'; +import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util'; +import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util'; +import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util'; +import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util'; +import { findOneOperationFactory } from 'test/integration/graphql/utils/find-one-operation-factory.util'; +import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; +import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util'; +import { updateOneOperationFactory } from 'test/integration/graphql/utils/update-one-operation-factory.util'; +import { generateRecordName } from 'test/integration/utils/generate-record-name'; + +const WEBHOOK_1_ID = '777a8457-eb2d-40ac-a707-551b615b6987'; +const WEBHOOK_2_ID = '777a8457-eb2d-40ac-a707-551b615b6988'; +const WEBHOOK_3_ID = '777a8457-eb2d-40ac-a707-551b615b6989'; + +const WEBHOOK_GQL_FIELDS = ` + id + targetUrl + operations + description + createdAt + updatedAt + deletedAt +`; + +describe('webhooks resolvers (integration)', () => { + it('1. should create and return webhooks', async () => { + const webhookDescription1 = generateRecordName(WEBHOOK_1_ID); + const webhookDescription2 = generateRecordName(WEBHOOK_2_ID); + + const graphqlOperation = createManyOperationFactory({ + objectMetadataSingularName: 'webhook', + objectMetadataPluralName: 'webhooks', + gqlFields: WEBHOOK_GQL_FIELDS, + data: [ + { + id: WEBHOOK_1_ID, + description: webhookDescription1, + }, + { + id: WEBHOOK_2_ID, + description: webhookDescription2, + }, + ], + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.createWebhooks).toHaveLength(2); + + response.body.data.createWebhooks.forEach((webhook) => { + expect(webhook).toHaveProperty('description'); + expect([webhookDescription1, webhookDescription2]).toContain( + webhook.description, + ); + expect(webhook).toHaveProperty('operations'); + expect(webhook).toHaveProperty('id'); + expect(webhook).toHaveProperty('targetUrl'); + expect(webhook).toHaveProperty('createdAt'); + expect(webhook).toHaveProperty('updatedAt'); + expect(webhook).toHaveProperty('deletedAt'); + }); + }); + + it('1b. should create and return one webhook', async () => { + const webhookDescription = generateRecordName(WEBHOOK_3_ID); + + const graphqlOperation = createOneOperationFactory({ + objectMetadataSingularName: 'webhook', + gqlFields: WEBHOOK_GQL_FIELDS, + data: { + id: WEBHOOK_3_ID, + description: webhookDescription, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const createdWebhook = response.body.data.createWebhook; + + expect(createdWebhook).toHaveProperty('description'); + expect(createdWebhook.description).toEqual(webhookDescription); + expect(createdWebhook).toHaveProperty('operations'); + expect(createdWebhook).toHaveProperty('id'); + expect(createdWebhook).toHaveProperty('targetUrl'); + expect(createdWebhook).toHaveProperty('createdAt'); + expect(createdWebhook).toHaveProperty('updatedAt'); + expect(createdWebhook).toHaveProperty('deletedAt'); + }); + + it('2. should find many webhooks', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'webhook', + objectMetadataPluralName: 'webhooks', + gqlFields: WEBHOOK_GQL_FIELDS, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const data = response.body.data.webhooks; + + expect(data).toBeDefined(); + expect(Array.isArray(data.edges)).toBe(true); + + if (data.edges.length > 0) { + const webhooks = data.edges[0].node; + + expect(webhooks).toHaveProperty('targetUrl'); + expect(webhooks).toHaveProperty('operations'); + expect(webhooks).toHaveProperty('id'); + expect(webhooks).toHaveProperty('description'); + expect(webhooks).toHaveProperty('createdAt'); + expect(webhooks).toHaveProperty('updatedAt'); + expect(webhooks).toHaveProperty('deletedAt'); + } + }); + + it('2b. should find one webhook', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'webhook', + gqlFields: WEBHOOK_GQL_FIELDS, + filter: { + id: { + eq: WEBHOOK_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const webhook = response.body.data.webhook; + + expect(webhook).toHaveProperty('targetUrl'); + expect(webhook).toHaveProperty('operations'); + expect(webhook).toHaveProperty('id'); + expect(webhook).toHaveProperty('description'); + expect(webhook).toHaveProperty('createdAt'); + expect(webhook).toHaveProperty('updatedAt'); + expect(webhook).toHaveProperty('deletedAt'); + }); + + it('3. should update many webhooks', async () => { + const graphqlOperation = updateManyOperationFactory({ + objectMetadataSingularName: 'webhook', + objectMetadataPluralName: 'webhooks', + gqlFields: WEBHOOK_GQL_FIELDS, + data: { + description: 'Updated Description', + }, + filter: { + id: { + in: [WEBHOOK_1_ID, WEBHOOK_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedWebhooks = response.body.data.updateWebhooks; + + expect(updatedWebhooks).toHaveLength(2); + + updatedWebhooks.forEach((webhook) => { + expect(webhook.description).toEqual('Updated Description'); + }); + }); + + it('3b. should update one webhook', async () => { + const graphqlOperation = updateOneOperationFactory({ + objectMetadataSingularName: 'webhook', + gqlFields: WEBHOOK_GQL_FIELDS, + data: { + description: 'New Description', + }, + recordId: WEBHOOK_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const updatedWebhook = response.body.data.updateWebhook; + + expect(updatedWebhook.description).toEqual('New Description'); + }); + + it('4. should find many webhooks with updated description', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'webhook', + objectMetadataPluralName: 'webhooks', + gqlFields: WEBHOOK_GQL_FIELDS, + filter: { + description: { + eq: 'Updated Description', + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.webhooks.edges).toHaveLength(2); + }); + + it('4b. should find one webhook with updated description', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'webhook', + gqlFields: WEBHOOK_GQL_FIELDS, + filter: { + description: { + eq: 'New Description', + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.webhook.description).toEqual('New Description'); + }); + + it('5. should delete many webhooks', async () => { + const graphqlOperation = deleteManyOperationFactory({ + objectMetadataSingularName: 'webhook', + objectMetadataPluralName: 'webhooks', + gqlFields: WEBHOOK_GQL_FIELDS, + filter: { + id: { + in: [WEBHOOK_1_ID, WEBHOOK_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + const deletedWebhooks = response.body.data.deleteWebhooks; + + expect(deletedWebhooks).toHaveLength(2); + + deletedWebhooks.forEach((webhook) => { + expect(webhook.deletedAt).toBeTruthy(); + }); + }); + + it('5b. should delete one webhook', async () => { + const graphqlOperation = deleteOneOperationFactory({ + objectMetadataSingularName: 'webhook', + gqlFields: WEBHOOK_GQL_FIELDS, + recordId: WEBHOOK_3_ID, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.deleteWebhook.deletedAt).toBeTruthy(); + }); + + it('6. should not find many webhooks anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'webhook', + objectMetadataPluralName: 'webhooks', + gqlFields: WEBHOOK_GQL_FIELDS, + filter: { + id: { + in: [WEBHOOK_1_ID, WEBHOOK_2_ID], + }, + }, + }); + + const findWebhooksResponse = await makeGraphqlAPIRequest(graphqlOperation); + + expect(findWebhooksResponse.body.data.webhooks.edges).toHaveLength(0); + }); + + it('6b. should not find one webhook anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'webhook', + gqlFields: WEBHOOK_GQL_FIELDS, + filter: { + id: { + eq: WEBHOOK_3_ID, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.webhook).toBeNull(); + }); + + it('7. should find many deleted webhooks with deletedAt filter', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'webhook', + objectMetadataPluralName: 'webhooks', + gqlFields: WEBHOOK_GQL_FIELDS, + filter: { + id: { + in: [WEBHOOK_1_ID, WEBHOOK_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.webhooks.edges).toHaveLength(2); + }); + + it('7b. should find one deleted webhook with deletedAt filter', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'webhook', + gqlFields: WEBHOOK_GQL_FIELDS, + filter: { + id: { + eq: WEBHOOK_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.webhook.id).toEqual(WEBHOOK_3_ID); + }); + + it('8. should destroy many webhooks', async () => { + const graphqlOperation = destroyManyOperationFactory({ + objectMetadataSingularName: 'webhook', + objectMetadataPluralName: 'webhooks', + gqlFields: WEBHOOK_GQL_FIELDS, + filter: { + id: { + in: [WEBHOOK_1_ID, WEBHOOK_2_ID], + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.destroyWebhooks).toHaveLength(2); + }); + + it('8b. should destroy one webhook', async () => { + const graphqlOperation = destroyOneOperationFactory({ + objectMetadataSingularName: 'webhook', + gqlFields: WEBHOOK_GQL_FIELDS, + recordId: WEBHOOK_3_ID, + }); + + const destroyWebhookResponse = + await makeGraphqlAPIRequest(graphqlOperation); + + expect(destroyWebhookResponse.body.data.destroyWebhook).toBeTruthy(); + }); + + it('9. should not find many webhooks anymore', async () => { + const graphqlOperation = findManyOperationFactory({ + objectMetadataSingularName: 'webhook', + objectMetadataPluralName: 'webhooks', + gqlFields: WEBHOOK_GQL_FIELDS, + filter: { + id: { + in: [WEBHOOK_1_ID, WEBHOOK_2_ID], + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.webhooks.edges).toHaveLength(0); + }); + + it('9b. should not find one webhook anymore', async () => { + const graphqlOperation = findOneOperationFactory({ + objectMetadataSingularName: 'webhook', + gqlFields: WEBHOOK_GQL_FIELDS, + filter: { + id: { + eq: WEBHOOK_3_ID, + }, + not: { + deletedAt: { + is: 'NULL', + }, + }, + }, + }); + + const response = await makeGraphqlAPIRequest(graphqlOperation); + + expect(response.body.data.webhook).toBeNull(); + }); +});