compile.test.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import { BindingTypes, CompilerOptions, RootNode } from '@vue/compiler-dom'
  2. // TODO remove it
  3. import { format } from 'prettier'
  4. import { compile as _compile } from '../src'
  5. import { ErrorCodes } from '../src/errors'
  6. async function compile(
  7. template: string | RootNode,
  8. options: CompilerOptions = {},
  9. ) {
  10. let { code } = _compile(template, options)
  11. code = await format(code, {
  12. parser: 'babel',
  13. printWidth: 999999,
  14. singleQuote: true,
  15. })
  16. return code
  17. }
  18. describe('compile', () => {
  19. test('static template', async () => {
  20. const code = await compile(
  21. `<div>
  22. <p>hello</p>
  23. <input />
  24. <span />
  25. </div>`,
  26. )
  27. expect(code).matchSnapshot()
  28. })
  29. test('dynamic root', async () => {
  30. const code = await compile(`{{ 1 }}{{ 2 }}`)
  31. expect(code).matchSnapshot()
  32. })
  33. test('dynamic root nodes and interpolation', async () => {
  34. const code = await compile(
  35. `<button @click="handleClick" :id="count">{{count}}foo{{count}}foo{{count}} </button>`,
  36. )
  37. expect(code).matchSnapshot()
  38. })
  39. test('static + dynamic root', async () => {
  40. const code = await compile(
  41. `{{ 1 }}{{ 2 }}3{{ 4 }}{{ 5 }}6{{ 7 }}{{ 8 }}9{{ 'A' }}{{ 'B' }}`,
  42. )
  43. expect(code).matchSnapshot()
  44. })
  45. test('fragment', async () => {
  46. const code = await compile(`<p/><span/><div/>`)
  47. expect(code).matchSnapshot()
  48. })
  49. test('bindings', async () => {
  50. const code = await compile(`<div>count is {{ count }}.</div>`, {
  51. bindingMetadata: {
  52. count: BindingTypes.SETUP_REF,
  53. },
  54. })
  55. expect(code).matchSnapshot()
  56. })
  57. describe('directives', () => {
  58. describe('v-bind', () => {
  59. test('simple expression', async () => {
  60. const code = await compile(`<div :id="id"></div>`, {
  61. bindingMetadata: {
  62. id: BindingTypes.SETUP_REF,
  63. },
  64. })
  65. expect(code).matchSnapshot()
  66. })
  67. test('should error if no expression', async () => {
  68. const onError = vi.fn()
  69. await compile(`<div v-bind:arg />`, { onError })
  70. expect(onError.mock.calls[0][0]).toMatchObject({
  71. code: ErrorCodes.VAPOR_BIND_NO_EXPRESSION,
  72. loc: {
  73. start: {
  74. line: 1,
  75. column: 6,
  76. },
  77. end: {
  78. line: 1,
  79. column: 16,
  80. },
  81. },
  82. })
  83. })
  84. })
  85. describe('v-on', () => {
  86. test('simple expression', async () => {
  87. const code = await compile(`<div @click="handleClick"></div>`, {
  88. bindingMetadata: {
  89. handleClick: BindingTypes.SETUP_CONST,
  90. },
  91. })
  92. expect(code).matchSnapshot()
  93. })
  94. test('should error if no expression AND no modifier', async () => {
  95. const onError = vi.fn()
  96. await compile(`<div v-on:click />`, { onError })
  97. expect(onError.mock.calls[0][0]).toMatchObject({
  98. code: ErrorCodes.VAPOR_ON_NO_EXPRESSION,
  99. loc: {
  100. start: {
  101. line: 1,
  102. column: 6,
  103. },
  104. end: {
  105. line: 1,
  106. column: 16,
  107. },
  108. },
  109. })
  110. })
  111. test('event modifier', async () => {
  112. const code = await compile(
  113. `<div @click.prevent.stop="handleClick"></div>`,
  114. {
  115. bindingMetadata: {
  116. handleClick: BindingTypes.SETUP_CONST,
  117. },
  118. },
  119. )
  120. expect(code).matchSnapshot()
  121. })
  122. })
  123. describe('v-html', () => {
  124. test('simple expression', async () => {
  125. const code = await compile(`<div v-html="code"></div>`, {
  126. bindingMetadata: {
  127. code: BindingTypes.SETUP_REF,
  128. },
  129. })
  130. expect(code).matchSnapshot()
  131. })
  132. test('no expression', async () => {
  133. const code = await compile(`<div v-html></div>`)
  134. expect(code).matchSnapshot()
  135. })
  136. })
  137. describe('v-text', () => {
  138. test('simple expression', async () => {
  139. const code = await compile(`<div v-text="str"></div>`, {
  140. bindingMetadata: {
  141. str: BindingTypes.SETUP_REF,
  142. },
  143. })
  144. expect(code).matchSnapshot()
  145. })
  146. test('no expression', async () => {
  147. const code = await compile(`<div v-text></div>`)
  148. expect(code).matchSnapshot()
  149. })
  150. })
  151. describe('v-once', () => {
  152. test('basic', async () => {
  153. const code = await compile(
  154. `<div v-once>
  155. {{ msg }}
  156. <span :class="clz" />
  157. </div>`,
  158. {
  159. bindingMetadata: {
  160. msg: BindingTypes.SETUP_REF,
  161. clz: BindingTypes.SETUP_REF,
  162. },
  163. },
  164. )
  165. expect(code).matchSnapshot()
  166. })
  167. test.fails('as root node', async () => {
  168. const code = await compile(`<div :id="foo" v-once />`)
  169. expect(code).toMatchSnapshot()
  170. expect(code).not.contains('effect')
  171. })
  172. })
  173. describe('v-pre', () => {
  174. test('basic', async () => {
  175. const code = await compile(
  176. `<div v-pre :id="foo"><Comp/>{{ bar }}</div>\n`,
  177. {
  178. bindingMetadata: {
  179. foo: BindingTypes.SETUP_REF,
  180. bar: BindingTypes.SETUP_REF,
  181. },
  182. },
  183. )
  184. expect(code).toMatchSnapshot()
  185. expect(code).contains('<div :id="foo"><Comp></Comp>{{ bar }}</div>')
  186. expect(code).not.contains('effect')
  187. })
  188. // TODO: support multiple root nodes and components
  189. test('should not affect siblings after it', async () => {
  190. const code = await compile(
  191. `<div v-pre :id="foo"><Comp/>{{ bar }}</div>\n` +
  192. `<div :id="foo"><Comp/>{{ bar }}</div>`,
  193. {
  194. bindingMetadata: {
  195. foo: BindingTypes.SETUP_REF,
  196. bar: BindingTypes.SETUP_REF,
  197. },
  198. },
  199. )
  200. expect(code).toMatchSnapshot()
  201. // Waiting for TODO, There should be more here.
  202. })
  203. // TODO: support multiple root nodes and components
  204. test('self-closing v-pre', async () => {
  205. const code = await compile(
  206. `<div v-pre/>\n<div :id="foo"><Comp/>{{ bar }}</div>`,
  207. )
  208. expect(code).toMatchSnapshot()
  209. expect(code).contains('<div></div><div><Comp></Comp></div>')
  210. // Waiting for TODO, There should be more here.
  211. })
  212. })
  213. })
  214. })