renderAttrs.spec.ts 3.5 KB

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