ssrTeleport.spec.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import { Teleport, createApp, h } from 'vue'
  2. import { renderToString } from '../src/renderToString'
  3. import { renderToSimpleStream } from '../src/renderToStream'
  4. import type { SSRContext } from '../src/render'
  5. import { ssrRenderTeleport } from '../src/helpers/ssrRenderTeleport'
  6. describe('ssrRenderTeleport', () => {
  7. test('teleport rendering (compiled)', async () => {
  8. const ctx: SSRContext = {}
  9. const html = await renderToString(
  10. createApp({
  11. data() {
  12. return { msg: 'hello' }
  13. },
  14. ssrRender(_ctx, _push, _parent) {
  15. ssrRenderTeleport(
  16. _push,
  17. _push => {
  18. _push(`<div>content</div>`)
  19. },
  20. '#target',
  21. false,
  22. _parent,
  23. )
  24. },
  25. }),
  26. ctx,
  27. )
  28. expect(html).toBe('<!--teleport start--><!--teleport end-->')
  29. expect(ctx.teleports!['#target']).toBe(
  30. `<!--teleport start anchor--><div>content</div><!--teleport anchor-->`,
  31. )
  32. })
  33. test('teleport rendering (compiled + disabled)', async () => {
  34. const ctx: SSRContext = {}
  35. const html = await renderToString(
  36. createApp({
  37. data() {
  38. return { msg: 'hello' }
  39. },
  40. ssrRender(_ctx, _push, _parent) {
  41. ssrRenderTeleport(
  42. _push,
  43. _push => {
  44. _push(`<div>content</div>`)
  45. },
  46. '#target',
  47. true,
  48. _parent,
  49. )
  50. },
  51. }),
  52. ctx,
  53. )
  54. expect(html).toBe(
  55. '<!--teleport start--><div>content</div><!--teleport end-->',
  56. )
  57. expect(ctx.teleports!['#target']).toBe(
  58. `<!--teleport start anchor--><!--teleport anchor-->`,
  59. )
  60. })
  61. test('teleport rendering (vnode)', async () => {
  62. const ctx: SSRContext = {}
  63. const html = await renderToString(
  64. h(
  65. Teleport,
  66. {
  67. to: `#target`,
  68. },
  69. h('span', 'hello'),
  70. ),
  71. ctx,
  72. )
  73. expect(html).toBe('<!--teleport start--><!--teleport end-->')
  74. expect(ctx.teleports!['#target']).toBe(
  75. '<!--teleport start anchor--><span>hello</span><!--teleport anchor-->',
  76. )
  77. })
  78. test('teleport rendering (vnode + disabled)', async () => {
  79. const ctx: SSRContext = {}
  80. const html = await renderToString(
  81. h(
  82. Teleport,
  83. {
  84. to: `#target`,
  85. disabled: true,
  86. },
  87. h('span', 'hello'),
  88. ),
  89. ctx,
  90. )
  91. expect(html).toBe(
  92. '<!--teleport start--><span>hello</span><!--teleport end-->',
  93. )
  94. expect(ctx.teleports!['#target']).toBe(
  95. `<!--teleport start anchor--><!--teleport anchor-->`,
  96. )
  97. })
  98. test('multiple teleports with same target', async () => {
  99. const ctx: SSRContext = {}
  100. const html = await renderToString(
  101. h('div', [
  102. h(
  103. Teleport,
  104. {
  105. to: `#target`,
  106. },
  107. h('span', 'hello'),
  108. ),
  109. h(Teleport, { to: `#target` }, 'world'),
  110. ]),
  111. ctx,
  112. )
  113. expect(html).toBe(
  114. '<div><!--teleport start--><!--teleport end--><!--teleport start--><!--teleport end--></div>',
  115. )
  116. expect(ctx.teleports!['#target']).toBe(
  117. '<!--teleport start anchor--><span>hello</span><!--teleport anchor-->' +
  118. '<!--teleport start anchor-->world<!--teleport anchor-->',
  119. )
  120. })
  121. test('teleport inside async component', async () => {
  122. const ctx: SSRContext = {}
  123. const asyncComponent = {
  124. template: '<teleport to="#target"><div>content</div></teleport>',
  125. async setup() {},
  126. }
  127. const html = await renderToString(
  128. h({
  129. template: '<async-component />',
  130. components: { asyncComponent },
  131. }),
  132. ctx,
  133. )
  134. expect(html).toBe('<!--teleport start--><!--teleport end-->')
  135. expect(ctx.teleports!['#target']).toBe(
  136. `<!--teleport start anchor--><div>content</div><!--teleport anchor-->`,
  137. )
  138. })
  139. test('teleport inside async component (stream)', async () => {
  140. const ctx: SSRContext = {}
  141. const asyncComponent = {
  142. template: '<teleport to="#target"><div>content</div></teleport>',
  143. async setup() {},
  144. }
  145. let html = ''
  146. let resolve: any
  147. const p = new Promise(r => (resolve = r))
  148. renderToSimpleStream(
  149. h({
  150. template: '<async-component />',
  151. components: { asyncComponent },
  152. }),
  153. ctx,
  154. {
  155. push(chunk) {
  156. if (chunk === null) {
  157. resolve()
  158. } else {
  159. html += chunk
  160. }
  161. },
  162. destroy(err) {
  163. throw err
  164. },
  165. },
  166. )
  167. await p
  168. expect(html).toBe('<!--teleport start--><!--teleport end-->')
  169. expect(ctx.teleports!['#target']).toBe(
  170. `<!--teleport start anchor--><div>content</div><!--teleport anchor-->`,
  171. )
  172. })
  173. })