snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s

This commit is contained in:
upstream-mirror
2026-09-17 23:28:13 +05:00
commit e7da97194a
32688 changed files with 4208681 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
import { joinColumnNameForManyToOneMorphRelationField1 } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
export const TEST_OBJECT_GQL_FIELDS = `
id
position
manyToOneRelationFieldId
manyToOneRelationField {
id
}
${joinColumnNameForManyToOneMorphRelationField1}
${joinColumnNameForManyToOneMorphRelationField1.replace('Id', '')}{
id
}
uuidField
textField
phonesField {
primaryPhoneNumber
primaryPhoneCallingCode
primaryPhoneCountryCode
additionalPhones {
number
callingCode
countryCode
}
}
emailsField {
primaryEmail
additionalEmails
}
dateTimeField
dateField
booleanField
numberField
linksField {
primaryLinkUrl
primaryLinkLabel
secondaryLinks {
label
url
}
}
currencyField {
amountMicros
currencyCode
}
fullNameField {
firstName
lastName
}
ratingField
selectField
multiSelectField
addressField {
addressStreet1
addressStreet2
addressCity
addressState
addressCountry
addressPostcode
}
rawJsonField
arrayField
richTextField {
blocknote
markdown
}
`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - ADDRESS Gql create input - failure ADDRESS - should fail with : {"addressField":"not-an-address"} 1`] = `"Invalid object value 'not-an-address' for field "addressField""`;
exports[`Create input validation - ADDRESS Rest create input - failure ADDRESS - should fail with : {"addressField":"not-an-address"} 1`] = `"["Invalid object value 'not-an-address' for field \\"addressField\\""]"`;

View File

@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - ARRAY Gql create input - failure ARRAY - should fail with : {"arrayField":1} 1`] = `"Invalid value 1 for field "arrayField - Array values need to be string""`;
exports[`Create input validation - ARRAY Gql create input - failure ARRAY - should fail with : {"arrayField":true} 1`] = `"Invalid value true for field "arrayField - Array values need to be string""`;
exports[`Create input validation - ARRAY Rest create input - failure ARRAY - should fail with : {"arrayField":1} 1`] = `"["Invalid value 1 for field \\"arrayField - Array values need to be string\\""]"`;
exports[`Create input validation - ARRAY Rest create input - failure ARRAY - should fail with : {"arrayField":true} 1`] = `"["Invalid value true for field \\"arrayField - Array values need to be string\\""]"`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - CURRENCY Gql create input - failure CURRENCY - should fail with : {"currencyField":"not-a-currency"} 1`] = `"Invalid object value 'not-a-currency' for field "currencyField""`;
exports[`Create input validation - CURRENCY Rest create input - failure CURRENCY - should fail with : {"currencyField":"not-a-currency"} 1`] = `"["Invalid object value 'not-a-currency' for field \\"currencyField\\""]"`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - DATE Gql create input - failure DATE - should fail with : {"dateField":"malformed-date"} 1`] = `"Invalid value 'malformed-date' for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`Create input validation - DATE Rest create input - failure DATE - should fail with : {"dateField":"malformed-date"} 1`] = `"["Invalid value 'malformed-date' for date field \\"dateField\\". Expected format: 'YYYY-MM-DD'"]"`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - DATE_TIME Gql create input - failure DATE_TIME - should fail with : {"dateTimeField":"malformed-date-time"} 1`] = `"Invalid value 'malformed-date-time' for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`Create input validation - DATE_TIME Rest create input - failure DATE_TIME - should fail with : {"dateTimeField":"malformed-date-time"} 1`] = `"["Invalid value 'malformed-date-time' for date-time field \\"dateTimeField\\". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"]"`;

View File

@@ -0,0 +1,29 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - EMAILS Gql create input - failure EMAILS - should fail with : {"emailsField":"not-an-email"} 1`] = `"Invalid object value 'not-an-email' for field "emailsField""`;
exports[`Create input validation - EMAILS Gql create input - failure EMAILS - should fail with : {"emailsField":{"additionalEmails":"not-an-email"}} 1`] = `"Invalid string value 'not-an-email' for email field "emailsField.additionalEmails""`;
exports[`Create input validation - EMAILS Gql create input - failure EMAILS - should fail with : {"emailsField":{"additionalEmails":["not-an-email","additional@email.com"]}} 1`] = `"Invalid string value 'not-an-email' for email field "emailsField.additionalEmails""`;
exports[`Create input validation - EMAILS Gql create input - failure EMAILS - should fail with : {"emailsField":{"additionalEmails":["not-an-email"]}} 1`] = `"Invalid string value 'not-an-email' for email field "emailsField.additionalEmails""`;
exports[`Create input validation - EMAILS Gql create input - failure EMAILS - should fail with : {"emailsField":{"primaryEmail":"email@email.com","additionalEmails":["not-an-email"]}} 1`] = `"Invalid string value 'not-an-email' for email field "emailsField.additionalEmails""`;
exports[`Create input validation - EMAILS Gql create input - failure EMAILS - should fail with : {"emailsField":{"primaryEmail":"not-an-email","additionalEmails":["additional@email.com"]}} 1`] = `"Invalid string value 'not-an-email' for email field "emailsField.primaryEmail""`;
exports[`Create input validation - EMAILS Gql create input - failure EMAILS - should fail with : {"emailsField":{"primaryEmail":"not-an-email"}} 1`] = `"Invalid string value 'not-an-email' for email field "emailsField.primaryEmail""`;
exports[`Create input validation - EMAILS Rest create input - failure EMAILS - should fail with : {"emailsField":"not-an-email"} 1`] = `"["Invalid object value 'not-an-email' for field \\"emailsField\\""]"`;
exports[`Create input validation - EMAILS Rest create input - failure EMAILS - should fail with : {"emailsField":{"additionalEmails":"not-an-email"}} 1`] = `"["Invalid string value 'not-an-email' for email field \\"emailsField.additionalEmails\\""]"`;
exports[`Create input validation - EMAILS Rest create input - failure EMAILS - should fail with : {"emailsField":{"additionalEmails":["not-an-email","additional@email.com"]}} 1`] = `"["Invalid string value 'not-an-email' for email field \\"emailsField.additionalEmails\\""]"`;
exports[`Create input validation - EMAILS Rest create input - failure EMAILS - should fail with : {"emailsField":{"additionalEmails":["not-an-email"]}} 1`] = `"["Invalid string value 'not-an-email' for email field \\"emailsField.additionalEmails\\""]"`;
exports[`Create input validation - EMAILS Rest create input - failure EMAILS - should fail with : {"emailsField":{"primaryEmail":"email@email.com","additionalEmails":["not-an-email"]}} 1`] = `"["Invalid string value 'not-an-email' for email field \\"emailsField.additionalEmails\\""]"`;
exports[`Create input validation - EMAILS Rest create input - failure EMAILS - should fail with : {"emailsField":{"primaryEmail":"not-an-email","additionalEmails":["additional@email.com"]}} 1`] = `"["Invalid string value 'not-an-email' for email field \\"emailsField.primaryEmail\\""]"`;
exports[`Create input validation - EMAILS Rest create input - failure EMAILS - should fail with : {"emailsField":{"primaryEmail":"not-an-email"}} 1`] = `"["Invalid string value 'not-an-email' for email field \\"emailsField.primaryEmail\\""]"`;

View File

@@ -0,0 +1,31 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - FILES Gql create input - failure FILES - should fail with : {"filesField":"not-an-addFiles-property"} 1`] = `"Invalid value "'not-an-addFiles-property'" for FILES field "filesField" - It should be an array of objects with "fileId" and "label" properties."`;
exports[`Create input validation - FILES Gql create input - failure FILES - should fail with : {"filesField":[{"addFiles":[{"fileId":"550e8400-e29b-41d4-a716-446655440000","label":12345}]}]} 1`] = `"Invalid value "[ { addFiles: [ [Object] ] } ]" for FILES field "filesField" - 0.fileId: Invalid input: expected string, received undefined, 0.label: Invalid input: expected string, received undefined, 0: Unrecognized key: "addFiles""`;
exports[`Create input validation - FILES Gql create input - failure FILES - should fail with : {"filesField":{"addFiles":[{"fileId":"550e8400-e29b-41d4-a716-446655440000","label":"Document.pdf","extension":"not-allowed-in-input"}]}} 1`] = `
"Invalid value "{
addFiles: [
{
fileId: '550e8400-e29b-41d4-a716-446655440000',
label: 'Document.pdf',
extension: 'not-allowed-in-input'
}
]
}" for FILES field "filesField" - : Invalid input: expected array, received object"
`;
exports[`Create input validation - FILES Gql create input - failure FILES - should fail with : {"filesField":{"addFiles":[{"fileId":"not-a-uuid","label":"Document.pdf"}]}} 1`] = `"Invalid value "{ addFiles: [ { fileId: 'not-a-uuid', label: 'Document.pdf' } ] }" for FILES field "filesField" - : Invalid input: expected array, received object"`;
exports[`Create input validation - FILES Gql create input - failure FILES - should fail with : {"filesField":{"addFiles":[{"invalidField":"test"}]}} 1`] = `"Invalid value "{ addFiles: [ { invalidField: 'test' } ] }" for FILES field "filesField" - : Invalid input: expected array, received object"`;
exports[`Create input validation - FILES Rest create input - failure FILES - should fail with : {"filesField":"not-an-addFiles-property"} 1`] = `"["Invalid value \\"'not-an-addFiles-property'\\" for FILES field \\"filesField\\" - It should be an array of objects with \\"fileId\\" and \\"label\\" properties."]"`;
exports[`Create input validation - FILES Rest create input - failure FILES - should fail with : {"filesField":[{"addFiles":[{"fileId":"550e8400-e29b-41d4-a716-446655440000","label":12345}]}]} 1`] = `"["Invalid value \\"[ { addFiles: [ [Object] ] } ]\\" for FILES field \\"filesField\\" - 0.fileId: Invalid input: expected string, received undefined, 0.label: Invalid input: expected string, received undefined, 0: Unrecognized key: \\"addFiles\\""]"`;
exports[`Create input validation - FILES Rest create input - failure FILES - should fail with : {"filesField":{"addFiles":[{"fileId":"550e8400-e29b-41d4-a716-446655440000","label":"Document.pdf","extension":"not-allowed-in-input"}]}} 1`] = `"["Invalid value \\"{\\n addFiles: [\\n {\\n fileId: '550e8400-e29b-41d4-a716-446655440000',\\n label: 'Document.pdf',\\n extension: 'not-allowed-in-input'\\n }\\n ]\\n}\\" for FILES field \\"filesField\\" - : Invalid input: expected array, received object"]"`;
exports[`Create input validation - FILES Rest create input - failure FILES - should fail with : {"filesField":{"addFiles":[{"fileId":"not-a-uuid","label":"Document.pdf"}]}} 1`] = `"["Invalid value \\"{ addFiles: [ { fileId: 'not-a-uuid', label: 'Document.pdf' } ] }\\" for FILES field \\"filesField\\" - : Invalid input: expected array, received object"]"`;
exports[`Create input validation - FILES Rest create input - failure FILES - should fail with : {"filesField":{"addFiles":[{"invalidField":"test"}]}} 1`] = `"["Invalid value \\"{ addFiles: [ { invalidField: 'test' } ] }\\" for FILES field \\"filesField\\" - : Invalid input: expected array, received object"]"`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - FULL_NAME Gql create input - failure FULL_NAME - should fail with : {"fullNameField":"not-a-full-name"} 1`] = `"Invalid object value 'not-a-full-name' for field "fullNameField""`;
exports[`Create input validation - FULL_NAME Rest create input - failure FULL_NAME - should fail with : {"fullNameField":"not-a-full-name"} 1`] = `"["Invalid object value 'not-a-full-name' for field \\"fullNameField\\""]"`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - LINKS Gql create input - failure LINKS - should fail with : {"linksField":"not-a-link"} 1`] = `"Invalid object value 'not-a-link' for field "linksField""`;
exports[`Create input validation - LINKS Rest create input - failure LINKS - should fail with : {"linksField":"not-a-link"} 1`] = `"["Invalid object value 'not-a-link' for field \\"linksField\\""]"`;

View File

@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - MORPH_RELATION Gql create input - failure MORPH_RELATION - should fail with : {"manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id":"not-a-morph-relation"} 1`] = `"Invalid UUID value 'not-a-morph-relation' for field "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id""`;
exports[`Create input validation - MORPH_RELATION Gql create input - failure MORPH_RELATION - should fail with : {"manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id":[]} 1`] = `"Invalid UUID value [] for field "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id""`;
exports[`Create input validation - MORPH_RELATION Gql create input - failure MORPH_RELATION - should fail with : {"manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id":{}} 1`] = `"Invalid UUID value {} for field "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id""`;
exports[`Create input validation - MORPH_RELATION Gql create input - failure MORPH_RELATION - should fail with : {"manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id":1} 1`] = `"Invalid UUID value 1 for field "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id""`;
exports[`Create input validation - MORPH_RELATION Gql create input - failure MORPH_RELATION - should fail with : {"manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id":true} 1`] = `"Invalid UUID value true for field "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id""`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - MULTI_SELECT Gql create input - failure MULTI_SELECT - should fail with : {"multiSelectField":"not-a-select-option"} 1`] = `"Invalid value 'not-a-select-option' for multi select field "multiSelectField""`;
exports[`Create input validation - MULTI_SELECT Rest create input - failure MULTI_SELECT - should fail with : {"multiSelectField":"not-a-select-option"} 1`] = `"["Invalid value 'not-a-select-option' for multi select field \\"multiSelectField\\""]"`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - NUMBER Gql create input - failure NUMBER - should fail with : {"numberField":"string"} 1`] = `"Invalid number value 'string' for field "numberField""`;
exports[`Create input validation - NUMBER Rest create input - failure NUMBER - should fail with : {"numberField":"string"} 1`] = `"["Invalid number value 'string' for field \\"numberField\\""]"`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - PHONES Gql create input - failure PHONES - should fail with : {"phonesField":"not-a-phone"} 1`] = `"Invalid object value 'not-a-phone' for field "phonesField""`;
exports[`Create input validation - PHONES Rest create input - failure PHONES - should fail with : {"phonesField":"not-a-phone"} 1`] = `"["Invalid object value 'not-a-phone' for field \\"phonesField\\""]"`;

View File

@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - POSITION Gql create input - failure POSITION - should fail with : {"position":"not-a-position"} 1`] = `"Invalid position value 'not-a-position' for field "position""`;
exports[`Create input validation - POSITION Gql create input - failure POSITION - should fail with : {"position":null} 1`] = `"Invalid position value null for field "position""`;
exports[`Create input validation - POSITION Rest create input - failure POSITION - should fail with : {"position":"not-a-position"} 1`] = `"["Invalid position value 'not-a-position' for field \\"position\\""]"`;
exports[`Create input validation - POSITION Rest create input - failure POSITION - should fail with : {"position":null} 1`] = `"["Invalid position value null for field \\"position\\""]"`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - RATING Gql create input - failure RATING - should fail with : {"ratingField":"not-a-rating"} 1`] = `"Invalid value \"not-a-rating\" for field \"ratingField\". Valid values are: RATING_1, RATING_2, RATING_3, RATING_4, RATING_5"`;
exports[`Create input validation - RATING Rest create input - failure RATING - should fail with : {"ratingField":"not-a-rating"} 1`] = `"[\"Invalid value \\\"not-a-rating\\\" for field \\\"ratingField\\\". Valid values are: RATING_1, RATING_2, RATING_3, RATING_4, RATING_5\"]"`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - RAW_JSON Gql create input - failure RAW_JSON - should fail with : {"rawJsonField":"not-a-stringified-json"} 1`] = `"Invalid object value 'not-a-stringified-json' for field "rawJsonField""`;
exports[`Create input validation - RAW_JSON Rest create input - failure RAW_JSON - should fail with : {"rawJsonField":"not-a-stringified-json"} 1`] = `"["Invalid object value 'not-a-stringified-json' for field \\"rawJsonField\\""]"`;

