ssrRenderAttrs.spec.ts 3.7 KB

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