componentProxy.spec.ts 5.2 KB

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