View File

@@ -0,0 +1,13 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - RELATION Gql create input - failure RELATION - should fail with : {"manyToOneRelationFieldId":"non-uuid"} 1`] = `"Invalid UUID value 'non-uuid' for field "manyToOneRelationFieldId""`;
exports[`Create input validation - RELATION Gql create input - failure RELATION - should fail with : {"oneToManyRelationFieldId":"not-existing-field"} 1`] = `"Object apiInputValidationTestObject doesn't have any "oneToManyRelationFieldId" field."`;
exports[`Create input validation - RELATION Gql create input - failure RELATION - should fail with : {"oneToOneRelationField":"not-existing-field"} 1`] = `"Object apiInputValidationTestObject doesn't have any "oneToOneRelationField" field."`;
exports[`Create input validation - RELATION Rest create input - failure RELATION - should fail with : {"manyToOneRelationFieldId":"non-uuid"} 1`] = `"["Invalid UUID value 'non-uuid' for field \\"manyToOneRelationFieldId\\""]"`;
exports[`Create input validation - RELATION Rest create input - failure RELATION - should fail with : {"oneToManyRelationFieldId":"not-existing-field"} 1`] = `"["Object apiInputValidationTestObject doesn't have any \\"oneToManyRelationFieldId\\" field."]"`;
exports[`Create input validation - RELATION Rest create input - failure RELATION - should fail with : {"oneToOneRelationField":"not-existing-field"} 1`] = `"["Object apiInputValidationTestObject doesn't have any \\"oneToOneRelationField\\" field."]"`;

View File

@@ -0,0 +1,13 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - RICH_TEXT Gql create input - failure RICH_TEXT - should fail with : {"richTextField":"not-a-rich-text"} 1`] = `"Invalid object value 'not-a-rich-text' for field "richTextField""`;
exports[`Create input validation - RICH_TEXT Gql create input - failure RICH_TEXT - should fail with : {"richTextField":{"blocknote":"[{\\"id\\":\\"1\\",\\"type\\":\\"paragraph\\",\\"props\\":{},\\"content\\":[{\\"type\\":\\"text\\",\\"text\\":\\"test\\"},\\"children\\":[]}]"}} 1`] = `"Invalid blocknote value for field "richTextField.blocknote" - must contain valid JSON"`;
exports[`Create input validation - RICH_TEXT Gql create input - failure RICH_TEXT - should fail with : {"richTextField":{"blocknote":"invalid-json"}} 1`] = `"Invalid blocknote value for field "richTextField.blocknote" - must contain valid JSON"`;
exports[`Create input validation - RICH_TEXT Rest create input - failure RICH_TEXT - should fail with : {"richTextField":"not-a-rich-text"} 1`] = `"["Invalid object value 'not-a-rich-text' for field \\"richTextField\\""]"`;
exports[`Create input validation - RICH_TEXT Rest create input - failure RICH_TEXT - should fail with : {"richTextField":{"blocknote":"[{\\"id\\":\\"1\\",\\"type\\":\\"paragraph\\",\\"props\\":{},\\"content\\":[{\\"type\\":\\"text\\",\\"text\\":\\"test\\"},\\"children\\":[]}]"}} 1`] = `"["Invalid blocknote value for field \\"richTextField.blocknote\\" - must contain valid JSON"]"`;
exports[`Create input validation - RICH_TEXT Rest create input - failure RICH_TEXT - should fail with : {"richTextField":{"blocknote":"invalid-json"}} 1`] = `"["Invalid blocknote value for field \\"richTextField.blocknote\\" - must contain valid JSON"]"`;

View File

@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - SELECT Gql create input - failure SELECT - should fail with : {"selectField":"not-a-select-option"} 1`] = `"Invalid value \"not-a-select-option\" for field \"selectField\". Valid values are: OPTION_1"`;
exports[`Create input validation - SELECT Gql create input - failure SELECT - should fail with : {"selectField":1} 1`] = `"Invalid string value 1 for text field "selectField""`;
exports[`Create input validation - SELECT Rest create input - failure SELECT - should fail with : {"selectField":"not-a-select-option"} 1`] = `"[\"Invalid value \\\"not-a-select-option\\\" for field \\\"selectField\\\". Valid values are: OPTION_1\"]"`;
exports[`Create input validation - SELECT Rest create input - failure SELECT - should fail with : {"selectField":1} 1`] = `"["Invalid string value 1 for text field \\"selectField\\""]"`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - TEXT Gql create input - failure TEXT - should fail with : {"textField":1} 1`] = `"Invalid string value 1 for text field "textField""`;
exports[`Create input validation - TEXT Rest create input - failure TEXT - should fail with : {"textField":1} 1`] = `"["Invalid string value 1 for text field \\"textField\\""]"`;

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - UUID Gql create input - failure UUID - should fail with : {"uuidField":"non-uuid"} 1`] = `"Invalid UUID value 'non-uuid' for field "uuidField""`;
exports[`Create input validation - UUID Rest create input - failure UUID - should fail with : {"uuidField":"non-uuid"} 1`] = `"["Invalid UUID value 'non-uuid' for field \\"uuidField\\""]"`;

View File

@@ -0,0 +1,114 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.ADDRESS;
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
});

View File

@@ -0,0 +1,113 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.ARRAY;
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,74 @@
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.BOOLEAN;
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,304 @@
import { type FieldMetadataTypesToTestForCreateInputValidation } from 'test/integration/graphql/suites/inputs-validation/types/field-metadata-type-to-test';
import { joinColumnNameForManyToOneMorphRelationField1 } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
export const failingCreateInputByFieldMetadataType: {
[K in FieldMetadataTypesToTestForCreateInputValidation]: {
input: any;
}[];
} = {
[FieldMetadataType.TEXT]: [
{
input: {
textField: 1,
},
},
],
[FieldMetadataType.NUMBER]: [
{
input: {
numberField: 'string',
},
},
],
[FieldMetadataType.UUID]: [
{
input: {
uuidField: 'non-uuid',
},
},
],
[FieldMetadataType.SELECT]: [
{
input: {
selectField: 'not-a-select-option',
},
},
{
input: {
selectField: 1,
},
},
],
[FieldMetadataType.RELATION]: [
{
input: {
manyToOneRelationFieldId: 'non-uuid',
},
},
{
input: {
oneToOneRelationField: 'not-existing-field',
},
},
{
input: {
oneToManyRelationFieldId: 'not-existing-field',
},
},
],
[FieldMetadataType.RAW_JSON]: [
{
input: {
rawJsonField: 'not-a-stringified-json',
},
},
],
[FieldMetadataType.ARRAY]: [
{
input: {
arrayField: true,
},
},
{
input: {
arrayField: 1,
},
},
],
[FieldMetadataType.MORPH_RELATION]: [
{
input: {
[joinColumnNameForManyToOneMorphRelationField1]: 'not-a-morph-relation',
},
},
{
input: {
[joinColumnNameForManyToOneMorphRelationField1]: {},
},
},
{
input: {
[joinColumnNameForManyToOneMorphRelationField1]: [],
},
},
{
input: {
[joinColumnNameForManyToOneMorphRelationField1]: true,
},
},
{
input: {
[joinColumnNameForManyToOneMorphRelationField1]: 1,
},
},
],
[FieldMetadataType.RATING]: [
{
input: {
ratingField: 'not-a-rating',
},
},
],
[FieldMetadataType.MULTI_SELECT]: [
{
input: {
multiSelectField: 'not-a-select-option',
},
},
],
[FieldMetadataType.DATE]: [
{
input: {
dateField: 'malformed-date',
},
},
],
[FieldMetadataType.DATE_TIME]: [
{
input: {
dateTimeField: 'malformed-date-time',
},
},
],
[FieldMetadataType.BOOLEAN]: [
{
input: {
booleanField: 1,
},
},
],
[FieldMetadataType.ADDRESS]: [
{
input: {
addressField: 'not-an-address',
},
},
],
[FieldMetadataType.CURRENCY]: [
{
input: {
currencyField: 'not-a-currency',
},
},
],
[FieldMetadataType.EMAILS]: [
{
input: {
emailsField: 'not-an-email',
},
},
{
input: {
emailsField: {
primaryEmail: 'not-an-email',
},
},
},
{
input: {
emailsField: {
additionalEmails: 'not-an-email',
},
},
},
{
input: {
emailsField: {
additionalEmails: ['not-an-email'],
},
},
},
{
input: {
emailsField: {
primaryEmail: 'email@email.com',
additionalEmails: ['not-an-email'],
},
},
},
{
input: {
emailsField: {
primaryEmail: 'not-an-email',
additionalEmails: ['additional@email.com'],
},
},
},
{
input: {
emailsField: {
additionalEmails: ['not-an-email', 'additional@email.com'],
},
},
},
],
[FieldMetadataType.PHONES]: [
{
input: {
phonesField: 'not-a-phone',
},
},
],
[FieldMetadataType.FULL_NAME]: [
{
input: {
fullNameField: 'not-a-full-name',
},
},
],
[FieldMetadataType.LINKS]: [
{
input: {
linksField: 'not-a-link',
},
},
],
[FieldMetadataType.RICH_TEXT]: [
{
input: {
richTextField: 'not-a-rich-text',
},
},
{
input: {
richTextField: {
blocknote: 'invalid-json',
},
},
},
{
input: {
richTextField: {
blocknote:
'[{"id":"1","type":"paragraph","props":{},"content":[{"type":"text","text":"test"},"children":[]}]',
},
},
},
],
[FieldMetadataType.POSITION]: [
{
input: {
position: 'not-a-position',
},
},
{
input: {
position: NaN,
},
},
],
[FieldMetadataType.FILES]: [
{
input: {
filesField: 'not-an-addFiles-property',
},
},
{
input: {
filesField: { addFiles: [{ invalidField: 'test' }] },
},
},
{
input: {
filesField: {
addFiles: [{ fileId: 'not-a-uuid', label: 'Document.pdf' }],
},
},
},
{
input: {
filesField: [
{
addFiles: [
{ fileId: '550e8400-e29b-41d4-a716-446655440000', label: 12345 },
],
},
],
},
},
{
input: {
filesField: {
addFiles: [
{
fileId: '550e8400-e29b-41d4-a716-446655440000',
label: 'Document.pdf',
extension: 'not-allowed-in-input',
},
],
},
},
},
],
};

