2
0

ssrRenderAttrs.spec.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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. test('preserve name on svg elements', () => {
  92. expect(
  93. ssrRenderAttrs(
  94. {
  95. viewBox: 'foo'
  96. },
  97. 'svg'
  98. )
  99. ).toBe(` viewBox="foo"`)
  100. })
  101. })
  102. describe('ssr: renderAttr', () => {
  103. test('basic', () => {
  104. expect(ssrRenderAttr('foo', 'bar')).toBe(` foo="bar"`)
  105. })
  106. test('null and undefined', () => {
  107. expect(ssrRenderAttr('foo', null)).toBe(``)
  108. expect(ssrRenderAttr('foo', undefined)).toBe(``)
  109. })
  110. test('escape', () => {
  111. expect(ssrRenderAttr('foo', '<script>')).toBe(
  112. ` foo="${escapeHtml(`<script>`)}"`
  113. )
  114. })
  115. })
  116. describe('ssr: renderClass', () => {
  117. test('via renderProps', () => {
  118. expect(
  119. ssrRenderAttrs({
  120. class: ['foo', 'bar']
  121. })
  122. ).toBe(` class="foo bar"`)
  123. })
  124. test('standalone', () => {
  125. expect(ssrRenderClass(`foo`)).toBe(`foo`)
  126. expect(ssrRenderClass([`foo`, `bar`])).toBe(`foo bar`)
  127. expect(ssrRenderClass({ foo: true, bar: false })).toBe(`foo`)
  128. expect(ssrRenderClass([{ foo: true, bar: false }, `baz`])).toBe(`foo baz`)
  129. })
  130. test('escape class values', () => {
  131. expect(ssrRenderClass(`"><script`)).toBe(`&quot;&gt;&lt;script`)
  132. })
  133. })
  134. describe('ssr: renderStyle', () => {
  135. test('via renderProps', () => {
  136. expect(
  137. ssrRenderAttrs({
  138. style: {
  139. color: 'red',
  140. '--a': 2,
  141. '-webkit-line-clamp': 1
  142. }
  143. })
  144. ).toBe(` style="color:red;--a:2;-webkit-line-clamp:1;"`)
  145. })
  146. test('standalone', () => {
  147. expect(ssrRenderStyle(`color:red`)).toBe(`color:red`)
  148. expect(
  149. ssrRenderStyle({
  150. color: `red`
  151. })
  152. ).toBe(`color:red;`)
  153. expect(
  154. ssrRenderStyle([
  155. { color: `red` },
  156. { fontSize: `15px` } // case conversion
  157. ])
  158. ).toBe(`color:red;font-size:15px;`)
  159. })
  160. test('number handling', () => {
  161. expect(
  162. ssrRenderStyle({
  163. fontSize: null, // invalid value should be ignored
  164. opacity: 0.5
  165. })
  166. ).toBe(`opacity:0.5;`)
  167. })
  168. test('escape inline CSS', () => {
  169. expect(ssrRenderStyle(`"><script`)).toBe(`&quot;&gt;&lt;script`)
  170. expect(
  171. ssrRenderStyle({
  172. color: `"><script`
  173. })
  174. ).toBe(`color:&quot;&gt;&lt;script;`)
  175. })
  176. })