1import { patch } from 'web/runtime/patch'2import { createPatchFunction } from 'core/vdom/patch'3import baseModules from 'core/vdom/modules/index'4import * as nodeOps from 'web/runtime/node-ops'5import platformModules from 'web/runtime/modules/index'6import VNode from 'core/vdom/vnode'78const modules = baseModules.concat(platformModules) as any[]910describe('vdom patch: hooks', () => {11 let vnode012 beforeEach(() => {13 vnode0 = new VNode('p', { attrs: { id: '1' } }, [14 createTextVNode('hello world')15 ])16 patch(null, vnode0)17 })1819 it('should call `insert` listener after both parents, siblings and children have been inserted', () => {20 const result: any[] = []21 function insert(vnode) {22 expect(vnode.elm.children.length).toBe(2)23 expect(vnode.elm.parentNode.children.length).toBe(3)24 result.push(vnode)25 }26 const vnode1 = new VNode('div', {}, [27 new VNode('span', {}, undefined, 'first sibling'),28 new VNode('div', { hook: { insert } }, [29 new VNode('span', {}, undefined, 'child 1'),30 new VNode('span', {}, undefined, 'child 2')31 ]),32 new VNode('span', {}, undefined, 'can touch me')33 ])34 patch(vnode0, vnode1)35 expect(result.length).toBe(1)36 })3738 it('should call `prepatch` listener', () => {39 const result: any[] = []40 function prepatch(oldVnode, newVnode) {41 expect(oldVnode).toEqual(vnode1.children[1])42 expect(newVnode).toEqual(vnode2.children[1])43 result.push(newVnode)44 }45 const vnode1 = new VNode('div', {}, [46 new VNode('span', {}, undefined, 'first sibling'),47 new VNode('div', { hook: { prepatch } }, [48 new VNode('span', {}, undefined, 'child 1'),49 new VNode('span', {}, undefined, 'child 2')50 ])51 ])52 const vnode2 = new VNode('div', {}, [53 new VNode('span', {}, undefined, 'first sibling'),54 new VNode('div', { hook: { prepatch } }, [55 new VNode('span', {}, undefined, 'child 1'),56 new VNode('span', {}, undefined, 'child 2')57 ])58 ])59 patch(vnode0, vnode1)60 patch(vnode1, vnode2)61 expect(result.length).toBe(1)62 })6364 it('should call `postpatch` after `prepatch` listener', () => {65 const pre: any[] = []66 const post: any[] = []67 function prepatch(oldVnode, newVnode) {68 pre.push(pre)69 }70 function postpatch(oldVnode, newVnode) {71 expect(pre.length).toBe(post.length + 1)72 post.push(post)73 }74 const vnode1 = new VNode('div', {}, [75 new VNode('span', {}, undefined, 'first sibling'),76 new VNode('div', { hook: { prepatch, postpatch } }, [77 new VNode('span', {}, undefined, 'child 1'),78 new VNode('span', {}, undefined, 'child 2')79 ])80 ])81 const vnode2 = new VNode('div', {}, [82 new VNode('span', {}, undefined, 'first sibling'),83 new VNode('div', { hook: { prepatch, postpatch } }, [84 new VNode('span', {}, undefined, 'child 1'),85 new VNode('span', {}, undefined, 'child 2')86 ])87 ])88 patch(vnode0, vnode1)89 patch(vnode1, vnode2)90 expect(pre.length).toBe(1)91 expect(post.length).toBe(1)92 })9394 it('should call `update` listener', () => {95 const result1: any[] = []96 const result2: any[] = []97 function cb(result, oldVnode, newVnode) {98 if (result.length > 1) {99 expect(result[result.length - 1]).toEqual(oldVnode)100 }101 result.push(newVnode)102 }103 const vnode1 = new VNode('div', {}, [104 new VNode('span', {}, undefined, 'first sibling'),105 new VNode('div', { hook: { update: cb.bind(null, result1) } }, [106 new VNode('span', {}, undefined, 'child 1'),107 new VNode(108 'span',109 { hook: { update: cb.bind(null, result2) } },110 undefined,111 'child 2'112 )113 ])114 ])115 const vnode2 = new VNode('div', {}, [116 new VNode('span', {}, undefined, 'first sibling'),117 new VNode('div', { hook: { update: cb.bind(null, result1) } }, [118 new VNode('span', {}, undefined, 'child 1'),119 new VNode(120 'span',121 { hook: { update: cb.bind(null, result2) } },122 undefined,123 'child 2'124 )125 ])126 ])127 patch(vnode0, vnode1)128 patch(vnode1, vnode2)129 expect(result1.length).toBe(1)130 expect(result2.length).toBe(1)131 })132133 it('should call `remove` listener', () => {134 const result: any[] = []135 function remove(vnode, rm) {136 const parent = vnode.elm.parentNode137 expect(vnode.elm.children.length).toBe(2)138 expect(vnode.elm.children.length).toBe(2)139 result.push(vnode)140 rm()141 expect(parent.children.length).toBe(1)142 }143 const vnode1 = new VNode('div', {}, [144 new VNode('span', {}, undefined, 'first sibling'),145 new VNode('div', { hook: { remove } }, [146 new VNode('span', {}, undefined, 'child 1'),147 new VNode('span', {}, undefined, 'child 2')148 ])149 ])150 const vnode2 = new VNode('div', {}, [151 new VNode('span', {}, undefined, 'first sibling')152 ])153 patch(vnode0, vnode1)154 patch(vnode1, vnode2)155 expect(result.length).toBe(1)156 })157158 it('should call `init` and `prepatch` listeners on root', () => {159 let count = 0160 function init(vnode) {161 count++162 }163 function prepatch(oldVnode, newVnode) {164 count++165 }166 const vnode1 = new VNode('div', { hook: { init, prepatch } })167 patch(vnode0, vnode1)168 expect(count).toBe(1)169 const vnode2 = new VNode('span', { hook: { init, prepatch } })170 patch(vnode1, vnode2)171 expect(count).toBe(2)172 })173174 it('should remove element when all remove listeners are done', () => {175 let rm1, rm2, rm3176 const patch1 = createPatchFunction({177 nodeOps,178 // @ts-ignore - TODO dtw179 modules: modules.concat([180 {181 remove(_, rm) {182 rm1 = rm183 }184 },185 {186 remove(_, rm) {187 rm2 = rm188 }189 }190 ])191 })192 const vnode1 = new VNode('div', {}, [193 new VNode('a', {194 hook: {195 remove(_, rm) {196 rm3 = rm197 }198 }199 })200 ])201 const vnode2 = new VNode('div', {}, [])202 let elm = patch1(vnode0, vnode1)203 expect(elm.children.length).toBe(1)204 elm = patch1(vnode1, vnode2)205 expect(elm.children.length).toBe(1)206 rm1()207 expect(elm.children.length).toBe(1)208 rm3()209 expect(elm.children.length).toBe(1)210 rm2()211 expect(elm.children.length).toBe(0)212 })213214 it('should invoke the remove hook on replaced root', () => {215 const result: any[] = []216 const parent = nodeOps.createElement('div')217 vnode0 = nodeOps.createElement('div')218 parent.appendChild(vnode0)219 function remove(vnode, rm) {220 result.push(vnode)221 rm()222 }223 const vnode1 = new VNode('div', { hook: { remove } }, [224 new VNode('b', {}, undefined, 'child 1'),225 new VNode('i', {}, undefined, 'child 2')226 ])227 const vnode2 = new VNode('span', {}, [228 new VNode('b', {}, undefined, 'child 1'),229 new VNode('i', {}, undefined, 'child 2')230 ])231 patch(vnode0, vnode1)232 patch(vnode1, vnode2)233 expect(result.length).toBe(1)234 })235236 it('should invoke global `destroy` hook for all removed children', () => {237 const result: any[] = []238 function destroy(vnode) {239 result.push(vnode)240 }241 const vnode1 = new VNode('div', {}, [242 new VNode('span', {}, undefined, 'first sibling'),243 new VNode('div', {}, [244 new VNode('span', { hook: { destroy } }, undefined, 'child 1'),245 new VNode('span', {}, undefined, 'child 2')246 ])247 ])248 const vnode2 = new VNode('div')249 patch(vnode0, vnode1)250 patch(vnode1, vnode2)251 expect(result.length).toBe(1)252 })253254 it('should handle text vnodes with `undefined` `data` property', () => {255 const vnode1 = new VNode('div', {}, [createTextVNode(' ')])256 const vnode2 = new VNode('div', {}, [])257 patch(vnode0, vnode1)258 patch(vnode1, vnode2)259 })260261 it('should invoke `destroy` module hook for all removed children', () => {262 let created = 0263 let destroyed = 0264 const patch1 = createPatchFunction({265 nodeOps,266 modules: modules.concat([267 {268 create() {269 created++270 }271 },272 {273 destroy() {274 destroyed++275 }276 }277 ])278 })279 const vnode1 = new VNode('div', {}, [280 new VNode('span', {}, undefined, 'first sibling'),281 new VNode('div', {}, [282 new VNode('span', {}, undefined, 'child 1'),283 new VNode('span', {}, undefined, 'child 2')284 ])285 ])286 const vnode2 = new VNode('div', {})287 patch1(vnode0, vnode1)288 expect(destroyed).toBe(1) // should invoke for replaced root nodes too289 patch1(vnode1, vnode2)290 expect(created).toBe(5)291 expect(destroyed).toBe(5)292 })293294 it('should not invoke `create` and `remove` module hook for text nodes', () => {295 let created = 0296 let removed = 0297 const patch1 = createPatchFunction({298 nodeOps,299 modules: modules.concat([300 {301 create() {302 created++303 }304 },305 {306 remove() {307 removed++308 }309 }310 ])311 })312 const vnode1 = new VNode('div', {}, [313 new VNode('span', {}, undefined, 'first child'),314 createTextVNode(''),315 new VNode('span', {}, undefined, 'third child')316 ])317 const vnode2 = new VNode('div', {})318 patch1(vnode0, vnode1)319 patch1(vnode1, vnode2)320 expect(created).toBe(3)321 expect(removed).toBe(2)322 })323324 it('should not invoke `destroy` module hook for text nodes', () => {325 let created = 0326 let destroyed = 0327 const patch1 = createPatchFunction({328 nodeOps,329 modules: modules.concat([330 {331 create() {332 created++333 }334 },335 {336 destroy() {337 destroyed++338 }339 }340 ])341 })342 const vnode1 = new VNode('div', {}, [343 new VNode('span', {}, undefined, 'first sibling'),344 new VNode('div', {}, [345 new VNode('span', {}, undefined, 'child 1'),346 new VNode('span', {}, [347 createTextVNode('text1'),348 createTextVNode('text2')349 ])350 ])351 ])352 const vnode2 = new VNode('div', {})353 patch1(vnode0, vnode1)354 expect(destroyed).toBe(1) // should invoke for replaced root nodes too355 patch1(vnode1, vnode2)356 expect(created).toBe(5)357 expect(destroyed).toBe(5)358 })359360 it('should call `create` listener before inserted into parent but after children', () => {361 const result: any[] = []362 function create(empty, vnode) {363 expect(vnode.elm.children.length).toBe(2)364 expect(vnode.elm.parentNode).toBe(null)365 result.push(vnode)366 }367 const vnode1 = new VNode('div', {}, [368 new VNode('span', {}, undefined, 'first sibling'),369 new VNode('div', { hook: { create } }, [370 new VNode('span', {}, undefined, 'child 1'),371 new VNode('span', {}, undefined, 'child 2')372 ]),373 new VNode('span', {}, undefined, "can't touch me")374 ])375 patch(vnode0, vnode1)376 expect(result.length).toBe(1)377 })378})
Findings
✓ No findings reported for this file.