View File

@@ -0,0 +1,435 @@
import { type FieldMetadataTypesToTestForCreateInputValidation } from 'test/integration/graphql/suites/inputs-validation/types/field-metadata-type-to-test';
import {
joinColumnNameForManyToOneMorphRelationField1,
TEST_TARGET_OBJECT_RECORD_ID_FIELD_VALUE,
} from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
export const successfulCreateInputByFieldMetadataType: {
[K in Exclude<
FieldMetadataTypesToTestForCreateInputValidation,
FieldMetadataType.FILES // Done in files-field-sync.integration-spec.ts
>]: {
input: any;
validateInput: (record: Record<string, any>) => boolean;
}[];
} = {
[FieldMetadataType.TEXT]: [
{
input: {
textField: 'test',
},
validateInput: (record: Record<string, any>) => {
return record.textField === 'test';
},
},
],
[FieldMetadataType.NUMBER]: [
{
input: {
numberField: 1,
},
validateInput: (record: Record<string, any>) => {
return record.numberField === 1;
},
},
],
[FieldMetadataType.UUID]: [
{
input: {
uuidField: '00000000-0000-4000-8000-000000000000',
},
validateInput: (record: Record<string, any>) => {
return record.uuidField === '00000000-0000-4000-8000-000000000000';
},
},
],
[FieldMetadataType.SELECT]: [
{
input: {
selectField: 'OPTION_1',
},
validateInput: (record: Record<string, any>) => {
return record.selectField === 'OPTION_1';
},
},
{
input: {
selectField: null,
},
validateInput: (record: Record<string, any>) => {
return record.selectField === null;
},
},
],
[FieldMetadataType.RELATION]: [
{
input: {
manyToOneRelationFieldId: TEST_TARGET_OBJECT_RECORD_ID_FIELD_VALUE,
},
validateInput: (record: Record<string, any>) => {
return (
record.manyToOneRelationFieldId ===
TEST_TARGET_OBJECT_RECORD_ID_FIELD_VALUE
);
},
},
{
input: {
manyToOneRelationFieldId: null,
},
validateInput: (record: Record<string, any>) => {
return record.manyToOneRelationFieldId === null;
},
},
],
[FieldMetadataType.MORPH_RELATION]: [
{
input: {
[joinColumnNameForManyToOneMorphRelationField1]:
TEST_TARGET_OBJECT_RECORD_ID_FIELD_VALUE,
},
validateInput: (record: Record<string, any>) => {
return (
record[joinColumnNameForManyToOneMorphRelationField1] ===
TEST_TARGET_OBJECT_RECORD_ID_FIELD_VALUE
);
},
},
{
input: {
[joinColumnNameForManyToOneMorphRelationField1]: null,
},
validateInput: (record: Record<string, any>) => {
return record[joinColumnNameForManyToOneMorphRelationField1] === null;
},
},
],
[FieldMetadataType.RAW_JSON]: [
{
input: {
rawJsonField: { key: 'value' },
},
validateInput: (record: Record<string, any>) => {
return record.rawJsonField.key === 'value';
},
},
{
input: {
rawJsonField: {},
},
validateInput: (record: Record<string, any>) => {
return record.rawJsonField === null;
},
},
],
[FieldMetadataType.ARRAY]: [
{
input: {
arrayField: ['item1', 'item2'],
},
validateInput: (record: Record<string, any>) => {
return (
record.arrayField.length === 2 &&
record.arrayField.includes('item1') &&
record.arrayField.includes('item2')
);
},
},
{
input: {
arrayField: 'item1',
},
validateInput: (record: Record<string, any>) => {
return (
record.arrayField.length === 1 && record.arrayField.includes('item1')
);
},
},
],
[FieldMetadataType.RATING]: [
{
input: {
ratingField: 'RATING_2',
},
validateInput: (record: Record<string, any>) => {
return record.ratingField === 'RATING_2';
},
},
],
[FieldMetadataType.MULTI_SELECT]: [
{
input: {
multiSelectField: ['OPTION_1'],
},
validateInput: (record: Record<string, any>) => {
return (
record.multiSelectField.includes('OPTION_1') &&
record.multiSelectField.length === 1
);
},
},
{
input: {
multiSelectField: [],
},
validateInput: (record: Record<string, any>) => {
return (
Array.isArray(record.multiSelectField) &&
record.multiSelectField.length === 0
);
},
},
{
input: {
multiSelectField: null,
},
validateInput: (record: Record<string, any>) => {
return (
Array.isArray(record.multiSelectField) &&
record.multiSelectField.length === 0
);
},
},
],
[FieldMetadataType.DATE]: [
{
input: {
dateField: null,
},
validateInput: (record: Record<string, any>) => {
return record.dateField === null;
},
},
{
input: {
dateField: '2025-01-13',
},
validateInput: (record: Record<string, any>) => {
return new Date(record.dateField).toDateString() === 'Mon Jan 13 2025';
},
},
],
[FieldMetadataType.DATE_TIME]: [
{
input: {
dateTimeField: '2025-01-13T10:30:00.000Z',
},
validateInput: (record: Record<string, any>) => {
const date = new Date(record.dateTimeField);
return (
date.toDateString() === 'Mon Jan 13 2025' &&
date.getUTCHours() === 10 &&
date.getUTCMinutes() === 30 &&
date.getUTCSeconds() === 0 &&
date.getUTCMilliseconds() === 0
);
},
},
{
input: {
dateTimeField: '2026-05-07',
},
validateInput: (record: Record<string, any>) => {
const date = new Date(record.dateTimeField);
return date.toISOString() === '2026-05-07T00:00:00.000Z';
},
},
],
[FieldMetadataType.BOOLEAN]: [
{
input: {
booleanField: null,
},
validateInput: (record: Record<string, any>) => {
return record.booleanField === null;
},
},
{
input: {
booleanField: false,
},
validateInput: (record: Record<string, any>) => {
return record.booleanField === false;
},
},
{
input: {
booleanField: true,
},
validateInput: (record: Record<string, any>) => {
return record.booleanField === true;
},
},
],
[FieldMetadataType.ADDRESS]: [
{
input: {
addressField: {
addressPostcode: 'address postcode',
addressStreet1: 'address street 1',
addressStreet2: 'address street 2',
addressCity: 'address city',
addressState: 'address state',
addressCountry: 'address country',
},
},
validateInput: (record: Record<string, any>) => {
return (
record.addressField.addressPostcode === 'address postcode' &&
record.addressField.addressStreet1 === 'address street 1' &&
record.addressField.addressStreet2 === 'address street 2' &&
record.addressField.addressCity === 'address city' &&
record.addressField.addressState === 'address state' &&
record.addressField.addressCountry === 'address country'
);
},
},
],
[FieldMetadataType.CURRENCY]: [
{
input: {
currencyField: { amountMicros: 1000000, currencyCode: 'USD' },
},
validateInput: (record: Record<string, any>) => {
return (
Number(record.currencyField.amountMicros) === 1000000 &&
record.currencyField.currencyCode === 'USD'
);
},
},
],
[FieldMetadataType.EMAILS]: [
{
input: {
emailsField: {
primaryEmail: 'test@test.com',
additionalEmails: ['test2@test.com'],
},
},
validateInput: (record: Record<string, any>) => {
return (
record.emailsField.primaryEmail === 'test@test.com' &&
record.emailsField.additionalEmails.length === 1 &&
record.emailsField.additionalEmails[0] === 'test2@test.com'
);
},
},
],
[FieldMetadataType.PHONES]: [
{
input: {
phonesField: {
primaryPhoneNumber: '1234567890',
primaryPhoneCountryCode: 'FR',
primaryPhoneCallingCode: '+33',
additionalPhones: [
{ number: '1234567890', callingCode: '+33', countryCode: 'FR' },
],
},
},
validateInput: (record: Record<string, any>) => {
return (
record.phonesField.primaryPhoneNumber === '1234567890' &&
record.phonesField.primaryPhoneCountryCode === 'FR' &&
record.phonesField.primaryPhoneCallingCode === '+33' &&
record.phonesField.additionalPhones.length === 1 &&
record.phonesField.additionalPhones[0].number === '1234567890' &&
record.phonesField.additionalPhones[0].callingCode === '+33' &&
record.phonesField.additionalPhones[0].countryCode === 'FR'
);
},
},
],
[FieldMetadataType.FULL_NAME]: [
{
input: {
fullNameField: {
firstName: 'John',
lastName: 'Doe',
},
},
validateInput: (record: Record<string, any>) => {
return (
record.fullNameField.firstName === 'John' &&
record.fullNameField.lastName === 'Doe'
);
},
},
],
[FieldMetadataType.LINKS]: [
{
input: {
linksField: {
primaryLinkUrl: 'https://twenty.com',
primaryLinkLabel: '#1 Open source CRM',
secondaryLinks: [{ url: 'twenty.com', label: '#1 Open source CRM' }],
},
},
validateInput: (record: Record<string, any>) => {
return (
record.linksField.primaryLinkUrl === 'https://twenty.com' &&
record.linksField.primaryLinkLabel === '#1 Open source CRM' &&
record.linksField.secondaryLinks.length === 1 &&
record.linksField.secondaryLinks[0].url === 'twenty.com' &&
record.linksField.secondaryLinks[0].label === '#1 Open source CRM'
);
},
},
],
[FieldMetadataType.RICH_TEXT]: [
{
input: {
richTextField: {
blocknote:
'[{"type":"paragraph","content":[{"type":"text","text":"test"}]}]',
markdown: 'test',
},
},
validateInput: (record: Record<string, any>) => {
return (
record.richTextField.blocknote ===
'[{"type":"paragraph","content":[{"type":"text","text":"test"}]}]' &&
record.richTextField.markdown === 'test'
);
},
},
],
[FieldMetadataType.POSITION]: [
{
input: {
position: 1000,
},
validateInput: (record: Record<string, any>) => {
return record.position === 1000;
},
},
{
input: {
position: 'last',
},
validateInput: (record: Record<string, any>) => {
return record.position > 1000;
},
},
{
input: {
position: 'first',
},
validateInput: (record: Record<string, any>) => {
return record.position < 1000;
},
},
{
input: {
name: 'position',
position: undefined,
},
validateInput: (record: Record<string, any>) => {
return typeof record.position === 'number';
},
},
],
};

View File

@@ -0,0 +1,114 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.CURRENCY;
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
});

View File

@@ -0,0 +1,113 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.DATE;
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,113 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,114 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.EMAILS;
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
});

View File

@@ -0,0 +1,71 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.FILES;
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes(true);
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
});

View File

@@ -0,0 +1,114 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
});

View File

@@ -0,0 +1,114 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.LINKS;
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
});

View File

@@ -0,0 +1,115 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.MORPH_RELATION;
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
// TODO - add when REST API can handle morph relations
xdescribe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
// TODO - add when REST API can handle morph relations
xdescribe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,113 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,114 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.NUMBER;
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,113 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.PHONES;
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
});

View File

@@ -0,0 +1,113 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.POSITION;
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,113 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.RATING;
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,113 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,113 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.RELATION;
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,114 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.RICH_TEXT;
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
});

View File

@@ -0,0 +1,113 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.SELECT;
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,113 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.TEXT;
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,20 @@
import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util';
import { makeGraphqlAPIRequestWithApiKey } from 'test/integration/graphql/utils/make-graphql-api-request-with-api-key.util';
export const expectGqlCreateInputValidationError = async (
objectMetadataSingularName: string,
input: any,
) => {
const createManyGraphqlOperation = createOneOperationFactory({
objectMetadataSingularName: objectMetadataSingularName,
gqlFields: 'id',
data: input,
});
const createManyResponse = await makeGraphqlAPIRequestWithApiKey(
createManyGraphqlOperation,
);
expect(createManyResponse.body.errors).toBeDefined();
expect(createManyResponse.body.errors[0].message).toMatchSnapshot();
};

View File

