github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/test/unit/specs/directives/element/slot_spec.js (about)

     1  var Vue = require('src')
     2  var nextTick = Vue.nextTick
     3  
     4  describe('Slot Distribution', function () {
     5    var el, vm, options
     6    beforeEach(function () {
     7      el = document.createElement('div')
     8      options = {
     9        el: el,
    10        data: {
    11          msg: 'self'
    12        }
    13      }
    14    })
    15  
    16    function mount () {
    17      vm = new Vue(options)
    18    }
    19  
    20    it('no content', function () {
    21      options.template = '<div><slot></slot></div>'
    22      mount()
    23      expect(el.firstChild.childNodes.length).toBe(0)
    24    })
    25  
    26    it('default content', function () {
    27      el.innerHTML = '<p>foo</p>'
    28      options.template = '<div><slot></slot></div>'
    29      mount()
    30      expect(el.firstChild.tagName).toBe('DIV')
    31      expect(el.firstChild.firstChild.tagName).toBe('P')
    32      expect(el.firstChild.firstChild.textContent).toBe('foo')
    33    })
    34  
    35    it('no template auto content', function () {
    36      el.innerHTML = '<p>foo</p>'
    37      options._asComponent = true
    38      mount()
    39      expect(el.firstChild.tagName).toBe('P')
    40      expect(el.firstChild.textContent).toBe('foo')
    41    })
    42  
    43    it('fallback content', function () {
    44      options.template = '<slot><p>{{msg}}</p></slot>'
    45      mount()
    46      expect(el.firstChild.tagName).toBe('P')
    47      expect(el.firstChild.textContent).toBe('self')
    48    })
    49  
    50    it('fallback content with multiple named slots', function () {
    51      el.innerHTML = '<p slot="b">slot b</p>'
    52      options.template =
    53        '<slot name="a"><p>fallback a</p></slot>' +
    54        '<slot name="b">fallback b</slot>'
    55      mount()
    56      expect(el.childNodes.length).toBe(2)
    57      expect(el.firstChild.textContent).toBe('fallback a')
    58      expect(el.lastChild.textContent).toBe('slot b')
    59    })
    60  
    61    it('fallback content with mixed named/unnamed slots', function () {
    62      el.innerHTML = '<p slot="b">slot b</p>'
    63      options.template =
    64        '<slot><p>fallback a</p></slot>' +
    65        '<slot name="b">fallback b</slot>'
    66      mount()
    67      expect(el.childNodes.length).toBe(2)
    68      expect(el.firstChild.textContent).toBe('fallback a')
    69      expect(el.lastChild.textContent).toBe('slot b')
    70    })
    71  
    72    it('selector matching multiple elements', function () {
    73      el.innerHTML = '<p slot="t">1</p><div></div><p slot="t">2</p>'
    74      options.template = '<slot name="t"></slot>'
    75      mount()
    76      expect(el.innerHTML).toBe('<p slot="t">1</p><p slot="t">2</p>')
    77    })
    78  
    79    it('default content should only render parts not selected', function () {
    80      el.innerHTML = '<div>foo</div><p slot="a">1</p><p slot="b">2</p>'
    81      options.template =
    82        '<slot name="a"></slot>' +
    83        '<slot></slot>' +
    84        '<slot name="b"></slot>'
    85      mount()
    86      expect(el.innerHTML).toBe('<p slot="a">1</p><div>foo</div><p slot="b">2</p>')
    87    })
    88  
    89    it('content transclusion with replace', function () {
    90      el.innerHTML = '<p>foo</p>'
    91      options.template = '<div><div><slot></slot></div></div>'
    92      options.replace = true
    93      mount()
    94      var res = vm.$el
    95      expect(res).not.toBe(el)
    96      expect(res.firstChild.tagName).toBe('DIV')
    97      expect(res.firstChild.firstChild.tagName).toBe('P')
    98      expect(res.firstChild.firstChild.textContent).toBe('foo')
    99    })
   100  
   101    it('block instance content transclusion', function () {
   102      el.innerHTML = '<p slot="p">foo</p><span slot="span">ho</span>'
   103      options.template = '<div></div><slot name="p"></slot><slot name="span"></slot>'
   104      options.replace = true
   105      mount()
   106      expect(getChild(1).tagName).toBe('DIV')
   107      expect(getChild(2).tagName).toBe('P')
   108      expect(getChild(3).tagName).toBe('SPAN')
   109  
   110      function getChild (n) {
   111        var el = vm._fragmentStart
   112        while (n--) {
   113          el = el.nextSibling
   114        }
   115        return el
   116      }
   117    })
   118  
   119    it('name should only match children', function () {
   120      el.innerHTML =
   121        '<p slot="b">select b</p>' +
   122        '<span><p slot="b">nested b</p></span>' +
   123        '<span><p slot="c">nested c</p></span>'
   124      options.template =
   125        '<slot name="a"><p>fallback a</p></slot>' +
   126        '<slot name="b">fallback b</slot>' +
   127        '<slot name="c">fallback c</slot>'
   128      mount()
   129      expect(el.childNodes.length).toBe(3)
   130      expect(el.firstChild.textContent).toBe('fallback a')
   131      expect(el.childNodes[1].textContent).toBe('select b')
   132      expect(el.lastChild.textContent).toBe('fallback c')
   133    })
   134  
   135    it('should accept expressions in selectors', function () {
   136      el.innerHTML = '<p>one</p><p slot="two">two</p>'
   137      options.template = '<slot :name="theName"></slot>'
   138      options.data = {
   139        theName: 'two'
   140      }
   141      mount()
   142      expect(el.innerHTML).toBe('<p slot="two">two</p>')
   143    })
   144  
   145    it('content should be dynamic and compiled in parent scope', function (done) {
   146      var vm = new Vue({
   147        el: el,
   148        data: {
   149          msg: 'foo'
   150        },
   151        template: '<test>{{msg}}</test>',
   152        components: {
   153          test: {
   154            template: '<slot></slot>'
   155          }
   156        }
   157      })
   158      expect(el.innerHTML).toBe('<test>foo</test>')
   159      vm.msg = 'bar'
   160      nextTick(function () {
   161        expect(el.innerHTML).toBe('<test>bar</test>')
   162        done()
   163      })
   164    })
   165  
   166    it('v-if with content transclusion', function (done) {
   167      var vm = new Vue({
   168        el: el,
   169        data: {
   170          a: 1,
   171          b: 2,
   172          show: true
   173        },
   174        template: '<test :show="show"><p slot="b">{{b}}</a><p>{{a}}</p></test>',
   175        components: {
   176          test: {
   177            props: ['show'],
   178            template: '<div v-if="show"><slot></slot><slot name="b"></slot></div>'
   179          }
   180        }
   181      })
   182      expect(el.textContent).toBe('12')
   183      vm.a = 2
   184      nextTick(function () {
   185        expect(el.textContent).toBe('22')
   186        vm.show = false
   187        nextTick(function () {
   188          expect(el.textContent).toBe('')
   189          vm.show = true
   190          vm.a = 3
   191          nextTick(function () {
   192            expect(el.textContent).toBe('32')
   193            done()
   194          })
   195        })
   196      })
   197    })
   198  
   199    it('inline v-for', function () {
   200      el.innerHTML = '<p slot="1">1</p><p slot="2">2</p><p slot="3">3</p>'
   201      new Vue({
   202        el: el,
   203        template: '<div v-for="n in list"><slot :name="$index + 1"></slot></div>',
   204        data: {
   205          list: 0
   206        },
   207        beforeCompile: function () {
   208          this.list = this.$options._content.querySelectorAll('p').length
   209        }
   210      })
   211      expect(el.innerHTML).toBe('<div><p slot="1">1</p></div><div><p slot="2">2</p></div><div><p slot="3">3</p></div>')
   212    })
   213  
   214    it('v-for + component + parent directive + transclusion', function (done) {
   215      var vm = new Vue({
   216        el: el,
   217        template: '<test v-for="n in list" :class="cls" :a="n.a">{{msg}}</test>',
   218        data: {
   219          cls: 'parent',
   220          msg: 'foo',
   221          list: [{a: 1}, {a: 2}, {a: 3}]
   222        },
   223        components: {
   224          test: {
   225            replace: true,
   226            props: ['a'],
   227            template: '<div class="child">{{a}} <slot></slot></div>'
   228          }
   229        }
   230      })
   231      var markup = vm.list.map(function (item) {
   232        return '<div class="child parent">' + item.a + ' foo</div>'
   233      }).join('')
   234      expect(el.innerHTML).toBe(markup)
   235      vm.msg = 'bar'
   236      markup = vm.list.map(function (item) {
   237        return '<div class="child parent">' + item.a + ' bar</div>'
   238      }).join('')
   239      nextTick(function () {
   240        expect(el.innerHTML).toBe(markup)
   241        done()
   242      })
   243    })
   244  
   245    it('nested transclusions', function (done) {
   246      vm = new Vue({
   247        el: el,
   248        template:
   249          '<testa>' +
   250            '<testb>' +
   251              '<div v-for="n in list">{{n}}</div>' +
   252            '</testb>' +
   253          '</testa>',
   254        data: {
   255          list: [1, 2]
   256        },
   257        components: {
   258          testa: { template: '<slot></slot>' },
   259          testb: { template: '<slot></slot>' }
   260        }
   261      })
   262      expect(el.innerHTML).toBe(
   263        '<testa><testb>' +
   264          '<div>1</div><div>2</div>' +
   265        '</testb></testa>'
   266      )
   267      vm.list.push(3)
   268      nextTick(function () {
   269        expect(el.innerHTML).toBe(
   270          '<testa><testb>' +
   271            '<div>1</div><div>2</div><div>3</div>' +
   272          '</testb></testa>'
   273        )
   274        done()
   275      })
   276    })
   277  
   278    it('nested transclusion, container dirs & props', function (done) {
   279      vm = new Vue({
   280        el: el,
   281        template:
   282          '<testa>' +
   283            '<testb v-if="ok" :msg="msg"></testb>' +
   284          '</testa>',
   285        data: {
   286          ok: false,
   287          msg: 'hello'
   288        },
   289        components: {
   290          testa: { template: '<slot></slot>' },
   291          testb: {
   292            props: ['msg'],
   293            template: '{{msg}}'
   294          }
   295        }
   296      })
   297      expect(el.innerHTML).toBe('<testa></testa>')
   298      vm.ok = true
   299      nextTick(function () {
   300        expect(el.innerHTML).toBe('<testa><testb>hello</testb></testa>')
   301        done()
   302      })
   303    })
   304  
   305    // #1010
   306    it('v-for inside transcluded content', function () {
   307      vm = new Vue({
   308        el: el,
   309        template:
   310          '<testa>' +
   311            '{{inner}} {{outer}}' +
   312            '<div v-for="item in list"> {{item.inner}} {{outer}}</div>' +
   313          '</testa>',
   314        data: {
   315          outer: 'outer',
   316          inner: 'parent-inner',
   317          list: [
   318            { inner: 'list-inner' }
   319          ]
   320        },
   321        components: {
   322          testa: {
   323            data: function () {
   324              return {
   325                inner: 'component-inner'
   326              }
   327            },
   328            template: '<slot></slot>'
   329          }
   330        }
   331      })
   332      expect(el.textContent).toBe('parent-inner outer list-inner outer')
   333    })
   334  
   335    it('single content outlet with replace: true', function () {
   336      vm = new Vue({
   337        el: el,
   338        template:
   339          '<test><p>1</p><p>2</p></test>',
   340        components: {
   341          test: {
   342            template: '<slot></slot>',
   343            replace: true
   344          }
   345        }
   346      })
   347      expect(el.innerHTML).toBe('<p>1</p><p>2</p>')
   348    })
   349  
   350    it('template slot', function () {
   351      vm = new Vue({
   352        el: el,
   353        template:
   354          '<test><template slot="test">hello</template></test>',
   355        components: {
   356          test: {
   357            template: '<slot name="test"></slot> world',
   358            replace: true
   359          }
   360        }
   361      })
   362      expect(el.innerHTML).toBe('hello world')
   363    })
   364  
   365    it('inside v-for', function () {
   366      new Vue({
   367        el: el,
   368        template: '<comp v-for="item in items">{{item.value}}</comp>',
   369        data: {
   370          items: [{value: 123}, {value: 234}]
   371        },
   372        components: {
   373          comp: {
   374            tempalte: '<div><slot></slot></div>'
   375          }
   376        }
   377      })
   378      expect(el.textContent).toBe('123234')
   379    })
   380  
   381    it('fallback inside v-for', function () {
   382      new Vue({
   383        el: el,
   384        template: '<div v-for="n in 3"><comp></comp></div>',
   385        components: {
   386          comp: {
   387            template: '<div><slot>{{foo}}</slot></div>',
   388            data: function () {
   389              return {
   390                foo: 'bar'
   391              }
   392            }
   393          }
   394        }
   395      })
   396      expect(el.textContent).toBe('barbarbar')
   397    })
   398  
   399    it('fallback for slot with v-if', function (done) {
   400      var vm = new Vue({
   401        el: el,
   402        data: {
   403          ok: false,
   404          msg: 'inserted'
   405        },
   406        template: '<div><comp><div v-if="ok">{{ msg }}</div></comp></div>',
   407        components: {
   408          comp: {
   409            data: function () {
   410              return { msg: 'fallback' }
   411            },
   412            template: '<div><slot>{{ msg }}</slot></div>'
   413          }
   414        }
   415      })
   416      expect(el.textContent).toBe('fallback')
   417      vm.ok = true
   418      nextTick(function () {
   419        expect(el.textContent).toBe('inserted')
   420        done()
   421      })
   422    })
   423  
   424    // #2435
   425    it('slot inside template', function () {
   426      var vm = new Vue({
   427        el: el,
   428        template: '<test>foo</test>',
   429        components: {
   430          test: {
   431            data: function () {
   432              return { ok: true }
   433            },
   434            template:
   435              '<div>' +
   436                '<template v-if="ok">' +
   437                  '<template v-if="ok">' +
   438                    '<slot>{{ msg }}</slot>' +
   439                  '</template>' +
   440                '</template>' +
   441              '</div>'
   442          }
   443        }
   444      })
   445      expect(vm.$el.textContent).toBe('foo')
   446    })
   447  
   448    it('warn dynamic slot attribute', function () {
   449      new Vue({
   450        el: el,
   451        template: '<test><div :slot="1"></div></test>',
   452        components: {
   453          test: {
   454            template: '<div><slot></slot></div>'
   455          }
   456        }
   457      })
   458      expect('"slot" attribute must be static').toHaveBeenWarned()
   459    })
   460  
   461    it('default slot should use fallback content if has only whitespace', function () {
   462      new Vue({
   463        el: el,
   464        template: '<test><div slot="first">1</div> <div slot="second">2</div></test>',
   465        components: {
   466          test: {
   467            replace: true,
   468            template:
   469              '<div class="wrapper">' +
   470                '<slot name="first"><p>first slot</p></slot>' +
   471                '<slot><p>this is the default slot</p></slot>' +
   472                '<slot name="second"><p>second named slot</p></slot>' +
   473              '</div>'
   474          }
   475        }
   476      })
   477      expect(el.children[0].innerHTML).toBe('<div slot="first">1</div><p>this is the default slot</p><div slot="second">2</div>')
   478    })
   479  })