ssrRenderAttrs.spec.ts 4.0 KB

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