@@ -0,0 +1,37 @@
import { TEST_OBJECT_GQL_FIELDS } from 'test/integration/graphql/suites/inputs-validation/constants/test-object-gql-fields.constant';
import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util';
import { makeGraphqlAPIRequestWithApiKey } from 'test/integration/graphql/utils/make-graphql-api-request-with-api-key.util';
import { pascalCase } from 'twenty-shared/utils';
export const expectGqlCreateInputValidationSuccess = async (
objectMetadataSingularName: string,
input: any,
validateInput: (record: Record<string, any>) => boolean,
withFilesField: boolean = false,
) => {
const createOneOperation = createOneOperationFactory({
objectMetadataSingularName: objectMetadataSingularName,
gqlFields:
TEST_OBJECT_GQL_FIELDS +
(withFilesField
? ` filesField {
fileId
label
}`
: ''),
data: input,
});
const createOneResponse =
await makeGraphqlAPIRequestWithApiKey(createOneOperation);
expect(createOneResponse.body.errors).toBeUndefined();
expect(createOneResponse.body.data).toBeDefined();
expect(
validateInput(
createOneResponse.body.data[
`create${pascalCase(objectMetadataSingularName)}`
],
),
).toBe(true);
};

View File

@@ -0,0 +1,15 @@
import { makeRestAPIRequest } from 'test/integration/rest/utils/make-rest-api-request.util';
export const expectRestCreateInputValidationError = async (
objectMetadataPluralName: string,
input: any,
) => {
const response = await makeRestAPIRequest({
method: 'post',
path: `/${objectMetadataPluralName}`,
body: input,
});
expect(response.body.error).toBeDefined();
expect(JSON.stringify(response.body.messages)).toMatchSnapshot();
};

View File

@@ -0,0 +1,21 @@
import { makeRestAPIRequest } from 'test/integration/rest/utils/make-rest-api-request.util';
import { pascalCase } from 'twenty-shared/utils';
export const expectRestCreateInputValidationSuccess = async (
objectMetadataPluralName: string,
objectMetadataSingularName: string,
input: any,
validateInput: (record: Record<string, any>) => boolean,
) => {
const response = await makeRestAPIRequest({
method: 'post',
path: `/${objectMetadataPluralName}`,
body: input,
});
const records =
response.body.data[`create${pascalCase(objectMetadataSingularName)}`];
expect(response.body.error).toBeUndefined();
expect(validateInput(records)).toBe(true);
};

View File

@@ -0,0 +1,113 @@
import { failingCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant';
import { successfulCreateInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant';
import { expectGqlCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-error.util';
import { expectGqlCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util';
import { expectRestCreateInputValidationError } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-error.util';
import { expectRestCreateInputValidationSuccess } from 'test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.UUID;
const failingTestCases =
failingCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulCreateInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Create input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectGqlCreateInputValidationError(
objectMetadataSingularName,
input,
);
},
);
});
describe('Rest create input - failure', () => {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should fail with : $stringifiedInput`,
async ({ input }) => {
await expectRestCreateInputValidationError(
objectMetadataPluralName,
input,
);
},
);
});
describe('Gql create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectGqlCreateInputValidationSuccess(
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
describe('Rest create input - success', () => {
it.each(
successfulTestCases.map((testCase) => ({
...testCase,
stringifiedInput: JSON.stringify(testCase.input),
})),
)(
`${FIELD_METADATA_TYPE} - should succeed with : $stringifiedInput`,
async ({ input, validateInput }) => {
await expectRestCreateInputValidationSuccess(
objectMetadataPluralName,
objectMetadataSingularName,
input,
validateInput,
);
},
);
});
});

View File

@@ -0,0 +1,33 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter args validation - ARRAY Gql filter input - failure ARRAY field type - should fail with filter : {"arrayField":{"containsIlike":[]}} 1`] = `"Filter operator "containsIlike" requires a string value for field "arrayField", got object"`;
exports[`Filter args validation - ARRAY Gql filter input - failure ARRAY field type - should fail with filter : {"arrayField":{"containsIlike":{}}} 1`] = `"Filter operator "containsIlike" requires a string value for field "arrayField", got object"`;
exports[`Filter args validation - ARRAY Gql filter input - failure ARRAY field type - should fail with filter : {"arrayField":{"containsIlike":2}} 1`] = `"Filter operator "containsIlike" requires a string value for field "arrayField", got number"`;
exports[`Filter args validation - ARRAY Gql filter input - failure ARRAY field type - should fail with filter : {"arrayField":{"containsIlike":true}} 1`] = `"Filter operator "containsIlike" requires a string value for field "arrayField", got boolean"`;
exports[`Filter args validation - ARRAY Rest filter input - failure ARRAY field type - should fail with filter : "arrayField[containsAny]:\\"[]\\"" 1`] = `
[
"'filter' invalid for 'containsAny' operator. Received '"[]"' but array value expected eg: 'field[containsAny]:[value_1,value_2]'",
]
`;
exports[`Filter args validation - ARRAY Rest filter input - failure ARRAY field type - should fail with filter : "arrayField[containsAny]:\\"{}\\"" 1`] = `
[
"'filter' invalid for 'containsAny' operator. Received '"{}"' but array value expected eg: 'field[containsAny]:[value_1,value_2]'",
]
`;
exports[`Filter args validation - ARRAY Rest filter input - failure ARRAY field type - should fail with filter : "arrayField[containsAny]:\\"true\\"" 1`] = `
[
"'filter' invalid for 'containsAny' operator. Received '"true"' but array value expected eg: 'field[containsAny]:[value_1,value_2]'",
]
`;
exports[`Filter args validation - ARRAY Rest filter input - failure ARRAY field type - should fail with filter : "arrayField[containsAny]:2" 1`] = `
[
"'filter' invalid for 'containsAny' operator. Received '2' but array value expected eg: 'field[containsAny]:[value_1,value_2]'",
]
`;

View File

@@ -0,0 +1,25 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - BOOLEAN Gql filter input - failure BOOLEAN field type - should fail with filter : {"booleanField":{"eq":"not-a-boolean"}} 1`] = `"Invalid boolean value 'not-a-boolean' for field "booleanField""`;
exports[`Filter input validation - BOOLEAN Gql filter input - failure BOOLEAN field type - should fail with filter : {"booleanField":{"eq":[]}} 1`] = `"Invalid boolean value [] for field "booleanField""`;
exports[`Filter input validation - BOOLEAN Gql filter input - failure BOOLEAN field type - should fail with filter : {"booleanField":{"eq":2}} 1`] = `"Invalid boolean value 2 for field "booleanField""`;
exports[`Filter input validation - BOOLEAN Rest filter input - failure BOOLEAN field type - should fail with filter : "booleanField[eq]:\\"[]\\"" 1`] = `
[
"Invalid boolean value '[]' for field "booleanField"",
]
`;
exports[`Filter input validation - BOOLEAN Rest filter input - failure BOOLEAN field type - should fail with filter : "booleanField[eq]:\\"not-a-boolean\\"" 1`] = `
[
"Invalid boolean value 'not-a-boolean' for field "booleanField"",
]
`;
exports[`Filter input validation - BOOLEAN Rest filter input - failure BOOLEAN field type - should fail with filter : "booleanField[eq]:2" 1`] = `
[
"Invalid boolean value '2' for field "booleanField"",
]
`;

View File

@@ -0,0 +1,25 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - DATE Gql filter input - failure DATE field type - should fail with filter : {"dateField":{"eq":"not-a-date"}} 1`] = `"Invalid value 'not-a-date' for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`Filter input validation - DATE Gql filter input - failure DATE field type - should fail with filter : {"dateField":{"eq":[]}} 1`] = `"Invalid value [] for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`Filter input validation - DATE Gql filter input - failure DATE field type - should fail with filter : {"dateField":{"eq":{}}} 1`] = `"Invalid value {} for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`Filter input validation - DATE Rest filter input - failure DATE field type - should fail with filter : "dateField[eq]:\\"[]\\"" 1`] = `
[
"Invalid value '[]' for date field "dateField". Expected format: 'YYYY-MM-DD'",
]
`;
exports[`Filter input validation - DATE Rest filter input - failure DATE field type - should fail with filter : "dateField[eq]:\\"{}\\"" 1`] = `
[
"Invalid value '{}' for date field "dateField". Expected format: 'YYYY-MM-DD'",
]
`;
exports[`Filter input validation - DATE Rest filter input - failure DATE field type - should fail with filter : "dateField[eq]:\\"not-a-date\\"" 1`] = `
[
"Invalid value 'not-a-date' for date field "dateField". Expected format: 'YYYY-MM-DD'",
]
`;

View File

@@ -0,0 +1,33 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - DATE_TIME Gql filter input - failure DATE_TIME field type - should fail with filter : {"dateTimeField":{"eq":"not-a-date-time"}} 1`] = `"Invalid value 'not-a-date-time' for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`Filter input validation - DATE_TIME Gql filter input - failure DATE_TIME field type - should fail with filter : {"dateTimeField":{"eq":[]}} 1`] = `"Invalid value [] for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`Filter input validation - DATE_TIME Gql filter input - failure DATE_TIME field type - should fail with filter : {"dateTimeField":{"eq":{}}} 1`] = `"Invalid value {} for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`Filter input validation - DATE_TIME Gql filter input - failure DATE_TIME field type - should fail with filter : {"dateTimeField":{"eq":true}} 1`] = `"Invalid value true for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`Filter input validation - DATE_TIME Rest filter input - failure DATE_TIME field type - should fail with filter : "dateTimeField[eq]:\\"[]\\"" 1`] = `
[
"Invalid value '[]' for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'",
]
`;
exports[`Filter input validation - DATE_TIME Rest filter input - failure DATE_TIME field type - should fail with filter : "dateTimeField[eq]:\\"{}\\"" 1`] = `
[
"Invalid value '{}' for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'",
]
`;
exports[`Filter input validation - DATE_TIME Rest filter input - failure DATE_TIME field type - should fail with filter : "dateTimeField[eq]:\\"not-a-date-time\\"" 1`] = `
[
"Invalid value 'not-a-date-time' for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'",
]
`;
exports[`Filter input validation - DATE_TIME Rest filter input - failure DATE_TIME field type - should fail with filter : "dateTimeField[eq]:\\"true\\"" 1`] = `
[
"Invalid value 'true' for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'",
]
`;

View File

@@ -0,0 +1,33 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - FILES Gql filter input - failure FILES field type - should fail with filter : {"filesField":{"containsIlike":[]}} 1`] = `"Operator "containsIlike" is not valid for field "filesField" of type FILES - Allowed operators: is, like"`;
exports[`Filter input validation - FILES Gql filter input - failure FILES field type - should fail with filter : {"filesField":{"containsIlike":{}}} 1`] = `"Operator "containsIlike" is not valid for field "filesField" of type FILES - Allowed operators: is, like"`;
exports[`Filter input validation - FILES Gql filter input - failure FILES field type - should fail with filter : {"filesField":{"containsIlike":2}} 1`] = `"Operator "containsIlike" is not valid for field "filesField" of type FILES - Allowed operators: is, like"`;
exports[`Filter input validation - FILES Gql filter input - failure FILES field type - should fail with filter : {"filesField":{"containsIlike":true}} 1`] = `"Operator "containsIlike" is not valid for field "filesField" of type FILES - Allowed operators: is, like"`;
exports[`Filter input validation - FILES Rest filter input - failure FILES field type - should fail with filter : "filesField[containsAny]:\\"[]\\"" 1`] = `
[
"'filter' invalid for 'containsAny' operator. Received '"[]"' but array value expected eg: 'field[containsAny]:[value_1,value_2]'",
]
`;
exports[`Filter input validation - FILES Rest filter input - failure FILES field type - should fail with filter : "filesField[containsAny]:\\"{}\\"" 1`] = `
[
"'filter' invalid for 'containsAny' operator. Received '"{}"' but array value expected eg: 'field[containsAny]:[value_1,value_2]'",
]
`;
exports[`Filter input validation - FILES Rest filter input - failure FILES field type - should fail with filter : "filesField[containsAny]:\\"true\\"" 1`] = `
[
"'filter' invalid for 'containsAny' operator. Received '"true"' but array value expected eg: 'field[containsAny]:[value_1,value_2]'",
]
`;
exports[`Filter input validation - FILES Rest filter input - failure FILES field type - should fail with filter : "filesField[containsAny]:2" 1`] = `
[
"'filter' invalid for 'containsAny' operator. Received '2' but array value expected eg: 'field[containsAny]:[value_1,value_2]'",
]
`;

View File

