499 lines
9.2 KiB
JavaScript
499 lines
9.2 KiB
JavaScript
|
/**
|
||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||
|
*
|
||
|
* This source code is licensed under the MIT license found in the
|
||
|
* LICENSE file in the root directory of this source tree.
|
||
|
*
|
||
|
* @jest-environment node
|
||
|
*/
|
||
|
'use strict';
|
||
|
|
||
|
const ReactNativeAttributePayload = '../ReactNativeAttributePayload' |> require(%);
|
||
|
const diff = ReactNativeAttributePayload.diff;
|
||
|
'ReactNativeAttributePayload' |> describe(%, () => {
|
||
|
'should work with simple example' |> it(%, () => {
|
||
|
({
|
||
|
a: null,
|
||
|
b: 2
|
||
|
}) |> (diff({
|
||
|
a: 1,
|
||
|
c: 3
|
||
|
}, {
|
||
|
b: 2,
|
||
|
c: 3
|
||
|
}, {
|
||
|
a: true,
|
||
|
b: true
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should skip fields that are equal' |> it(%, () => {
|
||
|
null |> (diff({
|
||
|
a: 1,
|
||
|
b: 'two',
|
||
|
c: true,
|
||
|
d: false,
|
||
|
e: undefined,
|
||
|
f: 0
|
||
|
}, {
|
||
|
a: 1,
|
||
|
b: 'two',
|
||
|
c: true,
|
||
|
d: false,
|
||
|
e: undefined,
|
||
|
f: 0
|
||
|
}, {
|
||
|
a: true,
|
||
|
b: true,
|
||
|
c: true,
|
||
|
d: true,
|
||
|
e: true,
|
||
|
f: true
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should remove fields' |> it(%, () => {
|
||
|
({
|
||
|
a: null
|
||
|
}) |> (diff({
|
||
|
a: 1
|
||
|
}, {}, {
|
||
|
a: true
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should remove fields that are set to undefined' |> it(%, () => {
|
||
|
({
|
||
|
a: null
|
||
|
}) |> (diff({
|
||
|
a: 1
|
||
|
}, {
|
||
|
a: undefined
|
||
|
}, {
|
||
|
a: true
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should ignore invalid fields' |> it(%, () => {
|
||
|
null |> (diff({
|
||
|
a: 1
|
||
|
}, {
|
||
|
b: 2
|
||
|
}, {}) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should use the diff attribute' |> it(%, () => {
|
||
|
const diffA = ((a, b) => true) |> jest.fn(%);
|
||
|
const diffB = ((a, b) => false) |> jest.fn(%);
|
||
|
({
|
||
|
a: [2]
|
||
|
}) |> (diff({
|
||
|
a: [1],
|
||
|
b: [3]
|
||
|
}, {
|
||
|
a: [2],
|
||
|
b: [4]
|
||
|
}, {
|
||
|
a: {
|
||
|
diff: diffA
|
||
|
},
|
||
|
b: {
|
||
|
diff: diffB
|
||
|
}
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
[1] |> (diffA |> expect(%)).toBeCalledWith(%, [2]);
|
||
|
[3] |> (diffB |> expect(%)).toBeCalledWith(%, [4]);
|
||
|
});
|
||
|
'should not use the diff attribute on addition/removal' |> it(%, () => {
|
||
|
const diffA = jest.fn();
|
||
|
const diffB = jest.fn();
|
||
|
({
|
||
|
a: null,
|
||
|
b: [2]
|
||
|
}) |> (diff({
|
||
|
a: [1]
|
||
|
}, {
|
||
|
b: [2]
|
||
|
}, {
|
||
|
a: {
|
||
|
diff: diffA
|
||
|
},
|
||
|
b: {
|
||
|
diff: diffB
|
||
|
}
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
(diffA |> expect(%)).not.toBeCalled();
|
||
|
(diffB |> expect(%)).not.toBeCalled();
|
||
|
});
|
||
|
'should do deep diffs of Objects by default' |> it(%, () => {
|
||
|
({
|
||
|
a: [2],
|
||
|
c: {
|
||
|
k: [4, 5]
|
||
|
}
|
||
|
}) |> (diff({
|
||
|
a: [1],
|
||
|
b: {
|
||
|
k: [3, 4]
|
||
|
},
|
||
|
c: {
|
||
|
k: [4, 4]
|
||
|
}
|
||
|
}, {
|
||
|
a: [2],
|
||
|
b: {
|
||
|
k: [3, 4]
|
||
|
},
|
||
|
c: {
|
||
|
k: [4, 5]
|
||
|
}
|
||
|
}, {
|
||
|
a: true,
|
||
|
b: true,
|
||
|
c: true
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should work with undefined styles' |> it(%, () => {
|
||
|
({
|
||
|
b: null
|
||
|
}) |> (diff({
|
||
|
style: {
|
||
|
a: '#ffffff',
|
||
|
b: 1
|
||
|
}
|
||
|
}, {
|
||
|
style: undefined
|
||
|
}, {
|
||
|
style: {
|
||
|
b: true
|
||
|
}
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
({
|
||
|
b: 1
|
||
|
}) |> (diff({
|
||
|
style: undefined
|
||
|
}, {
|
||
|
style: {
|
||
|
a: '#ffffff',
|
||
|
b: 1
|
||
|
}
|
||
|
}, {
|
||
|
style: {
|
||
|
b: true
|
||
|
}
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
null |> (diff({
|
||
|
style: undefined
|
||
|
}, {
|
||
|
style: undefined
|
||
|
}, {
|
||
|
style: {
|
||
|
b: true
|
||
|
}
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should work with empty styles' |> it(%, () => {
|
||
|
({
|
||
|
a: null
|
||
|
}) |> (diff({
|
||
|
a: 1,
|
||
|
c: 3
|
||
|
}, {}, {
|
||
|
a: true,
|
||
|
b: true
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
({
|
||
|
a: 1
|
||
|
}) |> (diff({}, {
|
||
|
a: 1,
|
||
|
c: 3
|
||
|
}, {
|
||
|
a: true,
|
||
|
b: true
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
null |> (diff({}, {}, {
|
||
|
a: true,
|
||
|
b: true
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should flatten nested styles and predefined styles' |> it(%, () => {
|
||
|
const validStyleAttribute = {
|
||
|
someStyle: {
|
||
|
foo: true,
|
||
|
bar: true
|
||
|
}
|
||
|
};
|
||
|
({
|
||
|
foo: 1,
|
||
|
bar: 2
|
||
|
}) |> (diff({}, {
|
||
|
someStyle: [{
|
||
|
foo: 1
|
||
|
}, {
|
||
|
bar: 2
|
||
|
}]
|
||
|
}, validStyleAttribute) |> expect(%)).toEqual(%);
|
||
|
({
|
||
|
foo: null,
|
||
|
bar: null
|
||
|
}) |> (diff({
|
||
|
someStyle: [{
|
||
|
foo: 1
|
||
|
}, {
|
||
|
bar: 2
|
||
|
}]
|
||
|
}, {}, validStyleAttribute) |> expect(%)).toEqual(%);
|
||
|
const barStyle = {
|
||
|
bar: 3
|
||
|
};
|
||
|
({
|
||
|
foo: 2,
|
||
|
bar: 3
|
||
|
}) |> (diff({}, {
|
||
|
someStyle: [[{
|
||
|
foo: 1
|
||
|
}, {
|
||
|
foo: 2
|
||
|
}], barStyle]
|
||
|
}, validStyleAttribute) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should reset a value to a previous if it is removed' |> it(%, () => {
|
||
|
const validStyleAttribute = {
|
||
|
someStyle: {
|
||
|
foo: true,
|
||
|
bar: true
|
||
|
}
|
||
|
};
|
||
|
({
|
||
|
foo: 1,
|
||
|
bar: 2
|
||
|
}) |> (diff({
|
||
|
someStyle: [{
|
||
|
foo: 1
|
||
|
}, {
|
||
|
foo: 3
|
||
|
}]
|
||
|
}, {
|
||
|
someStyle: [{
|
||
|
foo: 1
|
||
|
}, {
|
||
|
bar: 2
|
||
|
}]
|
||
|
}, validStyleAttribute) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should not clear removed props if they are still in another slot' |> it(%, () => {
|
||
|
const validStyleAttribute = {
|
||
|
someStyle: {
|
||
|
foo: true,
|
||
|
bar: true
|
||
|
}
|
||
|
};
|
||
|
// this should ideally be null. heuristic tradeoff.
|
||
|
({
|
||
|
foo: 3
|
||
|
}) |> (diff({
|
||
|
someStyle: [{}, {
|
||
|
foo: 3,
|
||
|
bar: 2
|
||
|
}]
|
||
|
}, {
|
||
|
someStyle: [{
|
||
|
foo: 3
|
||
|
}, {
|
||
|
bar: 2
|
||
|
}]
|
||
|
}, validStyleAttribute) |> expect(%)).toEqual(%);
|
||
|
({
|
||
|
bar: 2,
|
||
|
foo: 1
|
||
|
}) |> (diff({
|
||
|
someStyle: [{}, {
|
||
|
foo: 3,
|
||
|
bar: 2
|
||
|
}]
|
||
|
}, {
|
||
|
someStyle: [{
|
||
|
foo: 1,
|
||
|
bar: 1
|
||
|
}, {
|
||
|
bar: 2
|
||
|
}]
|
||
|
}, validStyleAttribute) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should clear a prop if a later style is explicit null/undefined' |> it(%, () => {
|
||
|
const validStyleAttribute = {
|
||
|
someStyle: {
|
||
|
foo: true,
|
||
|
bar: true
|
||
|
}
|
||
|
};
|
||
|
({
|
||
|
foo: null
|
||
|
}) |> (diff({
|
||
|
someStyle: [{}, {
|
||
|
foo: 3,
|
||
|
bar: 2
|
||
|
}]
|
||
|
}, {
|
||
|
someStyle: [{
|
||
|
foo: 1
|
||
|
}, {
|
||
|
bar: 2,
|
||
|
foo: null
|
||
|
}]
|
||
|
}, validStyleAttribute) |> expect(%)).toEqual(%);
|
||
|
({
|
||
|
foo: null
|
||
|
}) |> (diff({
|
||
|
someStyle: [{
|
||
|
foo: 3
|
||
|
}, {
|
||
|
foo: null,
|
||
|
bar: 2
|
||
|
}]
|
||
|
}, {
|
||
|
someStyle: [{
|
||
|
foo: null
|
||
|
}, {
|
||
|
bar: 2
|
||
|
}]
|
||
|
}, validStyleAttribute) |> expect(%)).toEqual(%);
|
||
|
// this should ideally be null. heuristic.
|
||
|
|
||
|
// Test the same case with object equality because an early bailout doesn't
|
||
|
// work in this case.
|
||
|
({
|
||
|
foo: null
|
||
|
}) |> (diff({
|
||
|
someStyle: [{
|
||
|
foo: 1
|
||
|
}, {
|
||
|
foo: null
|
||
|
}]
|
||
|
}, {
|
||
|
someStyle: [{
|
||
|
foo: 2
|
||
|
}, {
|
||
|
foo: null
|
||
|
}]
|
||
|
}, validStyleAttribute) |> expect(%)).toEqual(%);
|
||
|
const fooObj = {
|
||
|
foo: 3
|
||
|
};
|
||
|
// this should ideally be null. heuristic.
|
||
|
({
|
||
|
foo: 3
|
||
|
}) |> (diff({
|
||
|
someStyle: [{
|
||
|
foo: 1
|
||
|
}, fooObj]
|
||
|
}, {
|
||
|
someStyle: [{
|
||
|
foo: 2
|
||
|
}, fooObj]
|
||
|
}, validStyleAttribute) |> expect(%)).toEqual(%);
|
||
|
// this should ideally be null. heuristic.
|
||
|
({
|
||
|
foo: null
|
||
|
}) |> (diff({
|
||
|
someStyle: [{
|
||
|
foo: 1
|
||
|
}, {
|
||
|
foo: 3
|
||
|
}]
|
||
|
}, {
|
||
|
someStyle: [{
|
||
|
foo: 2
|
||
|
}, {
|
||
|
foo: undefined
|
||
|
}]
|
||
|
}, validStyleAttribute) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
// Function properties are just markers to native that events should be sent.
|
||
|
'handles attributes defined multiple times' |> it(%, () => {
|
||
|
const validAttributes = {
|
||
|
foo: true,
|
||
|
style: {
|
||
|
foo: true
|
||
|
}
|
||
|
};
|
||
|
({
|
||
|
foo: 2
|
||
|
}) |> (diff({}, {
|
||
|
foo: 4,
|
||
|
style: {
|
||
|
foo: 2
|
||
|
}
|
||
|
}, validAttributes) |> expect(%)).toEqual(%);
|
||
|
({
|
||
|
foo: 2
|
||
|
}) |> (diff({
|
||
|
foo: 4
|
||
|
}, {
|
||
|
style: {
|
||
|
foo: 2
|
||
|
}
|
||
|
}, validAttributes) |> expect(%)).toEqual(%);
|
||
|
({
|
||
|
foo: 4
|
||
|
}) |> (diff({
|
||
|
style: {
|
||
|
foo: 2
|
||
|
}
|
||
|
}, {
|
||
|
foo: 4
|
||
|
}, validAttributes) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should convert functions to booleans' |> it(%, () => {
|
||
|
// Note that if the property changes from one function to another, we don't
|
||
|
// need to send an update.
|
||
|
({
|
||
|
a: null,
|
||
|
c: true
|
||
|
}) |> (diff({
|
||
|
a: function () {
|
||
|
return 1;
|
||
|
},
|
||
|
b: function () {
|
||
|
return 2;
|
||
|
},
|
||
|
c: 3
|
||
|
}, {
|
||
|
b: function () {
|
||
|
return 9;
|
||
|
},
|
||
|
c: function () {
|
||
|
return 3;
|
||
|
}
|
||
|
}, {
|
||
|
a: true,
|
||
|
b: true,
|
||
|
c: true
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should skip changed functions' |> it(%, () => {
|
||
|
null |> (diff({
|
||
|
a: function () {
|
||
|
return 1;
|
||
|
}
|
||
|
}, {
|
||
|
a: function () {
|
||
|
return 9;
|
||
|
}
|
||
|
}, {
|
||
|
a: true
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
'should skip deeply-nested changed functions' |> it(%, () => {
|
||
|
null |> (diff({
|
||
|
wrapper: {
|
||
|
a: function () {
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
}, {
|
||
|
wrapper: {
|
||
|
a: function () {
|
||
|
return 9;
|
||
|
}
|
||
|
}
|
||
|
}, {
|
||
|
wrapper: true
|
||
|
}) |> expect(%)).toEqual(%);
|
||
|
});
|
||
|
});
|