[GQL_VIEW_FILTER_API_BREAKING_CHANGE][WHEN_RELEASED_REQUIRES_CACHE_FLUSH] ViewFilter migration to workspace migration v2 (#15010)
# Introduction Migrating `viewFilter` to v2 in order to migrate later the field update side effect on view to v2 too ## What's done - Created flat-view-filter - flat view filter runner - flat view filter builder - create view filter service v2 and input transpilers - refactor the existing view filter resolver to fix standard ( BREAKING_CHANGE on graphql api update especially ) REST stays the same - refactored the front to consume the mutations autogenerated ## New generic tools ### Compare two flat entity Introducing a new util to compare two flat entity, it's strictly typed and will be added to the generic builder in a following PR This will ease flat entity addition as won't required to create a specific abstraction for comparison Generic builder will expect specific constant: properties to compare and properties to stringify ### Transform flat entity for comparison Forked and refactor the initial existing method for flat entity business scope and type safety ## Coverage Migrated existing integration tests to fit new contract API This PR does not add strong coverage on validation exceptions Deadlines are too short close https://github.com/twentyhq/core-team-issues/issues/1666
This commit is contained in:
+14
-13
@@ -3,13 +3,14 @@ import { randomUUID } from 'crypto';
|
||||
import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields.constants';
|
||||
import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util';
|
||||
import { createViewFilterGroupOperationFactory } from 'test/integration/graphql/utils/create-view-filter-group-operation-factory.util';
|
||||
import { createViewFilterOperationFactory } from 'test/integration/graphql/utils/create-view-filter-operation-factory.util';
|
||||
import { createViewOperationFactory } from 'test/integration/graphql/utils/create-view-operation-factory.util';
|
||||
import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util';
|
||||
import { groupByOperationFactory } from 'test/integration/graphql/utils/group-by-operation-factory.util';
|
||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||
import { findManyObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/find-many-object-metadata.util';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
import { createOneCoreViewFilter } from 'test/integration/metadata/suites/view-filter/utils/create-one-core-view-filter.util';
|
||||
import { jestExpectToBeDefined } from 'test/utils/expect-to-be-defined.util.test';
|
||||
|
||||
import { type FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
|
||||
import { type ObjectMetadataDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto';
|
||||
@@ -443,18 +444,18 @@ describe('group-by resolvers (integration)', () => {
|
||||
const viewFilterGroupId = viewFilterGroupResponse.body.data
|
||||
.createCoreViewFilterGroup.id as string;
|
||||
|
||||
await makeGraphqlAPIRequest(
|
||||
createViewFilterOperationFactory({
|
||||
data: {
|
||||
viewId,
|
||||
viewFilterGroupId,
|
||||
fieldMetadataId: cityFieldMetadataId,
|
||||
operand: ViewFilterOperand.CONTAINS,
|
||||
value: cityToKeep,
|
||||
positionInViewFilterGroup: 0,
|
||||
},
|
||||
}),
|
||||
);
|
||||
jestExpectToBeDefined(cityFieldMetadataId);
|
||||
await createOneCoreViewFilter({
|
||||
input: {
|
||||
viewId,
|
||||
viewFilterGroupId,
|
||||
fieldMetadataId: cityFieldMetadataId,
|
||||
operand: ViewFilterOperand.CONTAINS,
|
||||
value: cityToKeep,
|
||||
positionInViewFilterGroup: 0,
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const response = await makeGraphqlAPIRequest(
|
||||
groupByOperationFactory({
|
||||
|
||||
+39
-42
@@ -1,10 +1,10 @@
|
||||
import { print } from 'graphql';
|
||||
import request from 'supertest';
|
||||
import { deleteOneRoleOperationFactory } from 'test/integration/graphql/utils/delete-one-role-operation-factory.util';
|
||||
import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util';
|
||||
import { updateWorkspaceMemberRole } from 'test/integration/graphql/utils/update-workspace-member-role.util';
|
||||
import { createOneObjectMetadataQueryFactory } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata-query-factory.util';
|
||||
import { deleteOneObjectMetadataQueryFactory } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata-query-factory.util';
|
||||
import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util';
|
||||
import { updateOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/update-one-object-metadata.util';
|
||||
import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util';
|
||||
|
||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
|
||||
@@ -16,6 +16,7 @@ const client = request(`http://localhost:${APP_PORT}`);
|
||||
describe('Granular settings permissions', () => {
|
||||
let customRoleId: string;
|
||||
let originalMemberRoleId: string;
|
||||
const createdObjectMetadataIds: string[] = [];
|
||||
|
||||
beforeAll(async () => {
|
||||
// Get the original Member role ID for restoration later
|
||||
@@ -123,54 +124,50 @@ describe('Granular settings permissions', () => {
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${APPLE_JANE_ADMIN_ACCESS_TOKEN}`)
|
||||
.send(deleteRoleQuery);
|
||||
|
||||
for (const objectMetadataId of createdObjectMetadataIds) {
|
||||
await updateOneObjectMetadata({
|
||||
expectToFail: false,
|
||||
input: {
|
||||
idToUpdate: objectMetadataId,
|
||||
updatePayload: {
|
||||
isActive: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await deleteOneObjectMetadata({
|
||||
input: {
|
||||
idToDelete: objectMetadataId,
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('Data Model Permissions', () => {
|
||||
it('should allow access to data model operations when user has DATA_MODEL setting permission', async () => {
|
||||
// Test creating an object metadata (requires DATA_MODEL permission)
|
||||
const { query: createObjectQuery, variables } =
|
||||
createOneObjectMetadataQueryFactory({
|
||||
input: {
|
||||
labelSingular: 'House',
|
||||
labelPlural: 'Houses',
|
||||
nameSingular: 'house',
|
||||
namePlural: 'houses',
|
||||
description: 'a house',
|
||||
icon: 'IconHome',
|
||||
},
|
||||
gqlFields: `
|
||||
const { data, errors } = await createOneObjectMetadata({
|
||||
input: {
|
||||
labelSingular: 'House',
|
||||
labelPlural: 'Houses',
|
||||
nameSingular: 'house',
|
||||
namePlural: 'houses',
|
||||
description: 'a house',
|
||||
icon: 'IconHome',
|
||||
},
|
||||
gqlFields: `
|
||||
id
|
||||
labelSingular
|
||||
labelPlural
|
||||
`,
|
||||
});
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const response = await client
|
||||
.post('/metadata')
|
||||
.set('Authorization', `Bearer ${APPLE_JONY_MEMBER_ACCESS_TOKEN}`)
|
||||
.send({ query: print(createObjectQuery), variables });
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.errors).toBeUndefined();
|
||||
expect(response.body.data.createOneObject).toBeDefined();
|
||||
expect(response.body.data.createOneObject.labelSingular).toBe('House');
|
||||
|
||||
// Clean up - delete the created object
|
||||
const { query: deleteObjectQuery, variables: deleteObjectVariables } =
|
||||
deleteOneObjectMetadataQueryFactory({
|
||||
input: {
|
||||
idToDelete: response.body.data.createOneObject.id,
|
||||
},
|
||||
gqlFields: 'id',
|
||||
});
|
||||
|
||||
await client
|
||||
.post('/graphql')
|
||||
.set('Authorization', `Bearer ${APPLE_JANE_ADMIN_ACCESS_TOKEN}`)
|
||||
.send({
|
||||
query: print(deleteObjectQuery),
|
||||
variables: deleteObjectVariables,
|
||||
});
|
||||
createdObjectMetadataIds.push(data.createOneObject.id);
|
||||
expect(errors).toBeUndefined();
|
||||
expect(data.createOneObject).toBeDefined();
|
||||
expect(data.createOneObject.labelSingular).toBe('House');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`View Filter Resolver deleteCoreViewFilter should throw an error when deleting non-existent view filter 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "NOT_FOUND",
|
||||
"userFriendlyMessage": "An error occurred.",
|
||||
},
|
||||
"message": "View filter to delete not found",
|
||||
"name": "NotFoundError",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`View Filter Resolver destroyCoreViewFilter should throw an error when destroying non-existent view filter 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "NOT_FOUND",
|
||||
"userFriendlyMessage": "An error occurred.",
|
||||
},
|
||||
"message": "View filter to destroy not found",
|
||||
"name": "NotFoundError",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`View Filter Resolver updateCoreViewFilter should throw an error when updating non-existent view filter 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "NOT_FOUND",
|
||||
"userFriendlyMessage": "An error occurred.",
|
||||
},
|
||||
"message": "View filter to update not found",
|
||||
"name": "NotFoundError",
|
||||
}
|
||||
`;
|
||||
+6
@@ -31,6 +31,7 @@ exports[`View Field Resolver - Failing Create Operation - v2 Should fail to crea
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
},
|
||||
"message": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
"summary": {
|
||||
@@ -43,6 +44,7 @@ exports[`View Field Resolver - Failing Create Operation - v2 Should fail to crea
|
||||
"invalidServerlessFunction": 0,
|
||||
"invalidView": 0,
|
||||
"invalidViewField": 0,
|
||||
"invalidViewFilter": 0,
|
||||
"totalErrors": 0,
|
||||
},
|
||||
"userFriendlyMessage": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
@@ -83,6 +85,7 @@ exports[`View Field Resolver - Failing Create Operation - v2 should fail to crea
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
},
|
||||
"message": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
"summary": {
|
||||
@@ -95,6 +98,7 @@ exports[`View Field Resolver - Failing Create Operation - v2 should fail to crea
|
||||
"invalidServerlessFunction": 0,
|
||||
"invalidView": 0,
|
||||
"invalidViewField": 0,
|
||||
"invalidViewFilter": 0,
|
||||
"totalErrors": 0,
|
||||
},
|
||||
"userFriendlyMessage": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
@@ -135,6 +139,7 @@ exports[`View Field Resolver - Failing Create Operation - v2 should fail to crea
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
},
|
||||
"message": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
"summary": {
|
||||
@@ -147,6 +152,7 @@ exports[`View Field Resolver - Failing Create Operation - v2 should fail to crea
|
||||
"invalidServerlessFunction": 0,
|
||||
"invalidView": 0,
|
||||
"invalidViewField": 0,
|
||||
"invalidViewFilter": 0,
|
||||
"totalErrors": 0,
|
||||
},
|
||||
"userFriendlyMessage": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
|
||||
+10
@@ -31,6 +31,7 @@ exports[`View Field Resolver - Successful object metadata identifier update side
|
||||
"type": "create_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
},
|
||||
"message": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
"summary": {
|
||||
@@ -43,6 +44,7 @@ exports[`View Field Resolver - Successful object metadata identifier update side
|
||||
"invalidServerlessFunction": 0,
|
||||
"invalidView": 0,
|
||||
"invalidViewField": 0,
|
||||
"invalidViewFilter": 0,
|
||||
"totalErrors": 0,
|
||||
},
|
||||
"userFriendlyMessage": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
@@ -83,6 +85,7 @@ exports[`View Field Resolver - Successful object metadata identifier update side
|
||||
"type": "update_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
},
|
||||
"message": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
"summary": {
|
||||
@@ -95,6 +98,7 @@ exports[`View Field Resolver - Successful object metadata identifier update side
|
||||
"invalidServerlessFunction": 0,
|
||||
"invalidView": 0,
|
||||
"invalidViewField": 0,
|
||||
"invalidViewFilter": 0,
|
||||
"totalErrors": 0,
|
||||
},
|
||||
"userFriendlyMessage": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
@@ -133,6 +137,7 @@ exports[`View Field Resolver - Successful object metadata identifier update side
|
||||
"type": "delete_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
},
|
||||
"message": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
"summary": {
|
||||
@@ -145,6 +150,7 @@ exports[`View Field Resolver - Successful object metadata identifier update side
|
||||
"invalidServerlessFunction": 0,
|
||||
"invalidView": 0,
|
||||
"invalidViewField": 0,
|
||||
"invalidViewFilter": 0,
|
||||
"totalErrors": 0,
|
||||
},
|
||||
"userFriendlyMessage": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
@@ -185,6 +191,7 @@ exports[`View Field Resolver - Successful object metadata identifier update side
|
||||
"type": "update_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
},
|
||||
"message": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
"summary": {
|
||||
@@ -197,6 +204,7 @@ exports[`View Field Resolver - Successful object metadata identifier update side
|
||||
"invalidServerlessFunction": 0,
|
||||
"invalidView": 0,
|
||||
"invalidViewField": 0,
|
||||
"invalidViewFilter": 0,
|
||||
"totalErrors": 0,
|
||||
},
|
||||
"userFriendlyMessage": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
@@ -237,6 +245,7 @@ exports[`View Field Resolver - Successful object metadata identifier update side
|
||||
"type": "update_view_field",
|
||||
},
|
||||
],
|
||||
"viewFilter": [],
|
||||
},
|
||||
"message": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
"summary": {
|
||||
@@ -249,6 +258,7 @@ exports[`View Field Resolver - Successful object metadata identifier update side
|
||||
"invalidServerlessFunction": 0,
|
||||
"invalidView": 0,
|
||||
"invalidViewField": 0,
|
||||
"invalidViewFilter": 0,
|
||||
"totalErrors": 0,
|
||||
},
|
||||
"userFriendlyMessage": "Validation failed for 0 object(s) and 0 field(s)",
|
||||
|
||||
+124
-142
@@ -1,31 +1,18 @@
|
||||
import { TEST_NOT_EXISTING_VIEW_FILTER_ID } from 'test/integration/constants/test-view-ids.constants';
|
||||
import { createViewFilterOperationFactory } from 'test/integration/graphql/utils/create-view-filter-operation-factory.util';
|
||||
import { deleteViewFilterOperationFactory } from 'test/integration/graphql/utils/delete-view-filter-operation-factory.util';
|
||||
import { destroyViewFilterOperationFactory } from 'test/integration/graphql/utils/destroy-view-filter-operation-factory.util';
|
||||
import { findViewFiltersOperationFactory } from 'test/integration/graphql/utils/find-view-filters-operation-factory.util';
|
||||
import {
|
||||
assertGraphQLErrorResponse,
|
||||
assertGraphQLSuccessfulResponse,
|
||||
} from 'test/integration/graphql/utils/graphql-test-assertions.util';
|
||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||
import { updateViewFilterOperationFactory } from 'test/integration/graphql/utils/update-view-filter-operation-factory.util';
|
||||
import { createViewFilterData } from 'test/integration/graphql/utils/view-data-factory.util';
|
||||
import { expectOneNotInternalServerErrorSnapshot } from 'test/integration/graphql/utils/expect-one-not-internal-server-error-snapshot.util';
|
||||
import { createTestViewWithGraphQL } from 'test/integration/graphql/utils/view-graphql.util';
|
||||
import { createOneFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata.util';
|
||||
import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util';
|
||||
import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util';
|
||||
import { updateOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/update-one-object-metadata.util';
|
||||
import {
|
||||
assertViewFilterStructure,
|
||||
cleanupViewRecords,
|
||||
} from 'test/integration/utils/view-test.util';
|
||||
import { createOneCoreViewFilter } from 'test/integration/metadata/suites/view-filter/utils/create-one-core-view-filter.util';
|
||||
import { deleteOneCoreViewFilter } from 'test/integration/metadata/suites/view-filter/utils/delete-one-core-view-filter.util';
|
||||
import { destroyOneCoreViewFilter } from 'test/integration/metadata/suites/view-filter/utils/destroy-one-core-view-filter.util';
|
||||
import { findCoreViewFilters } from 'test/integration/metadata/suites/view-filter/utils/find-core-view-filters.util';
|
||||
import { updateOneCoreViewFilter } from 'test/integration/metadata/suites/view-filter/utils/update-one-core-view-filter.util';
|
||||
import { cleanupViewRecords } from 'test/integration/utils/view-test.util';
|
||||
import { FieldMetadataType, ViewFilterOperand } from 'twenty-shared/types';
|
||||
|
||||
import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||
import {
|
||||
generateViewFilterExceptionMessage,
|
||||
ViewFilterExceptionMessageKey,
|
||||
} from 'src/engine/metadata-modules/view-filter/exceptions/view-filter.exception';
|
||||
const TEST_NOT_EXISTING_VIEW_FILTER_ID = '20202020-52c5-4152-8c09-76a845fb8ece';
|
||||
|
||||
describe('View Filter Resolver', () => {
|
||||
let testViewId: string;
|
||||
@@ -98,33 +85,34 @@ describe('View Filter Resolver', () => {
|
||||
|
||||
describe('getCoreViewFilters', () => {
|
||||
it('should return empty array when no view filters exist', async () => {
|
||||
const operation = findViewFiltersOperationFactory({ viewId: testViewId });
|
||||
const response = await makeGraphqlAPIRequest(operation);
|
||||
const { data, errors } = await findCoreViewFilters({
|
||||
viewId: testViewId,
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
assertGraphQLSuccessfulResponse(response);
|
||||
expect(response.body.data.getCoreViewFilters).toEqual([]);
|
||||
expect(errors).toBeUndefined();
|
||||
expect(data.getCoreViewFilters).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return view filters for a specific view', async () => {
|
||||
const filterData = createViewFilterData(testViewId, {
|
||||
operand: ViewFilterOperand.CONTAINS,
|
||||
value: 'test',
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
});
|
||||
const createOperation = createViewFilterOperationFactory({
|
||||
data: filterData,
|
||||
await createOneCoreViewFilter({
|
||||
input: {
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
viewId: testViewId,
|
||||
operand: ViewFilterOperand.CONTAINS,
|
||||
value: 'test',
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
await makeGraphqlAPIRequest(createOperation);
|
||||
|
||||
const getOperation = findViewFiltersOperationFactory({
|
||||
const { data, errors } = await findCoreViewFilters({
|
||||
viewId: testViewId,
|
||||
expectToFail: false,
|
||||
});
|
||||
const response = await makeGraphqlAPIRequest(getOperation);
|
||||
|
||||
assertGraphQLSuccessfulResponse(response);
|
||||
expect(response.body.data.getCoreViewFilters).toHaveLength(1);
|
||||
assertViewFilterStructure(response.body.data.getCoreViewFilters[0], {
|
||||
expect(errors).toBeUndefined();
|
||||
expect(data.getCoreViewFilters).toHaveLength(1);
|
||||
expect(data.getCoreViewFilters[0]).toMatchObject({
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
operand: ViewFilterOperand.CONTAINS,
|
||||
value: 'test',
|
||||
@@ -135,17 +123,18 @@ describe('View Filter Resolver', () => {
|
||||
|
||||
describe('createCoreViewFilter', () => {
|
||||
it('should create a new view filter with string value', async () => {
|
||||
const filterData = createViewFilterData(testViewId, {
|
||||
operand: ViewFilterOperand.IS,
|
||||
value: 'test value',
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
const { data, errors } = await createOneCoreViewFilter({
|
||||
input: {
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
viewId: testViewId,
|
||||
operand: ViewFilterOperand.IS,
|
||||
value: 'test value',
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const operation = createViewFilterOperationFactory({ data: filterData });
|
||||
const response = await makeGraphqlAPIRequest(operation);
|
||||
|
||||
assertGraphQLSuccessfulResponse(response);
|
||||
assertViewFilterStructure(response.body.data.createCoreViewFilter, {
|
||||
expect(errors).toBeUndefined();
|
||||
expect(data.createCoreViewFilter).toMatchObject({
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
operand: ViewFilterOperand.IS,
|
||||
value: 'test value',
|
||||
@@ -154,17 +143,18 @@ describe('View Filter Resolver', () => {
|
||||
});
|
||||
|
||||
it('should create a view filter with numeric value', async () => {
|
||||
const filterData = createViewFilterData(testViewId, {
|
||||
operand: ViewFilterOperand.GREATER_THAN_OR_EQUAL,
|
||||
value: 100,
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
const { data, errors } = await createOneCoreViewFilter({
|
||||
input: {
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
viewId: testViewId,
|
||||
operand: ViewFilterOperand.GREATER_THAN_OR_EQUAL,
|
||||
value: 100,
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const operation = createViewFilterOperationFactory({ data: filterData });
|
||||
const response = await makeGraphqlAPIRequest(operation);
|
||||
|
||||
assertGraphQLSuccessfulResponse(response);
|
||||
assertViewFilterStructure(response.body.data.createCoreViewFilter, {
|
||||
expect(errors).toBeUndefined();
|
||||
expect(data.createCoreViewFilter).toMatchObject({
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
operand: ViewFilterOperand.GREATER_THAN_OR_EQUAL,
|
||||
value: 100,
|
||||
@@ -173,18 +163,18 @@ describe('View Filter Resolver', () => {
|
||||
});
|
||||
|
||||
it('should create a view filter with boolean value', async () => {
|
||||
const operation = createViewFilterOperationFactory({
|
||||
data: createViewFilterData(testViewId, {
|
||||
const { data, errors } = await createOneCoreViewFilter({
|
||||
input: {
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
viewId: testViewId,
|
||||
operand: ViewFilterOperand.IS,
|
||||
value: true,
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
}),
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const response = await makeGraphqlAPIRequest(operation);
|
||||
|
||||
assertGraphQLSuccessfulResponse(response);
|
||||
assertViewFilterStructure(response.body.data.createCoreViewFilter, {
|
||||
expect(errors).toBeUndefined();
|
||||
expect(data.createCoreViewFilter).toMatchObject({
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
operand: ViewFilterOperand.IS,
|
||||
value: true,
|
||||
@@ -195,30 +185,31 @@ describe('View Filter Resolver', () => {
|
||||
|
||||
describe('updateCoreViewFilter', () => {
|
||||
it('should update an existing view filter', async () => {
|
||||
const createOperation = createViewFilterOperationFactory({
|
||||
data: createViewFilterData(testViewId, {
|
||||
const { data: createData } = await createOneCoreViewFilter({
|
||||
input: {
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
viewId: testViewId,
|
||||
operand: ViewFilterOperand.CONTAINS,
|
||||
value: 'original',
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
}),
|
||||
});
|
||||
|
||||
const createResponse = await makeGraphqlAPIRequest(createOperation);
|
||||
|
||||
const viewFilterId = createResponse.body.data.createCoreViewFilter.id;
|
||||
|
||||
const updateOperation = updateViewFilterOperationFactory({
|
||||
viewFilterId: viewFilterId,
|
||||
data: {
|
||||
operand: ViewFilterOperand.DOES_NOT_CONTAIN,
|
||||
value: 'updated',
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const response = await makeGraphqlAPIRequest(updateOperation);
|
||||
const viewFilterId = createData.createCoreViewFilter.id;
|
||||
|
||||
assertGraphQLSuccessfulResponse(response);
|
||||
assertViewFilterStructure(response.body.data.updateCoreViewFilter, {
|
||||
const { data, errors } = await updateOneCoreViewFilter({
|
||||
input: {
|
||||
id: viewFilterId,
|
||||
update: {
|
||||
operand: ViewFilterOperand.DOES_NOT_CONTAIN,
|
||||
value: 'updated',
|
||||
},
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
expect(errors).toBeUndefined();
|
||||
expect(data.updateCoreViewFilter).toMatchObject({
|
||||
id: viewFilterId,
|
||||
operand: ViewFilterOperand.DOES_NOT_CONTAIN,
|
||||
value: 'updated',
|
||||
@@ -226,101 +217,92 @@ describe('View Filter Resolver', () => {
|
||||
});
|
||||
|
||||
it('should throw an error when updating non-existent view filter', async () => {
|
||||
const operation = updateViewFilterOperationFactory({
|
||||
viewFilterId: TEST_NOT_EXISTING_VIEW_FILTER_ID,
|
||||
const { errors } = await updateOneCoreViewFilter({
|
||||
input: {
|
||||
id: TEST_NOT_EXISTING_VIEW_FILTER_ID,
|
||||
update: {},
|
||||
},
|
||||
expectToFail: true,
|
||||
});
|
||||
const response = await makeGraphqlAPIRequest(operation);
|
||||
|
||||
assertGraphQLErrorResponse(
|
||||
response,
|
||||
ErrorCode.NOT_FOUND,
|
||||
generateViewFilterExceptionMessage(
|
||||
ViewFilterExceptionMessageKey.VIEW_FILTER_NOT_FOUND,
|
||||
TEST_NOT_EXISTING_VIEW_FILTER_ID,
|
||||
),
|
||||
);
|
||||
expectOneNotInternalServerErrorSnapshot({ errors });
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteCoreViewFilter', () => {
|
||||
it('should delete an existing view filter', async () => {
|
||||
const createOperation = createViewFilterOperationFactory({
|
||||
data: createViewFilterData(testViewId, {
|
||||
const { data: createData } = await createOneCoreViewFilter({
|
||||
input: {
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
viewId: testViewId,
|
||||
operand: ViewFilterOperand.CONTAINS,
|
||||
value: 'to delete',
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
}),
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const createResponse = await makeGraphqlAPIRequest(createOperation);
|
||||
const viewFilterId = createData.createCoreViewFilter.id;
|
||||
|
||||
const viewFilterId = createResponse.body.data.createCoreViewFilter.id;
|
||||
|
||||
const deleteOperation = deleteViewFilterOperationFactory({
|
||||
viewFilterId: viewFilterId,
|
||||
const { data, errors } = await deleteOneCoreViewFilter({
|
||||
input: { id: viewFilterId },
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const response = await makeGraphqlAPIRequest(deleteOperation);
|
||||
|
||||
assertGraphQLSuccessfulResponse(response);
|
||||
expect(response.body.data.deleteCoreViewFilter).toBe(true);
|
||||
expect(errors).toBeUndefined();
|
||||
expect(data.deleteCoreViewFilter).toMatchObject({
|
||||
id: viewFilterId,
|
||||
});
|
||||
expect(data.deleteCoreViewFilter.deletedAt).toBeDefined();
|
||||
});
|
||||
|
||||
it('should throw an error when deleting non-existent view filter', async () => {
|
||||
const operation = deleteViewFilterOperationFactory({
|
||||
viewFilterId: TEST_NOT_EXISTING_VIEW_FILTER_ID,
|
||||
const { errors } = await deleteOneCoreViewFilter({
|
||||
input: { id: TEST_NOT_EXISTING_VIEW_FILTER_ID },
|
||||
expectToFail: true,
|
||||
});
|
||||
const response = await makeGraphqlAPIRequest(operation);
|
||||
|
||||
assertGraphQLErrorResponse(
|
||||
response,
|
||||
ErrorCode.NOT_FOUND,
|
||||
generateViewFilterExceptionMessage(
|
||||
ViewFilterExceptionMessageKey.VIEW_FILTER_NOT_FOUND,
|
||||
TEST_NOT_EXISTING_VIEW_FILTER_ID,
|
||||
),
|
||||
);
|
||||
expectOneNotInternalServerErrorSnapshot({ errors });
|
||||
});
|
||||
});
|
||||
|
||||
describe('destroyCoreViewFilter', () => {
|
||||
it('should destroy an existing view filter', async () => {
|
||||
const createOperation = createViewFilterOperationFactory({
|
||||
data: createViewFilterData(testViewId, {
|
||||
const { data: createData } = await createOneCoreViewFilter({
|
||||
input: {
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
viewId: testViewId,
|
||||
operand: ViewFilterOperand.CONTAINS,
|
||||
value: 'to destroy',
|
||||
fieldMetadataId: testFieldMetadataId,
|
||||
}),
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const createResponse = await makeGraphqlAPIRequest(createOperation);
|
||||
const viewFilterId = createData.createCoreViewFilter.id;
|
||||
|
||||
const viewFilterId = createResponse.body.data.createCoreViewFilter.id;
|
||||
|
||||
const destroyOperation = destroyViewFilterOperationFactory({
|
||||
viewFilterId: viewFilterId,
|
||||
await deleteOneCoreViewFilter({
|
||||
input: {
|
||||
id: viewFilterId,
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
const { data, errors } = await destroyOneCoreViewFilter({
|
||||
input: { id: viewFilterId },
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const response = await makeGraphqlAPIRequest(destroyOperation);
|
||||
|
||||
assertGraphQLSuccessfulResponse(response);
|
||||
expect(response.body.data.destroyCoreViewFilter).toBe(true);
|
||||
expect(errors).toBeUndefined();
|
||||
expect(data.destroyCoreViewFilter).toMatchObject({
|
||||
id: viewFilterId,
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error when destroying non-existent view filter', async () => {
|
||||
const operation = destroyViewFilterOperationFactory({
|
||||
viewFilterId: TEST_NOT_EXISTING_VIEW_FILTER_ID,
|
||||
const { errors } = await destroyOneCoreViewFilter({
|
||||
input: { id: TEST_NOT_EXISTING_VIEW_FILTER_ID },
|
||||
expectToFail: true,
|
||||
});
|
||||
const response = await makeGraphqlAPIRequest(operation);
|
||||
|
||||
assertGraphQLErrorResponse(
|
||||
response,
|
||||
ErrorCode.NOT_FOUND,
|
||||
generateViewFilterExceptionMessage(
|
||||
ViewFilterExceptionMessageKey.VIEW_FILTER_NOT_FOUND,
|
||||
TEST_NOT_EXISTING_VIEW_FILTER_ID,
|
||||
),
|
||||
);
|
||||
expectOneNotInternalServerErrorSnapshot({ errors });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
import gql from 'graphql-tag';
|
||||
import { VIEW_FILTER_GQL_FIELDS } from 'test/integration/constants/view-gql-fields.constants';
|
||||
|
||||
import { type ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity';
|
||||
|
||||
type CreateViewFilterOperationFactoryParams = {
|
||||
gqlFields?: string;
|
||||
data?: Partial<ViewFilterEntity>;
|
||||
};
|
||||
|
||||
export const createViewFilterOperationFactory = ({
|
||||
gqlFields = VIEW_FILTER_GQL_FIELDS,
|
||||
data = {},
|
||||
}: CreateViewFilterOperationFactoryParams = {}) => ({
|
||||
query: gql`
|
||||
mutation CreateCoreViewFilter($input: CreateViewFilterInput!) {
|
||||
createCoreViewFilter(input: $input) {
|
||||
${gqlFields}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input: data,
|
||||
},
|
||||
});
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export const deleteViewFilterOperationFactory = ({
|
||||
viewFilterId,
|
||||
}: {
|
||||
viewFilterId: string;
|
||||
}) => ({
|
||||
query: gql`
|
||||
mutation DeleteCoreViewFilter($id: String!) {
|
||||
deleteCoreViewFilter(id: $id)
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
id: viewFilterId,
|
||||
},
|
||||
});
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export const destroyViewFilterOperationFactory = ({
|
||||
viewFilterId,
|
||||
}: {
|
||||
viewFilterId: string;
|
||||
}) => ({
|
||||
query: gql`
|
||||
mutation DestroyCoreViewFilter($id: String!) {
|
||||
destroyCoreViewFilter(id: $id)
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
id: viewFilterId,
|
||||
},
|
||||
});
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
import gql from 'graphql-tag';
|
||||
import { VIEW_FILTER_GQL_FIELDS } from 'test/integration/constants/view-gql-fields.constants';
|
||||
|
||||
export const findViewFiltersOperationFactory = ({
|
||||
gqlFields = VIEW_FILTER_GQL_FIELDS,
|
||||
viewId,
|
||||
}: {
|
||||
gqlFields?: string;
|
||||
viewId: string;
|
||||
}) => ({
|
||||
query: gql`
|
||||
query GetCoreViewFilters($viewId: String!) {
|
||||
getCoreViewFilters(viewId: $viewId) {
|
||||
${gqlFields}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
viewId,
|
||||
},
|
||||
});
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
import gql from 'graphql-tag';
|
||||
import { VIEW_FILTER_GQL_FIELDS } from 'test/integration/constants/view-gql-fields.constants';
|
||||
|
||||
export const updateViewFilterOperationFactory = ({
|
||||
gqlFields = VIEW_FILTER_GQL_FIELDS,
|
||||
viewFilterId,
|
||||
data = {},
|
||||
}: {
|
||||
gqlFields?: string;
|
||||
viewFilterId: string;
|
||||
data?: object;
|
||||
}) => ({
|
||||
query: gql`
|
||||
mutation UpdateCoreViewFilter($id: String!, $input: UpdateViewFilterInput!) {
|
||||
updateCoreViewFilter(id: $id, input: $input) {
|
||||
${gqlFields}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
id: viewFilterId,
|
||||
input: data,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user