@@ -0,0 +1,17 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - MORPH_RELATION Gql filter input - failure MORPH_RELATION field type - should fail with filter : {"manyToOneMorphRelationFieldApiInputValidationTargetTestObject1":{"eq":"6dd71a46-68fe-4420-82b3-0d5b00ad2642"}} 1`] = `"Object apiInputValidationTargetTestObject1 doesn't have any "eq" field."`;
exports[`Filter input validation - MORPH_RELATION Gql filter input - failure MORPH_RELATION field type - should fail with filter : {"manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id":{"eq":"invalid-uuid"}} 1`] = `"Invalid UUID value 'invalid-uuid' for field "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id""`;
exports[`Filter input validation - MORPH_RELATION Rest filter input - failure MORPH_RELATION field type - should fail with filter : "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1[eq]:\\"6dd71a46-68fe-4420-82b3-0d5b00ad2642\\"" 1`] = `
[
"Object apiInputValidationTargetTestObject1 doesn't have any "eq" field.",
]
`;
exports[`Filter input validation - MORPH_RELATION Rest filter input - failure MORPH_RELATION field type - should fail with filter : "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id[eq]:\\"invalid-uuid\\"" 1`] = `
[
"Invalid UUID value 'invalid-uuid' for field "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id"",
]
`;

View File

@@ -0,0 +1,25 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - MULTI_SELECT Gql filter input - failure MULTI_SELECT field type - should fail with filter : {"multiSelectField":{"eq":"not-a-multi-select"}} 1`] = `"Operator "eq" is not valid for field "multiSelectField" of type MULTI_SELECT - Allowed operators: containsAny, is, isEmptyArray"`;
exports[`Filter input validation - MULTI_SELECT Gql filter input - failure MULTI_SELECT field type - should fail with filter : {"multiSelectField":{"in":["test"]}} 1`] = `"Operator "in" is not valid for field "multiSelectField" of type MULTI_SELECT - Allowed operators: containsAny, is, isEmptyArray"`;
exports[`Filter input validation - MULTI_SELECT Gql filter input - failure MULTI_SELECT field type - should fail with filter : {"multiSelectField":{"neq":"test"}} 1`] = `"Operator "neq" is not valid for field "multiSelectField" of type MULTI_SELECT - Allowed operators: containsAny, is, isEmptyArray"`;
exports[`Filter input validation - MULTI_SELECT Rest filter input - failure MULTI_SELECT field type - should fail with filter : "multiSelectField[eq]:\\"not-a-multi-select\\"" 1`] = `
[
"Operator "eq" is not valid for field "multiSelectField" of type MULTI_SELECT - Allowed operators: containsAny, is, isEmptyArray",
]
`;
exports[`Filter input validation - MULTI_SELECT Rest filter input - failure MULTI_SELECT field type - should fail with filter : "multiSelectField[in]:[\\"test\\"]" 1`] = `
[
"Operator "in" is not valid for field "multiSelectField" of type MULTI_SELECT - Allowed operators: containsAny, is, isEmptyArray",
]
`;
exports[`Filter input validation - MULTI_SELECT Rest filter input - failure MULTI_SELECT field type - should fail with filter : "multiSelectField[neq]:\\"test\\"" 1`] = `
[
"Operator "neq" is not valid for field "multiSelectField" of type MULTI_SELECT - Allowed operators: containsAny, is, isEmptyArray",
]
`;

View File

@@ -0,0 +1,33 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - NUMBER Gql filter input - failure NUMBER field type - should fail with filter : {"numberField":{"eq":"not-a-number"}} 1`] = `"Invalid number value NaN for field "numberField""`;
exports[`Filter input validation - NUMBER Gql filter input - failure NUMBER field type - should fail with filter : {"numberField":{"eq":[]}} 1`] = `"Invalid number value [] for field "numberField""`;
exports[`Filter input validation - NUMBER Gql filter input - failure NUMBER field type - should fail with filter : {"numberField":{"eq":{}}} 1`] = `"Invalid number value {} for field "numberField""`;
exports[`Filter input validation - NUMBER Gql filter input - failure NUMBER field type - should fail with filter : {"numberField":{"eq":true}} 1`] = `"Invalid number value true for field "numberField""`;
exports[`Filter input validation - NUMBER Rest filter input - failure NUMBER field type - should fail with filter : "numberField[eq]:\\"[]\\"" 1`] = `
[
"Invalid number value NaN for field "numberField"",
]
`;
exports[`Filter input validation - NUMBER Rest filter input - failure NUMBER field type - should fail with filter : "numberField[eq]:\\"{}\\"" 1`] = `
[
"Invalid number value NaN for field "numberField"",
]
`;
exports[`Filter input validation - NUMBER Rest filter input - failure NUMBER field type - should fail with filter : "numberField[eq]:\\"not-a-number\\"" 1`] = `
[
"Invalid number value NaN for field "numberField"",
]
`;
exports[`Filter input validation - NUMBER Rest filter input - failure NUMBER field type - should fail with filter : "numberField[eq]:\\"true\\"" 1`] = `
[
"Invalid number value NaN for field "numberField"",
]
`;

View File

@@ -0,0 +1,41 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - RATING Gql filter input - failure RATING field type - should fail with filter : {"ratingField":{"eq":"not-a-rating"}} 1`] = `"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_ratingField_enum": "not-a-rating""`;
exports[`Filter input validation - RATING Gql filter input - failure RATING field type - should fail with filter : {"ratingField":{"eq":[]}} 1`] = `"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_ratingField_enum": "{}""`;
exports[`Filter input validation - RATING Gql filter input - failure RATING field type - should fail with filter : {"ratingField":{"eq":{}}} 1`] = `"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_ratingField_enum": "{}""`;
exports[`Filter input validation - RATING Gql filter input - failure RATING field type - should fail with filter : {"ratingField":{"eq":2}} 1`] = `"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_ratingField_enum": "2""`;
exports[`Filter input validation - RATING Gql filter input - failure RATING field type - should fail with filter : {"ratingField":{"eq":true}} 1`] = `"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_ratingField_enum": "true""`;
exports[`Filter input validation - RATING Rest filter input - failure RATING field type - should fail with filter : "ratingField[eq]:\\"[]\\"" 1`] = `
[
"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_ratingField_enum": "[]"",
]
`;
exports[`Filter input validation - RATING Rest filter input - failure RATING field type - should fail with filter : "ratingField[eq]:\\"{}\\"" 1`] = `
[
"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_ratingField_enum": "{}"",
]
`;
exports[`Filter input validation - RATING Rest filter input - failure RATING field type - should fail with filter : "ratingField[eq]:\\"not-a-rating\\"" 1`] = `
[
"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_ratingField_enum": "not-a-rating"",
]
`;
exports[`Filter input validation - RATING Rest filter input - failure RATING field type - should fail with filter : "ratingField[eq]:\\"true\\"" 1`] = `
[
"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_ratingField_enum": "true"",
]
`;
exports[`Filter input validation - RATING Rest filter input - failure RATING field type - should fail with filter : "ratingField[eq]:2" 1`] = `
[
"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_ratingField_enum": "2"",
]
`;

View File

@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - RAW_JSON Gql filter input - failure RAW_JSON field type - should fail with filter : {"rawJsonField":{"like":[]}} 1`] = `"Filter operator "like" requires a string value for field "rawJsonField", got object"`;
exports[`Filter input validation - RAW_JSON Gql filter input - failure RAW_JSON field type - should fail with filter : {"rawJsonField":{"like":{}}} 1`] = `"Filter operator "like" requires a string value for field "rawJsonField", got object"`;
exports[`Filter input validation - RAW_JSON Gql filter input - failure RAW_JSON field type - should fail with filter : {"rawJsonField":{"like":2}} 1`] = `"Filter operator "like" requires a string value for field "rawJsonField", got number"`;
exports[`Filter input validation - RAW_JSON Gql filter input - failure RAW_JSON field type - should fail with filter : {"rawJsonField":{"like":true}} 1`] = `"Filter operator "like" requires a string value for field "rawJsonField", got boolean"`;

View File

@@ -0,0 +1,33 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - RELATION Gql filter input - failure RELATION field type - should fail with filter : {"manyToOneRelationField":{"eq":"6dd71a46-68fe-4420-82b3-0d5b00ad2642"}} 1`] = `"Object apiInputValidationTargetTestObject1 doesn't have any "eq" field."`;
exports[`Filter input validation - RELATION Gql filter input - failure RELATION field type - should fail with filter : {"manyToOneRelationFieldId":{"eq":"invalid-uuid"}} 1`] = `"Invalid UUID value 'invalid-uuid' for field "manyToOneRelationFieldId""`;
exports[`Filter input validation - RELATION Gql filter input - failure RELATION field type - should fail with filter : {"oneToManyRelationField":{"eq":"6dd71a46-68fe-4420-82b3-0d5b00ad2642"}} 1`] = `"Object apiInputValidationTargetTestObject1 doesn't have any "eq" field."`;
exports[`Filter input validation - RELATION Gql filter input - failure RELATION field type - should fail with filter : {"oneToManyRelationFieldId":{"eq":"invalid-uuid"}} 1`] = `"Object apiInputValidationTestObject doesn't have any "oneToManyRelationFieldId" field."`;
exports[`Filter input validation - RELATION Rest filter input - failure RELATION field type - should fail with filter : "manyToOneRelationField[eq]:\\"6dd71a46-68fe-4420-82b3-0d5b00ad2642\\"" 1`] = `
[
"Object apiInputValidationTargetTestObject1 doesn't have any "eq" field.",
]
`;
exports[`Filter input validation - RELATION Rest filter input - failure RELATION field type - should fail with filter : "manyToOneRelationFieldId[eq]:\\"invalid-uuid\\"" 1`] = `
[
"Invalid UUID value 'invalid-uuid' for field "manyToOneRelationFieldId"",
]
`;
exports[`Filter input validation - RELATION Rest filter input - failure RELATION field type - should fail with filter : "oneToManyRelationFieldId[eq]:\\"6dd71a46-68fe-4420-82b3-0d5b00ad2642\\"" 1`] = `
[
"Object apiInputValidationTestObject doesn't have any "oneToManyRelationFieldId" field.",
]
`;
exports[`Filter input validation - RELATION Rest filter input - failure RELATION field type - should fail with filter : "oneToManyRelationFieldId[eq]:\\"invalid-uuid\\"" 1`] = `
[
"Object apiInputValidationTestObject doesn't have any "oneToManyRelationFieldId" field.",
]
`;

View File

@@ -0,0 +1,33 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - SELECT Gql filter input - failure SELECT field type - should fail with filter : {"selectField":{"eq":"not-a-select"}} 1`] = `"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_selectField_enum": "not-a-select""`;
exports[`Filter input validation - SELECT Gql filter input - failure SELECT field type - should fail with filter : {"selectField":{"eq":[]}} 1`] = `"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_selectField_enum": "{}""`;
exports[`Filter input validation - SELECT Gql filter input - failure SELECT field type - should fail with filter : {"selectField":{"eq":{}}} 1`] = `"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_selectField_enum": "{}""`;
exports[`Filter input validation - SELECT Gql filter input - failure SELECT field type - should fail with filter : {"selectField":{"eq":true}} 1`] = `"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_selectField_enum": "true""`;
exports[`Filter input validation - SELECT Rest filter input - failure SELECT field type - should fail with filter : "selectField[eq]:\\"[]\\"" 1`] = `
[
"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_selectField_enum": "[]"",
]
`;
exports[`Filter input validation - SELECT Rest filter input - failure SELECT field type - should fail with filter : "selectField[eq]:\\"{}\\"" 1`] = `
[
"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_selectField_enum": "{}"",
]
`;
exports[`Filter input validation - SELECT Rest filter input - failure SELECT field type - should fail with filter : "selectField[eq]:\\"not-a-select\\"" 1`] = `
[
"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_selectField_enum": "not-a-select"",
]
`;
exports[`Filter input validation - SELECT Rest filter input - failure SELECT field type - should fail with filter : "selectField[eq]:\\"true\\"" 1`] = `
[
"invalid input value for enum workspace_1wgvd1injqtife6y4rvfbu3h5."_apiInputValidationTestObject_selectField_enum": "true"",
]
`;

View File

