componentProxy.spec.ts 5.3 KB

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