Files
twenty/packages/twenty-shared/src/utils/__tests__/compute-diff-between-objects.test.ts
T
Weiko c1e4756f9c Add is active to overridable entities and deactivation logic for page layouts (#19200)
- Replace soft-deletion (deletedAt) with isActive boolean for
overridable entities (tabs, widgets, viewFieldGroups, viewFields).
Standard entities are deactivated (isActive: false) when removed from
update payloads, while custom entities are hard-deleted.
- When a viewFieldGroup is deactivated/deleted, its viewFields are
reassigned to the next section by position (or null if none remain).
- Add isActive: true filters to viewFieldGroup and viewField API queries
so deactivated entities are excluded from responses.

Next: 
- fields-widget-upsert.service.ts should be refactored a bit
- Add restore logic
2026-04-02 14:50:50 +00:00

198 lines
5.6 KiB
TypeScript

import { isDefined } from '@/utils/validation';
import { computeDiffBetweenObjects } from '../compute-diff-between-objects';
const isEntityIncludedByDeletedAt = (entity: {
deletedAt: string | null;
}): boolean => !isDefined(entity.deletedAt);
const isEntityIncludedByIsActive = (entity: { isActive: boolean }): boolean =>
entity.isActive;
describe('computeDiffBetweenObjects', () => {
it('should return the correct diff', () => {
const existingObjects = [
{ id: '1', name: 'Object 1', deletedAt: null },
{ id: '2', name: 'Object 2', deletedAt: null },
];
const receivedObjects = [
{ id: '1', name: 'Object 1' },
{ id: '3', name: 'Object 3' },
];
const diff = computeDiffBetweenObjects({
existingObjects,
receivedObjects,
propertiesToCompare: ['name'],
isEntityIncluded: isEntityIncludedByDeletedAt,
});
expect(diff).toEqual({
toCreate: [{ id: '3', name: 'Object 3' }],
toUpdate: [],
toRestoreAndUpdate: [],
idsToRemove: ['2'],
});
});
it('should return the correct diff when the properties to compare are empty', () => {
const existingObjects = [{ id: '1', name: 'Object 1', deletedAt: null }];
const receivedObjects = [{ id: '1', name: 'Object 1' }];
const diff = computeDiffBetweenObjects({
existingObjects,
receivedObjects,
propertiesToCompare: [],
isEntityIncluded: isEntityIncludedByDeletedAt,
});
expect(diff).toEqual({
toCreate: [],
toUpdate: [],
toRestoreAndUpdate: [],
idsToRemove: [],
});
});
it('should return the correct diff when the existing objects are empty', () => {
const existingObjects: { id: string; name: string; deletedAt: null }[] = [];
const receivedObjects = [{ id: '1', name: 'Object 1' }];
const diff = computeDiffBetweenObjects({
existingObjects,
receivedObjects,
propertiesToCompare: ['name'],
isEntityIncluded: isEntityIncludedByDeletedAt,
});
expect(diff).toEqual({
toCreate: [{ id: '1', name: 'Object 1' }],
toUpdate: [],
toRestoreAndUpdate: [],
idsToRemove: [],
});
});
it('should return the correct diff when the received objects are empty', () => {
const existingObjects = [{ id: '1', name: 'Object 1', deletedAt: null }];
const receivedObjects: { id: string; name: string }[] = [];
const diff = computeDiffBetweenObjects({
existingObjects,
receivedObjects,
propertiesToCompare: ['name'],
isEntityIncluded: isEntityIncludedByDeletedAt,
});
expect(diff).toEqual({
toCreate: [],
toUpdate: [],
toRestoreAndUpdate: [],
idsToRemove: ['1'],
});
});
it('should detect updates when properties change', () => {
const existingObjects = [{ id: '1', name: 'Object 1', deletedAt: null }];
const receivedObjects = [{ id: '1', name: 'Updated Object 1' }];
const diff = computeDiffBetweenObjects({
existingObjects,
receivedObjects,
propertiesToCompare: ['name'],
isEntityIncluded: isEntityIncludedByDeletedAt,
});
expect(diff).toEqual({
toCreate: [],
toUpdate: [{ id: '1', name: 'Updated Object 1' }],
toRestoreAndUpdate: [],
idsToRemove: [],
});
});
it('should restore and update excluded objects when using deletedAt', () => {
const existingObjects = [
{ id: '1', name: 'Object 1', deletedAt: '2024-01-01' },
];
const receivedObjects = [{ id: '1', name: 'Restored Object 1' }];
const diff = computeDiffBetweenObjects({
existingObjects,
receivedObjects,
propertiesToCompare: ['name'],
isEntityIncluded: isEntityIncludedByDeletedAt,
});
expect(diff).toEqual({
toCreate: [],
toUpdate: [],
toRestoreAndUpdate: [{ id: '1', name: 'Restored Object 1' }],
idsToRemove: [],
});
});
it('should not include excluded objects in idsToRemove', () => {
const existingObjects = [
{ id: '1', name: 'Object 1', deletedAt: null },
{ id: '2', name: 'Object 2', deletedAt: '2024-01-01' },
];
const receivedObjects: { id: string; name: string }[] = [];
const diff = computeDiffBetweenObjects({
existingObjects,
receivedObjects,
propertiesToCompare: ['name'],
isEntityIncluded: isEntityIncludedByDeletedAt,
});
expect(diff).toEqual({
toCreate: [],
toUpdate: [],
toRestoreAndUpdate: [],
idsToRemove: ['1'],
});
});
it('should restore and update inactive objects when using isActive', () => {
const existingObjects = [{ id: '1', name: 'Object 1', isActive: false }];
const receivedObjects = [{ id: '1', name: 'Restored Object 1' }];
const diff = computeDiffBetweenObjects({
existingObjects,
receivedObjects,
propertiesToCompare: ['name'],
isEntityIncluded: isEntityIncludedByIsActive,
});
expect(diff).toEqual({
toCreate: [],
toUpdate: [],
toRestoreAndUpdate: [{ id: '1', name: 'Restored Object 1' }],
idsToRemove: [],
});
});
it('should not include inactive objects in idsToRemove when using isActive', () => {
const existingObjects = [
{ id: '1', name: 'Object 1', isActive: true },
{ id: '2', name: 'Object 2', isActive: false },
];
const receivedObjects: { id: string; name: string }[] = [];
const diff = computeDiffBetweenObjects({
existingObjects,
receivedObjects,
propertiesToCompare: ['name'],
isEntityIncluded: isEntityIncludedByIsActive,
});
expect(diff).toEqual({
toCreate: [],
toUpdate: [],
toRestoreAndUpdate: [],
idsToRemove: ['1'],
});
});
});