@@ -0,0 +1,17 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - TEXT Gql filter input - failure TEXT field type - should fail with filter : {"textField":{"iregex":"^test$"}} 1`] = `"Operator "iregex" is not valid for field "textField" of type TEXT - Allowed operators: eq, neq, gt, gte, lt, lte, in, is, like, ilike, startsWith, endsWith"`;
exports[`Filter input validation - TEXT Gql filter input - failure TEXT field type - should fail with filter : {"textField":{"regex":"^test$"}} 1`] = `"Operator "regex" is not valid for field "textField" of type TEXT - Allowed operators: eq, neq, gt, gte, lt, lte, in, is, like, ilike, startsWith, endsWith"`;
exports[`Filter input validation - TEXT Rest filter input - failure TEXT field type - should fail with filter : "textField[iregex]:\\"^test$\\"" 1`] = `
[
"'filter' invalid for 'textField[iregex]:"^test$"', comparator iregex not in eq, neq, in, containsAny, is, gt, gte, lt, lte, startsWith, endsWith, like, ilike",
]
`;
exports[`Filter input validation - TEXT Rest filter input - failure TEXT field type - should fail with filter : "textField[regex]:\\"^test$\\"" 1`] = `
[
"'filter' invalid for 'textField[regex]:"^test$"', comparator regex not in eq, neq, in, containsAny, is, gt, gte, lt, lte, startsWith, endsWith, like, ilike",
]
`;

View File

@@ -0,0 +1,49 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Filter input validation - UUID Gql filter input - failure UUID field type - should fail with filter : {"uuidField":{"eq":"2025-01-01"}} 1`] = `"Invalid UUID value '2025-01-01' for field "uuidField""`;
exports[`Filter input validation - UUID Gql filter input - failure UUID field type - should fail with filter : {"uuidField":{"eq":"invalid-uuid"}} 1`] = `"Invalid UUID value 'invalid-uuid' for field "uuidField""`;
exports[`Filter input validation - UUID Gql filter input - failure UUID field type - should fail with filter : {"uuidField":{"eq":[]}} 1`] = `"Invalid UUID value [] for field "uuidField""`;
exports[`Filter input validation - UUID Gql filter input - failure UUID field type - should fail with filter : {"uuidField":{"eq":{}}} 1`] = `"Invalid UUID value {} for field "uuidField""`;
exports[`Filter input validation - UUID Gql filter input - failure UUID field type - should fail with filter : {"uuidField":{"eq":2}} 1`] = `"Invalid UUID value 2 for field "uuidField""`;
exports[`Filter input validation - UUID Gql filter input - failure UUID field type - should fail with filter : {"uuidField":{"eq":true}} 1`] = `"Invalid UUID value true for field "uuidField""`;
exports[`Filter input validation - UUID Rest filter input - failure UUID field type - should fail with filter : "uuidField[eq]:\\"[]\\"" 1`] = `
[
"Invalid UUID value '[]' for field "uuidField"",
]
`;
exports[`Filter input validation - UUID Rest filter input - failure UUID field type - should fail with filter : "uuidField[eq]:\\"{}\\"" 1`] = `
[
"Invalid UUID value '{}' for field "uuidField"",
]
`;
exports[`Filter input validation - UUID Rest filter input - failure UUID field type - should fail with filter : "uuidField[eq]:\\"2025-01-01\\"" 1`] = `
[
"Invalid UUID value '2025-01-01' for field "uuidField"",
]
`;
exports[`Filter input validation - UUID Rest filter input - failure UUID field type - should fail with filter : "uuidField[eq]:\\"invalid-uuid\\"" 1`] = `
[
"Invalid UUID value 'invalid-uuid' for field "uuidField"",
]
`;
exports[`Filter input validation - UUID Rest filter input - failure UUID field type - should fail with filter : "uuidField[eq]:\\"true\\"" 1`] = `
[
"Invalid UUID value 'true' for field "uuidField"",
]
`;
exports[`Filter input validation - UUID Rest filter input - failure UUID field type - should fail with filter : "uuidField[eq]:2" 1`] = `
[
"Invalid UUID value '2' for field "uuidField"",
]
`;

View File

@@ -0,0 +1,73 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,114 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
});
describe('Gql filter input - 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 filter input - success', () => {
it.each(
successfulTestCases
.filter((testCase) => testCase.restFilterInput)
.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,
);
},
);
});
});

View File

@@ -0,0 +1,111 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,276 @@
import { type FieldMetadataTypesToTestForFilterInputValidation } from 'test/integration/graphql/suites/inputs-validation/types/field-metadata-type-to-test';
import { joinColumnNameForManyToOneMorphRelationField1 } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
import { type CompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/composite-field-metadata-type.type';
export const failingFilterInputByFieldMetadataType: {
[K in Exclude<
FieldMetadataTypesToTestForFilterInputValidation,
CompositeFieldMetadataType
>]: {
gqlFilterInput: any;
restFilterInput: string;
}[];
} = {
[FieldMetadataType.RELATION]: [
{
gqlFilterInput: {
manyToOneRelationField: {
eq: '6dd71a46-68fe-4420-82b3-0d5b00ad2642',
},
},
restFilterInput:
'manyToOneRelationField[eq]:"6dd71a46-68fe-4420-82b3-0d5b00ad2642"',
},
{
gqlFilterInput: {
manyToOneRelationFieldId: {
eq: 'invalid-uuid',
},
},
restFilterInput: 'manyToOneRelationFieldId[eq]:"invalid-uuid"',
},
{
gqlFilterInput: {
oneToManyRelationField: {
eq: '6dd71a46-68fe-4420-82b3-0d5b00ad2642',
},
},
restFilterInput:
'oneToManyRelationFieldId[eq]:"6dd71a46-68fe-4420-82b3-0d5b00ad2642"',
},
{
gqlFilterInput: {
oneToManyRelationFieldId: {
eq: 'invalid-uuid',
},
},
restFilterInput: 'oneToManyRelationFieldId[eq]:"invalid-uuid"',
},
],
[FieldMetadataType.MORPH_RELATION]: [
{
gqlFilterInput: {
[joinColumnNameForManyToOneMorphRelationField1]: { eq: 'invalid-uuid' },
},
restFilterInput: `${joinColumnNameForManyToOneMorphRelationField1}[eq]:"invalid-uuid"`,
},
{
gqlFilterInput: {
[joinColumnNameForManyToOneMorphRelationField1.replace('Id', '')]: {
eq: '6dd71a46-68fe-4420-82b3-0d5b00ad2642',
},
},
restFilterInput: `${[joinColumnNameForManyToOneMorphRelationField1.replace('Id', '')]}[eq]:"6dd71a46-68fe-4420-82b3-0d5b00ad2642"`,
},
],
[FieldMetadataType.UUID]: [
{
gqlFilterInput: { uuidField: { eq: 'invalid-uuid' } },
restFilterInput: 'uuidField[eq]:"invalid-uuid"',
},
{
gqlFilterInput: { uuidField: { eq: 2 } },
restFilterInput: 'uuidField[eq]:2',
},
{
gqlFilterInput: { uuidField: { eq: {} } },
restFilterInput: 'uuidField[eq]:"{}"',
},
{
gqlFilterInput: { uuidField: { eq: [] } },
restFilterInput: 'uuidField[eq]:"[]"',
},
{
gqlFilterInput: { uuidField: { eq: true } },
restFilterInput: 'uuidField[eq]:"true"',
},
{
gqlFilterInput: { uuidField: { eq: '2025-01-01' } },
restFilterInput: 'uuidField[eq]:"2025-01-01"',
},
],
[FieldMetadataType.TEXT]: [
{
gqlFilterInput: { textField: { regex: '^test$' } },
restFilterInput: 'textField[regex]:"^test$"',
},
{
gqlFilterInput: { textField: { iregex: '^test$' } },
restFilterInput: 'textField[iregex]:"^test$"',
},
],
[FieldMetadataType.DATE_TIME]: [
{
gqlFilterInput: { dateTimeField: { eq: 'not-a-date-time' } },
restFilterInput: 'dateTimeField[eq]:"not-a-date-time"',
},
{
gqlFilterInput: { dateTimeField: { eq: {} } },
restFilterInput: 'dateTimeField[eq]:"{}"',
},
{
gqlFilterInput: { dateTimeField: { eq: [] } },
restFilterInput: 'dateTimeField[eq]:"[]"',
},
{
gqlFilterInput: { dateTimeField: { eq: true } },
restFilterInput: 'dateTimeField[eq]:"true"',
},
],
[FieldMetadataType.DATE]: [
{
gqlFilterInput: { dateField: { eq: 'not-a-date' } },
restFilterInput: 'dateField[eq]:"not-a-date"',
},
{
gqlFilterInput: { dateField: { eq: {} } },
restFilterInput: 'dateField[eq]:"{}"',
},
{
gqlFilterInput: { dateField: { eq: [] } },
restFilterInput: 'dateField[eq]:"[]"',
},
],
[FieldMetadataType.BOOLEAN]: [
{
gqlFilterInput: { booleanField: { eq: 'not-a-boolean' } },
restFilterInput: 'booleanField[eq]:"not-a-boolean"',
},
{
gqlFilterInput: { booleanField: { eq: [] } },
restFilterInput: 'booleanField[eq]:"[]"',
},
{
gqlFilterInput: { booleanField: { eq: 2 } },
restFilterInput: 'booleanField[eq]:2',
},
],
[FieldMetadataType.NUMBER]: [
{
gqlFilterInput: { numberField: { eq: 'not-a-number' } },
restFilterInput: 'numberField[eq]:"not-a-number"',
},
{
gqlFilterInput: { numberField: { eq: {} } },
restFilterInput: 'numberField[eq]:"{}"',
},
{
gqlFilterInput: { numberField: { eq: [] } },
restFilterInput: 'numberField[eq]:"[]"',
},
{
gqlFilterInput: { numberField: { eq: true } },
restFilterInput: 'numberField[eq]:"true"',
},
],
[FieldMetadataType.RATING]: [
{
gqlFilterInput: { ratingField: { eq: 'not-a-rating' } },
restFilterInput: 'ratingField[eq]:"not-a-rating"',
},
{
gqlFilterInput: { ratingField: { eq: {} } },
restFilterInput: 'ratingField[eq]:"{}"',
},
{
gqlFilterInput: { ratingField: { eq: [] } },
restFilterInput: 'ratingField[eq]:"[]"',
},
{
gqlFilterInput: { ratingField: { eq: true } },
restFilterInput: 'ratingField[eq]:"true"',
},
{
gqlFilterInput: { ratingField: { eq: 2 } },
restFilterInput: 'ratingField[eq]:2',
},
],
[FieldMetadataType.SELECT]: [
{
gqlFilterInput: { selectField: { eq: 'not-a-select' } },
restFilterInput: 'selectField[eq]:"not-a-select"',
},
{
gqlFilterInput: { selectField: { eq: {} } },
restFilterInput: 'selectField[eq]:"{}"',
},
{
gqlFilterInput: { selectField: { eq: [] } },
restFilterInput: 'selectField[eq]:"[]"',
},
{
gqlFilterInput: { selectField: { eq: true } },
restFilterInput: 'selectField[eq]:"true"',
},
],
[FieldMetadataType.MULTI_SELECT]: [
{
gqlFilterInput: { multiSelectField: { eq: 'not-a-multi-select' } },
restFilterInput: 'multiSelectField[eq]:"not-a-multi-select"',
},
{
gqlFilterInput: { multiSelectField: { neq: 'test' } },
restFilterInput: 'multiSelectField[neq]:"test"',
},
{
gqlFilterInput: { multiSelectField: { in: ['test'] } },
restFilterInput: 'multiSelectField[in]:["test"]',
},
],
[FieldMetadataType.RAW_JSON]: [
{
gqlFilterInput: { rawJsonField: { like: {} } },
restFilterInput: '',
},
{
gqlFilterInput: { rawJsonField: { like: [] } },
restFilterInput: '',
},
{
gqlFilterInput: { rawJsonField: { like: true } },
restFilterInput: '',
},
{
gqlFilterInput: { rawJsonField: { like: 2 } },
restFilterInput: '',
},
],
[FieldMetadataType.ARRAY]: [
{
gqlFilterInput: { arrayField: { containsIlike: {} } },
restFilterInput: 'arrayField[containsAny]:"{}"',
},
{
gqlFilterInput: { arrayField: { containsIlike: [] } },
restFilterInput: 'arrayField[containsAny]:"[]"',
},
{
gqlFilterInput: { arrayField: { containsIlike: true } },
restFilterInput: 'arrayField[containsAny]:"true"',
},
{
gqlFilterInput: { arrayField: { containsIlike: 2 } },
restFilterInput: 'arrayField[containsAny]:2',
},
],
[FieldMetadataType.FILES]: [
{
gqlFilterInput: { filesField: { containsIlike: {} } },
restFilterInput: 'filesField[containsAny]:"{}"',
},
{
gqlFilterInput: { filesField: { containsIlike: [] } },
restFilterInput: 'filesField[containsAny]:"[]"',
},
{
gqlFilterInput: { filesField: { containsIlike: true } },
restFilterInput: 'filesField[containsAny]:"true"',
},
{
gqlFilterInput: { filesField: { containsIlike: 2 } },
restFilterInput: 'filesField[containsAny]:2',
},
],
};

View File

@@ -0,0 +1,976 @@
import { type FieldMetadataTypesToTestForFilterInputValidation } from 'test/integration/graphql/suites/inputs-validation/types/field-metadata-type-to-test';
import {
joinColumnNameForManyToOneMorphRelationField1,
TEST_TARGET_OBJECT_RECORD_ID,
TEST_UUID_FIELD_VALUE,
} from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
export const successfulFilterInputByFieldMetadataType: {
[K in FieldMetadataTypesToTestForFilterInputValidation]: {
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;
},
},
{
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.MORPH_RELATION]: [
{
gqlFilterInput: {
[joinColumnNameForManyToOneMorphRelationField1]: {
neq: '00000000-0000-4000-8000-000000000000',
},
},
restFilterInput: `${joinColumnNameForManyToOneMorphRelationField1}[neq]:"00000000-0000-4000-8000-000000000000"`,
validateFilter: (record: Record<string, any>) => {
return (
record[joinColumnNameForManyToOneMorphRelationField1] !==
'00000000-0000-4000-8000-000000000000'
);
},
},
{
gqlFilterInput: {
[joinColumnNameForManyToOneMorphRelationField1]: {
eq: TEST_TARGET_OBJECT_RECORD_ID,
},
},
restFilterInput: `${joinColumnNameForManyToOneMorphRelationField1}[eq]:"${TEST_TARGET_OBJECT_RECORD_ID}"`,
validateFilter: (record: Record<string, any>) => {
return (
record[joinColumnNameForManyToOneMorphRelationField1] ===
TEST_TARGET_OBJECT_RECORD_ID
);
},
},
{
gqlFilterInput: {
[joinColumnNameForManyToOneMorphRelationField1]: {
gt: '00000000-0000-4000-8000-000000000000',
},
},
restFilterInput: `${joinColumnNameForManyToOneMorphRelationField1}[gt]:"00000000-0000-4000-8000-000000000000"`,
validateFilter: (record: Record<string, any>) => {
return (
record[joinColumnNameForManyToOneMorphRelationField1] >
'00000000-0000-4000-8000-000000000000'
);
},
},
{
gqlFilterInput: {
[joinColumnNameForManyToOneMorphRelationField1]: {
gte: '00000000-0000-4000-8000-000000000000',
},
},
restFilterInput: `${joinColumnNameForManyToOneMorphRelationField1}[gte]:"00000000-0000-4000-8000-000000000000"`,
validateFilter: (record: Record<string, any>) => {
return (
record[joinColumnNameForManyToOneMorphRelationField1] >=
'00000000-0000-4000-8000-000000000000'
);
},
},
{
gqlFilterInput: {
[joinColumnNameForManyToOneMorphRelationField1]: {
lt: 'ffffffff-ffff-4fff-bfff-ffffffffffff',
},
},
restFilterInput: `${joinColumnNameForManyToOneMorphRelationField1}[lt]:"ffffffff-ffff-4fff-bfff-ffffffffffff"`,
validateFilter: (record: Record<string, any>) => {
return (
record[joinColumnNameForManyToOneMorphRelationField1] <
'ffffffff-ffff-4fff-bfff-ffffffffffff'
);
},
},
{
gqlFilterInput: {
[joinColumnNameForManyToOneMorphRelationField1]: {
lte: 'ffffffff-ffff-4fff-bfff-ffffffffffff',
},
},
restFilterInput: `${joinColumnNameForManyToOneMorphRelationField1}[lte]:"ffffffff-ffff-4fff-bfff-ffffffffffff"`,
validateFilter: (record: Record<string, any>) => {
return (
record[joinColumnNameForManyToOneMorphRelationField1] <=
'ffffffff-ffff-4fff-bfff-ffffffffffff'
);
},
},
{
gqlFilterInput: {
[joinColumnNameForManyToOneMorphRelationField1]: {
in: [TEST_TARGET_OBJECT_RECORD_ID],
},
},
restFilterInput: `${joinColumnNameForManyToOneMorphRelationField1}[in]:["${TEST_TARGET_OBJECT_RECORD_ID}"]`,
validateFilter: (record: Record<string, any>) => {
return (
record[joinColumnNameForManyToOneMorphRelationField1] ===
TEST_TARGET_OBJECT_RECORD_ID
);
},
},
{
gqlFilterInput: {
[joinColumnNameForManyToOneMorphRelationField1]: { is: 'NULL' },
},
restFilterInput: `${joinColumnNameForManyToOneMorphRelationField1}[is]:NULL`,
validateFilter: (record: Record<string, any>) => {
return record[joinColumnNameForManyToOneMorphRelationField1] === null;
},
},
{
gqlFilterInput: {
[joinColumnNameForManyToOneMorphRelationField1]: { is: 'NOT_NULL' },
},
restFilterInput: `${joinColumnNameForManyToOneMorphRelationField1}[is]:NOT_NULL`,
validateFilter: (record: Record<string, any>) => {
return isDefined(record[joinColumnNameForManyToOneMorphRelationField1]);
},
},
],
[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;
},
},
{
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';
},
},
{
gqlFilterInput: { textField: { eq: null } },
restFilterInput: '',
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';
},
},
{
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);
},
},
{
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');
},
},
],
[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');
},
},
],
[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]: [
{
gqlFilterInput: { dateTimeField: { eq: '2025-01-01T00:00:00Z' } },
restFilterInput: 'dateTimeField[eq]:"2025-01-01T00:00:00Z"',
validateFilter: (record: Record<string, any>) => {
return (
new Date(record.dateTimeField).getTime() ===
new Date('2025-01-01T00:00:00Z').getTime()
);
},
},
{
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';
},
},
{
gqlFilterInput: { dateTimeField: { in: ['2025-01-01T00:00:00Z'] } },
restFilterInput: 'dateTimeField[in]:["2025-01-01T00:00:00Z"]',
validateFilter: (record: Record<string, any>) => {
return (
new Date(record.dateTimeField).getTime() ===
new Date('2025-01-01T00:00:00Z').getTime()
);
},
},
{
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' } },
restFilterInput: 'dateTimeField[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return record.dateTimeField === null;
},
},
],
[FieldMetadataType.DATE]: [
{
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';
},
},
{
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;
},
},
],
[FieldMetadataType.BOOLEAN]: [
{
gqlFilterInput: { booleanField: { eq: true } },
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);
},
},
],
[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 (
Array.isArray(record.multiSelectField) &&
record.multiSelectField.length === 0
);
},
},
{
gqlFilterInput: { multiSelectField: { is: 'NOT_NULL' } },
restFilterInput: 'multiSelectField[is]:NOT_NULL',
validateFilter: (record: Record<string, any>) => {
return isDefined(record.multiSelectField);
},
},
],
[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' } },
restFilterInput: '',
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 ||
(Array.isArray(record.arrayField) && record.arrayField.length === 0)
);
},
},
],
[FieldMetadataType.FILES]: [
{
gqlFilterInput: { filesField: { is: 'NULL' } },
restFilterInput: 'filesField[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return record.filesField === null;
},
},
{
gqlFilterInput: { filesField: { is: 'NOT_NULL' } },
restFilterInput: 'filesField[is]:NOT_NULL',
validateFilter: (record: Record<string, any>) => {
return Array.isArray(record.filesField) && record.filesField.length > 0;
},
},
],
};

