looseEqual.spec.ts 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /**
  2. * @vitest-environment jsdom
  3. */
  4. import { looseEqual } from '../src'
  5. describe('utils/looseEqual', () => {
  6. test('compares booleans correctly', () => {
  7. expect(looseEqual(true, true)).toBe(true)
  8. expect(looseEqual(false, false)).toBe(true)
  9. expect(looseEqual(true, false)).toBe(false)
  10. expect(looseEqual(true, 1)).toBe(false)
  11. expect(looseEqual(false, 0)).toBe(false)
  12. })
  13. test('compares strings correctly', () => {
  14. const text = 'Lorem ipsum'
  15. const number = 1
  16. const bool = true
  17. expect(looseEqual(text, text)).toBe(true)
  18. expect(looseEqual(text, text.slice(0, -1))).toBe(false)
  19. expect(looseEqual(String(number), number)).toBe(true)
  20. expect(looseEqual(String(bool), bool)).toBe(true)
  21. })
  22. test('compares numbers correctly', () => {
  23. const number = 100
  24. const decimal = 2.5
  25. const multiplier = 1.0000001
  26. expect(looseEqual(number, number)).toBe(true)
  27. expect(looseEqual(number, number - 1)).toBe(false)
  28. expect(looseEqual(decimal, decimal)).toBe(true)
  29. expect(looseEqual(decimal, decimal * multiplier)).toBe(false)
  30. expect(looseEqual(number, number * multiplier)).toBe(false)
  31. expect(looseEqual(multiplier, multiplier)).toBe(true)
  32. })
  33. test('compares dates correctly', () => {
  34. const date1 = new Date(2019, 1, 2, 3, 4, 5, 6)
  35. const date2 = new Date(2019, 1, 2, 3, 4, 5, 6)
  36. const date3 = new Date(2019, 1, 2, 3, 4, 5, 7)
  37. const date4 = new Date(2219, 1, 2, 3, 4, 5, 6)
  38. // Identical date object references
  39. expect(looseEqual(date1, date1)).toBe(true)
  40. // Different date references with identical values
  41. expect(looseEqual(date1, date2)).toBe(true)
  42. // Dates with slightly different time (ms)
  43. expect(looseEqual(date1, date3)).toBe(false)
  44. // Dates with different year
  45. expect(looseEqual(date1, date4)).toBe(false)
  46. })
  47. test('compares symbols correctly', () => {
  48. const symbol1 = Symbol('a')
  49. const symbol2 = Symbol('a')
  50. const symbol3 = Symbol('b')
  51. const notSymbol = 0
  52. expect(looseEqual(symbol1, symbol1)).toBe(true)
  53. expect(looseEqual(symbol1, symbol2)).toBe(false)
  54. expect(looseEqual(symbol1, symbol3)).toBe(false)
  55. expect(looseEqual(symbol1, notSymbol)).toBe(false)
  56. })
  57. test('compares files correctly', () => {
  58. const date1 = new Date(2019, 1, 2, 3, 4, 5, 6)
  59. const date2 = new Date(2019, 1, 2, 3, 4, 5, 7)
  60. const file1 = new File([''], 'filename.txt', {
  61. type: 'text/plain',
  62. lastModified: date1.getTime(),
  63. })
  64. const file2 = new File([''], 'filename.txt', {
  65. type: 'text/plain',
  66. lastModified: date1.getTime(),
  67. })
  68. const file3 = new File([''], 'filename.txt', {
  69. type: 'text/plain',
  70. lastModified: date2.getTime(),
  71. })
  72. const file4 = new File([''], 'filename.csv', {
  73. type: 'text/csv',
  74. lastModified: date1.getTime(),
  75. })
  76. const file5 = new File(['abcdef'], 'filename.txt', {
  77. type: 'text/plain',
  78. lastModified: date1.getTime(),
  79. })
  80. const file6 = new File(['12345'], 'filename.txt', {
  81. type: 'text/plain',
  82. lastModified: date1.getTime(),
  83. })
  84. // Identical file object references
  85. expect(looseEqual(file1, file1)).toBe(true)
  86. // Different file references with identical values
  87. expect(looseEqual(file1, file2)).toBe(true)
  88. // Files with slightly different dates
  89. expect(looseEqual(file1, file3)).toBe(false)
  90. // Two different file types
  91. expect(looseEqual(file1, file4)).toBe(false)
  92. // Two files with same name, modified date, but different content
  93. expect(looseEqual(file5, file6)).toBe(false)
  94. })
  95. test('compares arrays correctly', () => {
  96. const arr1 = [1, 2, 3, 4]
  97. const arr2 = [1, 2, 3, '4']
  98. const arr3 = [1, 2, 3, 4, 5]
  99. const arr4 = [1, 2, 3, 4, { a: 5 }]
  100. // Identical array references
  101. expect(looseEqual(arr1, arr1)).toBe(true)
  102. // Different array references with identical values
  103. expect(looseEqual(arr1, arr1.slice())).toBe(true)
  104. expect(looseEqual(arr4, arr4.slice())).toBe(true)
  105. // Array with one value different (loose)
  106. expect(looseEqual(arr1, arr2)).toBe(true)
  107. // Array with one value different
  108. expect(looseEqual(arr3, arr4)).toBe(false)
  109. // Arrays with different lengths
  110. expect(looseEqual(arr1, arr3)).toBe(false)
  111. // Arrays with values in different order
  112. expect(looseEqual(arr1, arr1.slice().reverse())).toBe(false)
  113. })
  114. test('compares RegExp correctly', () => {
  115. const rx1 = /^foo$/
  116. const rx2 = /^foo$/
  117. const rx3 = /^bar$/
  118. const rx4 = /^bar$/i
  119. // Identical regex references
  120. expect(looseEqual(rx1, rx1)).toBe(true)
  121. // Different regex references with identical values
  122. expect(looseEqual(rx1, rx2)).toBe(true)
  123. // Different regex
  124. expect(looseEqual(rx1, rx3)).toBe(false)
  125. // Same regex with different options
  126. expect(looseEqual(rx3, rx4)).toBe(false)
  127. })
  128. test('compares objects correctly', () => {
  129. const obj1 = { foo: 'bar' }
  130. const obj2 = { foo: 'bar1' }
  131. const obj3 = { a: 1, b: 2, c: 3 }
  132. const obj4 = { b: 2, c: 3, a: 1 }
  133. const obj5 = { ...obj4, z: 999 }
  134. const nestedObj1 = { ...obj1, bar: [{ ...obj1 }, { ...obj1 }] }
  135. const nestedObj2 = { ...obj1, bar: [{ ...obj1 }, { ...obj2 }] }
  136. // Identical object references
  137. expect(looseEqual(obj1, obj1)).toBe(true)
  138. // Two objects with identical keys/values
  139. expect(looseEqual(obj1, { ...obj1 })).toBe(true)
  140. // Different key values
  141. expect(looseEqual(obj1, obj2)).toBe(false)
  142. // Keys in different orders
  143. expect(looseEqual(obj3, obj4)).toBe(true)
  144. // One object has additional key
  145. expect(looseEqual(obj4, obj5)).toBe(false)
  146. // Identical object references with nested array
  147. expect(looseEqual(nestedObj1, nestedObj1)).toBe(true)
  148. // Identical object definitions with nested array
  149. expect(looseEqual(nestedObj1, { ...nestedObj1 })).toBe(true)
  150. // Object definitions with nested array (which has different order)
  151. expect(looseEqual(nestedObj1, nestedObj2)).toBe(false)
  152. })
  153. test('compares different types correctly', () => {
  154. const obj1 = {}
  155. const obj2 = { a: 1 }
  156. const obj3 = { 0: 0, 1: 1, 2: 2 }
  157. const arr1: any[] = []
  158. const arr2 = [1]
  159. const arr3 = [0, 1, 2]
  160. const date1 = new Date(2019, 1, 2, 3, 4, 5, 6)
  161. const file1 = new File([''], 'filename.txt', {
  162. type: 'text/plain',
  163. lastModified: date1.getTime(),
  164. })
  165. expect(looseEqual(123, '123')).toBe(true)
  166. expect(looseEqual(123, new Date(123))).toBe(false)
  167. expect(looseEqual(`123`, new Date(123))).toBe(false)
  168. expect(looseEqual([1, 2, 3], '1,2,3')).toBe(false)
  169. expect(looseEqual(obj1, arr1)).toBe(false)
  170. expect(looseEqual(obj2, arr2)).toBe(false)
  171. expect(looseEqual(obj1, '[object Object]')).toBe(false)
  172. expect(looseEqual(arr1, '[object Array]')).toBe(false)
  173. expect(looseEqual(obj1, date1)).toBe(false)
  174. expect(looseEqual(obj2, date1)).toBe(false)
  175. expect(looseEqual(arr1, date1)).toBe(false)
  176. expect(looseEqual(arr2, date1)).toBe(false)
  177. expect(looseEqual(obj2, file1)).toBe(false)
  178. expect(looseEqual(arr2, file1)).toBe(false)
  179. expect(looseEqual(date1, file1)).toBe(false)
  180. // Special case where an object's keys are the same as keys (indexes) of an array
  181. expect(looseEqual(obj3, arr3)).toBe(false)
  182. })
  183. test('compares null and undefined values correctly', () => {
  184. expect(looseEqual(null, null)).toBe(true)
  185. expect(looseEqual(undefined, undefined)).toBe(true)
  186. expect(looseEqual(void 0, undefined)).toBe(true)
  187. expect(looseEqual(null, undefined)).toBe(false)
  188. expect(looseEqual(null, void 0)).toBe(false)
  189. expect(looseEqual(null, '')).toBe(false)
  190. expect(looseEqual(null, false)).toBe(false)
  191. expect(looseEqual(undefined, false)).toBe(false)
  192. })
  193. test('compares sparse arrays correctly', () => {
  194. // The following arrays all have a length of 3
  195. // But the first two are "sparse"
  196. const arr1 = []
  197. arr1[2] = true
  198. const arr2 = []
  199. arr2[2] = true
  200. const arr3 = [false, false, true]
  201. const arr4 = [undefined, undefined, true]
  202. // This one is also sparse (missing index 1)
  203. const arr5 = []
  204. arr5[0] = arr5[2] = true
  205. expect(looseEqual(arr1, arr2)).toBe(true)
  206. expect(looseEqual(arr2, arr1)).toBe(true)
  207. expect(looseEqual(arr1, arr3)).toBe(false)
  208. expect(looseEqual(arr3, arr1)).toBe(false)
  209. expect(looseEqual(arr1, arr4)).toBe(true)
  210. expect(looseEqual(arr4, arr1)).toBe(true)
  211. expect(looseEqual(arr1, arr5)).toBe(false)
  212. expect(looseEqual(arr5, arr1)).toBe(false)
  213. })
  214. })