compiler-options.spec.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import Vue from 'vue'
  2. import { compile } from 'web/compiler'
  3. import { getAndRemoveAttr } from 'compiler/helpers'
  4. describe('compile options', () => {
  5. it('should be compiled', () => {
  6. const { render, staticRenderFns, errors } = compile(
  7. `
  8. <div>
  9. <input type="text" v-model="msg" required max="8" v-validate:field1.group1.group2>
  10. </div>
  11. `,
  12. {
  13. directives: {
  14. validate(el, dir) {
  15. if (dir.name === 'validate' && dir.arg) {
  16. el.validate = {
  17. field: dir.arg,
  18. groups: dir.modifiers ? Object.keys(dir.modifiers) : []
  19. }
  20. }
  21. }
  22. },
  23. modules: [
  24. {
  25. transformNode(el) {
  26. el.validators = el.validators || []
  27. const validators = [
  28. 'required',
  29. 'min',
  30. 'max',
  31. 'pattern',
  32. 'maxlength',
  33. 'minlength'
  34. ]
  35. validators.forEach(name => {
  36. const rule = getAndRemoveAttr(el, name)
  37. if (rule !== undefined) {
  38. el.validators.push({ name, rule })
  39. }
  40. })
  41. },
  42. genData(el) {
  43. let data = ''
  44. if (el.validate) {
  45. data += `validate:${JSON.stringify(el.validate)},`
  46. }
  47. if (el.validators) {
  48. data += `validators:${JSON.stringify(el.validators)},`
  49. }
  50. return data
  51. },
  52. transformCode(el, code) {
  53. // check
  54. if (!el.validate || !el.validators) {
  55. return code
  56. }
  57. // setup validation result props
  58. const result = { dirty: false } // define something other prop
  59. el.validators.forEach(validator => {
  60. result[validator.name] = null
  61. })
  62. // generate code
  63. return `_c('validate',{props:{
  64. field:${JSON.stringify(el.validate.field)},
  65. groups:${JSON.stringify(el.validate.groups)},
  66. validators:${JSON.stringify(el.validators)},
  67. result:${JSON.stringify(result)},
  68. child:${code}}
  69. })`
  70. }
  71. }
  72. ]
  73. }
  74. )
  75. expect(render).not.toBeUndefined()
  76. expect(staticRenderFns).toEqual([])
  77. expect(errors).toEqual([])
  78. const renderFn = new Function(render)
  79. const vm = new Vue({
  80. data: {
  81. msg: 'hello'
  82. },
  83. components: {
  84. validate: {
  85. props: ['field', 'groups', 'validators', 'result', 'child'],
  86. render(h) {
  87. return this.child
  88. },
  89. computed: {
  90. valid() {
  91. let ret = true
  92. for (let i = 0; i < this.validators.length; i++) {
  93. const { name } = this.validators[i]
  94. if (!this.result[name]) {
  95. ret = false
  96. break
  97. }
  98. }
  99. return ret
  100. }
  101. },
  102. mounted() {
  103. // initialize validation
  104. const value = this.$el.value
  105. this.validators.forEach(validator => {
  106. const ret = this[validator.name](value, validator.rule)
  107. this.result[validator.name] = ret
  108. })
  109. },
  110. methods: {
  111. // something validators logic
  112. required(val) {
  113. return val.length > 0
  114. },
  115. max(val, rule) {
  116. return !(parseInt(val, 10) > parseInt(rule, 10))
  117. }
  118. }
  119. }
  120. },
  121. render: renderFn,
  122. staticRenderFns
  123. }).$mount()
  124. expect(vm.$el.innerHTML).toBe('<input type="text">')
  125. expect(vm.$children[0].valid).toBe(true)
  126. })
  127. it('should collect errors', () => {
  128. let compiled = compile('hello')
  129. expect(compiled.errors.length).toBe(1)
  130. expect(compiled.errors[0]).toContain('root element')
  131. compiled = compile('<div v-if="a----">{{ b++++ }}</div>')
  132. expect(compiled.errors.length).toBe(2)
  133. expect(compiled.errors[0]).toContain('Raw expression: v-if="a----"')
  134. expect(compiled.errors[1]).toContain('Raw expression: {{ b++++ }}')
  135. })
  136. it('should collect errors with source range', () => {
  137. let compiled = compile('hello', { outputSourceRange: true })
  138. expect(compiled.errors.length).toBe(1)
  139. expect(compiled.errors[0].start).toBe(0)
  140. expect(compiled.errors[0].end).toBeUndefined()
  141. compiled = compile('<div v-if="a----">{{ b++++ }}</div>', {
  142. outputSourceRange: true
  143. })
  144. expect(compiled.errors.length).toBe(2)
  145. expect(compiled.errors[0].start).toBe(5)
  146. expect(compiled.errors[0].end).toBe(17)
  147. expect(compiled.errors[1].start).toBe(18)
  148. expect(compiled.errors[1].end).toBe(29)
  149. compiled = compile('<div><span></div>', { outputSourceRange: true })
  150. expect(compiled.errors.length).toBe(1)
  151. expect(compiled.errors[0].start).toBe(5)
  152. expect(compiled.errors[0].end).toBe(11)
  153. })
  154. it('should collect source range for binding keys', () => {
  155. const compiled = compile('<div><slot v-bind:key="key" /></div>', {
  156. outputSourceRange: true
  157. })
  158. expect(compiled.errors.length).toBe(1)
  159. expect(compiled.errors[0].start).toBe(11)
  160. expect(compiled.errors[0].end).toBe(27)
  161. })
  162. })