ssrScopeId.spec.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /**
  2. * @jest-environment node
  3. */
  4. import { createApp, h, mergeProps, withCtx } from 'vue'
  5. import { renderToString } from '../src/renderToString'
  6. import { ssrRenderComponent, ssrRenderAttrs, ssrRenderSlot } from '../src'
  7. describe('ssr: scopedId runtime behavior', () => {
  8. test('id on component root', async () => {
  9. const Child = {
  10. ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
  11. push(`<div${ssrRenderAttrs(attrs)}></div>`)
  12. }
  13. }
  14. const Comp = {
  15. __scopeId: 'parent',
  16. ssrRender: (ctx: any, push: any, parent: any) => {
  17. push(ssrRenderComponent(Child), null, null, parent)
  18. }
  19. }
  20. const result = await renderToString(createApp(Comp))
  21. expect(result).toBe(`<div parent></div>`)
  22. })
  23. test('id and :slotted on component root', async () => {
  24. const Child = {
  25. // <div></div>
  26. ssrRender: (_: any, push: any, _parent: any, attrs: any) => {
  27. push(`<div${ssrRenderAttrs(attrs)} child></div>`)
  28. }
  29. }
  30. const Wrapper = {
  31. __scopeId: 'wrapper',
  32. ssrRender: (ctx: any, push: any, parent: any) => {
  33. // <slot/>
  34. ssrRenderSlot(
  35. ctx.$slots,
  36. 'default',
  37. {},
  38. null,
  39. push,
  40. parent,
  41. 'wrapper-s'
  42. )
  43. }
  44. }
  45. const Comp = {
  46. __scopeId: 'parent',
  47. ssrRender: (_: any, push: any, parent: any) => {
  48. // <Wrapper><Child/></Wrapper>
  49. push(
  50. ssrRenderComponent(
  51. Wrapper,
  52. null,
  53. {
  54. default: withCtx(
  55. (_: any, push: any, parent: any, scopeId: string) => {
  56. push(ssrRenderComponent(Child, null, null, parent, scopeId))
  57. }
  58. ),
  59. _: 1
  60. } as any,
  61. parent
  62. )
  63. )
  64. }
  65. }
  66. const result = await renderToString(createApp(Comp))
  67. expect(result).toBe(`<!--[--><div parent wrapper-s child></div><!--]-->`)
  68. })
  69. // #2892
  70. test(':slotted on forwarded slots', async () => {
  71. const Wrapper = {
  72. __scopeId: 'wrapper',
  73. ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
  74. // <div class="wrapper"><slot/></div>
  75. push(
  76. `<div${ssrRenderAttrs(
  77. mergeProps({ class: 'wrapper' }, attrs)
  78. )} wrapper>`
  79. )
  80. ssrRenderSlot(
  81. ctx.$slots,
  82. 'default',
  83. {},
  84. null,
  85. push,
  86. parent,
  87. 'wrapper-s'
  88. )
  89. push(`</div>`)
  90. }
  91. }
  92. const Slotted = {
  93. __scopeId: 'slotted',
  94. ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
  95. // <Wrapper><slot/></Wrapper>
  96. push(
  97. ssrRenderComponent(
  98. Wrapper,
  99. attrs,
  100. {
  101. default: withCtx(
  102. (_: any, push: any, parent: any, scopeId: string) => {
  103. ssrRenderSlot(
  104. ctx.$slots,
  105. 'default',
  106. {},
  107. null,
  108. push,
  109. parent,
  110. 'slotted-s' + scopeId
  111. )
  112. }
  113. ),
  114. _: 1
  115. } as any,
  116. parent
  117. )
  118. )
  119. }
  120. }
  121. const Root = {
  122. __scopeId: 'root',
  123. // <Slotted><div></div></Slotted>
  124. ssrRender: (_: any, push: any, parent: any, attrs: any) => {
  125. push(
  126. ssrRenderComponent(
  127. Slotted,
  128. attrs,
  129. {
  130. default: withCtx(
  131. (_: any, push: any, parent: any, scopeId: string) => {
  132. push(`<div root${scopeId}></div>`)
  133. }
  134. ),
  135. _: 1
  136. } as any,
  137. parent
  138. )
  139. )
  140. }
  141. }
  142. const result = await renderToString(createApp(Root))
  143. expect(result).toBe(
  144. `<div class="wrapper" root slotted wrapper>` +
  145. `<!--[--><!--[--><div root slotted-s wrapper-s></div><!--]--><!--]-->` +
  146. `</div>`
  147. )
  148. })
  149. // #3513
  150. test('scopeId inheritance across ssr-compiled andn on-ssr compiled parent chain', async () => {
  151. const Child = {
  152. ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
  153. push(`<div${ssrRenderAttrs(attrs)}></div>`)
  154. }
  155. }
  156. const Middle = {
  157. render() {
  158. return h(Child)
  159. }
  160. }
  161. const Comp = {
  162. __scopeId: 'parent',
  163. ssrRender: (ctx: any, push: any, parent: any) => {
  164. push(ssrRenderComponent(Middle, null, null, parent))
  165. }
  166. }
  167. const result = await renderToString(createApp(Comp)) // output: `<div></div>`
  168. expect(result).toBe(`<div parent></div>`)
  169. })
  170. })