objects.spec.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /**
  2. * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
  3. * SPDX-License-Identifier: MIT
  4. */
  5. import { describe, test, expect } from 'vitest';
  6. import {
  7. NOOP,
  8. deepFreeze,
  9. each,
  10. filter,
  11. getByKey,
  12. isEmpty,
  13. isPlainObject,
  14. mapKeys,
  15. mapValues,
  16. notEmpty,
  17. omit,
  18. pick,
  19. reduce,
  20. setByKey,
  21. values,
  22. } from './objects';
  23. describe('objects', () => {
  24. test('deepFreeze', async () => {
  25. const obj1 = { a: { b: 2 } };
  26. deepFreeze(obj1);
  27. expect(() => {
  28. obj1.a.b = 3;
  29. }).toThrow();
  30. expect(deepFreeze(null)).toBeNull();
  31. expect(deepFreeze(1)).toEqual(1);
  32. });
  33. test('notEmpty', async () => {
  34. expect(notEmpty({})).toBeTruthy();
  35. expect(notEmpty([])).toBeTruthy();
  36. expect(notEmpty(() => {})).toBeTruthy();
  37. expect(notEmpty(undefined)).toBeFalsy();
  38. expect(notEmpty(null)).toBeFalsy();
  39. });
  40. test('isEmpty', async () => {
  41. expect(isEmpty({})).toBeTruthy();
  42. expect(isEmpty({ a: 1 })).toBeFalsy();
  43. // WARNING: just for plain object
  44. expect(isEmpty(() => 1)).toBeFalsy();
  45. });
  46. const obj = Object.freeze({ a: 1, b: 2, c: 3 });
  47. test('each', async () => {
  48. const ret: any[] = [];
  49. each(obj, (v, k) => ret.push([k, v]));
  50. expect(ret).toEqual([
  51. ['a', 1],
  52. ['b', 2],
  53. ['c', 3],
  54. ]);
  55. });
  56. test('values', async () => {
  57. expect(values(obj)).toEqual([1, 2, 3]);
  58. const _values = Object.values;
  59. Object.values = null as any;
  60. expect(values(obj)).toEqual([1, 2, 3]);
  61. Object.values = _values;
  62. });
  63. test('filter', async () => {
  64. expect(filter(obj, (v, k) => v > 1)).toEqual({ b: 2, c: 3 });
  65. const dest = {};
  66. expect(filter(obj, (v, k) => v > 1, dest)).toEqual({ b: 2, c: 3 });
  67. expect(dest).toEqual({ b: 2, c: 3 });
  68. });
  69. test('pick', async () => {
  70. expect(pick(obj, ['b', 'c'])).toEqual({ b: 2, c: 3 });
  71. expect(pick(obj, ['a', 'b', 'c'])).toEqual(obj);
  72. expect(pick(obj, [])).toEqual({});
  73. const dest = {};
  74. expect(pick(obj, ['b', 'c'], dest)).toEqual({ b: 2, c: 3 });
  75. expect(dest).toEqual({ b: 2, c: 3 });
  76. });
  77. test('omit', async () => {
  78. expect(omit(obj, ['a'])).toEqual({ b: 2, c: 3 });
  79. expect(omit(obj, ['a', 'b', 'c', 'd'])).toEqual({});
  80. expect(omit(obj, [])).toEqual(obj);
  81. const dest = {};
  82. expect(omit(obj, ['a'], dest)).toEqual({ b: 2, c: 3 });
  83. expect(dest).toEqual({ b: 2, c: 3 });
  84. });
  85. test('reduce', async () => {
  86. // sum
  87. expect(reduce(obj, (res, v) => res + v, 0)).toEqual(6);
  88. // v + 1
  89. expect(
  90. reduce(obj, (res, v, k) => {
  91. res[k] = v + 1;
  92. return res;
  93. }),
  94. ).toEqual({ a: 2, b: 3, c: 4 });
  95. // entries
  96. expect(
  97. reduce(
  98. obj,
  99. (res, v, k) => {
  100. res.push([k, v]);
  101. return res;
  102. },
  103. [] as [string, number][],
  104. ),
  105. ).toEqual([
  106. ['a', 1],
  107. ['b', 2],
  108. ['c', 3],
  109. ]);
  110. });
  111. test('mapValues', async () => {
  112. expect(mapValues(obj, v => v + 1)).toEqual({ a: 2, b: 3, c: 4 });
  113. expect(mapValues(obj, (v, k) => `${k}${v}`)).toEqual({
  114. a: 'a1',
  115. b: 'b2',
  116. c: 'c3',
  117. });
  118. });
  119. test('mapKeys', async () => {
  120. expect(mapKeys(obj, (v, k) => `${k}1`)).toEqual({ a1: 1, b1: 2, c1: 3 });
  121. expect(mapKeys(obj, (v, k) => `${k}${v}`)).toEqual({ a1: 1, b2: 2, c3: 3 });
  122. });
  123. test('getByKey', async () => {
  124. const obj1 = Object.freeze({ a: { b: { c: 1 } } });
  125. expect(getByKey(obj1, 'a.b.c')).toEqual(1);
  126. expect(getByKey(obj1, 'a.b')).toEqual({ c: 1 });
  127. expect(getByKey(obj1, 'a')).toEqual({ b: { c: 1 } });
  128. // return undefined
  129. expect(getByKey(1, 'a')).toBeUndefined();
  130. expect(getByKey(obj1, '')).toBeUndefined();
  131. expect(getByKey(obj1, 'b')).toBeUndefined();
  132. expect(getByKey(obj1, 'a.d')).toBeUndefined();
  133. expect(getByKey(obj1, 'a.d.e')).toBeUndefined();
  134. expect(getByKey(obj1, 'a.b.c.d')).toBeUndefined();
  135. });
  136. test('setByKey', async () => {
  137. expect(setByKey({ a: { b: { c: 1 } } }, 'a.b.c', 2)).toEqual({
  138. a: { b: { c: 2 } },
  139. });
  140. const obj1 = { a: { b: { c: 1 } } };
  141. expect(setByKey(obj1, 'a.b.c', 2, true, true)).toEqual({
  142. a: { b: { c: 2 } },
  143. });
  144. expect(obj1).toEqual({ a: { b: { c: 1 } } });
  145. const arr = [1] as any;
  146. arr.b = 2;
  147. expect(setByKey({ a: [1] }, 'a.b', 2, true, true)).toEqual({ a: arr });
  148. expect(setByKey(1, 'a.b.c', 2)).toEqual(1);
  149. expect(setByKey({ a: { b: { c: 1 } } }, '', 2)).toEqual({
  150. a: { b: { c: 1 } },
  151. });
  152. expect(setByKey({ a: { b: { c: 1 } } }, 'a.b.d', 2)).toEqual({
  153. a: { b: { c: 1, d: 2 } },
  154. });
  155. expect(setByKey({ a: { b: { c: 1 } } }, 'a.b.d', 2, false)).toEqual({
  156. a: { b: { c: 1, d: 2 } },
  157. });
  158. expect(setByKey({ a: { b: { c: 1 } } }, 'a.b.c.d', 2)).toEqual({
  159. a: { b: { c: { d: 2 } } },
  160. });
  161. expect(setByKey({ a: { b: { c: 1 } } }, 'a.b.c.d', 2, false)).toEqual({
  162. a: { b: { c: 1 } },
  163. });
  164. });
  165. test('NOOP', async () => {
  166. expect(NOOP()).toBeUndefined();
  167. });
  168. test('isPlainObject', async () => {
  169. expect(isPlainObject({})).toBeTruthy();
  170. expect(isPlainObject({ a: 1 })).toBeTruthy();
  171. expect(isPlainObject({ a: { b: 1 } })).toBeTruthy();
  172. // eslint-disable-next-line prefer-object-spread
  173. expect(isPlainObject(Object.assign({}, { a: 1 }))).toBeTruthy();
  174. // eslint-disable-next-line prefer-arrow-callback
  175. expect(isPlainObject(function test1() {})).toBeFalsy();
  176. expect(isPlainObject(() => {})).toBeFalsy();
  177. expect(isPlainObject([])).toBeFalsy();
  178. expect(isPlainObject(null)).toBeFalsy();
  179. expect(isPlainObject(undefined)).toBeFalsy();
  180. expect(isPlainObject('')).toBeFalsy();
  181. expect(isPlainObject('1')).toBeFalsy();
  182. expect(isPlainObject(0)).toBeFalsy();
  183. expect(isPlainObject(1)).toBeFalsy();
  184. expect(isPlainObject(BigInt(0))).toBeFalsy();
  185. expect(isPlainObject(BigInt(1))).toBeFalsy();
  186. expect(isPlainObject(false)).toBeFalsy();
  187. expect(isPlainObject(true)).toBeFalsy();
  188. expect(isPlainObject(Symbol(''))).toBeFalsy();
  189. });
  190. });