inheritance.spec.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. import {
  2. Component,
  3. observable,
  4. h,
  5. nextTick,
  6. KeepAlive,
  7. ComponentPropsOptions,
  8. ComponentWatchOptions
  9. } from '@vue/runtime-core'
  10. import { createInstance, renderInstance } from '@vue/runtime-test'
  11. describe('class inheritance', () => {
  12. it('should merge data', () => {
  13. class Base extends Component {
  14. foo = 1
  15. data() {
  16. return {
  17. bar: 2
  18. }
  19. }
  20. }
  21. class Child extends Base {
  22. foo: number
  23. bar: number
  24. baz: number
  25. qux: number = 4
  26. data(): any {
  27. return {
  28. baz: 3
  29. }
  30. }
  31. }
  32. const child = createInstance(Child)
  33. expect(child.foo).toBe(1)
  34. expect(child.bar).toBe(2)
  35. expect(child.baz).toBe(3)
  36. expect(child.qux).toBe(4)
  37. })
  38. it('should merge props', () => {
  39. class Base extends Component {
  40. static props: ComponentPropsOptions = {
  41. foo: Number
  42. }
  43. }
  44. class Child extends Base {
  45. foo: number
  46. bar: number
  47. $props: { foo: number; bar: number }
  48. static props: ComponentPropsOptions = {
  49. bar: Number
  50. }
  51. }
  52. const child = createInstance(Child, {
  53. foo: 1,
  54. bar: 2
  55. })
  56. expect(child.foo).toBe(1)
  57. expect(child.bar).toBe(2)
  58. expect(child.$props.foo).toBe(1)
  59. expect(child.$props.bar).toBe(2)
  60. })
  61. it('should merge lifecycle hooks', async () => {
  62. const calls: string[] = []
  63. const state = observable({ ok: true })
  64. class Base extends Component {
  65. beforeCreate() {
  66. calls.push('base beforeCreate')
  67. }
  68. created() {
  69. calls.push('base created')
  70. }
  71. beforeMount() {
  72. calls.push('base beforeMount')
  73. }
  74. mounted() {
  75. calls.push('base mounted')
  76. }
  77. beforeUpdate() {
  78. calls.push('base beforeUpdate')
  79. }
  80. updated() {
  81. calls.push('base updated')
  82. }
  83. beforeUnmount() {
  84. calls.push('base beforeUnmount')
  85. }
  86. unmounted() {
  87. calls.push('base unmounted')
  88. }
  89. }
  90. class Child extends Base {
  91. beforeCreate() {
  92. calls.push('child beforeCreate')
  93. }
  94. created() {
  95. calls.push('child created')
  96. }
  97. beforeMount() {
  98. calls.push('child beforeMount')
  99. }
  100. mounted() {
  101. calls.push('child mounted')
  102. }
  103. beforeUpdate() {
  104. calls.push('child beforeUpdate')
  105. }
  106. updated() {
  107. calls.push('child updated')
  108. }
  109. beforeUnmount() {
  110. calls.push('child beforeUnmount')
  111. }
  112. unmounted() {
  113. calls.push('child unmounted')
  114. }
  115. render() {
  116. return state.ok ? 'foo' : 'bar'
  117. }
  118. }
  119. class Container extends Component {
  120. show = true
  121. render() {
  122. return this.show ? h(Child) : null
  123. }
  124. }
  125. const container = await renderInstance(Container)
  126. expect(calls).toEqual([
  127. 'base beforeCreate',
  128. 'child beforeCreate',
  129. 'base created',
  130. 'child created',
  131. 'base beforeMount',
  132. 'child beforeMount',
  133. 'base mounted',
  134. 'child mounted'
  135. ])
  136. calls.length = 0
  137. state.ok = false
  138. await nextTick()
  139. expect(calls).toEqual([
  140. 'base beforeUpdate',
  141. 'child beforeUpdate',
  142. 'base updated',
  143. 'child updated'
  144. ])
  145. calls.length = 0
  146. container.show = false
  147. await nextTick()
  148. expect(calls).toEqual([
  149. 'base beforeUnmount',
  150. 'child beforeUnmount',
  151. 'base unmounted',
  152. 'child unmounted'
  153. ])
  154. })
  155. it('should merge lifecycle hooks (activated/deactivated)', async () => {
  156. const calls: string[] = []
  157. class Base extends Component {
  158. activated() {
  159. calls.push('base activated')
  160. }
  161. deactivated() {
  162. calls.push('base deactivated')
  163. }
  164. }
  165. class Child extends Base {
  166. activated() {
  167. calls.push('child activated')
  168. }
  169. deactivated() {
  170. calls.push('child deactivated')
  171. }
  172. render() {
  173. return 'foo'
  174. }
  175. }
  176. class Container extends Component {
  177. ok = true
  178. render() {
  179. return h(KeepAlive, this.ok ? h(Child) : null)
  180. }
  181. }
  182. const container = await renderInstance(Container)
  183. expect(container.$el.text).toBe('foo')
  184. container.ok = false
  185. await nextTick()
  186. expect(container.$el.text).toBe('')
  187. expect(calls).toEqual(['base deactivated', 'child deactivated'])
  188. calls.length = 0
  189. container.ok = true
  190. await nextTick()
  191. expect(container.$el.text).toBe('foo')
  192. expect(calls).toEqual(['base activated', 'child activated'])
  193. })
  194. it('should merge watchers', async () => {
  195. const fooCallback = jest.fn()
  196. const barCallback = jest.fn()
  197. class Base extends Component {
  198. static watch: ComponentWatchOptions = {
  199. foo: fooCallback
  200. }
  201. }
  202. class Child extends Base {
  203. foo = 1
  204. bar = 2
  205. static watch: ComponentWatchOptions = {
  206. bar: barCallback
  207. }
  208. }
  209. const child = createInstance(Child)
  210. child.foo = 2
  211. await nextTick()
  212. expect(fooCallback).toHaveBeenCalledWith(2, 1)
  213. child.bar = 3
  214. await nextTick()
  215. expect(barCallback).toHaveBeenCalledWith(3, 2)
  216. })
  217. it('should inherit methods', () => {
  218. const fooCallback = jest.fn()
  219. const barCallback = jest.fn()
  220. class Base extends Component {
  221. foo() {
  222. fooCallback()
  223. }
  224. }
  225. class Child extends Base {
  226. bar() {
  227. barCallback()
  228. }
  229. }
  230. const child = createInstance(Child)
  231. child.foo()
  232. child.bar()
  233. expect(fooCallback).toHaveBeenCalled()
  234. expect(barCallback).toHaveBeenCalled()
  235. })
  236. it('should inherit computed properties', () => {
  237. class Base extends Component {
  238. a = 1
  239. get foo() {
  240. return this.a + 1
  241. }
  242. }
  243. class Child extends Base {
  244. b = 1
  245. get bar() {
  246. return this.b + this.foo + 1
  247. }
  248. }
  249. const child = createInstance(Child)
  250. expect(child.foo).toBe(2)
  251. expect(child.bar).toBe(4)
  252. child.a = 2
  253. expect(child.foo).toBe(3)
  254. expect(child.bar).toBe(5)
  255. })
  256. })