object.test.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import { describe, expect, it } from 'vitest';
  2. import { getIn, isEmptyArray, isNaN, isPromise, shallowSetIn } from '../src/utils';
  3. describe('object', () => {
  4. describe('isEmptyArray', () => {
  5. it('returns true when an empty array is passed in', () => {
  6. expect(isEmptyArray([])).toBe(true);
  7. });
  8. it('returns false when anything other than empty array is passed in', () => {
  9. expect(isEmptyArray()).toBe(false);
  10. expect(isEmptyArray(null)).toBe(false);
  11. expect(isEmptyArray(123)).toBe(false);
  12. expect(isEmptyArray('abc')).toBe(false);
  13. expect(isEmptyArray({})).toBe(false);
  14. expect(isEmptyArray({ a: 1 })).toBe(false);
  15. expect(isEmptyArray(['abc'])).toBe(false);
  16. });
  17. });
  18. describe('getIn', () => {
  19. const obj = {
  20. a: {
  21. b: 2,
  22. c: false,
  23. d: null,
  24. },
  25. t: true,
  26. s: 'a random string',
  27. };
  28. it('gets a value by array path', () => {
  29. expect(getIn(obj, ['a', 'b'])).toBe(2);
  30. });
  31. it('gets a value by string path', () => {
  32. expect(getIn(obj, 'a.b')).toBe(2);
  33. });
  34. it('return "undefined" if value was not found using given path', () => {
  35. expect(getIn(obj, 'a.z')).toBeUndefined();
  36. });
  37. it('return "undefined" if value was not found using given path and an intermediate value is "false"', () => {
  38. expect(getIn(obj, 'a.c.z')).toBeUndefined();
  39. });
  40. it('return "undefined" if value was not found using given path and an intermediate value is "null"', () => {
  41. expect(getIn(obj, 'a.d.z')).toBeUndefined();
  42. });
  43. it('return "undefined" if value was not found using given path and an intermediate value is "true"', () => {
  44. expect(getIn(obj, 't.z')).toBeUndefined();
  45. });
  46. it('return "undefined" if value was not found using given path and an intermediate value is a string', () => {
  47. expect(getIn(obj, 's.z')).toBeUndefined();
  48. });
  49. });
  50. describe('shallowSetIn', () => {
  51. it('sets flat value', () => {
  52. const obj = { x: 'y' };
  53. const newObj = shallowSetIn(obj, 'flat', 'value');
  54. expect(obj).toEqual({ x: 'y' });
  55. expect(newObj).toEqual({ x: 'y', flat: 'value' });
  56. });
  57. it('keep the same object if nothing is changed', () => {
  58. const obj = { x: 'y' };
  59. const newObj = shallowSetIn(obj, 'x', 'y');
  60. expect(obj).toBe(newObj);
  61. });
  62. it('keep key shen set undefined', () => {
  63. const obj = { x: 'y' };
  64. const newObj = shallowSetIn(obj, 'x', undefined);
  65. expect(obj).toEqual({ x: 'y' });
  66. expect(newObj).toEqual({ x: undefined });
  67. expect(Object.keys(newObj)).toEqual(['x']);
  68. });
  69. it('sets nested value', () => {
  70. const obj = { x: 'y' };
  71. const newObj = shallowSetIn(obj, 'nested.value', 'nested value');
  72. expect(obj).toEqual({ x: 'y' });
  73. expect(newObj).toEqual({ x: 'y', nested: { value: 'nested value' } });
  74. });
  75. it('updates nested value', () => {
  76. const obj = { x: 'y', nested: { value: 'a' } };
  77. const newObj = shallowSetIn(obj, 'nested.value', 'b');
  78. expect(obj).toEqual({ x: 'y', nested: { value: 'a' } });
  79. expect(newObj).toEqual({ x: 'y', nested: { value: 'b' } });
  80. });
  81. it('updates deep nested value', () => {
  82. const obj = { x: 'y', twofoldly: { nested: { value: 'a' } } };
  83. const newObj = shallowSetIn(obj, 'twofoldly.nested.value', 'b');
  84. expect(obj.twofoldly.nested === newObj.twofoldly.nested).toEqual(false); // fails, same object still
  85. expect(obj).toEqual({ x: 'y', twofoldly: { nested: { value: 'a' } } }); // fails, it's b here, too
  86. expect(newObj).toEqual({ x: 'y', twofoldly: { nested: { value: 'b' } } }); // works ofc
  87. });
  88. it('shallow clone data along the update path', () => {
  89. const obj = {
  90. x: 'y',
  91. twofoldly: { nested: ['a', { c: 'd' }] },
  92. other: { nestedOther: 'o' },
  93. };
  94. const newObj = shallowSetIn(obj, 'twofoldly.nested.0', 'b');
  95. // All new objects/arrays created along the update path.
  96. expect(obj).not.toBe(newObj);
  97. expect(obj.twofoldly).not.toBe(newObj.twofoldly);
  98. expect(obj.twofoldly.nested).not.toBe(newObj.twofoldly.nested);
  99. // All other objects/arrays copied, not cloned (retain same memory
  100. // location).
  101. expect(obj.other).toBe(newObj.other);
  102. expect(obj.twofoldly.nested[1]).toBe(newObj.twofoldly.nested[1]);
  103. });
  104. it('sets new array', () => {
  105. const obj = { x: 'y' };
  106. const newObj = shallowSetIn(obj, 'nested.0', 'value');
  107. expect(obj).toEqual({ x: 'y' });
  108. expect(newObj).toEqual({ x: 'y', nested: ['value'] });
  109. });
  110. it('sets new array when item is empty string', () => {
  111. const obj = { x: 'y' };
  112. const newObj = shallowSetIn(obj, 'nested.0', '');
  113. expect(obj).toEqual({ x: 'y' });
  114. expect(newObj).toEqual({ x: 'y', nested: [''] });
  115. });
  116. it('sets new array when item is empty string', () => {
  117. const obj = {};
  118. const newObj = shallowSetIn(obj, 'nested.0', '');
  119. expect(obj).toEqual({});
  120. expect(newObj).toEqual({ nested: [''] });
  121. });
  122. it('updates nested array value', () => {
  123. const obj = { x: 'y', nested: ['a'] };
  124. const newObj = shallowSetIn(obj, 'nested[0]', 'b');
  125. expect(obj).toEqual({ x: 'y', nested: ['a'] });
  126. expect(newObj).toEqual({ x: 'y', nested: ['b'] });
  127. });
  128. it('adds new item to nested array', () => {
  129. const obj = { x: 'y', nested: ['a'] };
  130. const newObj = shallowSetIn(obj, 'nested.1', 'b');
  131. expect(obj).toEqual({ x: 'y', nested: ['a'] });
  132. expect(newObj).toEqual({ x: 'y', nested: ['a', 'b'] });
  133. });
  134. it('sticks to object with int key when defined', () => {
  135. const obj = { x: 'y', nested: { 0: 'a' } };
  136. const newObj = shallowSetIn(obj, 'nested.0', 'b');
  137. expect(obj).toEqual({ x: 'y', nested: { 0: 'a' } });
  138. expect(newObj).toEqual({ x: 'y', nested: { 0: 'b' } });
  139. });
  140. it('supports bracket path', () => {
  141. const obj = { x: 'y' };
  142. const newObj = shallowSetIn(obj, 'nested[0]', 'value');
  143. expect(obj).toEqual({ x: 'y' });
  144. expect(newObj).toEqual({ x: 'y', nested: ['value'] });
  145. });
  146. it('supports path containing key of the object', () => {
  147. const obj = { x: 'y' };
  148. const newObj = shallowSetIn(obj, 'a.x.c', 'value');
  149. expect(obj).toEqual({ x: 'y' });
  150. expect(newObj).toEqual({ x: 'y', a: { x: { c: 'value' } } });
  151. });
  152. // This case is not used in form sdk for now,so we comment it.
  153. // it('should keep class inheritance for the top level object', () => {
  154. // class TestClass {
  155. // constructor(public key: string, public setObj?: any) {}
  156. // }
  157. // const obj = new TestClass('value');
  158. // const newObj = shallowSetIn(obj, 'setObj.nested', 'shallowSetInValue');
  159. // expect(obj).toEqual(new TestClass('value'));
  160. // expect(newObj).toEqual({
  161. // key: 'value',
  162. // setObj: { nested: 'shallowSetInValue' },
  163. // });
  164. // expect(obj instanceof TestClass).toEqual(true);
  165. // expect(newObj instanceof TestClass).toEqual(true);
  166. // });
  167. it('can convert primitives to objects before setting', () => {
  168. const obj = { x: [{ y: true }] };
  169. const newObj = shallowSetIn(obj, 'x.0.y.z', true);
  170. expect(obj).toEqual({ x: [{ y: true }] });
  171. expect(newObj).toEqual({ x: [{ y: { z: true } }] });
  172. });
  173. });
  174. describe('isPromise', () => {
  175. it('verifies that a value is a promise', () => {
  176. const alwaysResolve = (resolve: Function) => resolve();
  177. const promise = new Promise(alwaysResolve);
  178. expect(isPromise(promise)).toEqual(true);
  179. });
  180. it('verifies that a value is not a promise', () => {
  181. const emptyObject = {};
  182. const identity = (i: any) => i;
  183. const foo = 'foo';
  184. const answerToLife = 42;
  185. expect(isPromise(emptyObject)).toEqual(false);
  186. expect(isPromise(identity)).toEqual(false);
  187. expect(isPromise(foo)).toEqual(false);
  188. expect(isPromise(answerToLife)).toEqual(false);
  189. expect(isPromise(undefined)).toEqual(false);
  190. expect(isPromise(null)).toEqual(false);
  191. });
  192. });
  193. describe('isNaN', () => {
  194. it('correctly validate NaN', () => {
  195. expect(isNaN(NaN)).toBe(true);
  196. });
  197. it('correctly validate not NaN', () => {
  198. expect(isNaN(undefined)).toBe(false);
  199. expect(isNaN(1)).toBe(false);
  200. expect(isNaN('')).toBe(false);
  201. expect(isNaN([])).toBe(false);
  202. });
  203. });
  204. });