ssr-stream.spec.ts 3.4 KB

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