mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 20:54:07 -08:00
577 lines
12 KiB
TypeScript
577 lines
12 KiB
TypeScript
import type { IDataObject } from '@/Interfaces';
|
|
import { augmentArray, augmentObject } from '@/AugmentObject';
|
|
import { deepCopy } from '@/utils';
|
|
|
|
describe('AugmentObject', () => {
|
|
describe('augmentArray', () => {
|
|
test('should work with arrays', () => {
|
|
const originalObject = [1, 2, 3, 4, null];
|
|
const copyOriginal = deepCopy(originalObject);
|
|
|
|
const augmentedObject = augmentArray(originalObject);
|
|
|
|
expect(augmentedObject.push(5)).toEqual(6);
|
|
expect(augmentedObject).toEqual([1, 2, 3, 4, null, 5]);
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
expect(augmentedObject.pop()).toEqual(5);
|
|
expect(augmentedObject).toEqual([1, 2, 3, 4, null]);
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
expect(augmentedObject.shift()).toEqual(1);
|
|
expect(augmentedObject).toEqual([2, 3, 4, null]);
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
expect(augmentedObject.unshift(1)).toEqual(5);
|
|
expect(augmentedObject).toEqual([1, 2, 3, 4, null]);
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
expect(augmentedObject.splice(1, 1)).toEqual([2]);
|
|
expect(augmentedObject).toEqual([1, 3, 4, null]);
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
expect(augmentedObject.slice(1)).toEqual([3, 4, null]);
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
expect(augmentedObject.reverse()).toEqual([null, 4, 3, 1]);
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
});
|
|
|
|
test('should work with arrays on any level', () => {
|
|
const originalObject = {
|
|
a: {
|
|
b: {
|
|
c: [
|
|
{
|
|
a3: {
|
|
b3: {
|
|
c3: '03' as string | null,
|
|
},
|
|
},
|
|
aa3: '01',
|
|
},
|
|
{
|
|
a3: {
|
|
b3: {
|
|
c3: '13',
|
|
},
|
|
},
|
|
aa3: '11',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
aa: [
|
|
{
|
|
a3: {
|
|
b3: '2',
|
|
},
|
|
aa3: '1',
|
|
},
|
|
],
|
|
};
|
|
const copyOriginal = deepCopy(originalObject);
|
|
|
|
const augmentedObject = augmentObject(originalObject);
|
|
|
|
// On first level
|
|
augmentedObject.aa[0].a3.b3 = '22';
|
|
expect(augmentedObject.aa[0].a3.b3).toEqual('22');
|
|
expect(originalObject.aa[0].a3.b3).toEqual('2');
|
|
|
|
// Make sure that also array operations as push and length work as expected
|
|
// On lower levels
|
|
augmentedObject.a.b.c[0].a3.b3.c3 = '033';
|
|
expect(augmentedObject.a.b.c[0].a3.b3.c3).toEqual('033');
|
|
expect(originalObject.a.b.c[0].a3.b3.c3).toEqual('03');
|
|
|
|
augmentedObject.a.b.c[1].a3.b3.c3 = '133';
|
|
expect(augmentedObject.a.b.c[1].a3.b3.c3).toEqual('133');
|
|
expect(originalObject.a.b.c[1].a3.b3.c3).toEqual('13');
|
|
|
|
augmentedObject.a.b.c.push({
|
|
a3: {
|
|
b3: {
|
|
c3: '23',
|
|
},
|
|
},
|
|
aa3: '21',
|
|
});
|
|
augmentedObject.a.b.c[2].a3.b3.c3 = '233';
|
|
expect(augmentedObject.a.b.c[2].a3.b3.c3).toEqual('233');
|
|
|
|
augmentedObject.a.b.c[2].a3.b3.c3 = '2333';
|
|
expect(augmentedObject.a.b.c[2].a3.b3.c3).toEqual('2333');
|
|
|
|
augmentedObject.a.b.c[2].a3.b3.c3 = null;
|
|
expect(augmentedObject.a.b.c[2].a3.b3.c3).toEqual(null);
|
|
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
expect(augmentedObject.a.b.c.length).toEqual(3);
|
|
|
|
expect(augmentedObject.aa).toEqual([
|
|
{
|
|
a3: {
|
|
b3: '22',
|
|
},
|
|
aa3: '1',
|
|
},
|
|
]);
|
|
|
|
expect(augmentedObject.a.b.c).toEqual([
|
|
{
|
|
a3: {
|
|
b3: {
|
|
c3: '033',
|
|
},
|
|
},
|
|
aa3: '01',
|
|
},
|
|
{
|
|
a3: {
|
|
b3: {
|
|
c3: '133',
|
|
},
|
|
},
|
|
aa3: '11',
|
|
},
|
|
{
|
|
a3: {
|
|
b3: {
|
|
c3: null,
|
|
},
|
|
},
|
|
aa3: '21',
|
|
},
|
|
]);
|
|
|
|
expect(augmentedObject).toEqual({
|
|
a: {
|
|
b: {
|
|
c: [
|
|
{
|
|
a3: {
|
|
b3: {
|
|
c3: '033',
|
|
},
|
|
},
|
|
aa3: '01',
|
|
},
|
|
{
|
|
a3: {
|
|
b3: {
|
|
c3: '133',
|
|
},
|
|
},
|
|
aa3: '11',
|
|
},
|
|
{
|
|
a3: {
|
|
b3: {
|
|
c3: null,
|
|
},
|
|
},
|
|
aa3: '21',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
aa: [
|
|
{
|
|
a3: {
|
|
b3: '22',
|
|
},
|
|
aa3: '1',
|
|
},
|
|
],
|
|
});
|
|
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
});
|
|
});
|
|
|
|
describe('augmentObject', () => {
|
|
test('should work with simple values on first level', () => {
|
|
const date = new Date(1680089084200);
|
|
const regexp = new RegExp('^test$', 'ig');
|
|
const originalObject: IDataObject = {
|
|
1: 11,
|
|
2: '22',
|
|
a: 111,
|
|
b: '222',
|
|
d: date,
|
|
r: regexp,
|
|
};
|
|
const copyOriginal = deepCopy(originalObject);
|
|
|
|
const augmentedObject = augmentObject(originalObject);
|
|
|
|
augmentedObject[1] = 911;
|
|
expect(originalObject[1]).toEqual(11);
|
|
expect(augmentedObject[1]).toEqual(911);
|
|
|
|
augmentedObject[2] = '922';
|
|
expect(originalObject[2]).toEqual('22');
|
|
expect(augmentedObject[2]).toEqual('922');
|
|
|
|
augmentedObject.a = 9111;
|
|
expect(originalObject.a).toEqual(111);
|
|
expect(augmentedObject.a).toEqual(9111);
|
|
|
|
augmentedObject.b = '9222';
|
|
expect(originalObject.b).toEqual('222');
|
|
expect(augmentedObject.b).toEqual('9222');
|
|
|
|
augmentedObject.c = 3;
|
|
|
|
expect({ ...originalObject, d: date.toJSON(), r: {} }).toEqual(copyOriginal);
|
|
|
|
expect(augmentedObject).toEqual({
|
|
1: 911,
|
|
2: '922',
|
|
a: 9111,
|
|
b: '9222',
|
|
c: 3,
|
|
d: date.toJSON(),
|
|
r: regexp.toString(),
|
|
});
|
|
});
|
|
|
|
test('should work with simple values on sub-level', () => {
|
|
const originalObject = {
|
|
a: {
|
|
b: {
|
|
cc: '3',
|
|
},
|
|
bb: '2',
|
|
},
|
|
aa: '1',
|
|
};
|
|
const copyOriginal = deepCopy(originalObject);
|
|
|
|
const augmentedObject = augmentObject(originalObject);
|
|
|
|
augmentedObject.a.bb = '92';
|
|
expect(originalObject.a.bb).toEqual('2');
|
|
expect(augmentedObject.a.bb).toEqual('92');
|
|
|
|
augmentedObject.a.b.cc = '93';
|
|
expect(originalObject.a.b.cc).toEqual('3');
|
|
expect(augmentedObject.a.b.cc).toEqual('93');
|
|
|
|
// @ts-ignore
|
|
augmentedObject.a.b.ccc = {
|
|
d: '4',
|
|
};
|
|
|
|
// @ts-ignore
|
|
expect(augmentedObject.a.b.ccc).toEqual({ d: '4' });
|
|
|
|
// @ts-ignore
|
|
augmentedObject.a.b.ccc.d = '94';
|
|
// @ts-ignore
|
|
expect(augmentedObject.a.b.ccc.d).toEqual('94');
|
|
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
expect(augmentedObject).toEqual({
|
|
a: {
|
|
b: {
|
|
cc: '93',
|
|
ccc: {
|
|
d: '94',
|
|
},
|
|
},
|
|
bb: '92',
|
|
},
|
|
aa: '1',
|
|
});
|
|
});
|
|
|
|
test('should work with complex values on first level', () => {
|
|
const originalObject = {
|
|
a: {
|
|
b: {
|
|
cc: '3',
|
|
c2: null,
|
|
},
|
|
bb: '2',
|
|
},
|
|
aa: '1',
|
|
};
|
|
const copyOriginal = deepCopy(originalObject);
|
|
|
|
const augmentedObject = augmentObject(originalObject);
|
|
|
|
augmentedObject.a = { new: 'NEW' };
|
|
expect(originalObject.a).toEqual({
|
|
b: {
|
|
c2: null,
|
|
cc: '3',
|
|
},
|
|
bb: '2',
|
|
});
|
|
expect(augmentedObject.a).toEqual({ new: 'NEW' });
|
|
|
|
augmentedObject.aa = '11';
|
|
expect(originalObject.aa).toEqual('1');
|
|
expect(augmentedObject.aa).toEqual('11');
|
|
|
|
augmentedObject.aaa = {
|
|
bbb: {
|
|
ccc: '333',
|
|
},
|
|
};
|
|
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
expect(augmentedObject).toEqual({
|
|
a: {
|
|
new: 'NEW',
|
|
},
|
|
aa: '11',
|
|
aaa: {
|
|
bbb: {
|
|
ccc: '333',
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
test('should work with delete and reset', () => {
|
|
const originalObject = {
|
|
a: {
|
|
b: {
|
|
c: {
|
|
d: '4' as string | undefined,
|
|
} as { d?: string; dd?: string } | undefined,
|
|
cc: '3' as string | undefined,
|
|
},
|
|
bb: '2' as string | undefined,
|
|
},
|
|
aa: '1' as string | undefined,
|
|
};
|
|
const copyOriginal = deepCopy(originalObject);
|
|
|
|
const augmentedObject = augmentObject(originalObject);
|
|
|
|
// Remove multiple values
|
|
delete augmentedObject.a.b.c!.d;
|
|
expect(augmentedObject.a.b.c!.d).toEqual(undefined);
|
|
expect(originalObject.a.b.c!.d).toEqual('4');
|
|
|
|
expect(augmentedObject).toEqual({
|
|
a: {
|
|
b: {
|
|
c: {},
|
|
cc: '3',
|
|
},
|
|
bb: '2',
|
|
},
|
|
aa: '1',
|
|
});
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
delete augmentedObject.a.b.c;
|
|
expect(augmentedObject.a.b.c).toEqual(undefined);
|
|
expect(originalObject.a.b.c).toEqual({ d: '4' });
|
|
|
|
expect(augmentedObject).toEqual({
|
|
a: {
|
|
b: {
|
|
cc: '3',
|
|
},
|
|
bb: '2',
|
|
},
|
|
aa: '1',
|
|
});
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
// Set deleted values again
|
|
augmentedObject.a.b.c = { dd: '444' };
|
|
expect(augmentedObject.a.b.c).toEqual({ dd: '444' });
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
augmentedObject.a.b.c.d = '44';
|
|
expect(augmentedObject).toEqual({
|
|
a: {
|
|
b: {
|
|
c: {
|
|
d: '44',
|
|
dd: '444',
|
|
},
|
|
cc: '3',
|
|
},
|
|
bb: '2',
|
|
},
|
|
aa: '1',
|
|
});
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
});
|
|
|
|
// Is almost identical to above test
|
|
test('should work with setting to undefined and reset', () => {
|
|
const originalObject = {
|
|
a: {
|
|
b: {
|
|
c: {
|
|
d: '4' as string | undefined,
|
|
} as { d?: string; dd?: string } | undefined,
|
|
cc: '3' as string | undefined,
|
|
},
|
|
bb: '2' as string | undefined,
|
|
},
|
|
aa: '1' as string | undefined,
|
|
};
|
|
const copyOriginal = deepCopy(originalObject);
|
|
|
|
const augmentedObject = augmentObject(originalObject);
|
|
|
|
// Remove multiple values
|
|
augmentedObject.a.b.c!.d = undefined;
|
|
expect(augmentedObject.a.b.c!.d).toEqual(undefined);
|
|
expect(originalObject.a.b.c!.d).toEqual('4');
|
|
|
|
expect(augmentedObject).toEqual({
|
|
a: {
|
|
b: {
|
|
c: {},
|
|
cc: '3',
|
|
},
|
|
bb: '2',
|
|
},
|
|
aa: '1',
|
|
});
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
augmentedObject.a.b.c = undefined;
|
|
expect(augmentedObject.a.b.c).toEqual(undefined);
|
|
expect(originalObject.a.b.c).toEqual({ d: '4' });
|
|
|
|
expect(augmentedObject).toEqual({
|
|
a: {
|
|
b: {
|
|
cc: '3',
|
|
},
|
|
bb: '2',
|
|
},
|
|
aa: '1',
|
|
});
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
// Set deleted values again
|
|
augmentedObject.a.b.c = { dd: '444' };
|
|
expect(augmentedObject.a.b.c).toEqual({ dd: '444' });
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
|
|
augmentedObject.a.b.c.d = '44';
|
|
expect(augmentedObject).toEqual({
|
|
a: {
|
|
b: {
|
|
c: {
|
|
d: '44',
|
|
dd: '444',
|
|
},
|
|
cc: '3',
|
|
},
|
|
bb: '2',
|
|
},
|
|
aa: '1',
|
|
});
|
|
expect(originalObject).toEqual(copyOriginal);
|
|
});
|
|
|
|
test('should be faster than doing a deepCopy', () => {
|
|
const iterations = 100;
|
|
const originalObject: IDataObject = {
|
|
a: {
|
|
b: {
|
|
c: {
|
|
d: {
|
|
e: {
|
|
f: 12345,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
for (let i = 0; i < 10; i++) {
|
|
originalObject[i.toString()] = deepCopy(originalObject);
|
|
}
|
|
|
|
let startTime = new Date().getTime();
|
|
for (let i = 0; i < iterations; i++) {
|
|
const augmentedObject = augmentObject(originalObject);
|
|
for (let i = 0; i < 5000; i++) {
|
|
augmentedObject.a!.b.c.d.e.f++;
|
|
}
|
|
}
|
|
const timeAugmented = new Date().getTime() - startTime;
|
|
|
|
startTime = new Date().getTime();
|
|
for (let i = 0; i < iterations; i++) {
|
|
const copiedObject = deepCopy(originalObject);
|
|
for (let i = 0; i < 5000; i++) {
|
|
copiedObject.a!.b.c.d.e.f++;
|
|
}
|
|
}
|
|
const timeCopied = new Date().getTime() - startTime;
|
|
|
|
expect(timeAugmented).toBeLessThan(timeCopied);
|
|
});
|
|
|
|
test('should ignore non-enumerable keys', () => {
|
|
const originalObject = { a: 1, b: 2 };
|
|
Object.defineProperty(originalObject, '__hiddenProp', { enumerable: false });
|
|
|
|
const augmentedObject = augmentObject(originalObject);
|
|
expect(Object.keys(augmentedObject)).toEqual(['a', 'b']);
|
|
});
|
|
|
|
test('should return property descriptors', () => {
|
|
const originalObject = {
|
|
x: {
|
|
y: {},
|
|
z: {},
|
|
},
|
|
};
|
|
const augmentedObject = augmentObject(originalObject);
|
|
|
|
expect(Object.getOwnPropertyDescriptor(augmentedObject.x, 'y')).toEqual({
|
|
configurable: true,
|
|
enumerable: true,
|
|
value: {},
|
|
writable: true,
|
|
});
|
|
|
|
delete augmentedObject.x.y;
|
|
expect(augmentedObject.x.hasOwnProperty('y')).toEqual(false);
|
|
|
|
augmentedObject.x.y = 42;
|
|
expect(augmentedObject.x.hasOwnProperty('y')).toEqual(true);
|
|
expect(Object.getOwnPropertyDescriptor(augmentedObject.x, 'y')).toEqual({
|
|
configurable: true,
|
|
enumerable: true,
|
|
value: 42,
|
|
writable: true,
|
|
});
|
|
});
|
|
|
|
test('should return valid values on `has` calls', () => {
|
|
const originalObject = {
|
|
x: {
|
|
y: {},
|
|
},
|
|
};
|
|
const augmentedObject = augmentObject(originalObject);
|
|
expect('y' in augmentedObject.x).toBe(true);
|
|
expect('z' in augmentedObject.x).toBe(false);
|
|
|
|
augmentedObject.x.z = 5;
|
|
expect('z' in augmentedObject.x).toBe(true);
|
|
expect('y' in augmentedObject.x).toBe(true);
|
|
});
|
|
});
|
|
});
|