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  })