View File

@@ -0,0 +1,73 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,112 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,112 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,73 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,110 @@
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util';
import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util';
import { makeGraphqlAPIRequestWithApiKey } from 'test/integration/graphql/utils/make-graphql-api-request-with-api-key.util';
import { restoreManyOperationFactory } from 'test/integration/graphql/utils/restore-many-operation-factory.util';
import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util';
import { CommonQueryRunnerExceptionCode } from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception';
describe('Empty filter bulk mutation validation', () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
const expectEmptyFilterRejection = (response: {
body: { errors?: any[] };
}) => {
expect(response.body.errors).toBeDefined();
expect(response.body.errors?.[0].extensions.subCode).toBe(
CommonQueryRunnerExceptionCode.INVALID_ARGS_FILTER,
);
};
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
it('should reject destroyMany with an empty filter', async () => {
const graphqlOperation = destroyManyOperationFactory({
objectMetadataSingularName,
objectMetadataPluralName,
gqlFields: 'id',
filter: {},
});
const response = await makeGraphqlAPIRequestWithApiKey(graphqlOperation);
expectEmptyFilterRejection(response);
});
it('should reject deleteMany with an empty filter', async () => {
const graphqlOperation = deleteManyOperationFactory({
objectMetadataSingularName,
objectMetadataPluralName,
gqlFields: 'id',
filter: {},
});
const response = await makeGraphqlAPIRequestWithApiKey(graphqlOperation);
expectEmptyFilterRejection(response);
});
it('should reject updateMany with an empty filter', async () => {
const graphqlOperation = updateManyOperationFactory({
objectMetadataSingularName,
objectMetadataPluralName,
gqlFields: 'id',
data: { textField: 'updated' },
filter: {},
});
const response = await makeGraphqlAPIRequestWithApiKey(graphqlOperation);
expectEmptyFilterRejection(response);
});
it('should reject restoreMany with an empty filter', async () => {
const graphqlOperation = restoreManyOperationFactory({
objectMetadataSingularName,
objectMetadataPluralName,
gqlFields: 'id',
filter: {},
});
const response = await makeGraphqlAPIRequestWithApiKey(graphqlOperation);
expectEmptyFilterRejection(response);
});
it('should reject destroyMany with a nested empty logical filter', async () => {
const graphqlOperation = destroyManyOperationFactory({
objectMetadataSingularName,
objectMetadataPluralName,
gqlFields: 'id',
filter: { and: [] },
});
const response = await makeGraphqlAPIRequestWithApiKey(graphqlOperation);
expectEmptyFilterRejection(response);
});
});

View File

@@ -0,0 +1,114 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.FILES;
const failingTestCases =
failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes(true);
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
});
describe('Gql filter input - 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,
true,
);
},
);
});
describe('Rest filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,73 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,73 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,113 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const FIELD_METADATA_TYPE = FieldMetadataType.MORPH_RELATION;
const failingTestCases =
failingFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
const successfulTestCases =
successfulFilterInputByFieldMetadataType[FIELD_METADATA_TYPE];
describe(`Filter input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
});
describe('Gql filter input - 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,
);
},
);
});
// TODO @guillim - fix this once REST API can handle morph relations
xdescribe('Rest filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,112 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,112 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,73 @@
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,112 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,116 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
const restFailingTestCases = failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
}));
if (restFailingTestCases.length === 0) {
it.skip('No REST failing test cases for this field type', () => {});
} else {
it.each(restFailingTestCases)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
}
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,112 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,112 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
});
describe('Gql filter input - 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 filter input - 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,
);
},
);
});
});

View File

@@ -0,0 +1,122 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - failure', () => {
if (failingTestCases.length === 0) {
it.skip('No failing test cases for this field type', () => {});
} else {
it.each(
failingTestCases.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.gqlFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ gqlFilterInput: filter }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
}
});
describe('Rest filter input - failure', () => {
if (failingTestCases.length === 0) {
it.skip('No failing test cases for this field type', () => {});
} else {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
}
});
describe('Gql filter input - 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 filter input - success', () => {
it.each(
successfulTestCases
.filter((testCase) => testCase.restFilterInput)
.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,
);
},
);
});
});

View File

@@ -0,0 +1,20 @@
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,
) => {
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).toMatchSnapshot();
};

View File

@@ -0,0 +1,38 @@
import { TEST_OBJECT_GQL_FIELDS } from 'test/integration/graphql/suites/inputs-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,
withFilesField: boolean = false,
) => {
const graphqlOperation = findManyOperationFactory({
objectMetadataSingularName: objectMetadataSingularName,
objectMetadataPluralName: objectMetadataPluralName,
gqlFields:
TEST_OBJECT_GQL_FIELDS +
(withFilesField
? ` filesField {
fileId
label
}`
: ''),
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);
};

View File

@@ -0,0 +1,15 @@
import { makeRestAPIRequest } from 'test/integration/rest/utils/make-rest-api-request.util';
export const testRestFailingScenario = async (
objectMetadataPluralName: string,
filter: any,
) => {
const encodedFilter = encodeURIComponent(filter);
const response = await makeRestAPIRequest({
method: 'get',
path: `/${objectMetadataPluralName}?filter=${encodedFilter}`,
});
expect(response.body.error).toBeDefined();
expect(response.body.messages).toMatchSnapshot();
};

View File

@@ -0,0 +1,31 @@
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}`,
});
if (response.body.error || response.body.messages) {
throw new Error(
`REST API error: ${response.body.error} - ${JSON.stringify(response.body.messages)}`,
);
}
expect(response.body.data).toBeDefined();
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);
};

View File

