2
0

componentProxy.spec.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import { h, render, getCurrentInstance, nodeOps } from '@vue/runtime-test'
  2. import { mockWarn } from '@vue/shared'
  3. import { ComponentInternalInstance } from '../src/component'
  4. describe('component: proxy', () => {
  5. mockWarn()
  6. test('data', () => {
  7. let instance: ComponentInternalInstance
  8. let instanceProxy: any
  9. const Comp = {
  10. data() {
  11. return {
  12. foo: 1
  13. }
  14. },
  15. mounted() {
  16. instance = getCurrentInstance()!
  17. instanceProxy = this
  18. },
  19. render() {
  20. return null
  21. }
  22. }
  23. render(h(Comp), nodeOps.createElement('div'))
  24. expect(instanceProxy.foo).toBe(1)
  25. instanceProxy.foo = 2
  26. expect(instance!.data.foo).toBe(2)
  27. })
  28. test('renderContext', () => {
  29. let instance: ComponentInternalInstance
  30. let instanceProxy: any
  31. const Comp = {
  32. setup() {
  33. return {
  34. foo: 1
  35. }
  36. },
  37. mounted() {
  38. instance = getCurrentInstance()!
  39. instanceProxy = this
  40. },
  41. render() {
  42. return null
  43. }
  44. }
  45. render(h(Comp), nodeOps.createElement('div'))
  46. expect(instanceProxy.foo).toBe(1)
  47. instanceProxy.foo = 2
  48. expect(instance!.renderContext.foo).toBe(2)
  49. })
  50. test('propsProxy', () => {
  51. let instance: ComponentInternalInstance
  52. let instanceProxy: any
  53. const Comp = {
  54. props: {
  55. foo: {
  56. type: Number,
  57. default: 1
  58. }
  59. },
  60. setup() {
  61. return () => null
  62. },
  63. mounted() {
  64. instance = getCurrentInstance()!
  65. instanceProxy = this
  66. }
  67. }
  68. render(h(Comp), nodeOps.createElement('div'))
  69. expect(instanceProxy.foo).toBe(1)
  70. expect(instance!.propsProxy!.foo).toBe(1)
  71. expect(() => (instanceProxy.foo = 2)).toThrow(TypeError)
  72. expect(`Attempting to mutate prop "foo"`).toHaveBeenWarned()
  73. })
  74. test('should not expose non-declared props', () => {
  75. let instanceProxy: any
  76. const Comp = {
  77. setup() {
  78. return () => null
  79. },
  80. mounted() {
  81. instanceProxy = this
  82. }
  83. }
  84. render(h(Comp, { count: 1 }), nodeOps.createElement('div'))
  85. expect('count' in instanceProxy).toBe(false)
  86. })
  87. test('public properties', () => {
  88. let instance: ComponentInternalInstance
  89. let instanceProxy: any
  90. const Comp = {
  91. setup() {
  92. return () => null
  93. },
  94. mounted() {
  95. instance = getCurrentInstance()!
  96. instanceProxy = this
  97. }
  98. }
  99. render(h(Comp), nodeOps.createElement('div'))
  100. expect(instanceProxy.$data).toBe(instance!.data)
  101. expect(instanceProxy.$props).toBe(instance!.propsProxy)
  102. expect(instanceProxy.$attrs).toBe(instance!.attrs)
  103. expect(instanceProxy.$slots).toBe(instance!.slots)
  104. expect(instanceProxy.$refs).toBe(instance!.refs)
  105. expect(instanceProxy.$parent).toBe(
  106. instance!.parent && instance!.parent.proxy
  107. )
  108. expect(instanceProxy.$root).toBe(instance!.root.proxy)
  109. expect(instanceProxy.$emit).toBe(instance!.emit)
  110. expect(instanceProxy.$el).toBe(instance!.vnode.el)
  111. expect(instanceProxy.$options).toBe(instance!.type)
  112. expect(() => (instanceProxy.$data = {})).toThrow(TypeError)
  113. expect(`Attempting to mutate public property "$data"`).toHaveBeenWarned()
  114. })
  115. test('sink', async () => {
  116. let instance: ComponentInternalInstance
  117. let instanceProxy: any
  118. const Comp = {
  119. setup() {
  120. return () => null
  121. },
  122. mounted() {
  123. instance = getCurrentInstance()!
  124. instanceProxy = this
  125. }
  126. }
  127. render(h(Comp), nodeOps.createElement('div'))
  128. instanceProxy.foo = 1
  129. expect(instanceProxy.foo).toBe(1)
  130. expect(instance!.sink.foo).toBe(1)
  131. })
  132. test('has check', () => {
  133. let instanceProxy: any
  134. const Comp = {
  135. render() {},
  136. props: {
  137. msg: String
  138. },
  139. data() {
  140. return {
  141. foo: 0
  142. }
  143. },
  144. setup() {
  145. return {
  146. bar: 1
  147. }
  148. },
  149. mounted() {
  150. instanceProxy = this
  151. }
  152. }
  153. render(h(Comp, { msg: 'hello' }), nodeOps.createElement('div'))
  154. // props
  155. expect('msg' in instanceProxy).toBe(true)
  156. // data
  157. expect('foo' in instanceProxy).toBe(true)
  158. // renderContext
  159. expect('bar' in instanceProxy).toBe(true)
  160. // public properties
  161. expect('$el' in instanceProxy).toBe(true)
  162. // non-existent
  163. expect('$foobar' in instanceProxy).toBe(false)
  164. expect('baz' in instanceProxy).toBe(false)
  165. // set non-existent (goes into sink)
  166. instanceProxy.baz = 1
  167. expect('baz' in instanceProxy).toBe(true)
  168. // dev mode ownKeys check for console inspection
  169. expect(Object.keys(instanceProxy)).toMatchObject([
  170. 'msg',
  171. 'bar',
  172. 'foo',
  173. 'baz'
  174. ])
  175. })
  176. // #864
  177. test('should not warn declared but absent props', () => {
  178. const Comp = {
  179. props: ['test'],
  180. render(this: any) {
  181. return this.test
  182. }
  183. }
  184. render(h(Comp), nodeOps.createElement('div'))
  185. expect(
  186. `was accessed during render but is not defined`
  187. ).not.toHaveBeenWarned()
  188. })
  189. })