ssr-stream.spec.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // @vitest-environment node
  2. import Vue from 'vue'
  3. import { createRenderer } from 'server/index'
  4. const { renderToStream } = createRenderer()
  5. describe('SSR: renderToStream', () => {
  6. it('should render to a stream', done => {
  7. const stream = renderToStream(
  8. new Vue({
  9. template: `
  10. <div>
  11. <p class="hi">yoyo</p>
  12. <div id="ho" :class="[testClass, { red: isRed }]"></div>
  13. <span>{{ test }}</span>
  14. <input :value="test">
  15. <b-comp></b-comp>
  16. <c-comp></c-comp>
  17. </div>
  18. `,
  19. data: {
  20. test: 'hi',
  21. isRed: true,
  22. testClass: 'a'
  23. },
  24. components: {
  25. bComp(resolve) {
  26. return resolve({
  27. render(h) {
  28. return h('test-async-2')
  29. },
  30. components: {
  31. testAsync2(resolve) {
  32. return resolve({
  33. created() {
  34. this.$parent.$parent.testClass = 'b'
  35. },
  36. render(h) {
  37. return h(
  38. 'div',
  39. { class: [this.$parent.$parent.testClass] },
  40. 'test'
  41. )
  42. }
  43. })
  44. }
  45. }
  46. })
  47. },
  48. cComp: {
  49. render(h) {
  50. return h('div', { class: [this.$parent.testClass] }, 'test')
  51. }
  52. }
  53. }
  54. })
  55. )
  56. let res = ''
  57. stream.on('data', chunk => {
  58. res += chunk
  59. })
  60. stream.on('end', () => {
  61. expect(res).toContain(
  62. '<div data-server-rendered="true">' +
  63. '<p class="hi">yoyo</p> ' +
  64. '<div id="ho" class="a red"></div> ' +
  65. '<span>hi</span> ' +
  66. '<input value="hi"> ' +
  67. '<div class="b">test</div> ' +
  68. '<div class="b">test</div>' +
  69. '</div>'
  70. )
  71. done()
  72. })
  73. })
  74. it('should catch error', done => {
  75. const stream = renderToStream(
  76. new Vue({
  77. render() {
  78. throw new Error('oops')
  79. }
  80. })
  81. )
  82. stream.on('error', err => {
  83. expect(err.toString()).toMatch(/oops/)
  84. expect(`oops`).toHaveBeenWarned()
  85. done()
  86. })
  87. stream.on('data', _ => _)
  88. })
  89. it('should not mingle two components', done => {
  90. const padding = new Array(20000).join('x')
  91. const component1 = new Vue({
  92. template: `<div>${padding}<div></div></div>`,
  93. _scopeId: '_component1'
  94. })
  95. const component2 = new Vue({
  96. template: `<div></div>`,
  97. _scopeId: '_component2'
  98. })
  99. const stream1 = renderToStream(component1)
  100. const stream2 = renderToStream(component2)
  101. let res = ''
  102. stream1.on('data', text => {
  103. res += text.toString('utf-8').replace(/x/g, '')
  104. })
  105. stream1.on('end', () => {
  106. expect(res).not.toContain('_component2')
  107. done()
  108. })
  109. stream1.read(1)
  110. stream2.read(1)
  111. })
  112. it('should call context.rendered', done => {
  113. let a = 0
  114. const stream = renderToStream(
  115. new Vue({
  116. template: `
  117. <div>Hello</div>
  118. `
  119. }),
  120. {
  121. rendered: () => {
  122. a = 42
  123. }
  124. }
  125. )
  126. let res = ''
  127. stream.on('data', chunk => {
  128. res += chunk
  129. })
  130. stream.on('end', () => {
  131. expect(res).toContain('<div data-server-rendered="true">Hello</div>')
  132. expect(a).toBe(42)
  133. done()
  134. })
  135. })
  136. })