github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/test/unit/specs/compiler/compile_spec.js (about) 1 var Vue = require('src') 2 var _ = require('src/util') 3 var FragmentFactory = require('src/fragment/factory') 4 var compiler = require('src/compiler') 5 var compile = compiler.compile 6 var publicDirectives = require('src/directives/public') 7 var internalDirectives = require('src/directives/internal') 8 9 describe('Compile', function () { 10 var vm, el, data, directiveBind, directiveTeardown 11 beforeEach(function () { 12 // We mock vms here so we can assert what the generated 13 // linker functions do. 14 el = document.createElement('div') 15 data = {} 16 directiveBind = jasmine.createSpy('bind') 17 directiveTeardown = jasmine.createSpy('teardown') 18 vm = { 19 $options: {}, 20 _data: {}, 21 _directives: [], 22 _bindDir: function (descriptor, node) { 23 this._directives.push({ 24 name: descriptor.name, 25 descriptor: descriptor, 26 _bind: function () { 27 directiveBind(this.name) 28 }, 29 _teardown: directiveTeardown 30 }) 31 }, 32 $get: function (exp) { 33 return (new Vue()).$get(exp) 34 }, 35 $eval: function (value) { 36 return data[value] 37 }, 38 $interpolate: function (value) { 39 return data[value] 40 }, 41 _context: { 42 _directives: [], 43 $get: function (v) { 44 return 'from parent: ' + v 45 } 46 } 47 } 48 spyOn(vm, '_bindDir').and.callThrough() 49 spyOn(vm, '$eval').and.callThrough() 50 spyOn(vm, '$interpolate').and.callThrough() 51 }) 52 53 it('normal directives', function () { 54 el.setAttribute('v-a', 'b') 55 el.innerHTML = '<p v-a:hello.a.b="a" v-b="1">hello</p><div v-b.literal="foo"></div>' 56 var defA = { priority: 1 } 57 var defB = { priority: 2 } 58 var options = _.mergeOptions(Vue.options, { 59 directives: { 60 a: defA, 61 b: defB 62 } 63 }) 64 var linker = compile(el, options) 65 expect(typeof linker).toBe('function') 66 linker(vm, el) 67 expect(directiveBind.calls.count()).toBe(4) 68 expect(vm._bindDir.calls.count()).toBe(4) 69 70 // check if we are in firefox, which has different 71 // attribute interation order 72 var isAttrReversed = el.firstChild.attributes[0].name === 'v-b' 73 74 // 1 75 var args = vm._bindDir.calls.argsFor(0) 76 expect(args[0].name).toBe('a') 77 expect(args[0].expression).toBe('b') 78 expect(args[0].def).toBe(defA) 79 expect(args[1]).toBe(el) 80 // 2 81 args = vm._bindDir.calls.argsFor(isAttrReversed ? 2 : 1) 82 expect(args[0].name).toBe('a') 83 expect(args[0].expression).toBe('a') 84 expect(args[0].def).toBe(defA) 85 // args + multiple modifiers 86 expect(args[0].arg).toBe('hello') 87 expect(args[0].modifiers.a).toBe(true) 88 expect(args[0].modifiers.b).toBe(true) 89 expect(args[1]).toBe(el.firstChild) 90 // 3 (expression literal) 91 args = vm._bindDir.calls.argsFor(isAttrReversed ? 1 : 2) 92 expect(args[0].name).toBe('b') 93 expect(args[0].expression).toBe('1') 94 expect(args[0].def).toBe(defB) 95 expect(args[1]).toBe(el.firstChild) 96 // 4 (explicit literal) 97 args = vm._bindDir.calls.argsFor(3) 98 expect(args[0].name).toBe('b') 99 expect(args[0].expression).toBe('foo') 100 expect(args[0].def).toBe(defB) 101 expect(args[0].modifiers.literal).toBe(true) 102 expect(args[1]).toBe(el.lastChild) 103 // check the priority sorting 104 // the "b"s should be called first! 105 expect(directiveBind.calls.argsFor(0)[0]).toBe('b') 106 expect(directiveBind.calls.argsFor(1)[0]).toBe('b') 107 expect(directiveBind.calls.argsFor(2)[0]).toBe('a') 108 expect(directiveBind.calls.argsFor(3)[0]).toBe('a') 109 }) 110 111 it('v-bind shorthand', function () { 112 el.setAttribute(':class', 'a') 113 el.setAttribute(':style', 'b') 114 el.setAttribute(':title', 'c') 115 116 // The order of setAttribute is not guaranteed to be the same with 117 // the order of attribute enumberation, therefore we need to save 118 // it here! 119 var descriptors = { 120 ':class': { 121 name: 'class', 122 attr: ':class', 123 expression: 'a', 124 def: internalDirectives.class 125 }, 126 ':style': { 127 name: 'style', 128 attr: ':style', 129 expression: 'b', 130 def: internalDirectives.style 131 }, 132 ':title': { 133 name: 'bind', 134 attr: ':title', 135 expression: 'c', 136 arg: 'title', 137 def: publicDirectives.bind 138 } 139 } 140 var expects = [].map.call(el.attributes, function (attr) { 141 return descriptors[attr.name] 142 }) 143 144 var linker = compile(el, Vue.options) 145 linker(vm, el) 146 expect(vm._bindDir.calls.count()).toBe(3) 147 148 expects.forEach(function (e, i) { 149 var args = vm._bindDir.calls.argsFor(i) 150 for (var key in e) { 151 expect(args[0][key]).toBe(e[key]) 152 } 153 expect(args[1]).toBe(el) 154 }) 155 }) 156 157 it('v-on shorthand', function () { 158 el.innerHTML = '<div @click="a++"></div>' 159 el = el.firstChild 160 var linker = compile(el, Vue.options) 161 linker(vm, el) 162 expect(vm._bindDir.calls.count()).toBe(1) 163 var args = vm._bindDir.calls.argsFor(0) 164 expect(args[0].name).toBe('on') 165 expect(args[0].expression).toBe('a++') 166 expect(args[0].arg).toBe('click') 167 expect(args[0].def).toBe(publicDirectives.on) 168 expect(args[1]).toBe(el) 169 }) 170 171 it('text interpolation', function () { 172 data.b = 'yeah' 173 el.innerHTML = '{{a}} and {{*b}}' 174 var def = Vue.options.directives.text 175 var linker = compile(el, Vue.options) 176 linker(vm, el) 177 // expect 1 call because one-time bindings do not generate a directive. 178 expect(vm._bindDir.calls.count()).toBe(1) 179 var args = vm._bindDir.calls.argsFor(0) 180 expect(args[0].name).toBe('text') 181 expect(args[0].expression).toBe('a') 182 expect(args[0].def).toBe(def) 183 // skip the node because it's generated in the linker fn via cloneNode 184 // expect $eval to be called during onetime 185 expect(vm.$eval).toHaveBeenCalledWith('b') 186 // {{a}} is mocked so it's a space. 187 // but we want to make sure {{*b}} worked. 188 expect(el.innerHTML).toBe(' and yeah') 189 }) 190 191 it('text interpolation, adjacent nodes', function () { 192 data.b = 'yeah' 193 el.appendChild(document.createTextNode('{{a')) 194 el.appendChild(document.createTextNode('}} and {{')) 195 el.appendChild(document.createTextNode('*b}}')) 196 var def = Vue.options.directives.text 197 var linker = compile(el, Vue.options) 198 linker(vm, el) 199 // expect 1 call because one-time bindings do not generate a directive. 200 expect(vm._bindDir.calls.count()).toBe(1) 201 var args = vm._bindDir.calls.argsFor(0) 202 expect(args[0].name).toBe('text') 203 expect(args[0].expression).toBe('a') 204 expect(args[0].def).toBe(def) 205 // skip the node because it's generated in the linker fn via cloneNode 206 // expect $eval to be called during onetime 207 expect(vm.$eval).toHaveBeenCalledWith('b') 208 // {{a}} is mocked so it's a space. 209 // but we want to make sure {{*b}} worked. 210 expect(el.innerHTML).toBe(' and yeah') 211 }) 212 213 it('adjacent text nodes with no interpolation', function () { 214 el.appendChild(document.createTextNode('a')) 215 el.appendChild(document.createTextNode('b')) 216 el.appendChild(document.createTextNode('c')) 217 var linker = compile(el, Vue.options) 218 linker(vm, el) 219 expect(el.innerHTML).toBe('abc') 220 }) 221 222 it('inline html', function () { 223 data.html = '<div>foo</div>' 224 el.innerHTML = '{{{html}}} {{{*html}}}' 225 var htmlDef = Vue.options.directives.html 226 var linker = compile(el, Vue.options) 227 linker(vm, el) 228 expect(vm._bindDir.calls.count()).toBe(1) 229 var htmlArgs = vm._bindDir.calls.argsFor(0) 230 expect(htmlArgs[0].name).toBe('html') 231 expect(htmlArgs[0].expression).toBe('html') 232 expect(htmlArgs[0].def).toBe(htmlDef) 233 // with placeholder comments & interpolated one-time html 234 expect(el.innerHTML).toBe('<!--v-html--> <div>foo</div>') 235 }) 236 237 it('terminal directives', function () { 238 el.innerHTML = 239 '<div v-for="item in items"><p v-a="b"></p></div>' + // v-for 240 '<div v-pre><p v-a="b"></p></div>' // v-pre 241 var def = Vue.options.directives.for 242 var linker = compile(el, Vue.options) 243 linker(vm, el) 244 // expect 1 call because terminal should return early and let 245 // the directive handle the rest. 246 expect(vm._bindDir.calls.count()).toBe(1) 247 var args = vm._bindDir.calls.argsFor(0) 248 expect(args[0].name).toBe('for') 249 expect(args[0].expression).toBe('item in items') 250 expect(args[0].def).toBe(def) 251 expect(args[1]).toBe(el.firstChild) 252 }) 253 254 it('custom terminal directives', function () { 255 var defTerminal = { 256 terminal: true, 257 priority: Vue.options.directives.if.priority + 1 258 } 259 var options = _.mergeOptions(Vue.options, { 260 directives: { term: defTerminal } 261 }) 262 el.innerHTML = '<div v-term:arg1.modifier1.modifier2="foo"></div>' 263 var linker = compile(el, options) 264 linker(vm, el) 265 expect(vm._bindDir.calls.count()).toBe(1) 266 var args = vm._bindDir.calls.argsFor(0) 267 expect(args[0].name).toBe('term') 268 expect(args[0].expression).toBe('foo') 269 expect(args[0].attr).toBe('v-term:arg1.modifier1.modifier2') 270 expect(args[0].arg).toBe('arg1') 271 expect(args[0].modifiers.modifier1).toBe(true) 272 expect(args[0].modifiers.modifier2).toBe(true) 273 expect(args[0].def).toBe(defTerminal) 274 }) 275 276 it('custom terminal directives priority', function () { 277 var defTerminal = { 278 terminal: true, 279 priority: Vue.options.directives.if.priority + 1 280 } 281 var options = _.mergeOptions(Vue.options, { 282 directives: { term: defTerminal } 283 }) 284 el.innerHTML = '<div v-term:arg1 v-if="ok"></div>' 285 var linker = compile(el, options) 286 linker(vm, el) 287 expect(vm._bindDir.calls.count()).toBe(1) 288 var args = vm._bindDir.calls.argsFor(0) 289 expect(args[0].name).toBe('term') 290 expect(args[0].expression).toBe('') 291 expect(args[0].attr).toBe('v-term:arg1') 292 expect(args[0].arg).toBe('arg1') 293 expect(args[0].def).toBe(defTerminal) 294 }) 295 296 it('custom element components', function () { 297 var options = _.mergeOptions(Vue.options, { 298 components: { 299 'my-component': {} 300 } 301 }) 302 el.innerHTML = '<my-component><div v-a="b"></div></my-component>' 303 var linker = compile(el, options) 304 linker(vm, el) 305 expect(vm._bindDir.calls.count()).toBe(1) 306 var args = vm._bindDir.calls.argsFor(0) 307 expect(args[0].name).toBe('component') 308 expect(args[0].expression).toBe('my-component') 309 expect(args[0].modifiers.literal).toBe(true) 310 expect(args[0].def).toBe(internalDirectives.component) 311 expect(getWarnCount()).toBe(0) 312 }) 313 314 it('props', function () { 315 var bindingModes = Vue.config._propBindingModes 316 var props = { 317 testNormal: null, 318 testLiteral: null, 319 testBoolean: { type: Boolean }, 320 testTwoWay: null, 321 twoWayWarn: null, 322 testOneTime: null, 323 optimizeLiteral: null, 324 optimizeLiteralStr: null, 325 optimizeLiteralNegativeNumber: null, 326 literalWithFilter: null 327 } 328 el.innerHTML = '<div ' + 329 'v-bind:test-normal="a" ' + 330 'test-literal="1" ' + 331 'test-boolean ' + 332 ':optimize-literal="1" ' + 333 ':optimize-literal-str="\'true\'"' + 334 ':optimize-literal-negative-number="-1"' + 335 ':test-two-way.sync="a" ' + 336 ':two-way-warn.sync="a + 1" ' + 337 ':test-one-time.once="a" ' + 338 ':literal-with-filter="\'FOO\' | lowercase"' + 339 '></div>' 340 compiler.compileAndLinkProps(vm, el.firstChild, props) 341 // check bindDir calls: 342 // skip literal and one time, but not literal with filter 343 expect(vm._bindDir.calls.count()).toBe(4) 344 // literal 345 expect(vm.testLiteral).toBe('1') 346 expect(vm.testBoolean).toBe(true) 347 expect(vm.optimizeLiteral).toBe(1) 348 expect(vm.optimizeLiteralStr).toBe('true') 349 expect(vm.optimizeLiteralNegativeNumber).toBe(-1) 350 // one time 351 expect(vm.testOneTime).toBe('from parent: a') 352 // normal 353 var args = vm._bindDir.calls.argsFor(0) 354 var prop = args[0].prop 355 expect(args[0].name).toBe('prop') 356 expect(prop.path).toBe('testNormal') 357 expect(prop.parentPath).toBe('a') 358 expect(prop.mode).toBe(bindingModes.ONE_WAY) 359 // two way 360 args = vm._bindDir.calls.argsFor(1) 361 prop = args[0].prop 362 expect(args[0].name).toBe('prop') 363 expect(prop.path).toBe('testTwoWay') 364 expect(prop.parentPath).toBe('a') 365 expect(prop.mode).toBe(bindingModes.TWO_WAY) 366 // two way warn 367 expect('non-settable parent path').toHaveBeenWarned() 368 // literal with filter 369 args = vm._bindDir.calls.argsFor(3) 370 prop = args[0].prop 371 expect(args[0].name).toBe('prop') 372 expect(prop.path).toBe('literalWithFilter') 373 expect(prop.parentPath).toBe("'FOO'") 374 expect(prop.filters.length).toBe(1) 375 expect(prop.mode).toBe(bindingModes.ONE_WAY) 376 }) 377 378 it('props on root instance', function () { 379 // temporarily remove vm.$parent 380 var context = vm._context 381 vm._context = null 382 el.setAttribute('v-bind:a', '"foo"') 383 el.setAttribute(':b', '[1,2,3]') 384 compiler.compileAndLinkProps(vm, el, { a: null, b: null }) 385 expect(vm._bindDir.calls.count()).toBe(0) 386 expect(vm.a).toBe('foo') 387 expect(vm.b.join(',')).toBe('1,2,3') 388 // restore parent mock 389 vm._context = context 390 }) 391 392 it('DocumentFragment', function () { 393 var frag = document.createDocumentFragment() 394 frag.appendChild(el) 395 var el2 = document.createElement('div') 396 frag.appendChild(el2) 397 el.innerHTML = '{{*a}}' 398 el2.innerHTML = '{{*b}}' 399 data.a = 'A' 400 data.b = 'B' 401 var linker = compile(frag, Vue.options) 402 linker(vm, frag) 403 expect(el.innerHTML).toBe('A') 404 expect(el2.innerHTML).toBe('B') 405 }) 406 407 it('partial compilation', function () { 408 el.innerHTML = '<div v-bind:test="abc">{{bcd}}<p v-show="ok"></p></div>' 409 var linker = compile(el, Vue.options, true) 410 var decompile = linker(vm, el) 411 expect(vm._directives.length).toBe(3) 412 decompile() 413 expect(directiveTeardown.calls.count()).toBe(3) 414 expect(vm._directives.length).toBe(0) 415 }) 416 417 it('skip script tags', function () { 418 el.innerHTML = '<script type="x/template">{{test}}</script>' 419 var linker = compile(el, Vue.options) 420 linker(vm, el) 421 expect(vm._bindDir.calls.count()).toBe(0) 422 }) 423 424 it('should handle container/replacer directives with same name', function () { 425 var parentSpy = jasmine.createSpy() 426 var childSpy = jasmine.createSpy() 427 vm = new Vue({ 428 el: el, 429 template: 430 '<test class="a" v-on:click="test(1)"></test>', 431 methods: { 432 test: parentSpy 433 }, 434 components: { 435 test: { 436 template: '<div class="b" v-on:click="test(2)"></div>', 437 replace: true, 438 methods: { 439 test: childSpy 440 } 441 } 442 } 443 }) 444 expect(vm.$el.firstChild.className).toBe('b a') 445 var e = document.createEvent('HTMLEvents') 446 e.initEvent('click', true, true) 447 vm.$el.firstChild.dispatchEvent(e) 448 expect(parentSpy).toHaveBeenCalledWith(1) 449 expect(childSpy).toHaveBeenCalledWith(2) 450 }) 451 452 it('should teardown props and replacer directives when unlinking', function () { 453 var vm = new Vue({ 454 el: el, 455 template: '<test :msg="msg"></test>', 456 data: { 457 msg: 'foo' 458 }, 459 components: { 460 test: { 461 props: ['msg'], 462 template: '<div v-show="true"></div>', 463 replace: true 464 } 465 } 466 }) 467 var dirs = vm.$children[0]._directives 468 expect(dirs.length).toBe(2) 469 vm.$children[0].$destroy() 470 var i = dirs.length 471 while (i--) { 472 expect(dirs[i]._bound).toBe(false) 473 } 474 }) 475 476 it('should remove parent container directives from parent when unlinking', function () { 477 var vm = new Vue({ 478 el: el, 479 template: 480 '<test v-show="ok"></test>', 481 data: { 482 ok: true 483 }, 484 components: { 485 test: { 486 template: 'foo' 487 } 488 } 489 }) 490 expect(el.firstChild.style.display).toBe('') 491 expect(vm._directives.length).toBe(2) 492 expect(vm.$children.length).toBe(1) 493 vm.$children[0].$destroy() 494 expect(vm._directives.length).toBe(1) 495 expect(vm.$children.length).toBe(0) 496 }) 497 498 it('should remove transcluded directives from parent when unlinking (component)', function () { 499 var vm = new Vue({ 500 el: el, 501 template: 502 '<test>{{test}}</test>', 503 data: { 504 test: 'parent' 505 }, 506 components: { 507 test: { 508 template: '<slot></slot>' 509 } 510 } 511 }) 512 expect(vm.$el.textContent).toBe('parent') 513 expect(vm._directives.length).toBe(2) 514 expect(vm.$children.length).toBe(1) 515 vm.$children[0].$destroy() 516 expect(vm._directives.length).toBe(1) 517 expect(vm.$children.length).toBe(0) 518 }) 519 520 it('should remove transcluded directives from parent when unlinking (v-if + component)', function (done) { 521 var vm = new Vue({ 522 el: el, 523 template: 524 '<div v-if="ok">' + 525 '<test>{{test}}</test>' + 526 '</div>', 527 data: { 528 test: 'parent', 529 ok: true 530 }, 531 components: { 532 test: { 533 template: '<slot></slot>' 534 } 535 } 536 }) 537 expect(vm.$el.textContent).toBe('parent') 538 expect(vm._directives.length).toBe(3) 539 expect(vm.$children.length).toBe(1) 540 vm.ok = false 541 _.nextTick(function () { 542 expect(vm.$el.textContent).toBe('') 543 expect(vm._directives.length).toBe(1) 544 expect(vm.$children.length).toBe(0) 545 done() 546 }) 547 }) 548 549 it('element directive', function () { 550 new Vue({ 551 el: el, 552 template: '<test>{{a}}</test>', 553 elementDirectives: { 554 test: { 555 bind: function () { 556 this.el.setAttribute('test', '1') 557 } 558 } 559 } 560 }) 561 // should be terminal 562 expect(el.innerHTML).toBe('<test test="1">{{a}}</test>') 563 }) 564 565 it('attribute interpolation', function (done) { 566 var vm = new Vue({ 567 el: el, 568 template: '<div id="{{a}}" class="b bla-{{c}} d"></div>', 569 data: { 570 a: 'aaa', 571 c: 'ccc' 572 } 573 }) 574 expect(el.firstChild.id).toBe('aaa') 575 expect(el.firstChild.className).toBe('b bla-ccc d') 576 vm.a = 'aa' 577 vm.c = 'cc' 578 _.nextTick(function () { 579 expect(el.firstChild.id).toBe('aa') 580 expect(el.firstChild.className).toBe('b bla-cc d') 581 done() 582 }) 583 }) 584 585 it('attribute interpolation: one-time', function (done) { 586 var vm = new Vue({ 587 el: el, 588 template: '<div id="{{a}} b {{*c}}"></div>', 589 data: { 590 a: 'aaa', 591 c: 'ccc' 592 } 593 }) 594 expect(el.firstChild.id).toBe('aaa b ccc') 595 vm.a = 'aa' 596 vm.c = 'cc' 597 _.nextTick(function () { 598 expect(el.firstChild.id).toBe('aa b ccc') 599 done() 600 }) 601 }) 602 603 it('attribute interpolation: special cases', function () { 604 new Vue({ 605 el: el, 606 template: '<label for="{{a}}" data-test="{{b}}"></label><form accept-charset="{{c}}"></form>', 607 data: { 608 a: 'aaa', 609 b: 'bbb', 610 c: 'UTF-8' 611 } 612 }) 613 expect(el.innerHTML).toBe('<label for="aaa" data-test="bbb"></label><form accept-charset="UTF-8"></form>') 614 }) 615 616 it('attribute interpolation: warn invalid', function () { 617 new Vue({ 618 el: el, 619 template: '<div v-text="{{a}}"></div>', 620 data: { 621 a: '123' 622 } 623 }) 624 expect(el.innerHTML).toBe('<div></div>') 625 expect('attribute interpolation is not allowed in Vue.js directives').toHaveBeenWarned() 626 }) 627 628 it('attribute interpolation: warn mixed usage with v-bind', function () { 629 new Vue({ 630 el: el, 631 template: '<div class="{{a}}" :class="bcd"></div>', 632 data: { 633 a: 'foo' 634 } 635 }) 636 expect('Do not mix mustache interpolation and v-bind').toHaveBeenWarned() 637 }) 638 639 it('warn directives on fragment instances', function () { 640 new Vue({ 641 el: el, 642 template: '<test id="foo" class="ok" :prop="123"></test>', 643 components: { 644 test: { 645 replace: true, 646 props: ['prop'], 647 template: '{{prop}}' 648 } 649 } 650 }) 651 expect(getWarnCount()).toBe(1) 652 expect([ 653 'Attributes "id", "class" are ignored on component <test>', 654 'Attributes "class", "id" are ignored on component <test>' 655 ]).toHaveBeenWarned() 656 }) 657 658 it('should compile component container directives using correct context', function () { 659 new Vue({ 660 el: el, 661 directives: { 662 test: { 663 bind: function () { 664 this.el.textContent = 'worked!' 665 } 666 } 667 }, 668 template: '<comp v-test></comp>', 669 components: { comp: { template: '<div></div>' }} 670 }) 671 expect(el.textContent).toBe('worked!') 672 expect(getWarnCount()).toBe(0) 673 }) 674 675 // #xxx 676 it('should compile build-in terminal directive wihtout loop', function (done) { 677 var vm = new Vue({ 678 el: el, 679 data: { show: false }, 680 template: '<p v-if:arg1.modifier1="show">hello world</p>' 681 }) 682 vm.show = true 683 _.nextTick(function () { 684 expect(el.textContent).toBe('hello world') 685 done() 686 }) 687 }) 688 689 it('should compile custom terminal directive wihtout loop', function (done) { 690 var vm = new Vue({ 691 el: el, 692 data: { show: false }, 693 template: '<p v-if="show" v-inject:modal.modifier1="foo">hello world</p>', 694 directives: { 695 inject: { 696 terminal: true, 697 priority: Vue.options.directives.if.priority + 1, 698 bind: function () { 699 this.anchor = _.createAnchor('v-inject') 700 _.replace(this.el, this.anchor) 701 var factory = new FragmentFactory(this.vm, this.el) 702 this.frag = factory.create(this._host, this._scope, this._frag) 703 this.frag.before(this.anchor) 704 }, 705 unbind: function () { 706 this.frag.remove() 707 _.replace(this.anchor, this.el) 708 } 709 } 710 } 711 }) 712 vm.show = true 713 _.nextTick(function () { 714 expect(el.textContent).toBe('hello world') 715 done() 716 }) 717 }) 718 })