ssrSuspense.spec.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import { Suspense, createApp, defineComponent, h } from 'vue'
  2. import { renderToString } from '../src/renderToString'
  3. import { ssrRenderComponent } from '../src/helpers/ssrRenderComponent'
  4. import { ssrRenderSuspense } from '../src/helpers/ssrRenderSuspense'
  5. describe('SSR Suspense', () => {
  6. const ResolvingAsync = {
  7. async setup() {
  8. return () => h('div', 'async')
  9. },
  10. }
  11. const RejectingAsync = {
  12. setup() {
  13. return new Promise((_, reject) => reject('foo'))
  14. },
  15. }
  16. test('content', async () => {
  17. const Comp = {
  18. render() {
  19. return h(Suspense, null, {
  20. default: h(ResolvingAsync),
  21. fallback: h('div', 'fallback'),
  22. })
  23. },
  24. }
  25. expect(await renderToString(createApp(Comp))).toBe(`<div>async</div>`)
  26. })
  27. test('reject', async () => {
  28. const Comp = {
  29. errorCaptured: vi.fn(() => false),
  30. render() {
  31. return h(Suspense, null, {
  32. default: h(RejectingAsync),
  33. fallback: h('div', 'fallback'),
  34. })
  35. },
  36. }
  37. expect(await renderToString(createApp(Comp))).toBe(`<!---->`)
  38. expect(Comp.errorCaptured).toHaveBeenCalledTimes(1)
  39. expect('missing template').toHaveBeenWarned()
  40. })
  41. test('2 components', async () => {
  42. const Comp = {
  43. render() {
  44. return h(Suspense, null, {
  45. default: h('div', [h(ResolvingAsync), h(ResolvingAsync)]),
  46. fallback: h('div', 'fallback'),
  47. })
  48. },
  49. }
  50. expect(await renderToString(createApp(Comp))).toBe(
  51. `<div><div>async</div><div>async</div></div>`,
  52. )
  53. })
  54. test('resolving component + rejecting component', async () => {
  55. const Comp = {
  56. errorCaptured: vi.fn(() => false),
  57. render() {
  58. return h(Suspense, null, {
  59. default: h('div', [h(ResolvingAsync), h(RejectingAsync)]),
  60. fallback: h('div', 'fallback'),
  61. })
  62. },
  63. }
  64. expect(await renderToString(createApp(Comp))).toBe(
  65. `<div><div>async</div><!----></div>`,
  66. )
  67. expect(Comp.errorCaptured).toHaveBeenCalledTimes(1)
  68. expect('missing template or render function').toHaveBeenWarned()
  69. })
  70. test('failing suspense in passing suspense', async () => {
  71. const Comp = {
  72. errorCaptured: vi.fn(() => false),
  73. render() {
  74. return h(Suspense, null, {
  75. default: h('div', [
  76. h(ResolvingAsync),
  77. h(Suspense, null, {
  78. default: h('div', [h(RejectingAsync)]),
  79. fallback: h('div', 'fallback 2'),
  80. }),
  81. ]),
  82. fallback: h('div', 'fallback 1'),
  83. })
  84. },
  85. }
  86. expect(await renderToString(createApp(Comp))).toBe(
  87. `<div><div>async</div><div><!----></div></div>`,
  88. )
  89. expect(Comp.errorCaptured).toHaveBeenCalledTimes(1)
  90. expect('missing template').toHaveBeenWarned()
  91. })
  92. // nuxt/nuxt#28162
  93. test('propagates sync errors from compiled ssrRenderSuspense default slot', async () => {
  94. const Throwing = defineComponent({
  95. ssrRender(_ctx: any, _push: any) {
  96. throw new TypeError('bang')
  97. },
  98. })
  99. const Root = defineComponent({
  100. ssrRender(_ctx: any, _push: any, _parent: any) {
  101. ssrRenderSuspense(_push, {
  102. default: () => {
  103. _push(ssrRenderComponent(Throwing, null, null, _parent))
  104. },
  105. _: 1,
  106. } as any)
  107. },
  108. })
  109. await expect(renderToString(createApp(Root))).rejects.toThrow('bang')
  110. })
  111. test('passing suspense in failing suspense', async () => {
  112. const Comp = {
  113. errorCaptured: vi.fn(() => false),
  114. render() {
  115. return h(Suspense, null, {
  116. default: h('div', [
  117. h(RejectingAsync),
  118. h(Suspense, null, {
  119. default: h('div', [h(ResolvingAsync)]),
  120. fallback: h('div', 'fallback 2'),
  121. }),
  122. ]),
  123. fallback: h('div', 'fallback 1'),
  124. })
  125. },
  126. }
  127. expect(await renderToString(createApp(Comp))).toBe(
  128. `<div><!----><div><div>async</div></div></div>`,
  129. )
  130. expect(Comp.errorCaptured).toHaveBeenCalledTimes(1)
  131. expect('missing template').toHaveBeenWarned()
  132. })
  133. })