github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/themes/wind/static/libs/vue-1.0.24/test/unit/specs/misc_spec.js (about) 1 // test cases for edge cases & bug fixes 2 var Vue = require('src') 3 var _ = Vue.util 4 5 describe('Misc', function () { 6 it('should handle directive.bind() altering its childNode structure', function () { 7 var vm = new Vue({ 8 el: document.createElement('div'), 9 template: '<div v-test>{{test}}</div>', 10 data: { 11 test: 'foo' 12 }, 13 directives: { 14 test: { 15 bind: function () { 16 this.el.insertBefore(document.createTextNode('bar '), 17 this.el.firstChild) 18 } 19 } 20 } 21 }) 22 expect(vm.$el.textContent).toBe('bar foo') 23 }) 24 25 it('attached/detached hooks for transcluded components', function () { 26 var spy1 = jasmine.createSpy('attached') 27 var spy2 = jasmine.createSpy('detached') 28 var el = document.createElement('div') 29 el.innerHTML = '<outer v-ref:outter><inner></inner></outer>' 30 document.body.appendChild(el) 31 32 var vm = new Vue({ 33 el: el, 34 components: { 35 outer: { 36 template: '<slot></slot>' 37 }, 38 inner: { 39 template: 'foo', 40 attached: spy1, 41 detached: spy2 42 } 43 } 44 }) 45 expect(spy1).toHaveBeenCalled() 46 vm.$refs.outter.$remove() 47 expect(spy2).toHaveBeenCalled() 48 }) 49 50 it('v-for on component root node with replace:true', function () { 51 var el = document.createElement('div') 52 var vm = new Vue({ 53 el: el, 54 template: '<test></test>', 55 components: { 56 test: { 57 data: function () { 58 return { list: [1, 2, 3] } 59 }, 60 template: '<div v-for="n in list">{{n}}</div>', 61 replace: true 62 } 63 } 64 }) 65 expect(vm.$el.innerHTML).toBe('<div>1</div><div>2</div><div>3</div>') 66 }) 67 68 // #922 69 it('template v-for inside svg', function () { 70 var el = document.createElement('div') 71 new Vue({ 72 el: el, 73 template: '<svg><template v-for="n in list"><text>{{n}}</text></template></svg>', 74 data: { 75 list: [1, 2, 3] 76 } 77 }) 78 // IE inlines svg namespace 79 var xmlns = /\s?xmlns=".*svg"/ 80 expect(el.innerHTML.replace(xmlns, '')).toBe('<svg><text>1</text><text>2</text><text>3</text></svg>') 81 }) 82 83 // #1005 84 it('call lifecycle hooks for child components', function () { 85 Vue.options.replace = true 86 var el = document.createElement('div') 87 var logs = [] 88 function log (n) { 89 return function () { 90 logs.push(n) 91 } 92 } 93 document.body.appendChild(el) 94 var vm = new Vue({ 95 el: el, 96 attached: log(0), 97 ready: log(1), 98 detached: log(2), 99 beforeDestroy: log(3), 100 destroyed: log(4), 101 template: '<div><test></test><test></test></div>', 102 components: { 103 test: { 104 template: '<span>hi</span>', 105 attached: log(5), 106 ready: log(6), 107 detached: log(7), 108 beforeDestroy: log(8), 109 destroyed: log(9) 110 } 111 } 112 }) 113 expect(vm.$el.innerHTML).toBe('<span>hi</span><span>hi</span>') 114 expect(logs.join()).toBe('0,5,6,5,6,1') 115 logs = [] 116 vm.$destroy(true) 117 expect(logs.join()).toBe('2,7,7,3,8,9,8,9,4') 118 Vue.options.replace = false 119 }) 120 121 // #1966 122 it('call lifecycle hooks for child and grandchild components', function () { 123 Vue.options.replace = true 124 var el = document.createElement('div') 125 var logs = [] 126 function log (n) { 127 return function () { 128 logs.push(n) 129 } 130 } 131 document.body.appendChild(el) 132 var vm = new Vue({ 133 el: el, 134 attached: log(0), 135 ready: log(1), 136 detached: log(2), 137 beforeDestroy: log(3), 138 destroyed: log(4), 139 template: '<div><test></test></div>', 140 components: { 141 test: { 142 attached: log(5), 143 ready: log(6), 144 detached: log(7), 145 beforeDestroy: log(8), 146 destroyed: log(9), 147 template: '<div><test-inner></test-inner></div>', 148 components: { 149 'test-inner': { 150 attached: log(10), 151 ready: log(11), 152 detached: log(12), 153 beforeDestroy: log(13), 154 destroyed: log(14), 155 template: '<span>hi</span>' 156 } 157 } 158 159 } 160 } 161 }) 162 expect(vm.$el.innerHTML).toBe('<div><span>hi</span></div>') 163 expect(logs.join()).toBe('0,5,10,11,6,1') 164 logs = [] 165 vm.$destroy(true) 166 expect(logs.join()).toBe('2,7,12,3,8,13,14,9,4') 167 Vue.options.replace = false 168 }) 169 170 // #1006 171 it('destroyed hook for components inside v-if', function (done) { 172 var spy = jasmine.createSpy('v-if destroyed hook') 173 var vm = new Vue({ 174 el: document.createElement('div'), 175 template: '<template v-if="ok"><test></test></template>', 176 data: { 177 ok: true 178 }, 179 components: { 180 test: { 181 destroyed: spy 182 } 183 } 184 }) 185 vm.ok = false 186 Vue.nextTick(function () { 187 expect(spy).toHaveBeenCalled() 188 done() 189 }) 190 }) 191 192 it('frozen model, root', function (done) { 193 var vm = new Vue({ 194 el: document.createElement('div'), 195 template: '{{msg}}', 196 data: Object.freeze({ 197 msg: 'foo' 198 }) 199 }) 200 expect(vm.$el.textContent).toBe('foo') 201 try { vm.msg = 'bar' } catch (e) {} 202 Vue.nextTick(function () { 203 expect(vm.$el.textContent).toBe('foo') 204 done() 205 }) 206 }) 207 208 it('frozen model, non-root', function (done) { 209 var vm = new Vue({ 210 el: document.createElement('div'), 211 template: '{{msg}} {{frozen.msg}}', 212 data: { 213 msg: 'foo', 214 frozen: Object.freeze({ 215 msg: 'frozen' 216 }) 217 } 218 }) 219 expect(vm.$el.textContent).toBe('foo frozen') 220 vm.msg = 'bar' 221 try { 222 vm.frozen.msg = 'changed' 223 } catch (error) { 224 if (!(error instanceof TypeError)) { 225 throw error 226 } 227 } 228 Vue.nextTick(function () { 229 expect(vm.$el.textContent).toBe('bar frozen') 230 done() 231 }) 232 }) 233 234 it('should not trigger deep/Array watchers when digesting', function (done) { 235 var spy1 = jasmine.createSpy('deep') 236 var spy2 = jasmine.createSpy('Array') 237 var spy3 = jasmine.createSpy('test') 238 var spy4 = jasmine.createSpy('deep-mutated') 239 var vm = new Vue({ 240 el: document.createElement('div'), 241 data: { 242 obj: {}, 243 arr: [], 244 obj2: {} 245 }, 246 watch: { 247 obj: { 248 handler: spy1, 249 deep: true 250 }, 251 arr: spy2, 252 // if the watcher is watching the added value, 253 // it should still trigger properly 254 test: { 255 handler: spy3, 256 deep: true 257 }, 258 // if the object is in fact mutated, it should 259 // still trigger. 260 obj2: { 261 handler: spy4, 262 deep: true 263 } 264 } 265 }) 266 var test = [] 267 var obj2 = vm.obj2 268 vm.$set('test', test) 269 _.set(obj2, 'test', 123) 270 Vue.nextTick(function () { 271 expect(spy1).not.toHaveBeenCalled() 272 expect(spy2).not.toHaveBeenCalled() 273 expect(spy3).toHaveBeenCalledWith(test, undefined) 274 expect(spy4).toHaveBeenCalledWith(obj2, obj2) 275 done() 276 }) 277 }) 278 279 it('handle interpolated textarea', function (done) { 280 var el = document.createElement('div') 281 el.innerHTML = '<textarea>hello {{msg}}</textarea>' 282 var vm = new Vue({ 283 el: el, 284 data: { 285 msg: 'test' 286 } 287 }) 288 expect(el.innerHTML).toBe('<textarea>hello test</textarea>') 289 vm.msg = 'world' 290 Vue.nextTick(function () { 291 expect(el.innerHTML).toBe('<textarea>hello world</textarea>') 292 done() 293 }) 294 }) 295 296 it('nested object $set should trigger parent array notify', function (done) { 297 var vm = new Vue({ 298 el: document.createElement('div'), 299 template: '{{items | json}}{{items[0].a}}', 300 data: { 301 items: [{}] 302 } 303 }) 304 expect(vm.$el.textContent).toBe(JSON.stringify(vm.items, null, 2)) 305 _.set(vm.items[0], 'a', 123) 306 Vue.nextTick(function () { 307 expect(vm.$el.textContent).toBe(JSON.stringify(vm.items, null, 2) + '123') 308 done() 309 }) 310 }) 311 312 it('warn unkown custom element', function () { 313 new Vue({ 314 el: document.createElement('div'), 315 template: '<custom-stuff></custom-stuff>' 316 }) 317 expect('Unknown custom element').toHaveBeenWarned() 318 }) 319 320 it('prefer bound attributes over static attributes', function (done) { 321 var el = document.createElement('div') 322 var count = 0 323 var expected = [ 324 'bound', 325 'bound', 326 'static', 327 'bound', 328 'bound' 329 ] 330 function check (title) { 331 expect(title).toBe(expected[count]) 332 count++ 333 if (count === 4) { 334 done() 335 } 336 } 337 338 new Vue({ 339 el: el, 340 template: 341 '<div>' + 342 '<comp v-bind:title="title"></comp>' + 343 '<comp title="static" v-bind:title="title"></comp>' + 344 '<comp title="static"></comp>' + 345 '<comp :title="title"></comp>' + 346 '<comp title="static" :title="title"></comp>' + 347 '</div>', 348 data: { 349 title: 'bound' 350 }, 351 components: { 352 comp: { 353 props: ['title'], 354 created: function () { 355 check(this.title) 356 } 357 } 358 } 359 }) 360 }) 361 362 it('deep watch for class, style and bind', function (done) { 363 var el = document.createElement('div') 364 var vm = new Vue({ 365 el: el, 366 template: '<div :class="classes" :style="styles" v-bind="attrs"></div>', 367 data: { 368 classes: { a: true, b: false }, 369 styles: { color: 'red', fontSize: '14px' }, 370 attrs: { a: 1, b: 2 } 371 } 372 }) 373 var div = el.firstChild 374 expect(div.className).toBe('a') 375 expect(div.style.color).toBe('red') 376 expect(div.style.fontSize).toBe('14px') 377 expect(div.getAttribute('a')).toBe('1') 378 expect(div.getAttribute('b')).toBe('2') 379 vm.classes.b = true 380 vm.styles.color = 'green' 381 vm.attrs.a = 3 382 Vue.nextTick(function () { 383 expect(div.className).toBe('a b') 384 expect(div.style.color).toBe('green') 385 expect(div.style.fontSize).toBe('14px') 386 expect(div.getAttribute('a')).toBe('3') 387 expect(div.getAttribute('b')).toBe('2') 388 done() 389 }) 390 }) 391 392 it('IE9 class & :class merge during transclusion', function () { 393 var vm = new Vue({ 394 el: document.createElement('div'), 395 template: '<test class="outer"></test>', 396 components: { 397 test: { 398 replace: true, 399 template: '<div class="static-inner" :class="{\'inner\': true}"></div>' 400 } 401 } 402 }) 403 expect(vm.$el.firstChild.className).toBe('static-inner outer inner') 404 }) 405 406 it('SVG class interpolation', function () { 407 var vm = new Vue({ 408 el: document.createElement('div'), 409 template: '<icon class="abc" icon="def"></icon>', 410 components: { 411 icon: { 412 props: ['class', 'icon'], 413 replace: true, 414 template: '<svg class="si-icon {{icon}} {{class}}"><use xlink:href=""></use></svg>' 415 } 416 } 417 }) 418 expect(vm.$el.firstChild.getAttribute('class')).toBe('si-icon def abc') 419 }) 420 421 // #1960 422 it('class interpolation should preserve transition class', function () { 423 var vm = new Vue({ 424 el: document.createElement('div'), 425 template: '<div class="{{test}}" transition="test"></div>', 426 data: { 427 test: 'foo' 428 } 429 }) 430 expect(vm.$el.firstChild.className).toBe('foo test-transition') 431 }) 432 433 it('transclude class merging should skip interpolated class', function () { 434 var vm = new Vue({ 435 el: document.createElement('div'), 436 template: '<test class="outer-{{test}}"></test>', 437 data: { 438 test: 'foo' 439 }, 440 components: { 441 test: { 442 template: '<div class="inner"></div>', 443 replace: true 444 } 445 } 446 }) 447 expect(vm.$el.firstChild.className).toBe('outer-foo') 448 }) 449 450 // #2163 451 it('slot compilation order with v-if', function () { 452 var vm = new Vue({ 453 el: document.createElement('div'), 454 template: 455 '<test>' + 456 '<div slot="one">slot1</div>' + 457 'default content' + 458 '</test>', 459 components: { 460 test: { 461 template: 462 '<div>' + 463 '<slot v-if="true"></slot> ' + 464 '<slot name="one"></slot>' + 465 '</div>', 466 replace: true 467 } 468 } 469 }) 470 expect(vm.$el.textContent).toBe('default content slot1') 471 }) 472 473 // #2426 474 it('class merge untrimmed', function () { 475 expect(function () { 476 new Vue({ 477 el: document.createElement('div'), 478 template: '<test class="p1 p2 "></test>', 479 components: { 480 test: { 481 template: '<div class="hi"></div>', 482 replace: true 483 } 484 } 485 }) 486 }).not.toThrow() 487 }) 488 489 // #2445 490 it('fragment attach hook should check if child is inDoc', function (done) { 491 var el = document.createElement('div') 492 document.body.appendChild(el) 493 var spyParent = jasmine.createSpy('attached parent') 494 var spyChild = jasmine.createSpy('attached child') 495 496 new Vue({ 497 el: el, 498 template: '<comp v-for="n in 1"></comp>', 499 components: { 500 comp: { 501 template: '<div><child></child></div>', 502 attached: function () { 503 expect(_.inDoc(this.$el)).toBe(true) 504 spyParent() 505 }, 506 activate: function (next) { 507 setTimeout(function () { 508 next() 509 check() 510 }, 100) 511 }, 512 components: { 513 child: { 514 template: 'foo', 515 attached: spyChild 516 } 517 } 518 } 519 } 520 }) 521 522 function check () { 523 expect(spyParent).toHaveBeenCalled() 524 expect(spyChild).toHaveBeenCalled() 525 done() 526 } 527 }) 528 529 // #2500 530 it('template parser tag match should include hyphen', function () { 531 var vm = new Vue({ 532 el: document.createElement('div'), 533 template: '<div>{{{ test }}}</div>', 534 data: { 535 test: '<image-field></image-field>' 536 } 537 }) 538 expect(vm.$el.querySelector('image-field').namespaceURI).not.toMatch(/svg/) 539 }) 540 541 // #2657 542 it('template v-for with v-if', function () { 543 var vm = new Vue({ 544 el: document.createElement('div'), 545 template: '<div><template v-for="n in 6" v-if="n % 2">{{ n }}</template></div>' 546 }) 547 expect(vm.$el.textContent).toBe('135') 548 }) 549 550 // #2821 551 it('batcher should keep flushing until all queues are depleted', function (done) { 552 var spy = jasmine.createSpy() 553 var vm = new Vue({ 554 el: document.createElement('div'), 555 template: '<test :prop="model"></test>', 556 data: { 557 model: 0, 558 count: 0 559 }, 560 watch: { 561 count: function () { 562 this.model++ 563 } 564 }, 565 components: { 566 test: { 567 props: ['prop'], 568 watch: { 569 prop: spy 570 } 571 } 572 } 573 }) 574 vm.count++ 575 Vue.nextTick(function () { 576 expect(spy).toHaveBeenCalled() 577 done() 578 }) 579 }) 580 })