toDisplayString.spec.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /**
  2. * @vitest-environment jsdom
  3. */
  4. import { computed, ref } from '@vue/reactivity'
  5. import { toDisplayString } from '../src'
  6. describe('toDisplayString', () => {
  7. test('nullish values', () => {
  8. expect(toDisplayString(null)).toBe('')
  9. expect(toDisplayString(undefined)).toBe('')
  10. })
  11. test('primitive values', () => {
  12. expect(toDisplayString(1)).toBe('1')
  13. expect(toDisplayString(true)).toBe('true')
  14. expect(toDisplayString(false)).toBe('false')
  15. expect(toDisplayString('hello')).toBe('hello')
  16. })
  17. test('Object and Arrays', () => {
  18. const obj = { foo: 123 }
  19. expect(toDisplayString(obj)).toBe(JSON.stringify(obj, null, 2))
  20. const arr = [obj]
  21. expect(toDisplayString(arr)).toBe(JSON.stringify(arr, null, 2))
  22. const objWithToStringOverride = {
  23. foo: 555,
  24. toString() {
  25. return 'override'
  26. },
  27. }
  28. expect(toDisplayString(objWithToStringOverride)).toBe('override')
  29. const objWithNonInvokableToString = {
  30. foo: 555,
  31. toString: null,
  32. }
  33. expect(toDisplayString(objWithNonInvokableToString)).toBe(
  34. `{
  35. "foo": 555,
  36. "toString": null
  37. }`,
  38. )
  39. // object created from null does not have .toString in its prototype
  40. const nullObjectWithoutToString = Object.create(null)
  41. nullObjectWithoutToString.bar = 1
  42. expect(toDisplayString(nullObjectWithoutToString)).toBe(
  43. `{
  44. "bar": 1
  45. }`,
  46. )
  47. // array toString override is ignored
  48. const arrWithToStringOverride = [1, 2, 3]
  49. arrWithToStringOverride.toString = () =>
  50. 'override for array is not supported'
  51. expect(toDisplayString(arrWithToStringOverride)).toBe(
  52. `[
  53. 1,
  54. 2,
  55. 3
  56. ]`,
  57. )
  58. })
  59. test('refs', () => {
  60. const n = ref(1)
  61. const np = computed(() => n.value + 1)
  62. expect(
  63. toDisplayString({
  64. n,
  65. np,
  66. }),
  67. ).toBe(JSON.stringify({ n: 1, np: 2 }, null, 2))
  68. })
  69. test('objects with custom toString', () => {
  70. class TestClass {
  71. toString() {
  72. return 'foo'
  73. }
  74. }
  75. const instance = new TestClass()
  76. expect(toDisplayString(instance)).toBe('foo')
  77. const obj = { toString: () => 'bar' }
  78. expect(toDisplayString(obj)).toBe('bar')
  79. })
  80. test('native objects', () => {
  81. const div = document.createElement('div')
  82. expect(toDisplayString(div)).toMatch('[object HTMLDivElement]')
  83. expect(toDisplayString({ div })).toMatchInlineSnapshot(`
  84. "{
  85. "div": "[object HTMLDivElement]"
  86. }"
  87. `)
  88. })
  89. test('Map and Set', () => {
  90. const m = new Map<any, any>([
  91. [1, 'foo'],
  92. [{ baz: 1 }, { foo: 'bar', qux: 2 }],
  93. ])
  94. const s = new Set<any>([1, { foo: 'bar' }, m])
  95. expect(toDisplayString(m)).toMatchInlineSnapshot(`
  96. "{
  97. "Map(2)": {
  98. "1 =>": "foo",
  99. "[object Object] =>": {
  100. "foo": "bar",
  101. "qux": 2
  102. }
  103. }
  104. }"
  105. `)
  106. expect(toDisplayString(s)).toMatchInlineSnapshot(`
  107. "{
  108. "Set(3)": [
  109. 1,
  110. {
  111. "foo": "bar"
  112. },
  113. {
  114. "Map(2)": {
  115. "1 =>": "foo",
  116. "[object Object] =>": {
  117. "foo": "bar",
  118. "qux": 2
  119. }
  120. }
  121. }
  122. ]
  123. }"
  124. `)
  125. expect(
  126. toDisplayString({
  127. m,
  128. s,
  129. }),
  130. ).toMatchInlineSnapshot(`
  131. "{
  132. "m": {
  133. "Map(2)": {
  134. "1 =>": "foo",
  135. "[object Object] =>": {
  136. "foo": "bar",
  137. "qux": 2
  138. }
  139. }
  140. },
  141. "s": {
  142. "Set(3)": [
  143. 1,
  144. {
  145. "foo": "bar"
  146. },
  147. {
  148. "Map(2)": {
  149. "1 =>": "foo",
  150. "[object Object] =>": {
  151. "foo": "bar",
  152. "qux": 2
  153. }
  154. }
  155. }
  156. ]
  157. }
  158. }"
  159. `)
  160. })
  161. //#9727
  162. test('Map with Symbol keys', () => {
  163. const m = new Map<any, any>([
  164. [Symbol(), 'foo'],
  165. [Symbol(), 'bar'],
  166. [Symbol('baz'), 'baz'],
  167. ])
  168. expect(toDisplayString(m)).toMatchInlineSnapshot(`
  169. "{
  170. "Map(3)": {
  171. "Symbol(0) =>": "foo",
  172. "Symbol(1) =>": "bar",
  173. "Symbol(baz) =>": "baz"
  174. }
  175. }"
  176. `)
  177. // confirming the symbol renders Symbol(foo)
  178. expect(toDisplayString(new Map([[Symbol('foo'), 'foo']]))).toContain(
  179. String(Symbol('foo')),
  180. )
  181. })
  182. test('Set with Symbol values', () => {
  183. const s = new Set([Symbol('foo'), Symbol('bar'), Symbol()])
  184. expect(toDisplayString(s)).toMatchInlineSnapshot(`
  185. "{
  186. "Set(3)": [
  187. "Symbol(foo)",
  188. "Symbol(bar)",
  189. "Symbol()"
  190. ]
  191. }"
  192. `)
  193. })
  194. test('Object with Symbol values', () => {
  195. expect(toDisplayString({ foo: Symbol('x'), bar: Symbol() }))
  196. .toMatchInlineSnapshot(`
  197. "{
  198. "foo": "Symbol(x)",
  199. "bar": "Symbol()"
  200. }"
  201. `)
  202. })
  203. })