ssrRenderAttrs.spec.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /**
  2. * @jest-environment node
  3. */
  4. import {
  5. ssrRenderAttrs,
  6. ssrRenderClass,
  7. ssrRenderStyle,
  8. ssrRenderAttr
  9. } from '../src/helpers/ssrRenderAttrs'
  10. import { escapeHtml } from '@vue/shared'
  11. describe('ssr: renderAttrs', () => {
  12. test('ignore reserved props', () => {
  13. expect(
  14. ssrRenderAttrs({
  15. key: 1,
  16. ref_key: 'foo',
  17. ref_for: 'bar',
  18. ref: () => {},
  19. onClick: () => {}
  20. })
  21. ).toBe('')
  22. })
  23. test('normal attrs', () => {
  24. expect(
  25. ssrRenderAttrs({
  26. id: 'foo',
  27. title: 'bar'
  28. })
  29. ).toBe(` id="foo" title="bar"`)
  30. })
  31. test('empty value attrs', () => {
  32. expect(
  33. ssrRenderAttrs({
  34. 'data-v-abc': ''
  35. })
  36. ).toBe(` data-v-abc`)
  37. })
  38. test('escape attrs', () => {
  39. expect(
  40. ssrRenderAttrs({
  41. id: '"><script'
  42. })
  43. ).toBe(` id="&quot;&gt;&lt;script"`)
  44. })
  45. test('boolean attrs', () => {
  46. expect(
  47. ssrRenderAttrs({
  48. checked: true,
  49. multiple: false,
  50. readonly: 0,
  51. disabled: ''
  52. })
  53. ).toBe(` checked disabled`) // boolean attr w/ false should be ignored
  54. })
  55. test('ignore falsy values', () => {
  56. expect(
  57. ssrRenderAttrs({
  58. foo: false,
  59. title: null,
  60. baz: undefined
  61. })
  62. ).toBe(` foo="false"`) // non boolean should render `false` as is
  63. })
  64. test('ignore non-renderable values', () => {
  65. expect(
  66. ssrRenderAttrs({
  67. foo: {},
  68. bar: [],
  69. baz: () => {}
  70. })
  71. ).toBe(``)
  72. })
  73. test('props to attrs', () => {
  74. expect(
  75. ssrRenderAttrs({
  76. readOnly: true, // simple lower case conversion
  77. htmlFor: 'foobar' // special cases
  78. })
  79. ).toBe(` readonly for="foobar"`)
  80. })
  81. test('preserve name on custom element', () => {
  82. expect(
  83. ssrRenderAttrs(
  84. {
  85. fooBar: 'ok'
  86. },
  87. 'my-el'
  88. )
  89. ).toBe(` fooBar="ok"`)
  90. })
  91. })
  92. describe('ssr: renderAttr', () => {
  93. test('basic', () => {
  94. expect(ssrRenderAttr('foo', 'bar')).toBe(` foo="bar"`)
  95. })
  96. test('null and undefined', () => {
  97. expect(ssrRenderAttr('foo', null)).toBe(``)
  98. expect(ssrRenderAttr('foo', undefined)).toBe(``)
  99. })
  100. test('escape', () => {
  101. expect(ssrRenderAttr('foo', '<script>')).toBe(
  102. ` foo="${escapeHtml(`<script>`)}"`
  103. )
  104. })
  105. })
  106. describe('ssr: renderClass', () => {
  107. test('via renderProps', () => {
  108. expect(
  109. ssrRenderAttrs({
  110. class: ['foo', 'bar']
  111. })
  112. ).toBe(` class="foo bar"`)
  113. })
  114. test('standalone', () => {
  115. expect(ssrRenderClass(`foo`)).toBe(`foo`)
  116. expect(ssrRenderClass([`foo`, `bar`])).toBe(`foo bar`)
  117. expect(ssrRenderClass({ foo: true, bar: false })).toBe(`foo`)
  118. expect(ssrRenderClass([{ foo: true, bar: false }, `baz`])).toBe(`foo baz`)
  119. })
  120. test('escape class values', () => {
  121. expect(ssrRenderClass(`"><script`)).toBe(`&quot;&gt;&lt;script`)
  122. })
  123. })
  124. describe('ssr: renderStyle', () => {
  125. test('via renderProps', () => {
  126. expect(
  127. ssrRenderAttrs({
  128. style: {
  129. color: 'red'
  130. }
  131. })
  132. ).toBe(` style="color:red;"`)
  133. })
  134. test('standalone', () => {
  135. expect(ssrRenderStyle(`color:red`)).toBe(`color:red`)
  136. expect(
  137. ssrRenderStyle({
  138. color: `red`
  139. })
  140. ).toBe(`color:red;`)
  141. expect(
  142. ssrRenderStyle([
  143. { color: `red` },
  144. { fontSize: `15px` } // case conversion
  145. ])
  146. ).toBe(`color:red;font-size:15px;`)
  147. })
  148. test('number handling', () => {
  149. expect(
  150. ssrRenderStyle({
  151. fontSize: 15, // should be ignored since font-size requires unit
  152. opacity: 0.5
  153. })
  154. ).toBe(`opacity:0.5;`)
  155. })
  156. test('escape inline CSS', () => {
  157. expect(ssrRenderStyle(`"><script`)).toBe(`&quot;&gt;&lt;script`)
  158. expect(
  159. ssrRenderStyle({
  160. color: `"><script`
  161. })
  162. ).toBe(`color:&quot;&gt;&lt;script;`)
  163. })
  164. })