properties.spec.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. import Vue from 'vue'
  2. describe('Instance properties', () => {
  3. it('$data', () => {
  4. const data = { a: 1 }
  5. const vm = new Vue({
  6. data
  7. })
  8. expect(vm.a).toBe(1)
  9. expect(vm.$data).toBe(data)
  10. // vm -> data
  11. vm.a = 2
  12. expect(data.a).toBe(2)
  13. // data -> vm
  14. data.a = 3
  15. expect(vm.a).toBe(3)
  16. })
  17. it('$options', () => {
  18. const A = Vue.extend({
  19. methods: {
  20. a () {}
  21. }
  22. })
  23. const vm = new A({
  24. methods: {
  25. b () {}
  26. }
  27. })
  28. expect(typeof vm.$options.methods.a).toBe('function')
  29. expect(typeof vm.$options.methods.b).toBe('function')
  30. })
  31. it('$root/$children', done => {
  32. const vm = new Vue({
  33. template: '<div><test v-if="ok"></test></div>',
  34. data: { ok: true },
  35. components: {
  36. test: {
  37. template: '<div></div>'
  38. }
  39. }
  40. }).$mount()
  41. expect(vm.$root).toBe(vm)
  42. expect(vm.$children.length).toBe(1)
  43. expect(vm.$children[0].$root).toBe(vm)
  44. vm.ok = false
  45. waitForUpdate(() => {
  46. expect(vm.$children.length).toBe(0)
  47. vm.ok = true
  48. }).then(() => {
  49. expect(vm.$children.length).toBe(1)
  50. expect(vm.$children[0].$root).toBe(vm)
  51. }).then(done)
  52. })
  53. it('$parent', () => {
  54. const calls = []
  55. const makeOption = name => ({
  56. name,
  57. template: `<div><slot></slot></div>`,
  58. created () {
  59. calls.push(`${name}:${this.$parent.$options.name}`)
  60. }
  61. })
  62. new Vue({
  63. template: `
  64. <div>
  65. <outer><middle><inner></inner></middle></outer>
  66. <next></next>
  67. </div>
  68. `,
  69. components: {
  70. outer: makeOption('outer'),
  71. middle: makeOption('middle'),
  72. inner: makeOption('inner'),
  73. next: makeOption('next')
  74. }
  75. }).$mount()
  76. expect(calls).toEqual(['outer:undefined', 'middle:outer', 'inner:middle', 'next:undefined'])
  77. })
  78. it('$props', done => {
  79. const Comp = Vue.extend({
  80. props: ['msg'],
  81. template: '<div>{{ msg }} {{ $props.msg }}</div>'
  82. })
  83. const vm = new Comp({
  84. propsData: {
  85. msg: 'foo'
  86. }
  87. }).$mount()
  88. // check render
  89. expect(vm.$el.textContent).toContain('foo foo')
  90. // warn set
  91. vm.$props = {}
  92. expect('$props is readonly').toHaveBeenWarned()
  93. // check existence
  94. expect(vm.$props.msg).toBe('foo')
  95. // check change
  96. vm.msg = 'bar'
  97. expect(vm.$props.msg).toBe('bar')
  98. waitForUpdate(() => {
  99. expect(vm.$el.textContent).toContain('bar bar')
  100. }).then(() => {
  101. vm.$props.msg = 'baz'
  102. expect(vm.msg).toBe('baz')
  103. }).then(() => {
  104. expect(vm.$el.textContent).toContain('baz baz')
  105. }).then(done)
  106. })
  107. it('warn mutating $props', () => {
  108. const Comp = {
  109. props: ['msg'],
  110. render () {},
  111. mounted () {
  112. expect(this.$props.msg).toBe('foo')
  113. this.$props.msg = 'bar'
  114. }
  115. }
  116. new Vue({
  117. template: `<comp ref="comp" msg="foo" />`,
  118. components: { Comp }
  119. }).$mount()
  120. expect(`Avoid mutating a prop`).toHaveBeenWarned()
  121. })
  122. it('$attrs', done => {
  123. const vm = new Vue({
  124. template: `<foo :id="foo" bar="1"/>`,
  125. data: { foo: 'foo' },
  126. components: {
  127. foo: {
  128. props: ['bar'],
  129. template: `<div><div v-bind="$attrs"></div></div>`
  130. }
  131. }
  132. }).$mount()
  133. expect(vm.$el.children[0].id).toBe('foo')
  134. expect(vm.$el.children[0].hasAttribute('bar')).toBe(false)
  135. vm.foo = 'bar'
  136. waitForUpdate(() => {
  137. expect(vm.$el.children[0].id).toBe('bar')
  138. expect(vm.$el.children[0].hasAttribute('bar')).toBe(false)
  139. }).then(done)
  140. })
  141. // #6263
  142. it('$attrs should not be undefined when no props passed in', () => {
  143. const vm = new Vue({
  144. template: `<foo/>`,
  145. data: { foo: 'foo' },
  146. components: {
  147. foo: {
  148. template: `<div>{{ this.foo }}</div>`
  149. }
  150. }
  151. }).$mount()
  152. expect(vm.$attrs).toBeDefined()
  153. })
  154. it('warn mutating $attrs', () => {
  155. const vm = new Vue()
  156. vm.$attrs = {}
  157. expect(`$attrs is readonly`).toHaveBeenWarned()
  158. })
  159. it('$listeners', done => {
  160. const spyA = jasmine.createSpy('A')
  161. const spyB = jasmine.createSpy('B')
  162. const vm = new Vue({
  163. template: `<foo @click="foo"/>`,
  164. data: { foo: spyA },
  165. components: {
  166. foo: {
  167. template: `<div v-on="$listeners"></div>`
  168. }
  169. }
  170. }).$mount()
  171. // has to be in dom for test to pass in IE
  172. document.body.appendChild(vm.$el)
  173. triggerEvent(vm.$el, 'click')
  174. expect(spyA.calls.count()).toBe(1)
  175. expect(spyB.calls.count()).toBe(0)
  176. vm.foo = spyB
  177. waitForUpdate(() => {
  178. triggerEvent(vm.$el, 'click')
  179. expect(spyA.calls.count()).toBe(1)
  180. expect(spyB.calls.count()).toBe(1)
  181. document.body.removeChild(vm.$el)
  182. }).then(done)
  183. })
  184. it('warn mutating $listeners', () => {
  185. const vm = new Vue()
  186. vm.$listeners = {}
  187. expect(`$listeners is readonly`).toHaveBeenWarned()
  188. })
  189. })