@@ -0,0 +1,114 @@
import { failingFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/failing-filter-input-by-field-metadata-type.constant';
import { successfulFilterInputByFieldMetadataType } from 'test/integration/graphql/suites/inputs-validation/filter-validation/constants/successful-filter-input-by-field-metadata-type.constant';
import { testGqlFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-failing-scenario.util';
import { testGqlSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-gql-successful-scenario.util';
import { testRestFailingScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-failing-scenario.util';
import { testRestSuccessfulScenario } from 'test/integration/graphql/suites/inputs-validation/filter-validation/utils/test-rest-successful-scenario.util';
import { destroyManyObjectsMetadata } from 'test/integration/graphql/suites/inputs-validation/utils/destroy-many-objects-metadata';
import { setupTestObjectsWithAllFieldTypes } from 'test/integration/graphql/suites/inputs-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 input validation - ${FIELD_METADATA_TYPE}`, () => {
let objectMetadataId: string;
let objectMetadataSingularName: string;
let objectMetadataPluralName: string;
let targetObjectMetadata1Id: string;
let targetObjectMetadata2Id: string;
beforeAll(async () => {
const setupTest = await setupTestObjectsWithAllFieldTypes();
objectMetadataId = setupTest.objectMetadataId;
objectMetadataSingularName = setupTest.objectMetadataSingularName;
objectMetadataPluralName = setupTest.objectMetadataPluralName;
targetObjectMetadata1Id = setupTest.targetObjectMetadata1Id;
targetObjectMetadata2Id = setupTest.targetObjectMetadata2Id;
});
afterAll(async () => {
await destroyManyObjectsMetadata([
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
]);
});
describe('Gql filter input - 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 }) => {
await testGqlFailingScenario(
objectMetadataSingularName,
objectMetadataPluralName,
filter,
);
},
);
});
describe('Rest filter input - failure', () => {
it.each(
failingTestCases
.filter((testCase) => testCase.restFilterInput)
.map((testCase) => ({
...testCase,
stringifiedFilter: JSON.stringify(testCase.restFilterInput),
})),
)(
`${FIELD_METADATA_TYPE} field type - should fail with filter : $stringifiedFilter`,
async ({ restFilterInput: filter }) => {
await testRestFailingScenario(objectMetadataPluralName, filter);
},
);
});
describe('Gql filter input - 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 filter input - success', () => {
it.each(
successfulTestCases
.filter((testCase) => testCase.restFilterInput)
.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,
);
},
);
});
});

View File

@@ -0,0 +1,23 @@
import { type FieldMetadataType } from 'twenty-shared/types';
type FieldMetadataTypesNotTestedForFilterInputValidation =
| 'TS_VECTOR'
| 'POSITION'
| 'ACTOR'
| 'NUMERIC'
| 'RICH_TEXT';
type FieldMetadataTypesNotTestedForCreateInputValidation =
| 'TS_VECTOR'
| 'ACTOR'
| 'NUMERIC';
export type FieldMetadataTypesToTestForCreateInputValidation = Exclude<
FieldMetadataType,
FieldMetadataTypesNotTestedForCreateInputValidation
>;
export type FieldMetadataTypesToTestForFilterInputValidation = Exclude<
FieldMetadataType,
FieldMetadataTypesNotTestedForFilterInputValidation
>;

View File

@@ -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,
},
});
}
};

View File

@@ -0,0 +1,238 @@
import {
type FieldMetadataTypesToTestForCreateInputValidation,
type FieldMetadataTypesToTestForFilterInputValidation,
} from 'test/integration/graphql/suites/inputs-validation/types/field-metadata-type-to-test';
import {
type FieldMetadataComplexOption,
type FieldMetadataSettingsMapping,
FieldMetadataType,
RelationType,
type FieldMetadataMultiItemSettings,
type RelationCreationPayload,
} from 'twenty-shared/types';
type FieldMetadataCreationInput = {
name: string;
label: string;
type: FieldMetadataType;
objectMetadataId: string;
options?: FieldMetadataComplexOption[];
relationCreationPayload?: RelationCreationPayload;
morphRelationsCreationPayload?: RelationCreationPayload[];
settings?:
| FieldMetadataMultiItemSettings
| FieldMetadataSettingsMapping['FILES'];
};
export const getFieldMetadataCreationInputs = (
objectMetadataId: string,
targetObjectMetadata1Id: string,
targetObjectMetadata2Id: string,
) => {
const fieldInputsMap: {
[K in Exclude<
| FieldMetadataTypesToTestForCreateInputValidation
| FieldMetadataTypesToTestForFilterInputValidation,
'ACTOR' | 'POSITION'
>]: FieldMetadataCreationInput | FieldMetadataCreationInput[];
} = {
[FieldMetadataType.RICH_TEXT]: {
name: 'richTextField',
label: 'richTextField',
type: FieldMetadataType.RICH_TEXT,
objectMetadataId,
},
[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.FILES]: {
name: 'filesField',
label: 'filesField',
type: FieldMetadataType.FILES,
objectMetadataId,
settings: {
maxNumberOfValues: 2,
},
},
[FieldMetadataType.UUID]: {
name: 'uuidField',
label: 'uuidField',
type: FieldMetadataType.UUID,
objectMetadataId,
},
[FieldMetadataType.RELATION]: [
{
name: 'manyToOneRelationField',
label: 'manyToOneRelationField',
type: FieldMetadataType.RELATION,
objectMetadataId,
relationCreationPayload: {
targetObjectMetadataId: targetObjectMetadata1Id,
targetFieldLabel: 'oneToManyTargetRelationField',
targetFieldIcon: 'IconListOpportunity',
type: RelationType.MANY_TO_ONE,
},
},
{
name: 'oneToManyRelationField',
label: 'oneToManyRelationField',
type: FieldMetadataType.RELATION,
objectMetadataId,
relationCreationPayload: {
targetObjectMetadataId: targetObjectMetadata1Id,
targetFieldLabel: 'manyToOneTargetRelationField',
targetFieldIcon: 'IconListOpportunity',
type: RelationType.ONE_TO_MANY,
},
},
],
[FieldMetadataType.MORPH_RELATION]: [
{
name: 'manyToOneMorphRelationField',
label: 'manyToOneMorphRelationField',
type: FieldMetadataType.MORPH_RELATION,
objectMetadataId,
morphRelationsCreationPayload: [
{
targetObjectMetadataId: targetObjectMetadata1Id,
targetFieldLabel: 'oneToManyTarget1MorphRelationField',
targetFieldIcon: 'IconListOpportunity',
type: RelationType.MANY_TO_ONE,
},
{
targetObjectMetadataId: targetObjectMetadata2Id,
targetFieldLabel: 'oneToManyTarget2MorphRelationField',
targetFieldIcon: 'IconListOpportunity',
type: RelationType.MANY_TO_ONE,
},
],
},
// {
// name: 'oneToManyRelationField',
// label: 'oneToManyRelationField',
// type: FieldMetadataType.RELATION,
// objectMetadataId,
// relationCreationPayload: {
// targetObjectMetadataId: targetObjectMetadata1Id,
// targetFieldLabel: 'manyToOneTargetRelationField',
// targetFieldIcon: 'IconListOpportunity',
// type: RelationType.ONE_TO_MANY,
// },
// },
],
};
return Object.values(fieldInputsMap).flat();
};

View File

@@ -0,0 +1,237 @@
import { getFieldMetadataCreationInputs } from 'test/integration/graphql/suites/inputs-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 { uploadFileWithDirectUpload } from 'test/integration/graphql/utils/upload-file-with-direct-upload.util';
import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util';
import { getAppProviderByClassName } from 'test/integration/utils/get-app-provider-by-class-name.util';
import { FieldMetadataType, RelationType } from 'twenty-shared/types';
import { v4 } from 'uuid';
import { type FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service';
import { computeMorphRelationFlatFieldName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-relation-flat-field-name.util';
import { SEED_APPLE_WORKSPACE_ID } from 'src/engine/workspace-manager/dev-seeder/core/constants/seeder-workspaces.constant';
const TEST_OBJECT_METADATA_NAME_SINGULAR = 'apiInputValidationTestObject';
const TEST_OBJECT_METADATA_NAME_PLURAL = 'apiInputValidationTestObjects';
const TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR_1 =
'apiInputValidationTargetTestObject1';
const TEST_TARGET_OBJECT_METADATA_NAME_PLURAL_1 =
'apiInputValidationTargetTestObjects1';
const TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR_2 =
'apiInputValidationTargetTestObject2';
const TEST_TARGET_OBJECT_METADATA_NAME_PLURAL_2 =
'apiInputValidationTargetTestObjects2';
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 TEST_TARGET_OBJECT_RECORD_ID_FIELD_VALUE =
'20202020-b21e-4ec2-873b-de4264d89021';
export const joinColumnNameForManyToOneMorphRelationField1 =
computeMorphRelationFlatFieldName({
fieldName: 'manyToOneMorphRelationField',
relationType: RelationType.MANY_TO_ONE,
targetObjectMetadataNameSingular:
TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR_1,
targetObjectMetadataNamePlural: TEST_TARGET_OBJECT_METADATA_NAME_PLURAL_1,
}) + 'Id';
export const setupTestObjectsWithAllFieldTypes = async (
withFilesField: boolean = false,
) => {
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 createdTargetObjectMetadata1 = await createOneObjectMetadata({
input: {
nameSingular: TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR_1,
namePlural: TEST_TARGET_OBJECT_METADATA_NAME_PLURAL_1,
labelSingular: TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR_1,
labelPlural: TEST_TARGET_OBJECT_METADATA_NAME_PLURAL_1,
},
});
const createdTargetObjectMetadata2 = await createOneObjectMetadata({
input: {
nameSingular: TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR_2,
namePlural: TEST_TARGET_OBJECT_METADATA_NAME_PLURAL_2,
labelSingular: TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR_2,
labelPlural: TEST_TARGET_OBJECT_METADATA_NAME_PLURAL_2,
},
});
const targetObjectMetadata1Id =
createdTargetObjectMetadata1.data.createOneObject.id;
const targetObjectMetadata2Id =
createdTargetObjectMetadata2.data.createOneObject.id;
const fieldMetadataCreationInputs = getFieldMetadataCreationInputs(
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
);
const createdFlatFieldMetadatas =
await getAppProviderByClassName<FieldMetadataService>(
'FieldMetadataService',
).createManyFields({
createFieldInputs: fieldMetadataCreationInputs,
workspaceId: SEED_APPLE_WORKSPACE_ID,
});
const filesFieldMetadataId = createdFlatFieldMetadatas.find(
(flatFieldMetadata) => flatFieldMetadata.type === FieldMetadataType.FILES,
)?.id;
await makeGraphqlAPIRequest(
createManyOperationFactory({
objectMetadataSingularName: TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR_1,
objectMetadataPluralName: TEST_TARGET_OBJECT_METADATA_NAME_PLURAL_1,
gqlFields: `id`,
data: [
{
id: TEST_TARGET_OBJECT_RECORD_ID,
},
],
}),
);
let uploadedFileId: string | undefined;
if (withFilesField) {
jest.useRealTimers();
if (!filesFieldMetadataId) {
throw new Error('FILES field metadata was not created');
}
const uploadedFile = await uploadFileWithDirectUpload({
filename: 'Document.txt',
content: Buffer.from('Test document content'),
fileFolder: 'FilesField',
fieldMetadataId: filesFieldMetadataId,
});
jest.useFakeTimers();
uploadedFileId = uploadedFile.id;
}
await makeGraphqlAPIRequest(
createManyOperationFactory({
objectMetadataSingularName: TEST_OBJECT_METADATA_NAME_SINGULAR,
objectMetadataPluralName: TEST_OBJECT_METADATA_NAME_PLURAL,
gqlFields: `
id
${joinColumnNameForManyToOneMorphRelationField1}`,
data: [
{
id: v4(),
manyToOneRelationFieldId: TEST_TARGET_OBJECT_RECORD_ID,
[joinColumnNameForManyToOneMorphRelationField1]:
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'],
...(withFilesField && uploadedFileId
? {
filesField: [
{
fileId: uploadedFileId,
label: 'Document.pdf',
},
],
}
: {}),
},
{
id: v4(),
},
],
}),
);
await makeGraphqlAPIRequest(
createManyOperationFactory({
objectMetadataSingularName: TEST_TARGET_OBJECT_METADATA_NAME_SINGULAR_1,
objectMetadataPluralName: TEST_TARGET_OBJECT_METADATA_NAME_PLURAL_1,
gqlFields: `id`,
data: [
{
id: TEST_TARGET_OBJECT_RECORD_ID_FIELD_VALUE,
},
],
}),
);
return {
objectMetadataId,
targetObjectMetadata1Id,
targetObjectMetadata2Id,
objectMetadataSingularName: TEST_OBJECT_METADATA_NAME_SINGULAR,
objectMetadataPluralName: TEST_OBJECT_METADATA_NAME_PLURAL,
};
};