4fbdfb6abc
## Introduction After enabling flag by default got following errors: ```ts Test Suites: 48 failed, 1 skipped, 97 passed, 145 of 146 total Tests: 499 failed, 1 skipped, 644 passed, 1144 total Snapshots: 61 failed, 133 passed, 194 total Time: 363.226 s Ran all test suites. ``` ## From <img width="2952" height="1510" alt="image" src="https://github.com/user-attachments/assets/7e3b20c6-2552-40a7-90bb-2d7b3002c895" /> ## To <img width="3134" height="1510" alt="image" src="https://github.com/user-attachments/assets/4fc9ada4-3c14-4333-a1db-11daf87db8d6" /> There's a huge test bundle in the latest shard that we could split up ## Notes - Set as failing morph relation field rename as for the moment we do not handle relation field mutation - fixed the object update and creation validation adding label identifier field metadata id checks - and more Some integrations tests are still on the v1 ( they have before and after all disabling and re-enabling the flat ) but mainly we now have more coverage on the v2 than the v1. Mainly related records, uniqueness have to be migrated the v2 and so tests too
332 lines
11 KiB
TypeScript
332 lines
11 KiB
TypeScript
import { faker } from '@faker-js/faker';
|
|
import { createOneFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata.util';
|
|
import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util';
|
|
import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util';
|
|
import { getMockCreateObjectInput } from 'test/integration/metadata/suites/object-metadata/utils/generate-mock-create-object-metadata-input';
|
|
import { updateOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/update-one-object-metadata.util';
|
|
import { type EachTestingContext } from 'twenty-shared/testing';
|
|
import { FieldMetadataType } from 'twenty-shared/types';
|
|
import { extractRecordIdsAndDatesAsExpectAny } from 'test/utils/extract-record-ids-and-dates-as-expect-any';
|
|
|
|
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
|
|
|
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
|
|
|
type GlobalTestContext = {
|
|
objectMetadataIds: {
|
|
targetObjectId: string;
|
|
sourceObjectId: string;
|
|
};
|
|
collisionFieldName: string;
|
|
collisionFieldNameWithId: string;
|
|
collisionFieldLabel: string;
|
|
collisionFieldLabelWithId: string;
|
|
};
|
|
const globalTestContext: GlobalTestContext = {
|
|
objectMetadataIds: {
|
|
targetObjectId: '',
|
|
sourceObjectId: '',
|
|
},
|
|
collisionFieldLabel: 'Field Name',
|
|
collisionFieldName: 'fieldName',
|
|
collisionFieldNameWithId: 'fieldNameBisId',
|
|
collisionFieldLabelWithId: 'Field Name Bis Id',
|
|
};
|
|
|
|
type TestedRelationCreationPayload = Partial<
|
|
NonNullable<CreateFieldInput['relationCreationPayload']>
|
|
>;
|
|
|
|
type TestedContext = {
|
|
input: {
|
|
name?: string;
|
|
relationCreationPayload?: TestedRelationCreationPayload;
|
|
};
|
|
};
|
|
|
|
type CreateOneObjectMetadataItemTestingContext = EachTestingContext<
|
|
TestedContext | ((context: GlobalTestContext) => TestedContext)
|
|
>[];
|
|
describe('Field metadata relation creation should fail', () => {
|
|
const failingLabelsCreationTestsUseCase: CreateOneObjectMetadataItemTestingContext =
|
|
[
|
|
// TODO @prastoin add coverage other fields such as the Type, icon etc etc ( using edge cases fuzzing etc )
|
|
{
|
|
title: '(relationCreationPayload) when targetFieldLabel is empty',
|
|
context: {
|
|
input: { relationCreationPayload: { targetFieldLabel: '' } },
|
|
},
|
|
},
|
|
{
|
|
title:
|
|
'(relationCreationPayload) when targetFieldLabel exceeds maximum length',
|
|
context: {
|
|
input: {
|
|
relationCreationPayload: { targetFieldLabel: 'A'.repeat(64) },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
// Not handled gracefully should be refactored
|
|
title:
|
|
'(relationCreationPayload) when targetObjectMetadataId is unknown',
|
|
context: {
|
|
input: {
|
|
relationCreationPayload: {
|
|
targetObjectMetadataId: faker.string.uuid(),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
title:
|
|
'(relationCreationPayload) when targetFieldLabel contains only whitespace',
|
|
context: {
|
|
input: {
|
|
relationCreationPayload: { targetFieldLabel: ' ' },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
title:
|
|
'(relationCreationPayload) when targetFieldLabel conflicts with an existing field on target object metadata id',
|
|
context: ({ collisionFieldLabel, objectMetadataIds }) => ({
|
|
input: {
|
|
relationCreationPayload: {
|
|
targetObjectMetadataId: objectMetadataIds.targetObjectId,
|
|
targetFieldLabel: collisionFieldLabel,
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
{
|
|
title:
|
|
'(relationCreationPayload) when targetFieldLabel conflicts with an existing {name}Id on target object metadata id',
|
|
context: ({ collisionFieldLabelWithId, objectMetadataIds }) => ({
|
|
input: {
|
|
relationCreationPayload: {
|
|
targetObjectMetadataId: objectMetadataIds.targetObjectId,
|
|
targetFieldLabel: collisionFieldLabelWithId,
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
{
|
|
title: '(relationCreationPayload) when type is not provided',
|
|
context: {
|
|
input: {
|
|
relationCreationPayload: { type: undefined },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
title: '(relationCreationPayload) when type is a wrong value',
|
|
context: {
|
|
input: {
|
|
relationCreationPayload: { type: 'wrong' as RelationType },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
title: 'when {name}Id is already used',
|
|
context: ({ collisionFieldNameWithId }) => ({
|
|
input: {
|
|
name: collisionFieldNameWithId,
|
|
relationCreationPayload: { targetFieldIcon: '' },
|
|
},
|
|
}),
|
|
},
|
|
{
|
|
title:
|
|
'when target and source are the same object and name are the same',
|
|
context: {
|
|
input: {
|
|
name: 'relationName',
|
|
relationCreationPayload: {
|
|
targetObjectMetadataId:
|
|
globalTestContext.objectMetadataIds.sourceObjectId,
|
|
targetFieldLabel: 'Relation Name',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
beforeAll(async () => {
|
|
const {
|
|
data: {
|
|
createOneObject: { id: sourceObjectId },
|
|
},
|
|
} = await createOneObjectMetadata({
|
|
input: getMockCreateObjectInput({
|
|
namePlural: 'sourceObjects',
|
|
nameSingular: 'sourceObject',
|
|
}),
|
|
});
|
|
|
|
const {
|
|
data: {
|
|
createOneObject: { id: targetObjectId },
|
|
},
|
|
} = await createOneObjectMetadata({
|
|
input: getMockCreateObjectInput({
|
|
namePlural: 'targetObjects',
|
|
nameSingular: 'targetObject',
|
|
}),
|
|
});
|
|
|
|
globalTestContext.objectMetadataIds = {
|
|
sourceObjectId,
|
|
targetObjectId,
|
|
};
|
|
|
|
const { data: collisionFieldWithLabelTargetData } =
|
|
await createOneFieldMetadata({
|
|
input: {
|
|
objectMetadataId: targetObjectId,
|
|
name: globalTestContext.collisionFieldName,
|
|
label: 'LabelThatCouldBeAnything',
|
|
isLabelSyncedWithName: false,
|
|
type: FieldMetadataType.TEXT,
|
|
},
|
|
});
|
|
|
|
const { data: collisionFieldWithIdTargetData } =
|
|
await createOneFieldMetadata({
|
|
input: {
|
|
objectMetadataId: targetObjectId,
|
|
name: globalTestContext.collisionFieldNameWithId,
|
|
label: 'LabelThatCouldBeAnything',
|
|
isLabelSyncedWithName: false,
|
|
type: FieldMetadataType.TEXT,
|
|
},
|
|
});
|
|
|
|
const { data: collisionFieldWithLabelSourceData } =
|
|
await createOneFieldMetadata({
|
|
input: {
|
|
objectMetadataId: sourceObjectId,
|
|
name: globalTestContext.collisionFieldName,
|
|
label: 'LabelThatCouldBeAnything',
|
|
isLabelSyncedWithName: false,
|
|
type: FieldMetadataType.TEXT,
|
|
},
|
|
});
|
|
|
|
const { data: collisionFieldWithIdSourceData } =
|
|
await createOneFieldMetadata({
|
|
input: {
|
|
objectMetadataId: sourceObjectId,
|
|
name: globalTestContext.collisionFieldNameWithId,
|
|
label: 'LabelThatCouldBeAnything',
|
|
isLabelSyncedWithName: false,
|
|
type: FieldMetadataType.TEXT,
|
|
},
|
|
});
|
|
|
|
expect(collisionFieldWithLabelTargetData).toBeDefined();
|
|
expect(collisionFieldWithIdTargetData).toBeDefined();
|
|
expect(collisionFieldWithLabelSourceData).toBeDefined();
|
|
expect(collisionFieldWithIdSourceData).toBeDefined();
|
|
});
|
|
|
|
afterAll(async () => {
|
|
for (const objectMetadataId of Object.values(
|
|
globalTestContext.objectMetadataIds,
|
|
)) {
|
|
await updateOneObjectMetadata({
|
|
expectToFail: false,
|
|
input: {
|
|
idToUpdate: objectMetadataId,
|
|
updatePayload: {
|
|
isActive: false,
|
|
},
|
|
},
|
|
});
|
|
await deleteOneObjectMetadata({
|
|
input: {
|
|
idToDelete: objectMetadataId,
|
|
},
|
|
});
|
|
}
|
|
});
|
|
|
|
it.each(failingLabelsCreationTestsUseCase)(
|
|
'relation ONE_TO_MANY $title',
|
|
async ({ context }) => {
|
|
const computedRelationCreationPayload =
|
|
typeof context === 'function'
|
|
? context(globalTestContext).input.relationCreationPayload
|
|
: context.input.relationCreationPayload;
|
|
|
|
const computedName =
|
|
typeof context === 'function'
|
|
? context(globalTestContext).input.name
|
|
: context.input.name;
|
|
|
|
const { errors } = await createOneFieldMetadata({
|
|
expectToFail: true,
|
|
input: {
|
|
objectMetadataId: globalTestContext.objectMetadataIds.sourceObjectId,
|
|
name: computedName ?? 'fieldname',
|
|
label: 'Relation field',
|
|
isLabelSyncedWithName: false,
|
|
type: FieldMetadataType.RELATION,
|
|
relationCreationPayload: {
|
|
targetFieldLabel: 'defaultTargetFieldLabel',
|
|
type: RelationType.ONE_TO_MANY,
|
|
targetObjectMetadataId:
|
|
globalTestContext.objectMetadataIds.targetObjectId,
|
|
targetFieldIcon: 'IconBuildingSkyscraper',
|
|
...computedRelationCreationPayload,
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(errors).toBeDefined();
|
|
expect(errors).toMatchSnapshot(
|
|
extractRecordIdsAndDatesAsExpectAny(errors),
|
|
);
|
|
},
|
|
);
|
|
|
|
it.each(failingLabelsCreationTestsUseCase)(
|
|
'relation MANY_TO_ONE $title',
|
|
async ({ context }) => {
|
|
const computedRelationCreationPayload =
|
|
typeof context === 'function'
|
|
? context(globalTestContext).input.relationCreationPayload
|
|
: context.input.relationCreationPayload;
|
|
|
|
const computedName =
|
|
typeof context === 'function'
|
|
? context(globalTestContext).input.name
|
|
: context.input.name;
|
|
|
|
const { errors } = await createOneFieldMetadata({
|
|
expectToFail: true,
|
|
input: {
|
|
objectMetadataId: globalTestContext.objectMetadataIds.sourceObjectId,
|
|
name: computedName ?? 'fieldname',
|
|
label: 'Relation field',
|
|
isLabelSyncedWithName: false,
|
|
type: FieldMetadataType.RELATION,
|
|
relationCreationPayload: {
|
|
targetFieldLabel: 'defaultTargetFieldLabel',
|
|
type: RelationType.MANY_TO_ONE,
|
|
targetObjectMetadataId:
|
|
globalTestContext.objectMetadataIds.targetObjectId,
|
|
targetFieldIcon: 'IconBuildingSkyscraper',
|
|
...computedRelationCreationPayload,
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(errors).toBeDefined();
|
|
expect(errors).toMatchSnapshot(
|
|
extractRecordIdsAndDatesAsExpectAny(errors),
|
|
);
|
|
},
|
|
);
|
|
});
|