componentSlots.spec.ts 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939
  1. // NOTE: This test is implemented based on the case of `runtime-core/__test__/componentSlots.spec.ts`.
  2. import {
  3. child,
  4. createComponent,
  5. createFor,
  6. createForSlots,
  7. createIf,
  8. createSlot,
  9. createVaporApp,
  10. defineVaporComponent,
  11. insert,
  12. prepend,
  13. renderEffect,
  14. setInsertionState,
  15. template,
  16. txt,
  17. vaporInteropPlugin,
  18. withVaporCtx,
  19. } from '../src'
  20. import {
  21. type Ref,
  22. createApp,
  23. createSlots,
  24. currentInstance,
  25. h,
  26. nextTick,
  27. ref,
  28. renderSlot,
  29. toDisplayString,
  30. } from '@vue/runtime-dom'
  31. import { makeRender } from './_utils'
  32. import type { DynamicSlot } from '../src/componentSlots'
  33. import { setElementText, setText } from '../src/dom/prop'
  34. const define = makeRender<any>()
  35. function renderWithSlots(slots: any): any {
  36. let instance: any
  37. const Comp = defineVaporComponent({
  38. setup() {
  39. const t0 = template('<div></div>')
  40. const n0 = t0()
  41. instance = currentInstance
  42. return n0
  43. },
  44. })
  45. const { render } = define({
  46. render() {
  47. return createComponent(Comp, {}, slots)
  48. },
  49. })
  50. render()
  51. return instance
  52. }
  53. describe('component: slots', () => {
  54. test('initSlots: instance.slots should be set correctly', () => {
  55. const { slots } = renderWithSlots({
  56. default: () => template('<span></span>')(),
  57. })
  58. expect(slots.default()).toMatchObject(document.createElement('span'))
  59. })
  60. test('updateSlots: instance.slots should be updated correctly', async () => {
  61. const flag1 = ref(true)
  62. let instance: any
  63. const Child = () => {
  64. instance = currentInstance
  65. return template('child')()
  66. }
  67. const { render } = define({
  68. render() {
  69. return createComponent(
  70. Child,
  71. {},
  72. {
  73. $: [
  74. () =>
  75. flag1.value
  76. ? { name: 'one', fn: () => template('<span></span>')() }
  77. : { name: 'two', fn: () => template('<div></div>')() },
  78. ],
  79. },
  80. )
  81. },
  82. })
  83. render()
  84. expect(instance.slots).toHaveProperty('one')
  85. expect(instance.slots).not.toHaveProperty('two')
  86. flag1.value = false
  87. await nextTick()
  88. expect(instance.slots).not.toHaveProperty('one')
  89. expect(instance.slots).toHaveProperty('two')
  90. })
  91. test('should work with createFlorSlots', async () => {
  92. const loop = ref([1, 2, 3])
  93. let instance: any
  94. const Child = () => {
  95. instance = currentInstance
  96. return template('child')()
  97. }
  98. const { render } = define({
  99. setup() {
  100. return createComponent(Child, null, {
  101. $: [
  102. () =>
  103. createForSlots(loop.value, (item, i) => ({
  104. name: item,
  105. fn: () => template(item + i)(),
  106. })),
  107. ],
  108. })
  109. },
  110. })
  111. render()
  112. expect(instance.slots).toHaveProperty('1')
  113. expect(instance.slots).toHaveProperty('2')
  114. expect(instance.slots).toHaveProperty('3')
  115. loop.value.push(4)
  116. await nextTick()
  117. expect(instance.slots).toHaveProperty('4')
  118. loop.value.shift()
  119. await nextTick()
  120. expect(instance.slots).not.toHaveProperty('1')
  121. })
  122. // passes but no warning for slot invocation in vapor currently
  123. test.todo('should not warn when mounting another app in setup', () => {
  124. const Comp = defineVaporComponent({
  125. setup(_, { slots }) {
  126. return slots.default!()
  127. },
  128. })
  129. const mountComp = () => {
  130. createVaporApp({
  131. render() {
  132. return createComponent(
  133. Comp,
  134. {},
  135. { default: () => template('msg')() },
  136. )!
  137. },
  138. })
  139. }
  140. const App = {
  141. setup() {
  142. mountComp()
  143. return []
  144. },
  145. }
  146. createVaporApp(App).mount(document.createElement('div'))
  147. expect(
  148. 'Slot "default" invoked outside of the render function',
  149. ).not.toHaveBeenWarned()
  150. })
  151. describe('createSlot', () => {
  152. test('slot should be rendered correctly', () => {
  153. const Comp = defineVaporComponent(() => {
  154. const n0 = template('<div>')()
  155. insert(createSlot('header'), n0 as any as ParentNode)
  156. return n0
  157. })
  158. const { host } = define(() => {
  159. return createComponent(Comp, null, {
  160. header: withVaporCtx(() => template('header')()),
  161. })
  162. }).render()
  163. expect(host.innerHTML).toBe('<div>header<!--slot--></div>')
  164. })
  165. test('slot should be rendered correctly with slot props', async () => {
  166. const src = ref('header')
  167. const Comp = defineVaporComponent(() => {
  168. const n0 = template('<div></div>')()
  169. insert(
  170. createSlot('header', { title: () => src.value }),
  171. n0 as any as ParentNode,
  172. )
  173. return n0
  174. })
  175. const { host } = define(() => {
  176. return createComponent(Comp, null, {
  177. header: props => {
  178. const el = template('<h1></h1>')()
  179. renderEffect(() => {
  180. setElementText(el, props.title)
  181. })
  182. return el
  183. },
  184. })
  185. }).render()
  186. expect(host.innerHTML).toBe('<div><h1>header</h1><!--slot--></div>')
  187. src.value = 'footer'
  188. await nextTick()
  189. expect(host.innerHTML).toBe('<div><h1>footer</h1><!--slot--></div>')
  190. })
  191. test('dynamic slot props', async () => {
  192. let props: any
  193. const bindObj = ref<Record<string, any>>({ foo: 1, baz: 'qux' })
  194. const Comp = defineVaporComponent(() =>
  195. createSlot('default', { $: [() => bindObj.value] }),
  196. )
  197. define(() =>
  198. createComponent(Comp, null, {
  199. default: withVaporCtx((_props: any) => ((props = _props), [])),
  200. }),
  201. ).render()
  202. expect(props).toEqual({ foo: 1, baz: 'qux' })
  203. bindObj.value.foo = 2
  204. await nextTick()
  205. expect(props).toEqual({ foo: 2, baz: 'qux' })
  206. delete bindObj.value.baz
  207. await nextTick()
  208. expect(props).toEqual({ foo: 2 })
  209. })
  210. test('dynamic slot props with static slot props', async () => {
  211. let props: any
  212. const foo = ref(0)
  213. const bindObj = ref<Record<string, any>>({ foo: 100, baz: 'qux' })
  214. const Comp = defineVaporComponent(() =>
  215. createSlot('default', {
  216. foo: () => foo.value,
  217. $: [() => bindObj.value],
  218. }),
  219. )
  220. define(() =>
  221. createComponent(Comp, null, {
  222. default: withVaporCtx((_props: any) => ((props = _props), [])),
  223. }),
  224. ).render()
  225. expect(props).toEqual({ foo: 100, baz: 'qux' })
  226. foo.value = 2
  227. await nextTick()
  228. expect(props).toEqual({ foo: 100, baz: 'qux' })
  229. delete bindObj.value.foo
  230. await nextTick()
  231. expect(props).toEqual({ foo: 2, baz: 'qux' })
  232. })
  233. test('dynamic slot should be rendered correctly with slot props', async () => {
  234. const val = ref('header')
  235. const Comp = defineVaporComponent(() => {
  236. const n0 = template('<div></div>')()
  237. prepend(
  238. n0 as any as ParentNode,
  239. createSlot('header', { title: () => val.value }),
  240. )
  241. return n0
  242. })
  243. const { host } = define(() => {
  244. // dynamic slot
  245. return createComponent(Comp, null, {
  246. $: [
  247. () => ({
  248. name: 'header',
  249. fn: withVaporCtx((props: any) => {
  250. const el = template('<h1></h1>')()
  251. renderEffect(() => {
  252. setElementText(el, props.title)
  253. })
  254. return el
  255. }),
  256. }),
  257. ],
  258. })
  259. }).render()
  260. expect(host.innerHTML).toBe('<div><h1>header</h1><!--slot--></div>')
  261. val.value = 'footer'
  262. await nextTick()
  263. expect(host.innerHTML).toBe('<div><h1>footer</h1><!--slot--></div>')
  264. })
  265. test('dynamic slot outlet should be render correctly with slot props', async () => {
  266. const val = ref('header')
  267. const Comp = defineVaporComponent(() => {
  268. const n0 = template('<div></div>')()
  269. prepend(
  270. n0 as any as ParentNode,
  271. createSlot(
  272. () => val.value, // dynamic slot outlet name
  273. ),
  274. )
  275. return n0
  276. })
  277. const { host } = define(() => {
  278. return createComponent(Comp, null, {
  279. header: withVaporCtx(() => template('header')()),
  280. footer: withVaporCtx(() => template('footer')()),
  281. })
  282. }).render()
  283. expect(host.innerHTML).toBe('<div>header<!--slot--></div>')
  284. val.value = 'footer'
  285. await nextTick()
  286. expect(host.innerHTML).toBe('<div>footer<!--slot--></div>')
  287. })
  288. test('fallback should be render correctly', () => {
  289. const Comp = defineVaporComponent(() => {
  290. const n0 = template('<div></div>')()
  291. insert(
  292. createSlot('header', undefined, () => template('fallback')()),
  293. n0 as any as ParentNode,
  294. )
  295. return n0
  296. })
  297. const { host } = define(() => {
  298. return createComponent(Comp, {}, {})
  299. }).render()
  300. expect(host.innerHTML).toBe('<div>fallback<!--slot--></div>')
  301. })
  302. test('dynamic slot should be updated correctly', async () => {
  303. const flag1 = ref(true)
  304. const Child = defineVaporComponent(() => {
  305. const temp0 = template('<p></p>')
  306. const el0 = temp0()
  307. const el1 = temp0()
  308. const slot1 = createSlot('one', null, () => template('one fallback')())
  309. const slot2 = createSlot('two', null, () => template('two fallback')())
  310. insert(slot1, el0 as any as ParentNode)
  311. insert(slot2, el1 as any as ParentNode)
  312. return [el0, el1]
  313. })
  314. const { host } = define(() => {
  315. return createComponent(Child, null, {
  316. $: [
  317. () =>
  318. flag1.value
  319. ? {
  320. name: 'one',
  321. fn: withVaporCtx(() => template('one content')()),
  322. }
  323. : {
  324. name: 'two',
  325. fn: withVaporCtx(() => template('two content')()),
  326. },
  327. ],
  328. })
  329. }).render()
  330. expect(host.innerHTML).toBe(
  331. '<p>one content<!--slot--></p><p>two fallback<!--slot--></p>',
  332. )
  333. flag1.value = false
  334. await nextTick()
  335. expect(host.innerHTML).toBe(
  336. '<p>one fallback<!--slot--></p><p>two content<!--slot--></p>',
  337. )
  338. flag1.value = true
  339. await nextTick()
  340. expect(host.innerHTML).toBe(
  341. '<p>one content<!--slot--></p><p>two fallback<!--slot--></p>',
  342. )
  343. })
  344. test('dynamic slot outlet should be updated correctly', async () => {
  345. const slotOutletName = ref('one')
  346. const Child = defineVaporComponent(() => {
  347. const temp0 = template('<p>')
  348. const el0 = temp0()
  349. const slot1 = createSlot(
  350. () => slotOutletName.value,
  351. undefined,
  352. () => template('fallback')(),
  353. )
  354. insert(slot1, el0 as any as ParentNode)
  355. return el0
  356. })
  357. const { host } = define(() => {
  358. return createComponent(
  359. Child,
  360. {},
  361. {
  362. one: withVaporCtx(() => template('one content')()),
  363. two: withVaporCtx(() => template('two content')()),
  364. },
  365. )
  366. }).render()
  367. expect(host.innerHTML).toBe('<p>one content<!--slot--></p>')
  368. slotOutletName.value = 'two'
  369. await nextTick()
  370. expect(host.innerHTML).toBe('<p>two content<!--slot--></p>')
  371. slotOutletName.value = 'none'
  372. await nextTick()
  373. expect(host.innerHTML).toBe('<p>fallback<!--slot--></p>')
  374. })
  375. test('non-exist slot', async () => {
  376. const Child = defineVaporComponent(() => {
  377. const el0 = template('<p>')()
  378. const slot = createSlot('not-exist', undefined)
  379. insert(slot, el0 as any as ParentNode)
  380. return el0
  381. })
  382. const { host } = define(() => {
  383. return createComponent(Child)
  384. }).render()
  385. expect(host.innerHTML).toBe('<p><!--slot--></p>')
  386. })
  387. test('use fallback when inner content changes', async () => {
  388. const Child = {
  389. setup() {
  390. return createSlot('default', null, () =>
  391. document.createTextNode('fallback'),
  392. )
  393. },
  394. }
  395. const toggle = ref(true)
  396. const { html } = define({
  397. setup() {
  398. return createComponent(Child, null, {
  399. default: withVaporCtx(() => {
  400. return createIf(
  401. () => toggle.value,
  402. () => {
  403. return document.createTextNode('content')
  404. },
  405. )
  406. }),
  407. })
  408. },
  409. }).render()
  410. expect(html()).toBe('content<!--if--><!--slot-->')
  411. toggle.value = false
  412. await nextTick()
  413. expect(html()).toBe('fallback<!--if--><!--slot-->')
  414. toggle.value = true
  415. await nextTick()
  416. expect(html()).toBe('content<!--if--><!--slot-->')
  417. })
  418. test('use fallback on initial render', async () => {
  419. const Child = {
  420. setup() {
  421. return createSlot('default', null, () =>
  422. document.createTextNode('fallback'),
  423. )
  424. },
  425. }
  426. const toggle = ref(false)
  427. const { html } = define({
  428. setup() {
  429. return createComponent(Child, null, {
  430. default: withVaporCtx(() => {
  431. return createIf(
  432. () => toggle.value,
  433. () => {
  434. return document.createTextNode('content')
  435. },
  436. )
  437. }),
  438. })
  439. },
  440. }).render()
  441. expect(html()).toBe('fallback<!--if--><!--slot-->')
  442. toggle.value = true
  443. await nextTick()
  444. expect(html()).toBe('content<!--if--><!--slot-->')
  445. toggle.value = false
  446. await nextTick()
  447. expect(html()).toBe('fallback<!--if--><!--slot-->')
  448. })
  449. test('dynamic slot work with v-if', async () => {
  450. const val = ref('header')
  451. const toggle = ref(false)
  452. const Comp = defineVaporComponent(() => {
  453. const n0 = template('<div></div>')()
  454. prepend(n0 as any as ParentNode, createSlot('header', null))
  455. return n0
  456. })
  457. const { host } = define(() => {
  458. // dynamic slot
  459. return createComponent(Comp, null, {
  460. $: [
  461. () =>
  462. (toggle.value
  463. ? {
  464. name: val.value,
  465. fn: withVaporCtx(() => {
  466. return template('<h1></h1>')()
  467. }),
  468. }
  469. : void 0) as DynamicSlot,
  470. ],
  471. })
  472. }).render()
  473. expect(host.innerHTML).toBe('<div><!--slot--></div>')
  474. toggle.value = true
  475. await nextTick()
  476. expect(host.innerHTML).toBe('<div><h1></h1><!--slot--></div>')
  477. })
  478. test('render fallback when slot content is not valid', async () => {
  479. const Child = {
  480. setup() {
  481. return createSlot('default', null, () =>
  482. document.createTextNode('fallback'),
  483. )
  484. },
  485. }
  486. const { html } = define({
  487. setup() {
  488. return createComponent(Child, null, {
  489. default: withVaporCtx(() => {
  490. return template('<!--comment-->')()
  491. }),
  492. })
  493. },
  494. }).render()
  495. expect(html()).toBe('fallback<!--slot-->')
  496. })
  497. test('render fallback when v-if condition is false', async () => {
  498. const Child = {
  499. setup() {
  500. return createSlot('default', null, () =>
  501. document.createTextNode('fallback'),
  502. )
  503. },
  504. }
  505. const toggle = ref(false)
  506. const { html } = define({
  507. setup() {
  508. return createComponent(Child, null, {
  509. default: withVaporCtx(() => {
  510. return createIf(
  511. () => toggle.value,
  512. () => {
  513. return document.createTextNode('content')
  514. },
  515. )
  516. }),
  517. })
  518. },
  519. }).render()
  520. expect(html()).toBe('fallback<!--if--><!--slot-->')
  521. toggle.value = true
  522. await nextTick()
  523. expect(html()).toBe('content<!--if--><!--slot-->')
  524. toggle.value = false
  525. await nextTick()
  526. expect(html()).toBe('fallback<!--if--><!--slot-->')
  527. })
  528. test('render fallback with nested v-if', async () => {
  529. const Child = {
  530. setup() {
  531. return createSlot('default', null, () =>
  532. document.createTextNode('fallback'),
  533. )
  534. },
  535. }
  536. const outerShow = ref(false)
  537. const innerShow = ref(false)
  538. const { html } = define({
  539. setup() {
  540. return createComponent(Child, null, {
  541. default: withVaporCtx(() => {
  542. return createIf(
  543. () => outerShow.value,
  544. () => {
  545. return createIf(
  546. () => innerShow.value,
  547. () => {
  548. return document.createTextNode('content')
  549. },
  550. )
  551. },
  552. )
  553. }),
  554. })
  555. },
  556. }).render()
  557. expect(html()).toBe('fallback<!--if--><!--slot-->')
  558. outerShow.value = true
  559. await nextTick()
  560. expect(html()).toBe('fallback<!--if--><!--if--><!--slot-->')
  561. innerShow.value = true
  562. await nextTick()
  563. expect(html()).toBe('content<!--if--><!--if--><!--slot-->')
  564. innerShow.value = false
  565. await nextTick()
  566. expect(html()).toBe('fallback<!--if--><!--if--><!--slot-->')
  567. outerShow.value = false
  568. await nextTick()
  569. expect(html()).toBe('fallback<!--if--><!--slot-->')
  570. outerShow.value = true
  571. await nextTick()
  572. expect(html()).toBe('fallback<!--if--><!--if--><!--slot-->')
  573. innerShow.value = true
  574. await nextTick()
  575. expect(html()).toBe('content<!--if--><!--if--><!--slot-->')
  576. })
  577. test('render fallback with v-for', async () => {
  578. const Child = {
  579. setup() {
  580. return createSlot('default', null, () =>
  581. document.createTextNode('fallback'),
  582. )
  583. },
  584. }
  585. const items = ref<number[]>([1])
  586. const { html } = define({
  587. setup() {
  588. return createComponent(Child, null, {
  589. default: withVaporCtx(() => {
  590. const n2 = createFor(
  591. () => items.value,
  592. for_item0 => {
  593. const n4 = template('<span> </span>')() as any
  594. const x4 = child(n4) as any
  595. renderEffect(() =>
  596. setText(x4, toDisplayString(for_item0.value)),
  597. )
  598. return n4
  599. },
  600. )
  601. return n2
  602. }),
  603. })
  604. },
  605. }).render()
  606. expect(html()).toBe('<span>1</span><!--for--><!--slot-->')
  607. items.value.pop()
  608. await nextTick()
  609. expect(html()).toBe('fallback<!--for--><!--slot-->')
  610. items.value.pop()
  611. await nextTick()
  612. expect(html()).toBe('fallback<!--for--><!--slot-->')
  613. items.value.push(2)
  614. await nextTick()
  615. expect(html()).toBe('<span>2</span><!--for--><!--slot-->')
  616. })
  617. test('render fallback with v-for (empty source)', async () => {
  618. const Child = {
  619. setup() {
  620. return createSlot('default', null, () =>
  621. document.createTextNode('fallback'),
  622. )
  623. },
  624. }
  625. const items = ref<number[]>([])
  626. const { html } = define({
  627. setup() {
  628. return createComponent(Child, null, {
  629. default: withVaporCtx(() => {
  630. const n2 = createFor(
  631. () => items.value,
  632. for_item0 => {
  633. const n4 = template('<span> </span>')() as any
  634. const x4 = child(n4) as any
  635. renderEffect(() =>
  636. setText(x4, toDisplayString(for_item0.value)),
  637. )
  638. return n4
  639. },
  640. )
  641. return n2
  642. }),
  643. })
  644. },
  645. }).render()
  646. expect(html()).toBe('fallback<!--for--><!--slot-->')
  647. items.value.push(1)
  648. await nextTick()
  649. expect(html()).toBe('<span>1</span><!--for--><!--slot-->')
  650. items.value.pop()
  651. await nextTick()
  652. expect(html()).toBe('fallback<!--for--><!--slot-->')
  653. items.value.pop()
  654. await nextTick()
  655. expect(html()).toBe('fallback<!--for--><!--slot-->')
  656. items.value.push(2)
  657. await nextTick()
  658. expect(html()).toBe('<span>2</span><!--for--><!--slot-->')
  659. })
  660. test('work with v-once', async () => {
  661. const Child = defineVaporComponent({
  662. setup() {
  663. return createSlot(
  664. 'default',
  665. null,
  666. undefined,
  667. undefined,
  668. true /* once */,
  669. )
  670. },
  671. })
  672. const count = ref(0)
  673. const { html } = define({
  674. setup() {
  675. return createComponent(Child, null, {
  676. default: withVaporCtx(() => {
  677. const n3 = template('<div> </div>')() as any
  678. const x3 = txt(n3) as any
  679. renderEffect(() => setText(x3, toDisplayString(count.value)))
  680. return n3
  681. }),
  682. })
  683. },
  684. }).render()
  685. expect(html()).toBe('<div>0</div><!--slot-->')
  686. // expect no changes due to v-once
  687. count.value++
  688. await nextTick()
  689. expect(html()).toBe('<div>0</div><!--slot-->')
  690. })
  691. })
  692. describe('forwarded slot', () => {
  693. test('should work', async () => {
  694. const Child = defineVaporComponent({
  695. setup() {
  696. return createSlot('foo', null)
  697. },
  698. })
  699. const Parent = defineVaporComponent({
  700. setup() {
  701. const n2 = createComponent(
  702. Child,
  703. null,
  704. {
  705. foo: withVaporCtx(() => {
  706. return createSlot('foo', null)
  707. }),
  708. },
  709. true,
  710. )
  711. return n2
  712. },
  713. })
  714. const foo = ref('foo')
  715. const { host } = define({
  716. setup() {
  717. const n2 = createComponent(
  718. Parent,
  719. null,
  720. {
  721. foo: withVaporCtx(() => {
  722. const n0 = template(' ')() as any
  723. renderEffect(() => setText(n0, foo.value))
  724. return n0
  725. }),
  726. },
  727. true,
  728. )
  729. return n2
  730. },
  731. }).render()
  732. expect(host.innerHTML).toBe('foo<!--slot--><!--slot-->')
  733. foo.value = 'bar'
  734. await nextTick()
  735. expect(host.innerHTML).toBe('bar<!--slot--><!--slot-->')
  736. })
  737. test('mixed with non-forwarded slot', async () => {
  738. const Child = defineVaporComponent({
  739. setup() {
  740. return [createSlot('foo', null)]
  741. },
  742. })
  743. const Parent = defineVaporComponent({
  744. setup() {
  745. const n2 = createComponent(Child, null, {
  746. foo: withVaporCtx(() => {
  747. const n0 = createSlot('foo', null)
  748. return n0
  749. }),
  750. })
  751. const n3 = createSlot('default', null)
  752. return [n2, n3]
  753. },
  754. })
  755. const foo = ref('foo')
  756. const { host } = define({
  757. setup() {
  758. const n2 = createComponent(
  759. Parent,
  760. null,
  761. {
  762. foo: withVaporCtx(() => {
  763. const n0 = template(' ')() as any
  764. renderEffect(() => setText(n0, foo.value))
  765. return n0
  766. }),
  767. default: withVaporCtx(() => {
  768. const n3 = template(' ')() as any
  769. renderEffect(() => setText(n3, foo.value))
  770. return n3
  771. }),
  772. },
  773. true,
  774. )
  775. return n2
  776. },
  777. }).render()
  778. expect(host.innerHTML).toBe('foo<!--slot--><!--slot-->foo<!--slot-->')
  779. foo.value = 'bar'
  780. await nextTick()
  781. expect(host.innerHTML).toBe('bar<!--slot--><!--slot-->bar<!--slot-->')
  782. })
  783. test('forwarded slot with fallback', async () => {
  784. const Child = defineVaporComponent({
  785. setup() {
  786. return createSlot('default', null, () => template('child fallback')())
  787. },
  788. })
  789. const Parent = defineVaporComponent({
  790. setup() {
  791. const n2 = createComponent(Child, null, {
  792. default: withVaporCtx(() => {
  793. const n0 = createSlot('default', null, () => {
  794. return template('<!-- <div></div> -->')()
  795. })
  796. return n0
  797. }),
  798. })
  799. return n2
  800. },
  801. })
  802. const { html } = define({
  803. setup() {
  804. return createComponent(Parent, null, {
  805. default: withVaporCtx(() => template('<!-- <div>App</div> -->')()),
  806. })
  807. },
  808. }).render()
  809. expect(html()).toBe('child fallback<!--slot--><!--slot-->')
  810. })
  811. test('forwarded slot with fallback (v-if)', async () => {
  812. const Child = defineVaporComponent({
  813. setup() {
  814. return createSlot('default', null, () => template('child fallback')())
  815. },
  816. })
  817. const show = ref(false)
  818. const Parent = defineVaporComponent({
  819. setup() {
  820. const n2 = createComponent(Child, null, {
  821. default: withVaporCtx(() => {
  822. const n0 = createSlot('default', null, () => {
  823. const n2 = createIf(
  824. () => show.value,
  825. () => {
  826. const n4 = template('<div>if content</div>')()
  827. return n4
  828. },
  829. )
  830. return n2
  831. })
  832. return n0
  833. }),
  834. })
  835. return n2
  836. },
  837. })
  838. const { html } = define({
  839. setup() {
  840. return createComponent(Parent, null, {
  841. default: withVaporCtx(() => template('<!-- <div>App</div> -->')()),
  842. })
  843. },
  844. }).render()
  845. expect(html()).toBe('child fallback<!--if--><!--slot--><!--slot-->')
  846. show.value = true
  847. await nextTick()
  848. expect(html()).toBe(
  849. '<div>if content</div><!--if--><!--slot--><!--slot-->',
  850. )
  851. })
  852. test('forwarded slot with fallback (v-for)', async () => {
  853. const Child = defineVaporComponent({
  854. setup() {
  855. return createSlot('default', null, () => template('child fallback')())
  856. },
  857. })
  858. const items = ref<number[]>([])
  859. const Parent = defineVaporComponent({
  860. setup() {
  861. const n2 = createComponent(Child, null, {
  862. default: withVaporCtx(() => {
  863. const n0 = createSlot('default', null, () => {
  864. const n2 = createFor(
  865. () => items.value,
  866. for_item0 => {
  867. const n4 = template('<span> </span>')() as any
  868. const x4 = child(n4) as any
  869. renderEffect(() =>
  870. setText(x4, toDisplayString(for_item0.value)),
  871. )
  872. return n4
  873. },
  874. )
  875. return n2
  876. })
  877. return n0
  878. }),
  879. })
  880. return n2
  881. },
  882. })
  883. const { html } = define({
  884. setup() {
  885. return createComponent(Parent, null, {
  886. default: () => template('<!-- <div>App</div> -->')(),
  887. })
  888. },
  889. }).render()
  890. expect(html()).toBe('child fallback<!--for--><!--slot--><!--slot-->')
  891. items.value.push(1)
  892. await nextTick()
  893. expect(html()).toBe('<span>1</span><!--for--><!--slot--><!--slot-->')
  894. items.value.pop()
  895. await nextTick()
  896. expect(html()).toBe('child fallback<!--for--><!--slot--><!--slot-->')
  897. })
  898. test('consecutive slots with insertion state', async () => {
  899. const { component: Child } = define({
  900. setup() {
  901. const n2 = template('<div><div>baz</div></div>', true)() as any
  902. setInsertionState(n2, 0)
  903. createSlot('default', null)
  904. setInsertionState(n2, 0)
  905. createSlot('foo', null)
  906. return n2
  907. },
  908. })
  909. const { html } = define({
  910. setup() {
  911. return createComponent(Child, null, {
  912. default: withVaporCtx(() => template('default')()),
  913. foo: withVaporCtx(() => template('foo')()),
  914. })
  915. },
  916. }).render()
  917. expect(html()).toBe(
  918. `<div>` +
  919. `default<!--slot-->` +
  920. `foo<!--slot-->` +
  921. `<div>baz</div>` +
  922. `</div>`,
  923. )
  924. })
  925. describe('vdom interop', () => {
  926. const createVaporSlot = (fallbackText = 'fallback') => {
  927. return defineVaporComponent({
  928. setup() {
  929. const n0 = createSlot('foo', null, () => {
  930. const n2 = template(`<div>${fallbackText}</div>`)()
  931. return n2
  932. })
  933. return n0
  934. },
  935. })
  936. }
  937. const createVdomSlot = (fallbackText = 'fallback') => {
  938. return {
  939. render(this: any) {
  940. return renderSlot(this.$slots, 'foo', {}, () => [
  941. h('div', fallbackText),
  942. ])
  943. },
  944. }
  945. }
  946. const createVaporForwardedSlot = (
  947. targetComponent: any,
  948. fallbackText?: string,
  949. ) => {
  950. return defineVaporComponent({
  951. setup() {
  952. const n2 = createComponent(
  953. targetComponent,
  954. null,
  955. {
  956. foo: withVaporCtx(() => {
  957. return fallbackText
  958. ? createSlot('foo', null, () => {
  959. const n2 = template(`<div>${fallbackText}</div>`)()
  960. return n2
  961. })
  962. : createSlot('foo', null)
  963. }),
  964. },
  965. true,
  966. )
  967. return n2
  968. },
  969. })
  970. }
  971. const createVdomForwardedSlot = (
  972. targetComponent: any,
  973. fallbackText?: string,
  974. ) => {
  975. return {
  976. render(this: any) {
  977. return h(targetComponent, null, {
  978. foo: () => [
  979. fallbackText
  980. ? renderSlot(this.$slots, 'foo', {}, () => [
  981. h('div', fallbackText),
  982. ])
  983. : renderSlot(this.$slots, 'foo'),
  984. ],
  985. _: 3 /* FORWARDED */,
  986. })
  987. },
  988. }
  989. }
  990. const createMultipleVaporForwardedSlots = (
  991. targetComponent: any,
  992. count: number,
  993. ) => {
  994. let current = targetComponent
  995. for (let i = 0; i < count; i++) {
  996. current = createVaporForwardedSlot(current)
  997. }
  998. return current
  999. }
  1000. const createMultipleVdomForwardedSlots = (
  1001. targetComponent: any,
  1002. count: number,
  1003. ) => {
  1004. let current = targetComponent
  1005. for (let i = 0; i < count; i++) {
  1006. current = createVdomForwardedSlot(current)
  1007. }
  1008. return current
  1009. }
  1010. const createTestApp = (
  1011. rootComponent: any,
  1012. foo: Ref<string>,
  1013. show: Ref<Boolean>,
  1014. ) => {
  1015. return {
  1016. setup() {
  1017. return () =>
  1018. h(
  1019. rootComponent,
  1020. null,
  1021. createSlots({ _: 2 /* DYNAMIC */ } as any, [
  1022. show.value
  1023. ? {
  1024. name: 'foo',
  1025. fn: () => [h('span', foo.value)],
  1026. key: '0',
  1027. }
  1028. : undefined,
  1029. ]),
  1030. )
  1031. },
  1032. }
  1033. }
  1034. const createEmptyTestApp = (rootComponent: any) => {
  1035. return {
  1036. setup() {
  1037. return () => h(rootComponent)
  1038. },
  1039. }
  1040. }
  1041. test('vdom slot > vapor forwarded slot > vapor slot', async () => {
  1042. const foo = ref('foo')
  1043. const show = ref(true)
  1044. const VaporSlot = createVaporSlot()
  1045. const VaporForwardedSlot = createVaporForwardedSlot(VaporSlot)
  1046. const App = createTestApp(VaporForwardedSlot, foo, show)
  1047. const root = document.createElement('div')
  1048. createApp(App).use(vaporInteropPlugin).mount(root)
  1049. expect(root.innerHTML).toBe('<span>foo</span><!--slot-->')
  1050. foo.value = 'bar'
  1051. await nextTick()
  1052. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1053. show.value = false
  1054. await nextTick()
  1055. expect(root.innerHTML).toBe('<div>fallback</div><!--slot-->')
  1056. })
  1057. test('vdom slot > vapor forwarded slot(with fallback) > vapor slot', async () => {
  1058. const foo = ref('foo')
  1059. const show = ref(true)
  1060. const VaporSlot = createVaporSlot()
  1061. const VaporForwardedSlotWithFallback = createVaporForwardedSlot(
  1062. VaporSlot,
  1063. 'forwarded fallback',
  1064. )
  1065. const App = createTestApp(VaporForwardedSlotWithFallback, foo, show)
  1066. const root = document.createElement('div')
  1067. createApp(App).use(vaporInteropPlugin).mount(root)
  1068. expect(root.innerHTML).toBe('<span>foo</span><!--slot-->')
  1069. foo.value = 'bar'
  1070. await nextTick()
  1071. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1072. show.value = false
  1073. await nextTick()
  1074. expect(root.innerHTML).toBe('<div>forwarded fallback</div><!--slot-->')
  1075. })
  1076. test('vdom slot > vapor forwarded slot > vdom slot', async () => {
  1077. const foo = ref('foo')
  1078. const show = ref(true)
  1079. const VdomSlot = createVdomSlot()
  1080. const VaporForwardedSlot = createVaporForwardedSlot(VdomSlot)
  1081. const App = createTestApp(VaporForwardedSlot, foo, show)
  1082. const root = document.createElement('div')
  1083. createApp(App).use(vaporInteropPlugin).mount(root)
  1084. expect(root.innerHTML).toBe('<span>foo</span>')
  1085. foo.value = 'bar'
  1086. await nextTick()
  1087. expect(root.innerHTML).toBe('<span>bar</span>')
  1088. show.value = false
  1089. await nextTick()
  1090. expect(root.innerHTML).toBe('<div>fallback</div>')
  1091. show.value = true
  1092. await nextTick()
  1093. expect(root.innerHTML).toBe('<span>bar</span>')
  1094. })
  1095. test('vdom slot > vapor forwarded slot(with fallback) > vdom slot', async () => {
  1096. const foo = ref('foo')
  1097. const show = ref(true)
  1098. const VdomSlot = createVdomSlot()
  1099. const VaporForwardedSlotWithFallback = createVaporForwardedSlot(
  1100. VdomSlot,
  1101. 'forwarded fallback',
  1102. )
  1103. const App = createTestApp(VaporForwardedSlotWithFallback, foo, show)
  1104. const root = document.createElement('div')
  1105. createApp(App).use(vaporInteropPlugin).mount(root)
  1106. expect(root.innerHTML).toBe('<span>foo</span>')
  1107. foo.value = 'bar'
  1108. await nextTick()
  1109. expect(root.innerHTML).toBe('<span>bar</span>')
  1110. show.value = false
  1111. await nextTick()
  1112. expect(root.innerHTML).toBe('<div>forwarded fallback</div>')
  1113. })
  1114. test('vdom slot > vapor forwarded slot > vdom forwarded slot > vapor slot', async () => {
  1115. const foo = ref('foo')
  1116. const show = ref(true)
  1117. const VaporSlot = createVaporSlot()
  1118. const VdomForwardedSlot = createVdomForwardedSlot(VaporSlot)
  1119. const VaporForwardedSlot = createVaporForwardedSlot(VdomForwardedSlot)
  1120. const App = createTestApp(VaporForwardedSlot, foo, show)
  1121. const root = document.createElement('div')
  1122. createApp(App).use(vaporInteropPlugin).mount(root)
  1123. expect(root.innerHTML).toBe('<span>foo</span>')
  1124. foo.value = 'bar'
  1125. await nextTick()
  1126. expect(root.innerHTML).toBe('<span>bar</span>')
  1127. show.value = false
  1128. await nextTick()
  1129. expect(root.innerHTML).toBe('<div>fallback</div>')
  1130. show.value = true
  1131. await nextTick()
  1132. expect(root.innerHTML).toBe('<span>bar</span>')
  1133. })
  1134. test('vdom slot > vapor forwarded slot(with fallback) > vdom forwarded slot > vapor slot', async () => {
  1135. const foo = ref('foo')
  1136. const show = ref(true)
  1137. const VaporSlot = createVaporSlot()
  1138. const VdomForwardedSlot = createVdomForwardedSlot(VaporSlot)
  1139. const VaporForwardedSlotWithFallback = createVaporForwardedSlot(
  1140. VdomForwardedSlot,
  1141. 'forwarded fallback',
  1142. )
  1143. const App = createTestApp(VaporForwardedSlotWithFallback, foo, show)
  1144. const root = document.createElement('div')
  1145. createApp(App).use(vaporInteropPlugin).mount(root)
  1146. expect(root.innerHTML).toBe('<span>foo</span>')
  1147. foo.value = 'bar'
  1148. await nextTick()
  1149. expect(root.innerHTML).toBe('<span>bar</span>')
  1150. show.value = false
  1151. await nextTick()
  1152. expect(root.innerHTML).toBe('<div>forwarded fallback</div>')
  1153. show.value = true
  1154. await nextTick()
  1155. expect(root.innerHTML).toBe('<span>bar</span>')
  1156. })
  1157. test('vdom slot > vapor forwarded slot > vdom forwarded slot(with fallback) > vapor slot', async () => {
  1158. const foo = ref('foo')
  1159. const show = ref(true)
  1160. const VaporSlot = createVaporSlot()
  1161. const VdomForwardedSlotWithFallback = createVdomForwardedSlot(
  1162. VaporSlot,
  1163. 'vdom fallback',
  1164. )
  1165. const VaporForwardedSlot = createVaporForwardedSlot(
  1166. VdomForwardedSlotWithFallback,
  1167. )
  1168. const App = createTestApp(VaporForwardedSlot, foo, show)
  1169. const root = document.createElement('div')
  1170. createApp(App).use(vaporInteropPlugin).mount(root)
  1171. expect(root.innerHTML).toBe('<span>foo</span>')
  1172. foo.value = 'bar'
  1173. await nextTick()
  1174. expect(root.innerHTML).toBe('<span>bar</span>')
  1175. show.value = false
  1176. await nextTick()
  1177. expect(root.innerHTML).toBe('<div>vdom fallback</div>')
  1178. show.value = true
  1179. await nextTick()
  1180. expect(root.innerHTML).toBe('<span>bar</span>')
  1181. })
  1182. test('vdom slot(empty) > vapor forwarded slot > vdom forwarded slot(with fallback) > vapor slot', async () => {
  1183. const VaporSlot = createVaporSlot()
  1184. const VdomForwardedSlotWithFallback = createVdomForwardedSlot(
  1185. VaporSlot,
  1186. 'vdom fallback',
  1187. )
  1188. const VaporForwardedSlot = createVaporForwardedSlot(
  1189. VdomForwardedSlotWithFallback,
  1190. )
  1191. const App = createEmptyTestApp(VaporForwardedSlot)
  1192. const root = document.createElement('div')
  1193. createApp(App).use(vaporInteropPlugin).mount(root)
  1194. expect(root.innerHTML).toBe('<div>vdom fallback</div>')
  1195. })
  1196. test('vdom slot > vapor forwarded slot > vdom forwarded slot > vdom slot', async () => {
  1197. const foo = ref('foo')
  1198. const show = ref(true)
  1199. const VdomSlot = createVdomSlot()
  1200. const VdomForwardedSlot = createVdomForwardedSlot(VdomSlot)
  1201. const VaporForwardedSlot = createVaporForwardedSlot(VdomForwardedSlot)
  1202. const App = createTestApp(VaporForwardedSlot, foo, show)
  1203. const root = document.createElement('div')
  1204. createApp(App).use(vaporInteropPlugin).mount(root)
  1205. expect(root.innerHTML).toBe('<span>foo</span>')
  1206. foo.value = 'bar'
  1207. await nextTick()
  1208. expect(root.innerHTML).toBe('<span>bar</span>')
  1209. show.value = false
  1210. await nextTick()
  1211. expect(root.innerHTML).toBe('<div>fallback</div>')
  1212. show.value = true
  1213. await nextTick()
  1214. expect(root.innerHTML).toBe('<span>bar</span>')
  1215. })
  1216. test('vdom slot > vapor forwarded slot(with fallback) > vdom forwarded slot > vdom slot', async () => {
  1217. const foo = ref('foo')
  1218. const show = ref(true)
  1219. const VdomSlot = createVdomSlot()
  1220. const VdomForwardedSlot = createVdomForwardedSlot(VdomSlot)
  1221. const VaporForwardedSlotWithFallback = createVaporForwardedSlot(
  1222. VdomForwardedSlot,
  1223. 'vapor fallback',
  1224. )
  1225. const App = createTestApp(VaporForwardedSlotWithFallback, foo, show)
  1226. const root = document.createElement('div')
  1227. createApp(App).use(vaporInteropPlugin).mount(root)
  1228. expect(root.innerHTML).toBe('<span>foo</span>')
  1229. foo.value = 'bar'
  1230. await nextTick()
  1231. expect(root.innerHTML).toBe('<span>bar</span>')
  1232. show.value = false
  1233. await nextTick()
  1234. expect(root.innerHTML).toBe('<div>vapor fallback</div>')
  1235. show.value = true
  1236. await nextTick()
  1237. expect(root.innerHTML).toBe('<span>bar</span>')
  1238. })
  1239. test('vdom slot > vapor forwarded slot > vdom forwarded slot(with fallback) > vdom slot', async () => {
  1240. const foo = ref('foo')
  1241. const show = ref(true)
  1242. const VdomSlot = createVdomSlot()
  1243. const VdomForwardedSlotWithFallback = createVdomForwardedSlot(
  1244. VdomSlot,
  1245. 'vdom fallback',
  1246. )
  1247. const VaporForwardedSlot = createVaporForwardedSlot(
  1248. VdomForwardedSlotWithFallback,
  1249. )
  1250. const App = createTestApp(VaporForwardedSlot, foo, show)
  1251. const root = document.createElement('div')
  1252. createApp(App).use(vaporInteropPlugin).mount(root)
  1253. expect(root.innerHTML).toBe('<span>foo</span>')
  1254. foo.value = 'bar'
  1255. await nextTick()
  1256. expect(root.innerHTML).toBe('<span>bar</span>')
  1257. show.value = false
  1258. await nextTick()
  1259. expect(root.innerHTML).toBe('<div>vdom fallback</div>')
  1260. show.value = true
  1261. await nextTick()
  1262. expect(root.innerHTML).toBe('<span>bar</span>')
  1263. })
  1264. test('vdom slot > vapor forwarded slot (multiple) > vdom forwarded slot > vdom slot', async () => {
  1265. const foo = ref('foo')
  1266. const show = ref(true)
  1267. const VdomSlot = createVdomSlot()
  1268. const VdomForwardedSlot = createVdomForwardedSlot(VdomSlot)
  1269. const VaporForwardedSlot = createMultipleVaporForwardedSlots(
  1270. VdomForwardedSlot,
  1271. 3,
  1272. )
  1273. const App = createTestApp(VaporForwardedSlot, foo, show)
  1274. const root = document.createElement('div')
  1275. createApp(App).use(vaporInteropPlugin).mount(root)
  1276. expect(root.innerHTML).toBe('<span>foo</span><!--slot--><!--slot-->')
  1277. foo.value = 'bar'
  1278. await nextTick()
  1279. expect(root.innerHTML).toBe('<span>bar</span><!--slot--><!--slot-->')
  1280. show.value = false
  1281. await nextTick()
  1282. expect(root.innerHTML).toBe('<div>fallback</div><!--slot--><!--slot-->')
  1283. show.value = true
  1284. await nextTick()
  1285. expect(root.innerHTML).toBe('<span>bar</span><!--slot--><!--slot-->')
  1286. })
  1287. test('vdom slot > vapor forwarded slot (multiple) > vdom forwarded slot(with fallback) > vdom slot', async () => {
  1288. const foo = ref('foo')
  1289. const show = ref(true)
  1290. const VdomSlot = createVdomSlot()
  1291. const VdomForwardedSlotWithFallback = createVdomForwardedSlot(
  1292. VdomSlot,
  1293. 'vdom fallback',
  1294. )
  1295. const VaporForwardedSlot = createMultipleVaporForwardedSlots(
  1296. VdomForwardedSlotWithFallback,
  1297. 3,
  1298. )
  1299. const App = createTestApp(VaporForwardedSlot, foo, show)
  1300. const root = document.createElement('div')
  1301. createApp(App).use(vaporInteropPlugin).mount(root)
  1302. expect(root.innerHTML).toBe('<span>foo</span><!--slot--><!--slot-->')
  1303. foo.value = 'bar'
  1304. await nextTick()
  1305. expect(root.innerHTML).toBe('<span>bar</span><!--slot--><!--slot-->')
  1306. show.value = false
  1307. await nextTick()
  1308. expect(root.innerHTML).toBe(
  1309. '<div>vdom fallback</div><!--slot--><!--slot-->',
  1310. )
  1311. show.value = true
  1312. await nextTick()
  1313. expect(root.innerHTML).toBe('<span>bar</span><!--slot--><!--slot-->')
  1314. })
  1315. test('vdom slot > vdom forwarded slot > vapor slot', async () => {
  1316. const foo = ref('foo')
  1317. const show = ref(true)
  1318. const VaporSlot = createVaporSlot()
  1319. const VdomForwardedSlot = createVdomForwardedSlot(VaporSlot)
  1320. const App = createTestApp(VdomForwardedSlot, foo, show)
  1321. const root = document.createElement('div')
  1322. createApp(App).use(vaporInteropPlugin).mount(root)
  1323. expect(root.innerHTML).toBe('<span>foo</span>')
  1324. foo.value = 'bar'
  1325. await nextTick()
  1326. expect(root.innerHTML).toBe('<span>bar</span>')
  1327. show.value = false
  1328. await nextTick()
  1329. expect(root.innerHTML).toBe('<div>fallback</div>')
  1330. show.value = true
  1331. await nextTick()
  1332. expect(root.innerHTML).toBe('<span>bar</span>')
  1333. })
  1334. test('vdom slot > vdom forwarded slot > vapor forwarded slot > vapor slot', async () => {
  1335. const foo = ref('foo')
  1336. const show = ref(true)
  1337. const VaporSlot = createVaporSlot()
  1338. const VaporForwardedSlot = createVaporForwardedSlot(VaporSlot)
  1339. const VdomForwardedSlot = createVdomForwardedSlot(VaporForwardedSlot)
  1340. const App = createTestApp(VdomForwardedSlot, foo, show)
  1341. const root = document.createElement('div')
  1342. createApp(App).use(vaporInteropPlugin).mount(root)
  1343. expect(root.innerHTML).toBe('<span>foo</span><!--slot-->')
  1344. foo.value = 'bar'
  1345. await nextTick()
  1346. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1347. show.value = false
  1348. await nextTick()
  1349. expect(root.innerHTML).toBe('<div>fallback</div><!--slot-->')
  1350. show.value = true
  1351. await nextTick()
  1352. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1353. })
  1354. test('vdom slot > vdom forwarded slot (multiple) > vapor forwarded slot > vdom slot', async () => {
  1355. const foo = ref('foo')
  1356. const show = ref(true)
  1357. const VaporSlot = createVaporSlot()
  1358. const VaporForwardedSlot = createVaporForwardedSlot(VaporSlot)
  1359. const VdomForwardedSlot = createMultipleVdomForwardedSlots(
  1360. VaporForwardedSlot,
  1361. 3,
  1362. )
  1363. const App = createTestApp(VdomForwardedSlot, foo, show)
  1364. const root = document.createElement('div')
  1365. createApp(App).use(vaporInteropPlugin).mount(root)
  1366. expect(root.innerHTML).toBe('<span>foo</span><!--slot-->')
  1367. foo.value = 'bar'
  1368. await nextTick()
  1369. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1370. show.value = false
  1371. await nextTick()
  1372. expect(root.innerHTML).toBe('<div>fallback</div><!--slot-->')
  1373. show.value = true
  1374. await nextTick()
  1375. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1376. })
  1377. test('vdom slot > vdom forwarded slot (multiple) > vapor forwarded slot(with fallback) > vdom slot', async () => {
  1378. const foo = ref('foo')
  1379. const show = ref(true)
  1380. const VaporSlot = createVaporSlot()
  1381. const VaporForwardedSlot = createVaporForwardedSlot(
  1382. VaporSlot,
  1383. 'vapor fallback',
  1384. )
  1385. const VdomForwardedSlot = createMultipleVdomForwardedSlots(
  1386. VaporForwardedSlot,
  1387. 3,
  1388. )
  1389. const App = createTestApp(VdomForwardedSlot, foo, show)
  1390. const root = document.createElement('div')
  1391. createApp(App).use(vaporInteropPlugin).mount(root)
  1392. expect(root.innerHTML).toBe('<span>foo</span><!--slot-->')
  1393. foo.value = 'bar'
  1394. await nextTick()
  1395. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1396. show.value = false
  1397. await nextTick()
  1398. expect(root.innerHTML).toBe('<div>vapor fallback</div><!--slot-->')
  1399. show.value = true
  1400. await nextTick()
  1401. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1402. })
  1403. test('vdom slot > vapor forwarded slot > vapor forwarded slot > vdom slot', async () => {
  1404. const foo = ref('foo')
  1405. const show = ref(true)
  1406. const VdomSlot = createVdomSlot()
  1407. const VaporForwardedSlot1 = createMultipleVaporForwardedSlots(
  1408. VdomSlot,
  1409. 2,
  1410. )
  1411. const App = createTestApp(VaporForwardedSlot1, foo, show)
  1412. const root = document.createElement('div')
  1413. createApp(App).use(vaporInteropPlugin).mount(root)
  1414. expect(root.innerHTML).toBe('<span>foo</span><!--slot-->')
  1415. foo.value = 'bar'
  1416. await nextTick()
  1417. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1418. show.value = false
  1419. await nextTick()
  1420. expect(root.innerHTML).toBe('<div>fallback</div><!--slot-->')
  1421. show.value = true
  1422. await nextTick()
  1423. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1424. })
  1425. test('vdom slot > vapor forwarded slot(with fallback) > vapor forwarded slot > vdom slot', async () => {
  1426. const foo = ref('foo')
  1427. const show = ref(true)
  1428. const VdomSlot = createVdomSlot()
  1429. const VaporForwardedSlot2 = createVaporForwardedSlot(VdomSlot)
  1430. const VaporForwardedSlot1WithFallback = createVaporForwardedSlot(
  1431. VaporForwardedSlot2,
  1432. 'vapor1 fallback',
  1433. )
  1434. const App = createTestApp(VaporForwardedSlot1WithFallback, foo, show)
  1435. const root = document.createElement('div')
  1436. createApp(App).use(vaporInteropPlugin).mount(root)
  1437. expect(root.innerHTML).toBe('<span>foo</span><!--slot-->')
  1438. foo.value = 'bar'
  1439. await nextTick()
  1440. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1441. show.value = false
  1442. await nextTick()
  1443. expect(root.innerHTML).toBe('<div>vapor1 fallback</div><!--slot-->')
  1444. show.value = true
  1445. await nextTick()
  1446. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1447. })
  1448. test('vdom slot > vapor forwarded slot > vapor forwarded slot(with fallback) > vdom slot', async () => {
  1449. const foo = ref('foo')
  1450. const show = ref(true)
  1451. const VdomSlot = createVdomSlot()
  1452. const VaporForwardedSlot2WithFallback = createVaporForwardedSlot(
  1453. VdomSlot,
  1454. 'vapor2 fallback',
  1455. )
  1456. const VaporForwardedSlot1 = createVaporForwardedSlot(
  1457. VaporForwardedSlot2WithFallback,
  1458. )
  1459. const App = createTestApp(VaporForwardedSlot1, foo, show)
  1460. const root = document.createElement('div')
  1461. createApp(App).use(vaporInteropPlugin).mount(root)
  1462. expect(root.innerHTML).toBe('<span>foo</span><!--slot-->')
  1463. foo.value = 'bar'
  1464. await nextTick()
  1465. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1466. show.value = false
  1467. await nextTick()
  1468. expect(root.innerHTML).toBe('<div>vapor2 fallback</div><!--slot-->')
  1469. show.value = true
  1470. await nextTick()
  1471. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1472. })
  1473. test('vdom slot > vapor forwarded slot > vapor forwarded slot > vapor slot', async () => {
  1474. const foo = ref('foo')
  1475. const show = ref(true)
  1476. const VaporSlot = createVaporSlot()
  1477. const VaporForwardedSlot2 = createVaporForwardedSlot(VaporSlot)
  1478. const VaporForwardedSlot1 =
  1479. createVaporForwardedSlot(VaporForwardedSlot2)
  1480. const App = createTestApp(VaporForwardedSlot1, foo, show)
  1481. const root = document.createElement('div')
  1482. createApp(App).use(vaporInteropPlugin).mount(root)
  1483. expect(root.innerHTML).toBe('<span>foo</span><!--slot--><!--slot-->')
  1484. foo.value = 'bar'
  1485. await nextTick()
  1486. expect(root.innerHTML).toBe('<span>bar</span><!--slot--><!--slot-->')
  1487. show.value = false
  1488. await nextTick()
  1489. expect(root.innerHTML).toBe('<div>fallback</div><!--slot--><!--slot-->')
  1490. show.value = true
  1491. await nextTick()
  1492. expect(root.innerHTML).toBe('<span>bar</span><!--slot--><!--slot-->')
  1493. })
  1494. test('vdom slot > vapor forwarded slot(with fallback) > vapor forwarded slot(with fallback) > vdom slot', async () => {
  1495. const foo = ref('foo')
  1496. const show = ref(true)
  1497. const VdomSlot = createVdomSlot()
  1498. const VaporForwardedSlot2WithFallback = createVaporForwardedSlot(
  1499. VdomSlot,
  1500. 'vapor2 fallback',
  1501. )
  1502. const VaporForwardedSlot1WithFallback = createVaporForwardedSlot(
  1503. VaporForwardedSlot2WithFallback,
  1504. 'vapor1 fallback',
  1505. )
  1506. const App = createTestApp(VaporForwardedSlot1WithFallback, foo, show)
  1507. const root = document.createElement('div')
  1508. createApp(App).use(vaporInteropPlugin).mount(root)
  1509. expect(root.innerHTML).toBe('<span>foo</span><!--slot-->')
  1510. foo.value = 'bar'
  1511. await nextTick()
  1512. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1513. show.value = false
  1514. await nextTick()
  1515. expect(root.innerHTML).toBe('<div>vapor1 fallback</div><!--slot-->')
  1516. show.value = true
  1517. await nextTick()
  1518. expect(root.innerHTML).toBe('<span>bar</span><!--slot-->')
  1519. })
  1520. test('vdom slot > vapor forwarded slot(with fallback) > vapor forwarded slot(with fallback) > vapor slot', async () => {
  1521. const foo = ref('foo')
  1522. const show = ref(true)
  1523. const VaporSlot = createVaporSlot()
  1524. const VaporForwardedSlot2WithFallback = createVaporForwardedSlot(
  1525. VaporSlot,
  1526. 'vapor2 fallback',
  1527. )
  1528. const VaporForwardedSlot1WithFallback = createVaporForwardedSlot(
  1529. VaporForwardedSlot2WithFallback,
  1530. 'vapor1 fallback',
  1531. )
  1532. const App = createTestApp(VaporForwardedSlot1WithFallback, foo, show)
  1533. const root = document.createElement('div')
  1534. createApp(App).use(vaporInteropPlugin).mount(root)
  1535. expect(root.innerHTML).toBe('<span>foo</span><!--slot--><!--slot-->')
  1536. foo.value = 'bar'
  1537. await nextTick()
  1538. expect(root.innerHTML).toBe('<span>bar</span><!--slot--><!--slot-->')
  1539. show.value = false
  1540. await nextTick()
  1541. expect(root.innerHTML).toBe(
  1542. '<div>vapor1 fallback</div><!--slot--><!--slot-->',
  1543. )
  1544. show.value = true
  1545. await nextTick()
  1546. expect(root.innerHTML).toBe('<span>bar</span><!--slot--><!--slot-->')
  1547. })
  1548. test('vdom slot > vdom forwarded slot(with fallback) > vdom forwarded slot(with fallback) > vapor slot', async () => {
  1549. const foo = ref('foo')
  1550. const show = ref(true)
  1551. const VaporSlot = createVaporSlot()
  1552. const VdomForwardedSlot2WithFallback = createVdomForwardedSlot(
  1553. VaporSlot,
  1554. 'vdom2 fallback',
  1555. )
  1556. const VdomForwardedSlot1WithFallback = createVdomForwardedSlot(
  1557. VdomForwardedSlot2WithFallback,
  1558. 'vdom1 fallback',
  1559. )
  1560. const App = createTestApp(VdomForwardedSlot1WithFallback, foo, show)
  1561. const root = document.createElement('div')
  1562. createApp(App).use(vaporInteropPlugin).mount(root)
  1563. expect(root.innerHTML).toBe('<span>foo</span>')
  1564. foo.value = 'bar'
  1565. await nextTick()
  1566. expect(root.innerHTML).toBe('<span>bar</span>')
  1567. show.value = false
  1568. await nextTick()
  1569. expect(root.innerHTML).toBe('<div>vdom1 fallback</div>')
  1570. show.value = true
  1571. await nextTick()
  1572. expect(root.innerHTML).toBe('<span>bar</span>')
  1573. })
  1574. test('vdom slot > vdom forwarded slot(with fallback) > vdom forwarded slot(with fallback) > vdom slot', async () => {
  1575. const foo = ref('foo')
  1576. const show = ref(true)
  1577. const VdomSlot = createVdomSlot()
  1578. const VdomForwardedSlot2WithFallback = createVdomForwardedSlot(
  1579. VdomSlot,
  1580. 'vdom2 fallback',
  1581. )
  1582. const VdomForwardedSlot1WithFallback = createVdomForwardedSlot(
  1583. VdomForwardedSlot2WithFallback,
  1584. 'vdom1 fallback',
  1585. )
  1586. const App = createTestApp(VdomForwardedSlot1WithFallback, foo, show)
  1587. const root = document.createElement('div')
  1588. createApp(App).use(vaporInteropPlugin).mount(root)
  1589. expect(root.innerHTML).toBe('<span>foo</span>')
  1590. foo.value = 'bar'
  1591. await nextTick()
  1592. expect(root.innerHTML).toBe('<span>bar</span>')
  1593. show.value = false
  1594. await nextTick()
  1595. expect(root.innerHTML).toBe('<div>vdom1 fallback</div>')
  1596. show.value = true
  1597. await nextTick()
  1598. expect(root.innerHTML).toBe('<span>bar</span>')
  1599. })
  1600. test('vdom slot > vdom forwarded slot(with fallback) > vdom forwarded slot(with fallback) (multiple) > vapor slot', async () => {
  1601. const foo = ref('foo')
  1602. const show = ref(true)
  1603. const VaporSlot = createVaporSlot()
  1604. const VdomForwardedSlot3WithFallback = createVdomForwardedSlot(
  1605. VaporSlot,
  1606. 'vdom3 fallback',
  1607. )
  1608. const VdomForwardedSlot2WithFallback = createVdomForwardedSlot(
  1609. VdomForwardedSlot3WithFallback,
  1610. 'vdom2 fallback',
  1611. )
  1612. const VdomForwardedSlot1WithFallback = createVdomForwardedSlot(
  1613. VdomForwardedSlot2WithFallback,
  1614. 'vdom1 fallback',
  1615. )
  1616. const App = createTestApp(VdomForwardedSlot1WithFallback, foo, show)
  1617. const root = document.createElement('div')
  1618. createApp(App).use(vaporInteropPlugin).mount(root)
  1619. expect(root.innerHTML).toBe('<span>foo</span>')
  1620. foo.value = 'bar'
  1621. await nextTick()
  1622. expect(root.innerHTML).toBe('<span>bar</span>')
  1623. show.value = false
  1624. await nextTick()
  1625. expect(root.innerHTML).toBe('<div>vdom1 fallback</div>')
  1626. show.value = true
  1627. await nextTick()
  1628. expect(root.innerHTML).toBe('<span>bar</span>')
  1629. })
  1630. })
  1631. })
  1632. })