component-scoped-slot.spec.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. import Vue from 'vue'
  2. describe('Component scoped slot', () => {
  3. it('default slot', done => {
  4. const vm = new Vue({
  5. template: `
  6. <test ref="test">
  7. <template scope="props">
  8. <span>{{ props.msg }}</span>
  9. </template>
  10. </test>
  11. `,
  12. components: {
  13. test: {
  14. data () {
  15. return { msg: 'hello' }
  16. },
  17. template: `
  18. <div>
  19. <slot :msg="msg"></slot>
  20. </div>
  21. `
  22. }
  23. }
  24. }).$mount()
  25. expect(vm.$el.innerHTML).toBe('<span>hello</span>')
  26. vm.$refs.test.msg = 'world'
  27. waitForUpdate(() => {
  28. expect(vm.$el.innerHTML).toBe('<span>world</span>')
  29. }).then(done)
  30. })
  31. it('template slot', done => {
  32. const vm = new Vue({
  33. template: `
  34. <test ref="test">
  35. <template slot="item" scope="props">
  36. <span>{{ props.foo }}</span><span>{{ props.bar }}</span>
  37. </template>
  38. </test>
  39. `,
  40. components: {
  41. test: {
  42. data () {
  43. return { foo: 'FOO', bar: 'BAR' }
  44. },
  45. template: `
  46. <div>
  47. <slot name="item" :foo="foo" :bar="bar"></slot>
  48. </div>
  49. `
  50. }
  51. }
  52. }).$mount()
  53. expect(vm.$el.innerHTML).toBe('<span>FOO</span><span>BAR</span>')
  54. vm.$refs.test.foo = 'BAZ'
  55. waitForUpdate(() => {
  56. expect(vm.$el.innerHTML).toBe('<span>BAZ</span><span>BAR</span>')
  57. }).then(done)
  58. })
  59. it('fallback content', () => {
  60. const vm = new Vue({
  61. template: `<test></test>`,
  62. components: {
  63. test: {
  64. data () {
  65. return { msg: 'hello' }
  66. },
  67. template: `
  68. <div>
  69. <slot name="item" :text="msg">
  70. <span>{{ msg }} fallback</span>
  71. </slot>
  72. </div>
  73. `
  74. }
  75. }
  76. }).$mount()
  77. expect(vm.$el.innerHTML).toBe('<span>hello fallback</span>')
  78. })
  79. it('slot with v-for', done => {
  80. const vm = new Vue({
  81. template: `
  82. <test ref="test">
  83. <template slot="item" scope="props">
  84. <span>{{ props.text }}</span>
  85. </template>
  86. </test>
  87. `,
  88. components: {
  89. test: {
  90. data () {
  91. return {
  92. items: ['foo', 'bar', 'baz']
  93. }
  94. },
  95. template: `
  96. <div>
  97. <slot v-for="item in items" name="item" :text="item"></slot>
  98. </div>
  99. `
  100. }
  101. }
  102. }).$mount()
  103. function assertOutput () {
  104. expect(vm.$el.innerHTML).toBe(vm.$refs.test.items.map(item => {
  105. return `<span>${item}</span>`
  106. }).join(''))
  107. }
  108. assertOutput()
  109. vm.$refs.test.items.reverse()
  110. waitForUpdate(assertOutput).then(() => {
  111. vm.$refs.test.items.push('qux')
  112. }).then(assertOutput).then(done)
  113. })
  114. it('slot inside v-for', done => {
  115. const vm = new Vue({
  116. template: `
  117. <test ref="test">
  118. <template slot="item" scope="props">
  119. <span>{{ props.text }}</span>
  120. </template>
  121. </test>
  122. `,
  123. components: {
  124. test: {
  125. data () {
  126. return {
  127. items: ['foo', 'bar', 'baz']
  128. }
  129. },
  130. template: `
  131. <ul>
  132. <li v-for="item in items">
  133. <slot name="item" :text="item"></slot>
  134. </li>
  135. </ul>
  136. `
  137. }
  138. }
  139. }).$mount()
  140. function assertOutput () {
  141. expect(vm.$el.innerHTML).toBe(vm.$refs.test.items.map(item => {
  142. return `<li><span>${item}</span></li>`
  143. }).join(''))
  144. }
  145. assertOutput()
  146. vm.$refs.test.items.reverse()
  147. waitForUpdate(assertOutput).then(() => {
  148. vm.$refs.test.items.push('qux')
  149. }).then(assertOutput).then(done)
  150. })
  151. it('scoped slot without scope alias', () => {
  152. const vm = new Vue({
  153. template: `
  154. <test ref="test">
  155. <span slot="item">I am static</span>
  156. </test>
  157. `,
  158. components: {
  159. test: {
  160. data () {
  161. return { msg: 'hello' }
  162. },
  163. template: `
  164. <div>
  165. <slot name="item" :text="msg"></slot>
  166. </div>
  167. `
  168. }
  169. }
  170. }).$mount()
  171. expect(vm.$el.innerHTML).toBe('<span>I am static</span>')
  172. })
  173. it('non-scoped slot with scope alias', () => {
  174. const vm = new Vue({
  175. template: `
  176. <test ref="test">
  177. <template slot="item" scope="props">
  178. <span>{{ props.text || 'meh' }}</span>
  179. </template>
  180. </test>
  181. `,
  182. components: {
  183. test: {
  184. data () {
  185. return { msg: 'hello' }
  186. },
  187. template: `
  188. <div>
  189. <slot name="item"></slot>
  190. </div>
  191. `
  192. }
  193. }
  194. }).$mount()
  195. expect(vm.$el.innerHTML).toBe('<span>meh</span>')
  196. })
  197. it('warn key on slot', () => {
  198. new Vue({
  199. template: `
  200. <test ref="test">
  201. <template slot="item" scope="props">
  202. <span>{{ props.text }}</span>
  203. </template>
  204. </test>
  205. `,
  206. components: {
  207. test: {
  208. data () {
  209. return {
  210. items: ['foo', 'bar', 'baz']
  211. }
  212. },
  213. template: `
  214. <div>
  215. <slot v-for="item in items" name="item" :text="item" :key="item"></slot>
  216. </div>
  217. `
  218. }
  219. }
  220. }).$mount()
  221. expect(`\`key\` does not work on <slot>`).toHaveBeenWarned()
  222. })
  223. it('render function usage (named, via data)', done => {
  224. const vm = new Vue({
  225. render (h) {
  226. return h('test', {
  227. ref: 'test',
  228. scopedSlots: {
  229. item: props => h('span', props.text)
  230. }
  231. })
  232. },
  233. components: {
  234. test: {
  235. data () {
  236. return { msg: 'hello' }
  237. },
  238. render (h) {
  239. return h('div', [
  240. this.$scopedSlots.item({
  241. text: this.msg
  242. })
  243. ])
  244. }
  245. }
  246. }
  247. }).$mount()
  248. expect(vm.$el.innerHTML).toBe('<span>hello</span>')
  249. vm.$refs.test.msg = 'world'
  250. waitForUpdate(() => {
  251. expect(vm.$el.innerHTML).toBe('<span>world</span>')
  252. }).then(done)
  253. })
  254. it('render function usage (default, as children)', () => {
  255. const vm = new Vue({
  256. render (h) {
  257. return h('test', [
  258. props => h('span', [props.msg])
  259. ])
  260. },
  261. components: {
  262. test: {
  263. data () {
  264. return { msg: 'hello' }
  265. },
  266. render (h) {
  267. return h('div', [
  268. this.$scopedSlots.default({ msg: this.msg })
  269. ])
  270. }
  271. }
  272. }
  273. }).$mount()
  274. expect(vm.$el.innerHTML).toBe('<span>hello</span>')
  275. })
  276. it('render function usage (JSX)', () => {
  277. const vm = new Vue({
  278. render (h) {
  279. return <test>{
  280. props => <span>{props.msg}</span>
  281. }</test>
  282. },
  283. components: {
  284. test: {
  285. data () {
  286. return { msg: 'hello' }
  287. },
  288. render (h) {
  289. return <div>
  290. {this.$scopedSlots.default({ msg: this.msg })}
  291. </div>
  292. }
  293. }
  294. }
  295. }).$mount()
  296. expect(vm.$el.innerHTML).toBe('<span>hello</span>')
  297. })
  298. })