children.spec.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. import { patch } from 'web/runtime/patch'
  2. import VNode, { createEmptyVNode } from 'core/vdom/vnode'
  3. function prop(name) {
  4. return obj => {
  5. return obj[name]
  6. }
  7. }
  8. function map(fn, list) {
  9. const ret: any[] = []
  10. for (let i = 0; i < list.length; i++) {
  11. ret[i] = fn(list[i])
  12. }
  13. return ret
  14. }
  15. function spanNum(n) {
  16. if (typeof n === 'string') {
  17. return new VNode('span', {}, undefined, n)
  18. } else {
  19. return new VNode('span', { key: n }, undefined, n.toString())
  20. }
  21. }
  22. function shuffle(array) {
  23. let currentIndex = array.length
  24. let temporaryValue
  25. let randomIndex
  26. // while there remain elements to shuffle...
  27. while (currentIndex !== 0) {
  28. // pick a remaining element...
  29. randomIndex = Math.floor(Math.random() * currentIndex)
  30. currentIndex -= 1
  31. // and swap it with the current element.
  32. temporaryValue = array[currentIndex]
  33. array[currentIndex] = array[randomIndex]
  34. array[randomIndex] = temporaryValue
  35. }
  36. return array
  37. }
  38. const inner = prop('innerHTML')
  39. const tag = prop('tagName')
  40. describe('vdom patch: children', () => {
  41. let vnode0
  42. beforeEach(() => {
  43. vnode0 = new VNode('p', { attrs: { id: '1' } }, [
  44. createTextVNode('hello world')
  45. ])
  46. patch(null, vnode0)
  47. })
  48. it('should appends elements', () => {
  49. const vnode1 = new VNode('p', {}, [1].map(spanNum))
  50. const vnode2 = new VNode('p', {}, [1, 2, 3].map(spanNum))
  51. let elm = patch(vnode0, vnode1)
  52. expect(elm.children.length).toBe(1)
  53. elm = patch(vnode1, vnode2)
  54. expect(elm.children.length).toBe(3)
  55. expect(elm.children[1].innerHTML).toBe('2')
  56. expect(elm.children[2].innerHTML).toBe('3')
  57. })
  58. it('should prepends elements', () => {
  59. const vnode1 = new VNode('p', {}, [4, 5].map(spanNum))
  60. const vnode2 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
  61. let elm = patch(vnode0, vnode1)
  62. expect(elm.children.length).toBe(2)
  63. elm = patch(vnode1, vnode2)
  64. expect(map(inner, elm.children)).toEqual(['1', '2', '3', '4', '5'])
  65. })
  66. it('should add elements in the middle', () => {
  67. const vnode1 = new VNode('p', {}, [1, 2, 4, 5].map(spanNum))
  68. const vnode2 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
  69. let elm = patch(vnode0, vnode1)
  70. expect(elm.children.length).toBe(4)
  71. elm = patch(vnode1, vnode2)
  72. expect(map(inner, elm.children)).toEqual(['1', '2', '3', '4', '5'])
  73. })
  74. it('should add elements at begin and end', () => {
  75. const vnode1 = new VNode('p', {}, [2, 3, 4].map(spanNum))
  76. const vnode2 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
  77. let elm = patch(vnode0, vnode1)
  78. expect(elm.children.length).toBe(3)
  79. elm = patch(vnode1, vnode2)
  80. expect(map(inner, elm.children)).toEqual(['1', '2', '3', '4', '5'])
  81. })
  82. it('should add children to parent with no children', () => {
  83. const vnode1 = new VNode('p', { key: 'p' })
  84. const vnode2 = new VNode('p', { key: 'p' }, [1, 2, 3].map(spanNum))
  85. let elm = patch(vnode0, vnode1)
  86. expect(elm.children.length).toBe(0)
  87. elm = patch(vnode1, vnode2)
  88. expect(map(inner, elm.children)).toEqual(['1', '2', '3'])
  89. })
  90. it('should remove all children from parent', () => {
  91. const vnode1 = new VNode('p', { key: 'p' }, [1, 2, 3].map(spanNum))
  92. const vnode2 = new VNode('p', { key: 'p' })
  93. let elm = patch(vnode0, vnode1)
  94. expect(map(inner, elm.children)).toEqual(['1', '2', '3'])
  95. elm = patch(vnode1, vnode2)
  96. expect(elm.children.length).toBe(0)
  97. })
  98. it('should remove elements from the beginning', () => {
  99. const vnode1 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
  100. const vnode2 = new VNode('p', {}, [3, 4, 5].map(spanNum))
  101. let elm = patch(vnode0, vnode1)
  102. expect(elm.children.length).toBe(5)
  103. elm = patch(vnode1, vnode2)
  104. expect(map(inner, elm.children)).toEqual(['3', '4', '5'])
  105. })
  106. it('should removes elements from end', () => {
  107. const vnode1 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
  108. const vnode2 = new VNode('p', {}, [1, 2, 3].map(spanNum))
  109. let elm = patch(vnode0, vnode1)
  110. expect(elm.children.length).toBe(5)
  111. elm = patch(vnode1, vnode2)
  112. expect(elm.children.length).toBe(3)
  113. expect(map(inner, elm.children)).toEqual(['1', '2', '3'])
  114. })
  115. it('should remove elements from the middle', () => {
  116. const vnode1 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
  117. const vnode2 = new VNode('p', {}, [1, 2, 4, 5].map(spanNum))
  118. let elm = patch(vnode0, vnode1)
  119. expect(elm.children.length).toBe(5)
  120. elm = patch(vnode1, vnode2)
  121. expect(elm.children.length).toBe(4)
  122. expect(map(inner, elm.children)).toEqual(['1', '2', '4', '5'])
  123. })
  124. it('should moves element forward', () => {
  125. const vnode1 = new VNode('p', {}, [1, 2, 3, 4].map(spanNum))
  126. const vnode2 = new VNode('p', {}, [2, 3, 1, 4].map(spanNum))
  127. let elm = patch(vnode0, vnode1)
  128. expect(elm.children.length).toBe(4)
  129. elm = patch(vnode1, vnode2)
  130. expect(elm.children.length).toBe(4)
  131. expect(map(inner, elm.children)).toEqual(['2', '3', '1', '4'])
  132. })
  133. it('should move elements to end', () => {
  134. const vnode1 = new VNode('p', {}, [1, 2, 3].map(spanNum))
  135. const vnode2 = new VNode('p', {}, [2, 3, 1].map(spanNum))
  136. let elm = patch(vnode0, vnode1)
  137. expect(elm.children.length).toBe(3)
  138. elm = patch(vnode1, vnode2)
  139. expect(elm.children.length).toBe(3)
  140. expect(map(inner, elm.children)).toEqual(['2', '3', '1'])
  141. })
  142. it('should move element backwards', () => {
  143. const vnode1 = new VNode('p', {}, [1, 2, 3, 4].map(spanNum))
  144. const vnode2 = new VNode('p', {}, [1, 4, 2, 3].map(spanNum))
  145. let elm = patch(vnode0, vnode1)
  146. expect(elm.children.length).toBe(4)
  147. elm = patch(vnode1, vnode2)
  148. expect(elm.children.length).toBe(4)
  149. expect(map(inner, elm.children)).toEqual(['1', '4', '2', '3'])
  150. })
  151. it('should swap first and last', () => {
  152. const vnode1 = new VNode('p', {}, [1, 2, 3, 4].map(spanNum))
  153. const vnode2 = new VNode('p', {}, [4, 2, 3, 1].map(spanNum))
  154. let elm = patch(vnode0, vnode1)
  155. expect(elm.children.length).toBe(4)
  156. elm = patch(vnode1, vnode2)
  157. expect(elm.children.length).toBe(4)
  158. expect(map(inner, elm.children)).toEqual(['4', '2', '3', '1'])
  159. })
  160. it('should move to left and replace', () => {
  161. const vnode1 = new VNode('p', {}, [1, 2, 3, 4, 5].map(spanNum))
  162. const vnode2 = new VNode('p', {}, [4, 1, 2, 3, 6].map(spanNum))
  163. let elm = patch(vnode0, vnode1)
  164. expect(elm.children.length).toBe(5)
  165. elm = patch(vnode1, vnode2)
  166. expect(elm.children.length).toBe(5)
  167. expect(map(inner, elm.children)).toEqual(['4', '1', '2', '3', '6'])
  168. })
  169. it('should move to left and leaves hold', () => {
  170. const vnode1 = new VNode('p', {}, [1, 4, 5].map(spanNum))
  171. const vnode2 = new VNode('p', {}, [4, 6].map(spanNum))
  172. let elm = patch(vnode0, vnode1)
  173. expect(elm.children.length).toBe(3)
  174. elm = patch(vnode1, vnode2)
  175. expect(map(inner, elm.children)).toEqual(['4', '6'])
  176. })
  177. it('should handle moved and set to undefined element ending at the end', () => {
  178. const vnode1 = new VNode('p', {}, [2, 4, 5].map(spanNum))
  179. const vnode2 = new VNode('p', {}, [4, 5, 3].map(spanNum))
  180. let elm = patch(vnode0, vnode1)
  181. expect(elm.children.length).toBe(3)
  182. elm = patch(vnode1, vnode2)
  183. expect(elm.children.length).toBe(3)
  184. expect(map(inner, elm.children)).toEqual(['4', '5', '3'])
  185. })
  186. it('should move a key in non-keyed nodes with a size up', () => {
  187. const vnode1 = new VNode('p', {}, [1, 'a', 'b', 'c'].map(spanNum))
  188. const vnode2 = new VNode('p', {}, ['d', 'a', 'b', 'c', 1, 'e'].map(spanNum))
  189. let elm = patch(vnode0, vnode1)
  190. expect(elm.children.length).toBe(4)
  191. expect(elm.textContent, '1abc')
  192. elm = patch(vnode1, vnode2)
  193. expect(elm.children.length).toBe(6)
  194. expect(elm.textContent, 'dabc1e')
  195. })
  196. it('should reverse element', () => {
  197. const vnode1 = new VNode('p', {}, [1, 2, 3, 4, 5, 6, 7, 8].map(spanNum))
  198. const vnode2 = new VNode('p', {}, [8, 7, 6, 5, 4, 3, 2, 1].map(spanNum))
  199. let elm = patch(vnode0, vnode1)
  200. expect(elm.children.length).toBe(8)
  201. elm = patch(vnode1, vnode2)
  202. expect(map(inner, elm.children)).toEqual([
  203. '8',
  204. '7',
  205. '6',
  206. '5',
  207. '4',
  208. '3',
  209. '2',
  210. '1'
  211. ])
  212. })
  213. it('something', () => {
  214. const vnode1 = new VNode('p', {}, [0, 1, 2, 3, 4, 5].map(spanNum))
  215. const vnode2 = new VNode('p', {}, [4, 3, 2, 1, 5, 0].map(spanNum))
  216. let elm = patch(vnode0, vnode1)
  217. expect(elm.children.length).toBe(6)
  218. elm = patch(vnode1, vnode2)
  219. expect(map(inner, elm.children)).toEqual(['4', '3', '2', '1', '5', '0'])
  220. })
  221. it('should handle random shuffle', () => {
  222. let n
  223. let i
  224. const arr: any[] = []
  225. const opacities: any[] = []
  226. const elms = 14
  227. const samples = 5
  228. function spanNumWithOpacity(n, o) {
  229. return new VNode(
  230. 'span',
  231. { key: n, style: { opacity: o } },
  232. undefined,
  233. n.toString()
  234. )
  235. }
  236. for (n = 0; n < elms; ++n) {
  237. arr[n] = n
  238. }
  239. for (n = 0; n < samples; ++n) {
  240. const vnode1 = new VNode(
  241. 'span',
  242. {},
  243. arr.map(n => {
  244. return spanNumWithOpacity(n, '1')
  245. })
  246. )
  247. const shufArr = shuffle(arr.slice(0))
  248. let elm = patch(vnode0, vnode1)
  249. for (i = 0; i < elms; ++i) {
  250. expect(elm.children[i].innerHTML).toBe(i.toString())
  251. opacities[i] = Math.random().toFixed(5).toString()
  252. }
  253. const vnode2 = new VNode(
  254. 'span',
  255. {},
  256. arr.map(n => {
  257. return spanNumWithOpacity(shufArr[n], opacities[n])
  258. })
  259. )
  260. elm = patch(vnode1, vnode2)
  261. for (i = 0; i < elms; ++i) {
  262. expect(elm.children[i].innerHTML).toBe(shufArr[i].toString())
  263. expect(opacities[i].indexOf(elm.children[i].style.opacity)).toBe(0)
  264. }
  265. }
  266. })
  267. it('should append elements with updating children without keys', () => {
  268. const vnode1 = new VNode('div', {}, [
  269. new VNode('span', {}, undefined, 'hello')
  270. ])
  271. const vnode2 = new VNode('div', {}, [
  272. new VNode('span', {}, undefined, 'hello'),
  273. new VNode('span', {}, undefined, 'world')
  274. ])
  275. let elm = patch(vnode0, vnode1)
  276. expect(map(inner, elm.children)).toEqual(['hello'])
  277. elm = patch(vnode1, vnode2)
  278. expect(map(inner, elm.children)).toEqual(['hello', 'world'])
  279. })
  280. it('should handle unmoved text nodes with updating children without keys', () => {
  281. const vnode1 = new VNode('div', {}, [
  282. createTextVNode('text'),
  283. new VNode('span', {}, undefined, 'hello')
  284. ])
  285. const vnode2 = new VNode('div', {}, [
  286. createTextVNode('text'),
  287. new VNode('span', {}, undefined, 'hello')
  288. ])
  289. let elm = patch(vnode0, vnode1)
  290. expect(elm.childNodes[0].textContent).toBe('text')
  291. elm = patch(vnode1, vnode2)
  292. expect(elm.childNodes[0].textContent).toBe('text')
  293. })
  294. it('should handle changing text children with updating children without keys', () => {
  295. const vnode1 = new VNode('div', {}, [
  296. createTextVNode('text'),
  297. new VNode('span', {}, undefined, 'hello')
  298. ])
  299. const vnode2 = new VNode('div', {}, [
  300. createTextVNode('text2'),
  301. new VNode('span', {}, undefined, 'hello')
  302. ])
  303. let elm = patch(vnode0, vnode1)
  304. expect(elm.childNodes[0].textContent).toBe('text')
  305. elm = patch(vnode1, vnode2)
  306. expect(elm.childNodes[0].textContent).toBe('text2')
  307. })
  308. it('should prepend element with updating children without keys', () => {
  309. const vnode1 = new VNode('div', {}, [
  310. new VNode('span', {}, undefined, 'world')
  311. ])
  312. const vnode2 = new VNode('div', {}, [
  313. new VNode('span', {}, undefined, 'hello'),
  314. new VNode('span', {}, undefined, 'world')
  315. ])
  316. let elm = patch(vnode0, vnode1)
  317. expect(map(inner, elm.children)).toEqual(['world'])
  318. elm = patch(vnode1, vnode2)
  319. expect(map(inner, elm.children)).toEqual(['hello', 'world'])
  320. })
  321. it('should prepend element of different tag type with updating children without keys', () => {
  322. const vnode1 = new VNode('div', {}, [
  323. new VNode('span', {}, undefined, 'world')
  324. ])
  325. const vnode2 = new VNode('div', {}, [
  326. new VNode('div', {}, undefined, 'hello'),
  327. new VNode('span', {}, undefined, 'world')
  328. ])
  329. let elm = patch(vnode0, vnode1)
  330. expect(map(inner, elm.children)).toEqual(['world'])
  331. elm = patch(vnode1, vnode2)
  332. expect(map(prop('tagName'), elm.children)).toEqual(['DIV', 'SPAN'])
  333. expect(map(inner, elm.children)).toEqual(['hello', 'world'])
  334. })
  335. it('should remove elements with updating children without keys', () => {
  336. const vnode1 = new VNode('div', {}, [
  337. new VNode('span', {}, undefined, 'one'),
  338. new VNode('span', {}, undefined, 'two'),
  339. new VNode('span', {}, undefined, 'three')
  340. ])
  341. const vnode2 = new VNode('div', {}, [
  342. new VNode('span', {}, undefined, 'one'),
  343. new VNode('span', {}, undefined, 'three')
  344. ])
  345. let elm = patch(vnode0, vnode1)
  346. expect(map(inner, elm.children)).toEqual(['one', 'two', 'three'])
  347. elm = patch(vnode1, vnode2)
  348. expect(map(inner, elm.children)).toEqual(['one', 'three'])
  349. })
  350. it('should remove a single text node with updating children without keys', () => {
  351. const vnode1 = new VNode('div', {}, undefined, 'one')
  352. const vnode2 = new VNode('div', {})
  353. let elm = patch(vnode0, vnode1)
  354. expect(elm.textContent).toBe('one')
  355. elm = patch(vnode1, vnode2)
  356. expect(elm.textContent).toBe('')
  357. })
  358. it('should remove a single text node when children are updated', () => {
  359. const vnode1 = new VNode('div', {}, undefined, 'one')
  360. const vnode2 = new VNode('div', {}, [
  361. new VNode('div', {}, undefined, 'two'),
  362. new VNode('span', {}, undefined, 'three')
  363. ])
  364. let elm = patch(vnode0, vnode1)
  365. expect(elm.textContent).toBe('one')
  366. elm = patch(vnode1, vnode2)
  367. expect(map(prop('textContent'), elm.childNodes)).toEqual(['two', 'three'])
  368. })
  369. it('should remove a text node among other elements', () => {
  370. const vnode1 = new VNode('div', {}, [
  371. createTextVNode('one'),
  372. new VNode('span', {}, undefined, 'two')
  373. ])
  374. const vnode2 = new VNode('div', {}, [
  375. new VNode('div', {}, undefined, 'three')
  376. ])
  377. let elm = patch(vnode0, vnode1)
  378. expect(map(prop('textContent'), elm.childNodes)).toEqual(['one', 'two'])
  379. elm = patch(vnode1, vnode2)
  380. expect(elm.childNodes.length).toBe(1)
  381. expect(elm.childNodes[0].tagName).toBe('DIV')
  382. expect(elm.childNodes[0].textContent).toBe('three')
  383. })
  384. it('should reorder elements', () => {
  385. const vnode1 = new VNode('div', {}, [
  386. new VNode('span', {}, undefined, 'one'),
  387. new VNode('div', {}, undefined, 'two'),
  388. new VNode('b', {}, undefined, 'three')
  389. ])
  390. const vnode2 = new VNode('div', {}, [
  391. new VNode('b', {}, undefined, 'three'),
  392. new VNode('span', {}, undefined, 'two'),
  393. new VNode('div', {}, undefined, 'one')
  394. ])
  395. let elm = patch(vnode0, vnode1)
  396. expect(map(inner, elm.children)).toEqual(['one', 'two', 'three'])
  397. elm = patch(vnode1, vnode2)
  398. expect(map(inner, elm.children)).toEqual(['three', 'two', 'one'])
  399. })
  400. it('should handle children with the same key but with different tag', () => {
  401. const vnode1 = new VNode('div', {}, [
  402. new VNode('div', { key: 1 }, undefined, 'one'),
  403. new VNode('div', { key: 2 }, undefined, 'two'),
  404. new VNode('div', { key: 3 }, undefined, 'three'),
  405. new VNode('div', { key: 4 }, undefined, 'four')
  406. ])
  407. const vnode2 = new VNode('div', {}, [
  408. new VNode('div', { key: 4 }, undefined, 'four'),
  409. new VNode('span', { key: 3 }, undefined, 'three'),
  410. new VNode('span', { key: 2 }, undefined, 'two'),
  411. new VNode('div', { key: 1 }, undefined, 'one')
  412. ])
  413. let elm = patch(vnode0, vnode1)
  414. expect(map(tag, elm.children)).toEqual(['DIV', 'DIV', 'DIV', 'DIV'])
  415. expect(map(inner, elm.children)).toEqual(['one', 'two', 'three', 'four'])
  416. elm = patch(vnode1, vnode2)
  417. expect(map(tag, elm.children)).toEqual(['DIV', 'SPAN', 'SPAN', 'DIV'])
  418. expect(map(inner, elm.children)).toEqual(['four', 'three', 'two', 'one'])
  419. })
  420. it('should handle children with the same tag, same key, but one with data and one without data', () => {
  421. const vnode1 = new VNode('div', {}, [
  422. new VNode('div', { class: 'hi' }, undefined, 'one')
  423. ])
  424. const vnode2 = new VNode('div', {}, [
  425. new VNode('div', undefined, undefined, 'four')
  426. ])
  427. let elm = patch(vnode0, vnode1)
  428. const child1 = elm.children[0]
  429. expect(child1.className).toBe('hi')
  430. elm = patch(vnode1, vnode2)
  431. const child2 = elm.children[0]
  432. expect(child1).not.toBe(child2)
  433. expect(child2.className).toBe('')
  434. })
  435. it('should handle static vnodes properly', () => {
  436. function makeNode(text) {
  437. return new VNode('div', undefined, [
  438. new VNode(undefined, undefined, undefined, text)
  439. ])
  440. }
  441. const b = makeNode('B')
  442. b.isStatic = true
  443. b.key = `__static__1`
  444. const vnode1 = new VNode('div', {}, [makeNode('A'), b, makeNode('C')])
  445. const vnode2 = new VNode('div', {}, [b])
  446. const vnode3 = new VNode('div', {}, [makeNode('A'), b, makeNode('C')])
  447. let elm = patch(vnode0, vnode1)
  448. expect(elm.textContent).toBe('ABC')
  449. elm = patch(vnode1, vnode2)
  450. expect(elm.textContent).toBe('B')
  451. elm = patch(vnode2, vnode3)
  452. expect(elm.textContent).toBe('ABC')
  453. })
  454. it('should handle static vnodes inside ', () => {
  455. function makeNode(text) {
  456. return new VNode('div', undefined, [
  457. new VNode(undefined, undefined, undefined, text)
  458. ])
  459. }
  460. const b = makeNode('B')
  461. b.isStatic = true
  462. b.key = `__static__1`
  463. const vnode1 = new VNode('div', {}, [makeNode('A'), b, makeNode('C')])
  464. const vnode2 = new VNode('div', {}, [b])
  465. const vnode3 = new VNode('div', {}, [makeNode('A'), b, makeNode('C')])
  466. let elm = patch(vnode0, vnode1)
  467. expect(elm.textContent).toBe('ABC')
  468. elm = patch(vnode1, vnode2)
  469. expect(elm.textContent).toBe('B')
  470. elm = patch(vnode2, vnode3)
  471. expect(elm.textContent).toBe('ABC')
  472. })
  473. // #6502
  474. it('should not de-opt when both head and tail are changed', () => {
  475. const vnode1 = new VNode('div', {}, [
  476. createEmptyVNode(),
  477. new VNode('div'),
  478. createEmptyVNode()
  479. ])
  480. const vnode2 = new VNode('div', {}, [
  481. new VNode('p'),
  482. new VNode('div'),
  483. new VNode('p')
  484. ])
  485. let root = patch(null, vnode1)
  486. const original = root.childNodes[1]
  487. root = patch(vnode1, vnode2)
  488. const postPatch = root.childNodes[1]
  489. expect(postPatch).toBe(original)
  490. })
  491. it('should warn with duplicate keys: createChildren', () => {
  492. function makeNode(key) {
  493. return new VNode('div', { key: key })
  494. }
  495. const vnode = new VNode('p', {}, ['b', 'a', 'c', 'b'].map(makeNode))
  496. patch(null, vnode)
  497. expect(`Duplicate keys detected: 'b'`).toHaveBeenWarned()
  498. })
  499. it('should warn with duplicate keys: updateChildren', () => {
  500. function makeNode(key) {
  501. return new VNode('div', { key: key })
  502. }
  503. const vnode2 = new VNode('p', {}, ['b', 'a', 'c', 'b'].map(makeNode))
  504. const vnode3 = new VNode('p', {}, ['b', 'x', 'd', 'b'].map(makeNode))
  505. patch(vnode0, vnode2)
  506. expect(`Duplicate keys detected: 'b'`).toHaveBeenWarned()
  507. patch(vnode2, vnode3)
  508. expect(`Duplicate keys detected: 'b'`).toHaveBeenWarned()
  509. })
  510. it('should warn with duplicate keys: patchVnode with empty oldVnode', () => {
  511. function makeNode(key) {
  512. return new VNode('li', { key: key })
  513. }
  514. const vnode1 = new VNode('div')
  515. const vnode2 = new VNode(
  516. 'div',
  517. undefined,
  518. ['1', '2', '3', '4', '4'].map(makeNode)
  519. )
  520. patch(vnode1, vnode2)
  521. expect(`Duplicate keys detected: '4'`).toHaveBeenWarned()
  522. })
  523. })