apiExpose.spec.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. import { createApp, nodeOps, render } from '@vue/runtime-test'
  2. import { defineComponent, h, ref } from '../src'
  3. describe('api: expose', () => {
  4. test('via setup context', () => {
  5. const Child = defineComponent({
  6. render() {},
  7. setup(_, { expose }) {
  8. expose({
  9. foo: 1,
  10. bar: ref(2),
  11. })
  12. return {
  13. bar: ref(3),
  14. baz: ref(4),
  15. }
  16. },
  17. })
  18. const childRef = ref()
  19. const Parent = {
  20. setup() {
  21. return () => h(Child, { ref: childRef })
  22. },
  23. }
  24. const root = nodeOps.createElement('div')
  25. render(h(Parent), root)
  26. expect(childRef.value).toBeTruthy()
  27. expect(childRef.value.foo).toBe(1)
  28. expect(childRef.value.bar).toBe(2)
  29. expect(childRef.value.baz).toBeUndefined()
  30. })
  31. test('via options', () => {
  32. const Child = defineComponent({
  33. render() {},
  34. data() {
  35. return {
  36. foo: 1,
  37. }
  38. },
  39. setup() {
  40. return {
  41. bar: ref(2),
  42. baz: ref(3),
  43. }
  44. },
  45. expose: ['foo', 'bar'],
  46. })
  47. const childRef = ref()
  48. const Parent = {
  49. setup() {
  50. return () => h(Child, { ref: childRef })
  51. },
  52. }
  53. const root = nodeOps.createElement('div')
  54. render(h(Parent), root)
  55. expect(childRef.value).toBeTruthy()
  56. expect(childRef.value.foo).toBe(1)
  57. expect(childRef.value.bar).toBe(2)
  58. expect(childRef.value.baz).toBeUndefined()
  59. })
  60. test('options + context', () => {
  61. const Child = defineComponent({
  62. render() {},
  63. expose: ['foo'],
  64. data() {
  65. return {
  66. foo: 1,
  67. }
  68. },
  69. setup(_, { expose }) {
  70. expose({
  71. bar: ref(2),
  72. })
  73. return {
  74. bar: ref(3),
  75. baz: ref(4),
  76. }
  77. },
  78. })
  79. const childRef = ref()
  80. const Parent = {
  81. setup() {
  82. return () => h(Child, { ref: childRef })
  83. },
  84. }
  85. const root = nodeOps.createElement('div')
  86. render(h(Parent), root)
  87. expect(childRef.value).toBeTruthy()
  88. expect(childRef.value.foo).toBe(1)
  89. expect(childRef.value.bar).toBe(2)
  90. expect(childRef.value.baz).toBeUndefined()
  91. })
  92. test('options: empty', () => {
  93. const Child = defineComponent({
  94. render() {},
  95. expose: [],
  96. data() {
  97. return {
  98. foo: 1,
  99. }
  100. },
  101. })
  102. const childRef = ref()
  103. const Parent = {
  104. setup() {
  105. return () => h(Child, { ref: childRef })
  106. },
  107. }
  108. const root = nodeOps.createElement('div')
  109. render(h(Parent), root)
  110. expect(childRef.value).toBeTruthy()
  111. expect('foo' in childRef.value).toBe(false)
  112. })
  113. test('options: empty + setup context', () => {
  114. const Child = defineComponent({
  115. render() {},
  116. expose: [],
  117. setup(_, { expose }) {
  118. expose({
  119. foo: 1,
  120. })
  121. },
  122. })
  123. const childRef = ref()
  124. const Parent = {
  125. setup() {
  126. return () => h(Child, { ref: childRef })
  127. },
  128. }
  129. const root = nodeOps.createElement('div')
  130. render(h(Parent), root)
  131. expect(childRef.value).toBeTruthy()
  132. expect(childRef.value.foo).toBe(1)
  133. })
  134. test('with $parent/$root', () => {
  135. const Child = defineComponent({
  136. render() {
  137. expect((this.$parent! as any).foo).toBe(1)
  138. expect((this.$parent! as any).bar).toBe(undefined)
  139. expect((this.$root! as any).foo).toBe(1)
  140. expect((this.$root! as any).bar).toBe(undefined)
  141. },
  142. })
  143. const Parent = defineComponent({
  144. expose: [],
  145. setup(_, { expose }) {
  146. expose({
  147. foo: 1,
  148. })
  149. return {
  150. bar: 2,
  151. }
  152. },
  153. render() {
  154. return h(Child)
  155. },
  156. })
  157. const root = nodeOps.createElement('div')
  158. render(h(Parent), root)
  159. })
  160. test('with mount', () => {
  161. const Component = defineComponent({
  162. setup(_, { expose }) {
  163. expose({
  164. foo: 1,
  165. })
  166. return {
  167. bar: 2,
  168. }
  169. },
  170. render() {
  171. return h('div')
  172. },
  173. })
  174. const root = nodeOps.createElement('div')
  175. const vm = createApp(Component).mount(root) as any
  176. expect(vm.foo).toBe(1)
  177. expect(vm.bar).toBe(undefined)
  178. })
  179. test('expose should allow access to built-in instance properties', () => {
  180. const GrandChild = defineComponent({
  181. render() {
  182. return h('div')
  183. },
  184. })
  185. const grandChildRef = ref()
  186. const Child = defineComponent({
  187. render() {
  188. return h('div')
  189. },
  190. setup(_, { expose }) {
  191. expose({
  192. foo: 42,
  193. })
  194. return () => h(GrandChild, { ref: grandChildRef })
  195. },
  196. })
  197. const childRef = ref()
  198. const Parent = {
  199. setup() {
  200. return () => h(Child, { ref: childRef })
  201. },
  202. }
  203. const root = nodeOps.createElement('div')
  204. render(h(Parent), root)
  205. expect('$el' in childRef.value).toBe(true)
  206. expect(childRef.value.$el.tag).toBe('div')
  207. expect('foo' in childRef.value).toBe(true)
  208. expect('$parent' in grandChildRef.value).toBe(true)
  209. expect(grandChildRef.value.$parent).toBe(childRef.value)
  210. expect(grandChildRef.value.$parent.$parent).toBe(grandChildRef.value.$root)
  211. })
  212. test('warning for ref', () => {
  213. const Comp = defineComponent({
  214. setup(_, { expose }) {
  215. expose(ref(1))
  216. return () => null
  217. },
  218. })
  219. render(h(Comp), nodeOps.createElement('div'))
  220. expect(
  221. 'expose() should be passed a plain object, received ref',
  222. ).toHaveBeenWarned()
  223. })
  224. test('warning for array', () => {
  225. const Comp = defineComponent({
  226. setup(_, { expose }) {
  227. expose(['focus'])
  228. return () => null
  229. },
  230. })
  231. render(h(Comp), nodeOps.createElement('div'))
  232. expect(
  233. 'expose() should be passed a plain object, received array',
  234. ).toHaveBeenWarned()
  235. })
  236. test('warning for function', () => {
  237. const Comp = defineComponent({
  238. setup(_, { expose }) {
  239. expose(() => null)
  240. return () => null
  241. },
  242. })
  243. render(h(Comp), nodeOps.createElement('div'))
  244. expect(
  245. 'expose() should be passed a plain object, received function',
  246. ).toHaveBeenWarned()
  247. })
  248. })