Rest/Gql - Filter input - Integration tests (#14836)

This commit is contained in:
Etienne
2025-10-08 18:42:22 +02:00
committed by GitHub
parent 9fceb2354e
commit 3b992ed549
29 changed files with 3619 additions and 0 deletions
@@ -0,0 +1,70 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.ADDRESS;
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,110 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.ARRAY;
// const failingTestCases =
// failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
// describe('Gql filterInput - failure', () => {
// it.each(
// failingTestCases.map((testCase) => ({
// ...testCase,
// stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
// })),
// )(
// `${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
// async ({ gqlFilterInput: filter, gqlErrorMessage: errorMessage }) => {
// await testGqlFailingScenario(
// objectMetadataSingularName,
// objectMetadataPluralName,
// filter,
// errorMessage,
// );
// },
// );
// });
// // TODO : Refacto-common - Uncomment this
// describe('Rest filterInput - failure', () => {
// it.each(
// failingTestCases.map((testCase) => ({
// ...testCase,
// stringifiedFilter: JSON.stringify(testCase.restFilterInput),
// })),
// )(
// `${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
// async ({ restFilterInput: filter, restErrorMessage: errorMessage }) => {
// await testRestFailingScenario(
// objectMetadataPluralName,
// filter,
// errorMessage,
// );
// },
// );
// });
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,110 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.BOOLEAN;
// const failingTestCases =
// failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
// describe('Gql filterInput - failure', () => {
// it.each(
// failingTestCases.map((testCase) => ({
// ...testCase,
// stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
// })),
// )(
// `${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
// async ({ gqlFilterInput: filter, gqlErrorMessage: errorMessage }) => {
// await testGqlFailingScenario(
// objectMetadataSingularName,
// objectMetadataPluralName,
// filter,
// errorMessage,
// );
// },
// );
// });
// // TODO : Refacto-common - Uncomment this
// describe('Rest filterInput - failure', () => {
// it.each(
// failingTestCases.map((testCase) => ({
// ...testCase,
// stringifiedFilter: JSON.stringify(testCase.restFilterInput),
// })),
// )(
// `${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
// async ({ restFilterInput: filter, restErrorMessage: errorMessage }) => {
// await testRestFailingScenario(
// objectMetadataPluralName,
// filter,
// errorMessage,
// );
// },
// );
// });
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,416 @@
import { type FieldMetadataTypeToTest } from 'test/integration/graphql/suites/args-validation/types/field-metadata-type-to-test';
import { FieldMetadataType } from 'twenty-shared/types';
import { type CompositeFieldMetadataType } from 'src/engine/metadata-modules/workspace-migration/factories/composite-column-action.factory';
export const failingFilterInputByFieldMetadataType: {
[K in Exclude<FieldMetadataTypeToTest, CompositeFieldMetadataType>]: {
gqlFilterInput: any;
restFilterInput: any;
gqlErrorMessage: string;
restErrorMessage: string;
}[];
} = {
[FieldMetadataType.RELATION]: [
{
gqlFilterInput: {
manyToOneRelationField: {
eq: '6dd71a46-68fe-4420-82b3-0d5b00ad2642',
},
},
gqlErrorMessage: 'is not defined by type',
restFilterInput:
'manyToOneRelationField[eq]:"6dd71a46-68fe-4420-82b3-0d5b00ad2642"',
restErrorMessage: "'manyToOneRelationField' does not exist",
},
{
gqlFilterInput: {
manyToOneRelationFieldId: {
eq: 'invalid-uuid',
},
},
gqlErrorMessage: 'Invalid UUID',
restFilterInput: 'manyToOneRelationFieldId[eq]:"invalid-uuid"',
restErrorMessage: 'invalid input syntax for type uuid',
},
{
gqlFilterInput: {
oneToManyRelationField: {
eq: '6dd71a46-68fe-4420-82b3-0d5b00ad2642',
},
},
gqlErrorMessage: 'is not defined by type',
restFilterInput:
'oneToManyRelationFieldId[eq]:"6dd71a46-68fe-4420-82b3-0d5b00ad2642"',
restErrorMessage: "'oneToManyRelationFieldId' does not exist",
},
// {
// gqlFilterInput: {
// oneToManyRelationFieldId: {
// eq: 'invalid-uuid',
// },
// },
// restFilterInput: 'oneToManyRelationFieldId[eq]:"invalid-uuid"',
// gqlErrorMessage: 'is not defined by type',
// restErrorMessage: "'oneToManyRelationFieldId' does not exist",
// },
],
[FieldMetadataType.UUID]: [
{
gqlFilterInput: { uuidField: { eq: 'invalid-uuid' } },
gqlErrorMessage: 'Invalid UUID',
restFilterInput: 'uuidField[eq]:"invalid-uuid"',
restErrorMessage: 'invalid input syntax for type uuid',
},
{
gqlFilterInput: { uuidField: { eq: undefined } },
gqlErrorMessage:
'undefined is not iterable (cannot read property Symbol(Symbol.iterator))',
restFilterInput: 'uuidField[eq]:"undefined"',
restErrorMessage: 'invalid input syntax for type uuid',
},
{
gqlFilterInput: { uuidField: { eq: 2 } },
gqlErrorMessage: 'UUID must be a string',
restFilterInput: 'uuidField[eq]:2',
restErrorMessage: 'invalid input syntax for type uuid',
},
{
gqlFilterInput: { uuidField: { eq: {} } },
gqlErrorMessage: 'UUID must be a string',
restFilterInput: 'uuidField[eq]:"{}"',
restErrorMessage: 'invalid input syntax for type uuid',
},
{
gqlFilterInput: { uuidField: { eq: [] } },
gqlErrorMessage: 'UUID must be a string',
restFilterInput: 'uuidField[eq]:"[]"',
restErrorMessage: 'invalid input syntax for type uuid',
},
{
gqlFilterInput: { uuidField: { eq: true } },
gqlErrorMessage: 'UUID must be a string',
restFilterInput: 'uuidField[eq]:"true"',
restErrorMessage: 'invalid input syntax for type uuid',
},
{
gqlFilterInput: { uuidField: { eq: '2025-01-01' } },
gqlErrorMessage: 'Invalid UUID',
restFilterInput: 'uuidField[eq]:"2025-01-01"',
restErrorMessage: 'invalid input syntax for type uuid',
},
],
[FieldMetadataType.TEXT]: [
{
gqlFilterInput: {
textField: { regex: 'test' },
},
gqlErrorMessage: 'Operator "regex" is not supported',
restFilterInput: 'textField[regex]:test',
restErrorMessage: 'comparator regex not in',
},
{
gqlFilterInput: {
textField: { iregex: 'test' },
},
gqlErrorMessage: 'Operator "iregex" is not supported',
restFilterInput: 'textField[iregex]:test',
restErrorMessage: 'comparator iregex not in',
},
],
[FieldMetadataType.DATE_TIME]: [
{
gqlFilterInput: { dateTimeField: { eq: 'not-a-date-time' } },
gqlErrorMessage:
'invalid input syntax for type timestamp with time zone: "0NaN-NaN-NaNTNaN:NaN:NaN.NaN+NaN:NaN"',
restFilterInput: 'dateTimeField[eq]:"not-a-date-time"',
restErrorMessage:
'invalid input syntax for type timestamp with time zone',
},
{
gqlFilterInput: { dateTimeField: { eq: {} } },
gqlErrorMessage:
'invalid input syntax for type timestamp with time zone: "0NaN-NaN-NaNTNaN:NaN:NaN.NaN+NaN:NaN"',
restFilterInput: 'dateTimeField[eq]:"{}"',
restErrorMessage:
'invalid input syntax for type timestamp with time zone',
},
{
gqlFilterInput: { dateTimeField: { eq: [] } },
gqlErrorMessage:
'invalid input syntax for type timestamp with time zone: "0NaN-NaN-NaNTNaN:NaN:NaN.NaN+NaN:NaN"',
restFilterInput: 'dateTimeField[eq]:"[]"',
restErrorMessage:
'invalid input syntax for type timestamp with time zone',
},
// TODO - fix this, should throw an error
// {
// gqlFilterInput: { dateTimeField: { eq: true } },
// gqlErrorMessage:
// 'invalid input syntax for type timestamp with time zone: "0NaN-NaN-NaNTNaN:NaN:NaN.NaN+NaN:NaN"',
// },
],
[FieldMetadataType.DATE]: [
{
gqlFilterInput: { dateField: { eq: 'not-a-date' } },
gqlErrorMessage:
'invalid input syntax for type date: "0NaN-NaN-NaNTNaN:NaN:NaN.NaN+NaN:NaN"',
restFilterInput: 'dateField[eq]:"{}"',
restErrorMessage: 'invalid input syntax for type date',
},
{
gqlFilterInput: { dateField: { eq: {} } },
gqlErrorMessage:
'invalid input syntax for type date: "0NaN-NaN-NaNTNaN:NaN:NaN.NaN+NaN:NaN"',
restFilterInput: 'dateField[eq]:"{}"',
restErrorMessage: 'invalid input syntax for type date',
},
{
gqlFilterInput: { dateField: { eq: [] } },
gqlErrorMessage:
'invalid input syntax for type date: "0NaN-NaN-NaNTNaN:NaN:NaN.NaN+NaN:NaN"',
restFilterInput: 'dateField[eq]:"[]"',
restErrorMessage: 'invalid input syntax for type date',
},
],
[FieldMetadataType.BOOLEAN]: [
// {
// gqlFilterInput: { booleanField: { eq: 'not-a-boolean' } },
// gqlErrorMessage:
// 'Boolean cannot represent a non boolean value: "not-a-boolean"',
// // TODO - fix this, should throw an error
// // restFilterInput: 'booleanField[eq]:"not-a-boolean"',
// // restErrorMessage: 'invalid input syntax for type boolean',
// },
// {
// gqlFilterInput: { booleanField: { eq: [] } },
// gqlErrorMessage: 'Boolean cannot represent a non boolean value: []',
// // TODO - fix this, should throw an error
// // restFilterInput: 'booleanField[eq]:"[]"',
// // restErrorMessage: 'invalid input syntax for type boolean',
// },
// {
// gqlFilterInput: { booleanField: { eq: 2 } },
// gqlErrorMessage: 'Boolean cannot represent a non boolean value: 2',
// // TODO - fix this, should throw an error
// // restFilterInput: 'booleanField[eq]:2',
// // restErrorMessage: 'invalid input syntax for type boolean',
// },
// TODO - fix this, should throw an error
// {
// gqlFilterInput: { booleanField: { eq: null } },
// gqlErrorMessage: 'Boolean cannot represent a non boolean value: null',
// },
],
[FieldMetadataType.NUMBER]: [
// {
// gqlFilterInput: { numberField: { eq: 'not-a-number' } },
// gqlErrorMessage:
// 'Float cannot represent non numeric value: "not-a-number"',
// // TODO - fix this, should throw an error
// // restFilterInput: 'numberField[eq]:"not-a-number"',
// // restErrorMessage: 'invalid input syntax for type float',
// },
// {
// gqlFilterInput: { numberField: { eq: {} } },
// gqlErrorMessage: 'Float cannot represent non numeric value: {}',
// // TODO - fix this, should throw an error
// // restFilterInput: 'numberField[eq]:"{}"',
// // restErrorMessage: 'invalid input syntax for type float',
// },
// {
// gqlFilterInput: { numberField: { eq: [] } },
// gqlErrorMessage: 'Float cannot represent non numeric value: []',
// // TODO - fix this, should throw an error
// // restFilterInput: 'numberField[eq]:"[]"',
// // restErrorMessage: 'invalid input syntax for type float',
// },
// {
// gqlFilterInput: { numberField: { eq: true } },
// gqlErrorMessage: 'Float cannot represent non numeric value: true',
// // TODO - fix this, should throw an error
// // restFilterInput: 'numberField[eq]:"true"',
// // restErrorMessage: 'invalid input syntax for type float',
// },
// TODO - ensure it should throw
// {
// gqlFilterInput: { numberField: { eq: null } },
// gqlErrorMessage: 'Float cannot represent non numeric value: null',
// },
],
[FieldMetadataType.RATING]: [
{
gqlFilterInput: { ratingField: { eq: 'not-a-rating' } },
gqlErrorMessage: 'Value "not-a-rating" does not exist in ',
restFilterInput: 'ratingField[eq]:"not-a-rating"',
restErrorMessage: 'invalid input value for enum',
},
{
gqlFilterInput: { ratingField: { eq: {} } },
gqlErrorMessage: 'cannot represent non-string value: {}.',
restFilterInput: 'ratingField[eq]:"{}"',
restErrorMessage: 'invalid input value for enum',
},
{
gqlFilterInput: { ratingField: { eq: [] } },
gqlErrorMessage: 'cannot represent non-string value: [].',
restFilterInput: 'ratingField[eq]:"[]"',
restErrorMessage: 'invalid input value for enum',
},
{
gqlFilterInput: { ratingField: { eq: true } },
gqlErrorMessage: 'cannot represent non-string value: true.',
restFilterInput: 'ratingField[eq]:"true"',
restErrorMessage: 'invalid input value for enum',
},
{
gqlFilterInput: { ratingField: { eq: 2 } },
gqlErrorMessage: 'cannot represent non-string value: 2.',
restFilterInput: 'ratingField[eq]:2',
restErrorMessage: 'invalid input value for enum',
},
// TODO - ensure it should throw
// {
// gqlFilterInput: { ratingField: { eq: null } },
// gqlErrorMessage: 'cannot represent non-string value: null.',
// },
],
[FieldMetadataType.SELECT]: [
{
gqlFilterInput: { selectField: { eq: 'not-a-select' } },
gqlErrorMessage: 'Value "not-a-select" does not exist in',
restFilterInput: 'selectField[eq]:"not-a-select"',
restErrorMessage: "not available in 'selectField'",
},
{
gqlFilterInput: { selectField: { eq: {} } },
gqlErrorMessage: 'cannot represent non-string value: {}.',
restFilterInput: 'selectField[eq]:"{}"',
restErrorMessage: "not available in 'selectField'",
},
{
gqlFilterInput: { selectField: { eq: [] } },
gqlErrorMessage: 'cannot represent non-string value: [].',
restFilterInput: 'selectField[eq]:"[]"',
restErrorMessage: "not available in 'selectField'",
},
{
gqlFilterInput: { selectField: { eq: true } },
gqlErrorMessage: 'cannot represent non-string value: true.',
restFilterInput: 'selectField[eq]:"true"',
restErrorMessage: "not available in 'selectField'",
},
// TODO - ensure it should throw
// {
// gqlFilterInput: { selectField: { eq: null } },
// gqlErrorMessage: 'cannot represent non-string value: null.',
// },
],
[FieldMetadataType.MULTI_SELECT]: [
{
gqlFilterInput: { multiSelectField: { eq: 'not-a-multi-select' } },
gqlErrorMessage: 'Value "not-a-multi-select" does not exist ',
restFilterInput: 'multiSelectField[eq]:"not-a-multi-select"',
restErrorMessage: "not available in 'multiSelectField'",
},
{
gqlFilterInput: { multiSelectField: { eq: {} } },
gqlErrorMessage: 'cannot represent non-string value: {}.',
restFilterInput: 'multiSelectField[eq]:"{}"',
restErrorMessage: "not available in 'multiSelectField'",
},
{
gqlFilterInput: { multiSelectField: { eq: [] } },
gqlErrorMessage: 'cannot represent non-string value: [].',
restFilterInput: 'multiSelectField[eq]:"[]"',
restErrorMessage: "not available in 'multiSelectField'",
},
{
gqlFilterInput: { multiSelectField: { eq: true } },
gqlErrorMessage: 'cannot represent non-string value: true.',
restFilterInput: 'multiSelectField[eq]:"true"',
restErrorMessage: "not available in 'multiSelectField'",
},
{
gqlFilterInput: { multiSelectField: { eq: 2 } },
gqlErrorMessage: 'cannot represent non-string value: 2.',
restFilterInput: 'multiSelectField[eq]:2',
restErrorMessage: "enum value '2' not available in 'multiSelectField' ",
},
// TODO - ensure it should throw
// {
// gqlFilterInput: { multiSelectField: { eq: null } },
// gqlErrorMessage: 'cannot represent non-string value: null.',
// },
],
[FieldMetadataType.RAW_JSON]: [
// {
// gqlFilterInput: { rawJsonField: { like: {} } },
// gqlErrorMessage: 'cannot represent a non string value',
// // TODO - fix this ? for rest
// // restFilterInput: 'rawJsonField[like]:"{}"',
// // restErrorMessage: 'cannot represent a non string value',
// },
// {
// gqlFilterInput: { rawJsonField: { like: [] } },
// gqlErrorMessage: 'cannot represent a non string value',
// // TODO - fix this ? for rest
// // restFilterInput: 'rawJsonField[like]:"[]"',
// // restErrorMessage: 'cannot represent a non string value',
// },
// {
// gqlFilterInput: { rawJsonField: { like: true } },
// gqlErrorMessage: 'cannot represent a non string value',
// // TODO - fix this ? for rest
// // restFilterInput: 'rawJsonField[like]:"true"',
// // restErrorMessage: 'cannot represent a non string value',
// },
// {
// gqlFilterInput: { rawJsonField: { like: 2 } },
// gqlErrorMessage: 'cannot represent a non string value',
// // TODO - fix this ? for rest
// // restFilterInput: 'rawJsonField[like]:2',
// // restErrorMessage: 'cannot represent a non string value',
// },
// TODO - ensure it should throw
// {
// gqlFilterInput: { rawJsonField: { like: null } },
// gqlErrorMessage: 'cannot represent non-string value: null.',
// },
],
[FieldMetadataType.ARRAY]: [
// {
// gqlFilterInput: { arrayField: { containsIlike: {} } },
// gqlErrorMessage: 'cannot represent a non string value',
// // TODO - fix this ? containsIlike not existing for rest
// // restFilterInput: 'arrayField[containsIlike]:"{}"',
// // restErrorMessage: '',
// },
// {
// gqlFilterInput: { arrayField: { containsIlike: [] } },
// gqlErrorMessage: 'cannot represent a non string value',
// // TODO - fix this ? containsIlike not existing for rest
// // restFilterInput: 'arrayField[containsIlike]:"[]"',
// // restErrorMessage: '',
// },
// {
// gqlFilterInput: { arrayField: { containsIlike: true } },
// gqlErrorMessage: 'cannot represent a non string value',
// // TODO - fix this ? containsIlike not existing for rest
// // restFilterInput: 'arrayField[containsIlike]:"true"',
// // restErrorMessage: '',
// },
// {
// gqlFilterInput: { arrayField: { containsIlike: 2 } },
// gqlErrorMessage: 'cannot represent a non string value',
// // TODO - fix this ? containsIlike not existing for rest
// // restFilterInput: 'arrayField[containsIlike]:2',
// // restErrorMessage: '',
// },
// TODO - ensure it should throw
// {
// gqlFilterInput: { arrayField: { containsIlike: null } },
// gqlErrorMessage: 'cannot represent a non string value',
// },
],
};
@@ -0,0 +1,938 @@
import { isDefined } from 'class-validator';
import { type FieldMetadataTypeToTest } from 'test/integration/graphql/suites/args-validation/types/field-metadata-type-to-test';
import {
TEST_TARGET_OBJECT_RECORD_ID,
TEST_UUID_FIELD_VALUE,
} from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
export const successfulFilterInputByFieldMetadataType: {
[K in FieldMetadataTypeToTest]: {
gqlFilterInput: any;
restFilterInput: string;
validateFilter: (record: Record<string, any>) => boolean;
}[];
} = {
[FieldMetadataType.RELATION]: [
{
gqlFilterInput: {
manyToOneRelationFieldId: {
neq: '00000000-0000-4000-8000-000000000000',
},
},
restFilterInput: `manyToOneRelationFieldId[neq]:"00000000-0000-4000-8000-000000000000"`,
validateFilter: (record: Record<string, any>) => {
return (
record.manyToOneRelationFieldId !==
'00000000-0000-4000-8000-000000000000'
);
},
},
{
gqlFilterInput: {
manyToOneRelationFieldId: {
eq: TEST_TARGET_OBJECT_RECORD_ID,
},
},
restFilterInput: `manyToOneRelationFieldId[eq]:"${TEST_TARGET_OBJECT_RECORD_ID}"`,
validateFilter: (record: Record<string, any>) => {
return record.manyToOneRelationFieldId === TEST_TARGET_OBJECT_RECORD_ID;
},
},
// TODO - fix this, should be returning or not be allowed
// {
// gqlFilterInput: {
// manyToOneRelationFieldId: {
// eq: null,
// },
// },
// restFilterInput: 'manyToOneRelationFieldId[eq]=null',
// validateFilter: (record: Record<string, any>) => {
// return record.manyToOneRelationField === null;
// },
// },
{
gqlFilterInput: {
manyToOneRelationFieldId: {
gt: '00000000-0000-4000-8000-000000000000',
},
},
restFilterInput:
'manyToOneRelationFieldId[gt]:"00000000-0000-4000-8000-000000000000"',
validateFilter: (record: Record<string, any>) => {
return (
record.manyToOneRelationFieldId >
'00000000-0000-4000-8000-000000000000'
);
},
},
{
gqlFilterInput: {
manyToOneRelationFieldId: {
gte: '00000000-0000-4000-8000-000000000000',
},
},
restFilterInput: `manyToOneRelationFieldId[gte]:"00000000-0000-4000-8000-000000000000"`,
validateFilter: (record: Record<string, any>) => {
return (
record.manyToOneRelationFieldId >=
'00000000-0000-4000-8000-000000000000'
);
},
},
{
gqlFilterInput: {
manyToOneRelationFieldId: {
lt: 'ffffffff-ffff-4fff-bfff-ffffffffffff',
},
},
restFilterInput: `manyToOneRelationFieldId[lt]:"ffffffff-ffff-4fff-bfff-ffffffffffff"`,
validateFilter: (record: Record<string, any>) => {
return (
record.manyToOneRelationFieldId <
'ffffffff-ffff-4fff-bfff-ffffffffffff'
);
},
},
{
gqlFilterInput: {
manyToOneRelationFieldId: {
lte: 'ffffffff-ffff-4fff-bfff-ffffffffffff',
},
},
restFilterInput: `manyToOneRelationFieldId[lte]:"ffffffff-ffff-4fff-bfff-ffffffffffff"`,
validateFilter: (record: Record<string, any>) => {
return (
record.manyToOneRelationFieldId <=
'ffffffff-ffff-4fff-bfff-ffffffffffff'
);
},
},
{
gqlFilterInput: {
manyToOneRelationFieldId: {
in: [TEST_TARGET_OBJECT_RECORD_ID],
},
},
restFilterInput: `manyToOneRelationFieldId[in]:["${TEST_TARGET_OBJECT_RECORD_ID}"]`,
validateFilter: (record: Record<string, any>) => {
return record.manyToOneRelationFieldId === TEST_TARGET_OBJECT_RECORD_ID;
},
},
{
gqlFilterInput: {
manyToOneRelationFieldId: { is: 'NULL' },
},
restFilterInput: 'manyToOneRelationFieldId[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return record.manyToOneRelationFieldId === null;
},
},
{
gqlFilterInput: {
manyToOneRelationFieldId: { is: 'NOT_NULL' },
},
restFilterInput: 'manyToOneRelationFieldId[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.manyToOneRelationFieldId);
},
},
],
[FieldMetadataType.UUID]: [
{
gqlFilterInput: {
uuidField: { neq: '00000000-0000-4000-8000-000000000000' },
},
restFilterInput: `uuidField[neq]:"00000000-0000-4000-8000-000000000000"`,
validateFilter: (record: Record<string, any>) => {
return record.uuidField !== '00000000-0000-4000-8000-000000000000';
},
},
{
gqlFilterInput: {
uuidField: { eq: TEST_UUID_FIELD_VALUE },
},
restFilterInput: `uuidField[eq]:"${TEST_UUID_FIELD_VALUE}"`,
validateFilter: (record: Record<string, any>) => {
return record.uuidField === TEST_UUID_FIELD_VALUE;
},
},
// TODO - fix this, should be returning or not be allowed
// {
// gqlFilterInput: { uuidField: { eq: null } },
// restFilterInput: 'uuidField[eq]=null',
// validateFilter: (record: Record<string, any>) => {
// return record.uuidField === null;
// },
// },
{
gqlFilterInput: {
uuidField: { gt: '00000000-0000-4000-8000-000000000000' },
},
restFilterInput: `uuidField[gt]:"00000000-0000-4000-8000-000000000000"`,
validateFilter: (record: Record<string, any>) => {
return record.uuidField > '00000000-0000-4000-8000-000000000000';
},
},
{
gqlFilterInput: {
uuidField: { gte: '00000000-0000-4000-8000-000000000000' },
},
restFilterInput: `uuidField[gte]:"00000000-0000-4000-8000-000000000000"`,
validateFilter: (record: Record<string, any>) => {
return record.uuidField >= '00000000-0000-4000-8000-000000000000';
},
},
{
gqlFilterInput: {
uuidField: { lt: 'ffffffff-ffff-4fff-bfff-ffffffffffff' },
},
restFilterInput: `uuidField[lt]:"ffffffff-ffff-4fff-bfff-ffffffffffff"`,
validateFilter: (record: Record<string, any>) => {
return record.uuidField < 'ffffffff-ffff-4fff-bfff-ffffffffffff';
},
},
{
gqlFilterInput: {
uuidField: { lte: 'ffffffff-ffff-4fff-bfff-ffffffffffff' },
},
restFilterInput: `uuidField[lte]:"ffffffff-ffff-4fff-bfff-ffffffffffff"`,
validateFilter: (record: Record<string, any>) => {
return record.uuidField <= 'ffffffff-ffff-4fff-bfff-ffffffffffff';
},
},
{
gqlFilterInput: {
uuidField: { in: [TEST_UUID_FIELD_VALUE] },
},
restFilterInput: `uuidField[in]:["${TEST_UUID_FIELD_VALUE}"]`,
validateFilter: (record: Record<string, any>) => {
return record.uuidField === TEST_UUID_FIELD_VALUE;
},
},
{
gqlFilterInput: { uuidField: { is: 'NULL' } },
restFilterInput: 'uuidField[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return record.uuidField === null;
},
},
{
gqlFilterInput: { uuidField: { is: 'NOT_NULL' } },
restFilterInput: 'uuidField[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.uuidField);
},
},
],
[FieldMetadataType.TEXT]: [
{
gqlFilterInput: { textField: { neq: 'neqtest' } },
restFilterInput: 'textField[neq]:"neqtest"',
validateFilter: (record: Record<string, any>) => {
return record.textField !== 'neqtest';
},
},
{
gqlFilterInput: { textField: { eq: 'test' } },
restFilterInput: 'textField[eq]:"test"',
validateFilter: (record: Record<string, any>) => {
return record.textField === 'test';
},
},
// TODO - fix this ? not working
// {
// gqlFilterInput: { textField: { eq: null } },
// restFilterInput: 'textField[eq]:"null"',
// validateFilter: (record: Record<string, any>) => {
// return record.textField === '';
// },
// },
{
gqlFilterInput: { textField: { gt: 'tess' } },
restFilterInput: 'textField[gt]:"tess"',
validateFilter: (record: Record<string, any>) => {
return record.textField > 'tess';
},
},
{
gqlFilterInput: { textField: { gte: 'tess' } },
restFilterInput: 'textField[gte]:"tess"',
validateFilter: (record: Record<string, any>) => {
return record.textField >= 'tess';
},
},
{
gqlFilterInput: { textField: { lt: 'tesu' } },
restFilterInput: 'textField[lt]:"tesu"',
validateFilter: (record: Record<string, any>) => {
return record.textField < 'tesu';
},
},
{
gqlFilterInput: { textField: { lte: 'tesu' } },
restFilterInput: 'textField[lte]:"tesu"',
validateFilter: (record: Record<string, any>) => {
return record.textField <= 'tesu';
},
},
{
gqlFilterInput: { textField: { in: ['test'] } },
restFilterInput: 'textField[in]:["test"]',
validateFilter: (record: Record<string, any>) => {
return record.textField === 'test';
},
},
// TODO - fix this ? not working
// {
// gqlFilterInput: { textField: { is: 'NULL' } },
// restFilterInput: 'textField[is]:"NULL"',
// validateFilter: (record: Record<string, any>) => {
// return record.textField === '';
// },
// },
{
gqlFilterInput: { textField: { is: 'NOT_NULL' } },
restFilterInput: 'textField[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.textField);
},
},
// TODO - fix this ? not working
// {
// gqlFilterInput: { textField: { startsWith: 'tes' } },
// restFilterInput: 'textField[startsWith]:"tes"',
// validateFilter: (record: Record<string, any>) => {
// return record.textField.startsWith('tes');
// },
// },
{
gqlFilterInput: { textField: { like: '%es%' } },
restFilterInput: 'textField[like]:"%es%"',
validateFilter: (record: Record<string, any>) => {
return record.textField.includes('es');
},
},
{
gqlFilterInput: { textField: { ilike: '%ES%' } },
restFilterInput: 'textField[ilike]:"%ES%"',
validateFilter: (record: Record<string, any>) => {
return record.textField.toLowerCase().includes('es');
},
},
//TODO - regex, iregex not working ? to remove from gql schema ?
// {
// gqlFilterInput: { textField: { regex: '^test$' } },
// restFilterInput: 'textField[regex]:"^test$"',
// validateFilter: (record: Record<string, any>) => {
// return record.textField.includes('test');
// },
// },
// {
// gqlFilterInput: { textField: { iregex: '^test$' } },
// restFilterInput: 'textField[iregex]:"^test$"',
// validateFilter: (record: Record<string, any>) => {
// return record.textField.toLowerCase().includes('test');
// },
// },
],
[FieldMetadataType.PHONES]: [
{
gqlFilterInput: {
phonesField: { primaryPhoneNumber: { eq: '1234567890' } },
},
restFilterInput: 'phonesField.primaryPhoneNumber[eq]:"1234567890"',
validateFilter: (record: Record<string, any>) => {
return record.phonesField.primaryPhoneNumber === '1234567890';
},
},
{
gqlFilterInput: {
phonesField: { primaryPhoneCallingCode: { is: 'NOT_NULL' } },
},
restFilterInput: 'phonesField.primaryPhoneCallingCode[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return record.phonesField.primaryPhoneCallingCode !== null;
},
},
{
gqlFilterInput: {
phonesField: {
additionalPhones: {
is: 'NOT_NULL',
},
},
},
restFilterInput: 'phonesField.additionalPhones[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return record.phonesField.additionalPhones !== null;
},
},
{
gqlFilterInput: {
phonesField: { primaryPhoneCountryCode: { like: 'FR' } },
},
restFilterInput: 'phonesField.primaryPhoneCountryCode[like]:"FR"',
validateFilter: (record: Record<string, any>) => {
return record.phonesField.primaryPhoneCountryCode.includes('FR');
},
},
// TODO - should be allowed ? two conditions simultaneously
// {
// gqlFilterInput: {
// phonesField: {
// primaryPhoneCountryCode: { is: 'NULL' },
// primaryPhoneCallingCode: { is: 'NULL' },
// },
// },
// restFilterInput:
// 'phonesField[primaryPhoneCountryCode][is]=NULL&phonesField[primaryPhoneCallingCode][is]=NULL',
// },
],
[FieldMetadataType.EMAILS]: [
{
gqlFilterInput: {
emailsField: { primaryEmail: { eq: 'test@test.com' } },
},
restFilterInput: 'emailsField.primaryEmail[eq]:"test@test.com"',
validateFilter: (record: Record<string, any>) => {
return record.emailsField.primaryEmail === 'test@test.com';
},
},
{
gqlFilterInput: {
emailsField: { additionalEmails: { is: 'NOT_NULL' } },
},
restFilterInput: 'emailsField.additionalEmails[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return record.emailsField.additionalEmails !== null;
},
},
],
[FieldMetadataType.DATE_TIME]: [
// TODO - fix this ? not working
// {
// gqlFilterInput: { dateTimeField: { eq: '2025-01-01T00:00:00Z' } },
// restFilterInput: 'dateTimeField[eq]=2025-01-01T00:00:00Z',
// validateFilter: (record: Record<string, any>) => {
// return record.dateTimeField === '2025-01-01T00:00:00Z';
// },
// },
{
gqlFilterInput: { dateTimeField: { gt: '2005-01-01T00:00:00Z' } },
restFilterInput: 'dateTimeField[gt]:"2005-01-01T00:00:00Z"',
validateFilter: (record: Record<string, any>) => {
return record.dateTimeField > '2005-01-01T00:00:00Z';
},
},
{
gqlFilterInput: { dateTimeField: { gte: '2005-01-01T00:00:00Z' } },
restFilterInput: 'dateTimeField[gte]:"2005-01-01T00:00:00Z"',
validateFilter: (record: Record<string, any>) => {
return record.dateTimeField >= '2005-01-01T00:00:00Z';
},
},
// TODO - fix this ? not working
// {
// gqlFilterInput: { dateTimeField: { in: ['2025-01-01T00:00:00Z'] } },
// restFilterInput: 'dateTimeField[in]=2025-01-01T00:00:00Z',
// validateFilter: (record: Record<string, any>) => {
// return record.dateTimeField === '2025-01-01T00:00:00Z';
// },
// },
{
gqlFilterInput: { dateTimeField: { lt: '2125-01-01T00:00:00Z' } },
restFilterInput: 'dateTimeField[lt]:"2125-01-01T00:00:00Z"',
validateFilter: (record: Record<string, any>) => {
return record.dateTimeField < '2125-01-01T00:00:00Z';
},
},
{
gqlFilterInput: { dateTimeField: { lte: '2125-01-01T00:00:00Z' } },
restFilterInput: 'dateTimeField[lte]:"2125-01-01T00:00:00Z"',
validateFilter: (record: Record<string, any>) => {
return record.dateTimeField <= '2125-01-01T00:00:00Z';
},
},
{
gqlFilterInput: { dateTimeField: { neq: '2005-01-01T00:00:00Z' } },
restFilterInput: 'dateTimeField[neq]:"2005-01-01T00:00:00Z"',
validateFilter: (record: Record<string, any>) => {
return record.dateTimeField !== '2005-01-01T00:00:00Z';
},
},
{
gqlFilterInput: { dateTimeField: { is: 'NOT_NULL' } },
restFilterInput: 'dateTimeField[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.dateTimeField);
},
},
// {
// gqlFilterInput: { dateTimeField: { is: 'NULL' } },
// // TODO - fix this ? not working
// // restFilterInput: 'dateTimeField[is]:"NULL"',
// validateFilter: (record: Record<string, any>) => {
// return record.dateTimeField === null;
// },
// },
// TODO - fix this, should be returning or not be allowed
// {
// gqlFilterInput: { dateTimeField: { eq: null } },
// restFilterInput: 'dateTimeField[eq]=null',
// validateFilter: (record: Record<string, any>) => {
// return record.dateTimeField === null;
// },
// },
// TODO - why float are allowed ?
// {
// gqlFilterInput: { dateTimeField: { eq: 2 } },
// restFilterInput: 'dateTimeField[eq]=2',
// validateFilter: (record: Record<string, any>) => {
// return record.dateTimeField === 2;
// },
// },
],
[FieldMetadataType.DATE]: [
// TODO - fix this ? not working
// {
// gqlFilterInput: { dateField: { eq: '2025-01-01' } },
// restFilterInput: 'dateField[eq]=2025-01-01',
// validateFilter: (record: Record<string, any>) => {
// return record.dateField === '2025-01-01';
// },
// },
{
gqlFilterInput: { dateField: { neq: '2005-01-01' } },
restFilterInput: 'dateField[neq]:"2005-01-01"',
validateFilter: (record: Record<string, any>) => {
return record.dateField !== '2005-01-01';
},
},
{
gqlFilterInput: { dateField: { gt: '2005-01-01' } },
restFilterInput: 'dateField[gt]:"2005-01-01"',
validateFilter: (record: Record<string, any>) => {
return record.dateField > '2005-01-01';
},
},
{
gqlFilterInput: { dateField: { gte: '2005-01-01' } },
restFilterInput: 'dateField[gte]:"2005-01-01"',
validateFilter: (record: Record<string, any>) => {
return record.dateField >= '2005-01-01';
},
},
// TODO - fix this ? not working
// {
// gqlFilterInput: { dateField: { in: ['2025-01-01'] } },
// restFilterInput: 'dateField[in]=2025-01-01',
// validateFilter: (record: Record<string, any>) => {
// return record.dateField === '2025-01-01';
// },
// },
{
gqlFilterInput: { dateField: { lt: '2125-01-01' } },
restFilterInput: 'dateField[lt]:"2125-01-01"',
validateFilter: (record: Record<string, any>) => {
return record.dateField < '2125-01-01';
},
},
{
gqlFilterInput: { dateField: { lte: '2125-01-01' } },
restFilterInput: 'dateField[lte]:"2125-01-01"',
validateFilter: (record: Record<string, any>) => {
return record.dateField <= '2125-01-01';
},
},
{
gqlFilterInput: { dateField: { is: 'NOT_NULL' } },
restFilterInput: 'dateField[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.dateField);
},
},
{
gqlFilterInput: { dateField: { is: 'NULL' } },
restFilterInput: 'dateField[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return record.dateField === null;
},
},
// TODO - fix this, should be returning or not be allowed
// {
// gqlFilterInput: { dateField: { eq: null } },
// restFilterInput: 'dateField[eq]=null',
// validateFilter: (record: Record<string, any>) => {
// return record.dateField === null;
// },
// },
// TODO - why float are allowed ?
// {
// gqlFilterInput: { dateField: { eq: 2 } },
// restFilterInput: 'dateField[eq]=2',
// validateFilter: (record: Record<string, any>) => {
// return record.dateField === 2;
// },
// },
],
[FieldMetadataType.BOOLEAN]: [
// {
// gqlFilterInput: { booleanField: { eq: true } },
// // TODO - fix this ? not working
// // restFilterInput: 'booleanField[eq]:"true"',
// validateFilter: (record: Record<string, any>) => {
// return record.booleanField === true;
// },
// },
{
gqlFilterInput: { booleanField: { is: 'NULL' } },
restFilterInput: 'booleanField[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return record.booleanField === null;
},
},
{
gqlFilterInput: { booleanField: { is: 'NOT_NULL' } },
restFilterInput: 'booleanField[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.booleanField);
},
},
],
[FieldMetadataType.NUMBER]: [
{
gqlFilterInput: { numberField: { eq: 1 } },
restFilterInput: 'numberField[eq]:1',
validateFilter: (record: Record<string, any>) => {
return record.numberField === 1;
},
},
{
gqlFilterInput: { numberField: { gt: 0 } },
restFilterInput: 'numberField[gt]:0',
validateFilter: (record: Record<string, any>) => {
return record.numberField > 0;
},
},
{
gqlFilterInput: { numberField: { gte: 0 } },
restFilterInput: 'numberField[gte]:0',
validateFilter: (record: Record<string, any>) => {
return record.numberField >= 0;
},
},
{
gqlFilterInput: { numberField: { lt: 2 } },
restFilterInput: 'numberField[lt]:2',
validateFilter: (record: Record<string, any>) => {
return record.numberField < 2;
},
},
{
gqlFilterInput: { numberField: { lte: 1 } },
restFilterInput: 'numberField[lte]:1',
validateFilter: (record: Record<string, any>) => {
return record.numberField <= 1;
},
},
{
gqlFilterInput: { numberField: { neq: 2 } },
restFilterInput: 'numberField[neq]:2',
validateFilter: (record: Record<string, any>) => {
return record.numberField !== 2;
},
},
{
gqlFilterInput: { numberField: { is: 'NULL' } },
restFilterInput: 'numberField[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return record.numberField === null;
},
},
{
gqlFilterInput: { numberField: { is: 'NOT_NULL' } },
restFilterInput: 'numberField[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.numberField);
},
},
],
[FieldMetadataType.LINKS]: [
{
gqlFilterInput: {
linksField: { primaryLinkUrl: { eq: 'twenty.com' } },
},
restFilterInput: 'linksField.primaryLinkUrl[eq]:"twenty.com"',
validateFilter: (record: Record<string, any>) => {
return record.linksField.primaryLinkUrl === 'twenty.com';
},
},
{
gqlFilterInput: {
linksField: {
primaryLinkLabel: { eq: 'twenty - #1 Open source CRM' },
},
},
restFilterInput:
'linksField.primaryLinkLabel[eq]:"twenty - #1 Open source CRM"',
validateFilter: (record: Record<string, any>) => {
return (
record.linksField.primaryLinkLabel === 'twenty - #1 Open source CRM'
);
},
},
{
gqlFilterInput: { linksField: { secondaryLinks: { like: '%twenty%' } } },
restFilterInput: 'linksField.secondaryLinks[like]:"%twenty%"',
validateFilter: (record: Record<string, any>) => {
return JSON.stringify(record.linksField.secondaryLinks).includes(
'twenty',
);
},
},
],
[FieldMetadataType.CURRENCY]: [
{
gqlFilterInput: {
currencyField: { amountMicros: { eq: 1000000 } },
},
restFilterInput: 'currencyField.amountMicros[eq]:1000000',
validateFilter: (record: Record<string, any>) => {
return Number(record.currencyField.amountMicros) === 1000000;
},
},
{
gqlFilterInput: { currencyField: { currencyCode: { eq: 'USD' } } },
restFilterInput: 'currencyField.currencyCode[eq]:"USD"',
validateFilter: (record: Record<string, any>) => {
return record.currencyField.currencyCode === 'USD';
},
},
],
[FieldMetadataType.FULL_NAME]: [
{
gqlFilterInput: { fullNameField: { firstName: { eq: 'John' } } },
restFilterInput: 'fullNameField.firstName[eq]:"John"',
validateFilter: (record: Record<string, any>) => {
return record.fullNameField.firstName === 'John';
},
},
{
gqlFilterInput: { fullNameField: { lastName: { eq: 'Doe' } } },
restFilterInput: 'fullNameField.lastName[eq]:"Doe"',
validateFilter: (record: Record<string, any>) => {
return record.fullNameField.lastName === 'Doe';
},
},
],
[FieldMetadataType.RATING]: [
{
gqlFilterInput: { ratingField: { eq: 'RATING_5' } },
restFilterInput: 'ratingField[eq]:"RATING_5"',
validateFilter: (record: Record<string, any>) => {
return record.ratingField === 'RATING_5';
},
},
{
gqlFilterInput: { ratingField: { neq: 'RATING_3' } },
restFilterInput: 'ratingField[neq]:"RATING_3"',
validateFilter: (record: Record<string, any>) => {
return record.ratingField !== 'RATING_3';
},
},
{
gqlFilterInput: { ratingField: { is: 'NULL' } },
restFilterInput: 'ratingField[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return record.ratingField === null;
},
},
{
gqlFilterInput: { ratingField: { in: ['RATING_5', 'RATING_4'] } },
restFilterInput: 'ratingField[in]:["RATING_5","RATING_4"]',
validateFilter: (record: Record<string, any>) => {
return ['RATING_5', 'RATING_4'].includes(record.ratingField);
},
},
{
gqlFilterInput: { ratingField: { is: 'NOT_NULL' } },
restFilterInput: 'ratingField[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.ratingField);
},
},
// TODO - fix this, should be ok
// {
// gqlFilterInput: { ratingField: { isEmptyArray: true } },
// restFilterInput: 'ratingField[isEmptyArray]=true',
// },
],
[FieldMetadataType.SELECT]: [
{
gqlFilterInput: { selectField: { in: ['OPTION_1'] } },
restFilterInput: 'selectField[in]:[OPTION_1]',
validateFilter: (record: Record<string, any>) => {
return ['OPTION_1'].includes(record.selectField);
},
},
{
gqlFilterInput: { selectField: { is: 'NULL' } },
restFilterInput: 'selectField[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return record.selectField === null;
},
},
{
gqlFilterInput: { selectField: { is: 'NOT_NULL' } },
restFilterInput: 'selectField[is]:NOT_NULL',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.selectField);
},
},
],
[FieldMetadataType.MULTI_SELECT]: [
{
gqlFilterInput: { multiSelectField: { containsAny: ['OPTION_1'] } },
restFilterInput: 'multiSelectField[containsAny]:[OPTION_1]',
validateFilter: (record: Record<string, any>) => {
return record.multiSelectField.includes('OPTION_1');
},
},
{
gqlFilterInput: { multiSelectField: { is: 'NULL' } },
restFilterInput: 'multiSelectField[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return record.multiSelectField === null;
},
},
{
gqlFilterInput: { multiSelectField: { is: 'NOT_NULL' } },
restFilterInput: 'multiSelectField[is]:NOT_NULL',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.multiSelectField);
},
},
//TODO - null and empty array should be equivalent
// {
// gqlFilterInput: { multiSelectField: { isEmptyArray: true } },
// restFilterInput: 'multiSelectField[isEmptyArray]=true',
// validateFilter: (record: Record<string, any>) => {
// return record.multiSelectField.length === 0;
// },
// },
],
[FieldMetadataType.ADDRESS]: [
{
gqlFilterInput: {
addressField: { addressStreet1: { eq: 'address street 1' } },
},
restFilterInput: 'addressField.addressStreet1[eq]:"address street 1"',
validateFilter: (record: Record<string, any>) => {
return record.addressField.addressStreet1 === 'address street 1';
},
},
{
gqlFilterInput: {
addressField: { addressStreet2: { eq: 'address street 2' } },
},
restFilterInput: 'addressField.addressStreet2[eq]:"address street 2"',
validateFilter: (record: Record<string, any>) => {
return record.addressField.addressStreet2 === 'address street 2';
},
},
{
gqlFilterInput: {
addressField: { addressStreet2: { is: 'NOT_NULL' } },
},
restFilterInput: 'addressField.addressStreet2[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.addressField.addressStreet2);
},
},
{
gqlFilterInput: {
addressField: { addressCity: { eq: 'address city' } },
},
restFilterInput: 'addressField.addressCity[eq]:"address city"',
validateFilter: (record: Record<string, any>) => {
return record.addressField.addressCity === 'address city';
},
},
{
gqlFilterInput: {
addressField: { addressState: { eq: 'address state' } },
},
restFilterInput: 'addressField.addressState[eq]:"address state"',
validateFilter: (record: Record<string, any>) => {
return record.addressField.addressState === 'address state';
},
},
{
gqlFilterInput: {
addressField: { addressCountry: { eq: 'address country' } },
},
restFilterInput: 'addressField.addressCountry[eq]:"address country"',
validateFilter: (record: Record<string, any>) => {
return record.addressField.addressCountry === 'address country';
},
},
{
gqlFilterInput: {
addressField: { addressPostcode: { eq: 'address postcode' } },
},
restFilterInput: 'addressField.addressPostcode[eq]:"address postcode"',
validateFilter: (record: Record<string, any>) => {
return record.addressField.addressPostcode === 'address postcode';
},
},
],
[FieldMetadataType.RAW_JSON]: [
{
gqlFilterInput: { rawJsonField: { is: 'NULL' } },
restFilterInput: 'rawJsonField[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return record.rawJsonField === null;
},
},
{
gqlFilterInput: { rawJsonField: { is: 'NOT_NULL' } },
restFilterInput: 'rawJsonField[is]:"NOT_NULL"',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.rawJsonField);
},
},
{
gqlFilterInput: { rawJsonField: { like: '%test%' } },
restFilterInput: 'rawJsonField[like]:"%test%"',
validateFilter: (record: Record<string, any>) => {
return JSON.stringify(record.rawJsonField).includes('test');
},
},
],
[FieldMetadataType.ARRAY]: [
// {
// gqlFilterInput: { arrayField: { containsIlike: 'test' } },
// // TODO - fix this ? not existing for rest
// // restFilterInput: 'arrayField[containsIlike]:"test"',
// validateFilter: (record: Record<string, any>) => {
// return JSON.stringify(record.arrayField).includes('test');
// },
// },
{
gqlFilterInput: { arrayField: { is: 'NULL' } },
restFilterInput: 'arrayField[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return record.arrayField === null;
},
},
//TODO - null and empty array should be equivalent
// {
// gqlFilterInput: { arrayField: { isEmptyArray: true } },
// restFilterInput: 'arrayField[isEmptyArray]=true',
// validateFilter: (record: Record<string, any>) => {
// return record.arrayField.length === 0;
// },
// },
],
};
@@ -0,0 +1,49 @@
export const TEST_OBJECT_GQL_FIELDS = `
id
manyToOneRelationFieldId
manyToOneRelationField {
id
}
uuidField
textField
phonesField {
primaryPhoneNumber
primaryPhoneCallingCode
primaryPhoneCountryCode
additionalPhones
}
emailsField {
primaryEmail
additionalEmails
}
dateTimeField
dateField
booleanField
numberField
linksField {
primaryLinkUrl
primaryLinkLabel
secondaryLinks
}
currencyField {
amountMicros
currencyCode
}
fullNameField {
firstName
lastName
}
ratingField
selectField
multiSelectField
addressField {
addressStreet1
addressStreet2
addressCity
addressState
addressCountry
addressPostcode
}
rawJsonField
arrayField
`;
@@ -0,0 +1,70 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.CURRENCY;
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,113 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.DATE;
const failingTestCases =
failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, gqlErrorMessage: errorMessage }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
// TODO : Refacto-common - Uncomment this
describe('Rest filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter, restErrorMessage: errorMessage }) => {
await testRestFailingScenario(
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,113 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.DATE_TIME;
const failingTestCases =
failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, gqlErrorMessage: errorMessage }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
// TODO : Refacto-common - Uncomment this
describe('Rest filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter, restErrorMessage: errorMessage }) => {
await testRestFailingScenario(
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,70 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.EMAILS;
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,70 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.FULL_NAME;
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,70 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.LINKS;
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,113 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.MULTI_SELECT;
const failingTestCases =
failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, gqlErrorMessage: errorMessage }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
// TODO : Refacto-common - Uncomment this
describe('Rest filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter, restErrorMessage: errorMessage }) => {
await testRestFailingScenario(
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,110 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.NUMBER;
// const failingTestCases =
// failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
// describe('Gql filterInput - failure', () => {
// it.each(
// failingTestCases.map((testCase) => ({
// ...testCase,
// stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
// })),
// )(
// `${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
// async ({ gqlFilterInput: filter, gqlErrorMessage: errorMessage }) => {
// await testGqlFailingScenario(
// objectMetadataSingularName,
// objectMetadataPluralName,
// filter,
// errorMessage,
// );
// },
// );
// });
// // TODO : Refacto-common - Uncomment this
// describe('Rest filterInput - failure', () => {
// it.each(
// failingTestCases.map((testCase) => ({
// ...testCase,
// stringifiedFilter: JSON.stringify(testCase.restFilterInput),
// })),
// )(
// `${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
// async ({ restFilterInput: filter, restErrorMessage: errorMessage }) => {
// await testRestFailingScenario(
// objectMetadataPluralName,
// filter,
// errorMessage,
// );
// },
// );
// });
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,70 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.PHONES;
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,113 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.RATING;
const failingTestCases =
failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, gqlErrorMessage: errorMessage }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
// TODO : Refacto-common - Uncomment this
describe('Rest filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter, restErrorMessage: errorMessage }) => {
await testRestFailingScenario(
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,110 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.RAW_JSON;
// const failingTestCases =
// failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
// describe('Gql filterInput - failure', () => {
// it.each(
// failingTestCases.map((testCase) => ({
// ...testCase,
// stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
// })),
// )(
// `${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
// async ({ gqlFilterInput: filter, gqlErrorMessage: errorMessage }) => {
// await testGqlFailingScenario(
// objectMetadataSingularName,
// objectMetadataPluralName,
// filter,
// errorMessage,
// );
// },
// );
// });
// // TODO : Refacto-common - Uncomment this
// describe('Rest filterInput - failure', () => {
// it.each(
// failingTestCases.map((testCase) => ({
// ...testCase,
// stringifiedFilter: JSON.stringify(testCase.restFilterInput),
// })),
// )(
// `${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
// async ({ restFilterInput: filter, restErrorMessage: errorMessage }) => {
// await testRestFailingScenario(
// objectMetadataPluralName,
// filter,
// errorMessage,
// );
// },
// );
// });
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,113 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.RELATION;
const failingTestCases =
failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, gqlErrorMessage: errorMessage }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
// TODO : Refacto-common - Uncomment this
describe('Rest filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter, restErrorMessage: errorMessage }) => {
await testRestFailingScenario(
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,112 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.SELECT;
const failingTestCases =
failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, gqlErrorMessage: errorMessage }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
// TODO : Refacto-common - Uncomment this
// describe('Rest filterInput - failure', () => {
// it.each(
// failingTestCases.map((testCase) => ({
// ...testCase,
// stringifiedFilter: JSON.stringify(testCase.restFilterInput),
// })),
// )(
// `${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
// async ({ restFilterInput: filter, restErrorMessage: errorMessage }) => {
// await testRestFailingScenario(
// objectMetadataPluralName,
// filter,
// errorMessage,
// );
// },
// );
// });
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,113 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.TEXT;
const failingTestCases =
failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, gqlErrorMessage: errorMessage }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
// TODO : Refacto-common - Uncomment this
describe('Rest filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter, restErrorMessage: errorMessage }) => {
await testRestFailingScenario(
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,21 @@
import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util';
import { makeGraphqlAPIRequestWithApiKey } from 'test/integration/graphql/utils/make-graphql-api-request-with-api-key.util';
export const testGqlFailingScenario = async (
objectMetadataSingularName: string,
objectMetadataPluralName: string,
filter: any,
errorMessage: string,
) => {
const graphqlOperation = findManyOperationFactory({
objectMetadataSingularName: objectMetadataSingularName,
objectMetadataPluralName: objectMetadataPluralName,
gqlFields: 'id',
filter,
});
const response = await makeGraphqlAPIRequestWithApiKey(graphqlOperation);
expect(response.body.errors).toBeDefined();
expect(response.body.errors[0].message).toContain(errorMessage);
};
@@ -0,0 +1,30 @@
import { TEST_OBJECT_GQL_FIELDS } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/test-object-gql-fields.constant';
import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util';
import { makeGraphqlAPIRequestWithApiKey } from 'test/integration/graphql/utils/make-graphql-api-request-with-api-key.util';
export const testGqlSuccessfulScenario = async (
objectMetadataSingularName: string,
objectMetadataPluralName: string,
filter: any,
validateFilter: (record: Record<string, any>) => boolean,
) => {
const graphqlOperation = findManyOperationFactory({
objectMetadataSingularName: objectMetadataSingularName,
objectMetadataPluralName: objectMetadataPluralName,
gqlFields: TEST_OBJECT_GQL_FIELDS,
filter,
});
const response = await makeGraphqlAPIRequestWithApiKey(graphqlOperation);
const records: Record<string, any>[] = response.body.data[
objectMetadataPluralName
].edges.map((edge: any) => edge.node);
expect(response.body.errors).toBeUndefined();
expect(records.length).toBeGreaterThan(0);
expect(
records.every((record: Record<string, any>) => validateFilter?.(record)),
).toBe(true);
};
@@ -0,0 +1,16 @@
import { makeRestAPIRequest } from 'test/integration/rest/utils/make-rest-api-request.util';
export const testRestFailingScenario = async (
objectMetadataPluralName: string,
filter: any,
errorMessage: string,
) => {
const encodedFilter = encodeURIComponent(filter);
const response = await makeRestAPIRequest({
method: 'get',
path: `/${objectMetadataPluralName}?filter=${encodedFilter}`,
});
expect(response.body.error).toBeDefined();
expect(JSON.stringify(response.body.messages)).toContain(errorMessage);
};
@@ -0,0 +1,23 @@
import { makeRestAPIRequest } from 'test/integration/rest/utils/make-rest-api-request.util';
export const testRestSuccessfulScenario = async (
objectMetadataPluralName: string,
filter: any,
validateFilter: (record: Record<string, any>) => boolean,
) => {
const encodedFilter = encodeURIComponent(filter);
const response = await makeRestAPIRequest({
method: 'get',
path: `/${objectMetadataPluralName}?filter=${encodedFilter}`,
});
const records = response.body.data[objectMetadataPluralName];
expect(response.body.errors).toBeUndefined();
expect(records.length).toBeGreaterThan(0);
expect(
records.every((record: Record<string, any>) => validateFilter?.(record)),
).toBe(true);
};
@@ -0,0 +1,113 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/args-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/args-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/args-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.UUID;
const failingTestCases =
failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter args validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadataId: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadataId = setupTest.targetObjectMetadataId;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadataId,
]);
});
describe('Gql filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, gqlErrorMessage: errorMessage }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
// TODO : Refacto-common - Uncomment this
describe('Rest filterInput - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter, restErrorMessage: errorMessage }) => {
await testRestFailingScenario(
objectMetadataPluralName,
filter,
errorMessage,
);
},
);
});
describe('Gql filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter, validateFilter }) => {
await testGqlSuccessfulScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
validateFilter,
);
},
);
});
describe('Rest filterInput - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should succeed with filter : $stringifiedFilter`,
async ({ restFilterInput, validateFilter }) => {
await testRestSuccessfulScenario(
objectMetadataPluralName,
restFilterInput,
validateFilter,
);
},
);
});
});
@@ -0,0 +1,15 @@
import { type FieldMetadataType } from 'twenty-shared/types';
type FieldMetadataTypesNotTested =
| 'TS_VECTOR'
| 'RICH_TEXT'
| 'POSITION'
| 'ACTOR'
| 'MORPH_RELATION'
| 'NUMERIC'
| 'RICH_TEXT_V2';
export type FieldMetadataTypeToTest = Exclude<
FieldMetadataType,
FieldMetadataTypesNotTested
>;
@@ -0,0 +1,22 @@
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';
export const destroyManyObjectsMetadata = async (
objectMetadataIds: string[],
) => {
for (const objectMetadataId of objectMetadataIds) {
await updateOneObjectMetadata({
input: {
idToUpdate: objectMetadataId,
updatePayload: {
isActive: false,
},
},
});
await deleteOneObjectMetadata({
input: {
idToDelete: objectMetadataId,
},
});
}
};
@@ -0,0 +1,178 @@
import { type FieldMetadataTypeToTest } from 'test/integration/graphql/suites/args-validation/types/field-metadata-type-to-test';
import {
FieldMetadataType,
RelationType,
type RelationCreationPayload,
} from 'twenty-shared/types';
import { type FieldMetadataComplexOption } from 'src/engine/metadata-modules/field-metadata/dtos/options.input';
type FieldMetadataCreationInput = {
name: string;
label: string;
type: FieldMetadataType;
objectMetadataId: string;
options?: FieldMetadataComplexOption[];
relationCreationPayload?: RelationCreationPayload;
};
export const getFieldMetadataCreationInputs = (
objectMetadataId: string,
targetObjectMetadataId: string,
) => {
const fieldInputsMap: {
[K in FieldMetadataTypeToTest]:
| FieldMetadataCreationInput
| FieldMetadataCreationInput[];
} = {
[FieldMetadataType.TEXT]: {
name: 'textField',
label: 'textField',
type: FieldMetadataType.TEXT,
objectMetadataId,
},
[FieldMetadataType.PHONES]: {
name: 'phonesField',
label: 'phonesField',
type: FieldMetadataType.PHONES,
objectMetadataId,
},
[FieldMetadataType.EMAILS]: {
name: 'emailsField',
label: 'emailsField',
type: FieldMetadataType.EMAILS,
objectMetadataId,
},
[FieldMetadataType.DATE_TIME]: {
name: 'dateTimeField',
label: 'dateTimeField',
type: FieldMetadataType.DATE_TIME,
objectMetadataId,
},
[FieldMetadataType.DATE]: {
name: 'dateField',
label: 'dateField',
type: FieldMetadataType.DATE,
objectMetadataId,
},
[FieldMetadataType.BOOLEAN]: {
name: 'booleanField',
label: 'booleanField',
type: FieldMetadataType.BOOLEAN,
objectMetadataId,
},
[FieldMetadataType.NUMBER]: {
name: 'numberField',
label: 'numberField',
type: FieldMetadataType.NUMBER,
objectMetadataId,
},
[FieldMetadataType.LINKS]: {
name: 'linksField',
label: 'linksField',
type: FieldMetadataType.LINKS,
objectMetadataId,
},
[FieldMetadataType.CURRENCY]: {
name: 'currencyField',
label: 'currencyField',
type: FieldMetadataType.CURRENCY,
objectMetadataId,
},
[FieldMetadataType.FULL_NAME]: {
name: 'fullNameField',
label: 'fullNameField',
type: FieldMetadataType.FULL_NAME,
objectMetadataId,
},
[FieldMetadataType.RATING]: {
name: 'ratingField',
label: 'ratingField',
type: FieldMetadataType.RATING,
objectMetadataId,
},
[FieldMetadataType.SELECT]: {
name: 'selectField',
label: 'selectField',
type: FieldMetadataType.SELECT,
options: [
{
label: 'Option 1',
value: 'OPTION_1',
color: 'green',
position: 1,
id: '26c602c3-cba9-4d83-92d4-4ba7dbae2f31',
},
],
objectMetadataId,
},
[FieldMetadataType.MULTI_SELECT]: {
name: 'multiSelectField',
label: 'multiSelectField',
type: FieldMetadataType.MULTI_SELECT,
options: [
{
label: 'Option 1',
value: 'OPTION_1',
color: 'green',
position: 1,
id: '26c602c3-cba9-4d83-92d4-4ba7dbae2f31',
},
],
objectMetadataId,
},
[FieldMetadataType.ADDRESS]: {
name: 'addressField',
label: 'addressField',
type: FieldMetadataType.ADDRESS,
objectMetadataId,
},
[FieldMetadataType.RAW_JSON]: {
name: 'rawJsonField',
label: 'rawJsonField',
type: FieldMetadataType.RAW_JSON,
objectMetadataId,
},
[FieldMetadataType.ARRAY]: {
name: 'arrayField',
label: 'arrayField',
type: FieldMetadataType.ARRAY,
objectMetadataId,
},
[FieldMetadataType.UUID]: {
name: 'uuidField',
label: 'uuidField',
type: FieldMetadataType.UUID,
objectMetadataId,
},
[FieldMetadataType.RELATION]: [
{
name: 'manyToOneRelationField',
label: 'manyToOneRelationField',
type: FieldMetadataType.RELATION,
objectMetadataId,
relationCreationPayload: {
targetObjectMetadataId: targetObjectMetadataId,
targetFieldLabel: 'oneToManyTargetRelationField',
targetFieldIcon: 'IconListOpportunity',
type: RelationType.MANY_TO_ONE,
},
},
{
name: 'oneToManyRelationField',
label: 'oneToManyRelationField',
type: FieldMetadataType.RELATION,
objectMetadataId,
relationCreationPayload: {
targetObjectMetadataId: targetObjectMetadataId,
targetFieldLabel: 'manyToOneTargetRelationField',
targetFieldIcon: 'IconListOpportunity',
type: RelationType.ONE_TO_MANY,
},
},
],
};
return Object.values(fieldInputsMap).flat();
};
@@ -0,0 +1,148 @@
import { randomUUID } from 'crypto';
import { TEST_OBJECT_GQL_FIELDS } from 'test/integration/graphql/suites/args-validation/filter-validation/constants/test-object-gql-fields.constant';
import { getFieldMetadataCreationInputs } from 'test/integration/graphql/suites/args-validation/utils/get-field-metadata-creation-inputs.util';
import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util';
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.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';
const TEST_OBJECT_METADATA_NAME_SINGULAR = 'apiFilterValidationTestObject';
const TEST_OBJECT_METADATA_NAME_PLURAL = 'apiFilterValidationTestObjects';
const TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR =
'apiFilterValidationTargetTestObject';
const TEST_TARGET_OBJECT_METADATA_NAME_PLURAL =
'apiFilterValidationTargetTestObjects';
export const TEST_TARGET_OBJECT_RECORD_ID =
'20202020-a21e-4ec2-873b-de4264d89025';
export const TEST_UUID_FIELD_VALUE = '20202020-b21e-4ec2-873b-de4264d89025';
export const setupTestObjectsWithAllFieldTypes = async () => {
const createdObjectMetadata = await createOneObjectMetadata({
input: {
nameSingular: TEST_OBJECT_METADATA_NAME_SINGULAR,
namePlural: TEST_OBJECT_METADATA_NAME_PLURAL,
labelSingular: TEST_OBJECT_METADATA_NAME_SINGULAR,
labelPlural: TEST_OBJECT_METADATA_NAME_PLURAL,
},
});
const objectMetadataId = createdObjectMetadata.data.createOneObject.id;
const createdTargetObjectMetadata = await createOneObjectMetadata({
input: {
nameSingular: TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR,
namePlural: TEST_TARGET_OBJECT_METADATA_NAME_PLURAL,
labelSingular: TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR,
labelPlural: TEST_TARGET_OBJECT_METADATA_NAME_PLURAL,
},
});
const targetObjectMetadataId =
createdTargetObjectMetadata.data.createOneObject.id;
const fieldMetadataCreationInputs = getFieldMetadataCreationInputs(
objectMetadataId,
targetObjectMetadataId,
);
for (const input of fieldMetadataCreationInputs) {
await createOneFieldMetadata({
input,
});
}
await makeGraphqlAPIRequest(
createManyOperationFactory({
objectMetadataSingularName: TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR,
objectMetadataPluralName: TEST_TARGET_OBJECT_METADATA_NAME_PLURAL,
gqlFields: `id`,
data: [
{
id: TEST_TARGET_OBJECT_RECORD_ID,
},
],
}),
);
await makeGraphqlAPIRequest(
createManyOperationFactory({
objectMetadataSingularName: TEST_OBJECT_METADATA_NAME_SINGULAR,
objectMetadataPluralName: TEST_OBJECT_METADATA_NAME_PLURAL,
gqlFields: TEST_OBJECT_GQL_FIELDS,
data: [
{
id: randomUUID(),
manyToOneRelationFieldId: TEST_TARGET_OBJECT_RECORD_ID,
uuidField: TEST_UUID_FIELD_VALUE,
textField: 'test',
phonesField: {
primaryPhoneNumber: '01234567890',
primaryPhoneCallingCode: '+33',
primaryPhoneCountryCode: 'FR',
additionalPhones: [
{
number: '01234567890',
callingCode: '+33',
countryCode: 'FR',
},
],
},
emailsField: {
primaryEmail: 'test@test.com',
additionalEmails: ['test@test.com'],
},
dateTimeField: '2025-01-01T00:00:00Z',
dateField: '2025-01-01',
booleanField: true,
numberField: 1,
linksField: {
primaryLinkUrl: 'twenty.com',
primaryLinkLabel: 'twenty - #1 Open source CRM',
secondaryLinks: [
{
url: 'twenty.com',
label: 'twenty - #1 Open source CRM',
},
],
},
currencyField: {
amountMicros: 1000000,
currencyCode: 'USD',
},
fullNameField: {
firstName: 'John',
lastName: 'Doe',
},
ratingField: 'RATING_5',
selectField: 'OPTION_1',
multiSelectField: ['OPTION_1'],
addressField: {
addressStreet1: 'address street 1',
addressStreet2: 'address street 2',
addressCity: 'address city',
addressState: 'address state',
addressCountry: 'address country',
addressPostcode: 'address postcode',
},
rawJsonField: {
test: 'test',
},
arrayField: ['test'],
},
{
id: randomUUID(),
},
],
}),
);
return {
objectMetadataId,
targetObjectMetadataId,
objectMetadataSingularName: TEST_OBJECT_METADATA_NAME_SINGULAR,
objectMetadataPluralName: TEST_OBJECT_METADATA_NAME_PLURAL,
};
};