instance.spec.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. import Vue from '@vue/compat'
  2. import { Slots } from '../../runtime-core/src/componentSlots'
  3. import { Text } from '../../runtime-core/src/vnode'
  4. import {
  5. DeprecationTypes,
  6. deprecationData,
  7. toggleDeprecationWarning
  8. } from '../../runtime-core/src/compat/compatConfig'
  9. import { LegacyPublicInstance } from '../../runtime-core/src/compat/instance'
  10. beforeEach(() => {
  11. toggleDeprecationWarning(true)
  12. Vue.configureCompat({
  13. MODE: 2,
  14. GLOBAL_MOUNT: 'suppress-warning'
  15. })
  16. })
  17. afterEach(() => {
  18. toggleDeprecationWarning(false)
  19. Vue.configureCompat({ MODE: 3 })
  20. })
  21. test('INSTANCE_SET', () => {
  22. const obj: any = {}
  23. new Vue().$set(obj, 'foo', 1)
  24. expect(obj.foo).toBe(1)
  25. expect(
  26. deprecationData[DeprecationTypes.INSTANCE_SET].message
  27. ).toHaveBeenWarned()
  28. })
  29. test('INSTANCE_DELETE', () => {
  30. const obj: any = { foo: 1 }
  31. new Vue().$delete(obj, 'foo')
  32. expect('foo' in obj).toBe(false)
  33. expect(
  34. deprecationData[DeprecationTypes.INSTANCE_DELETE].message
  35. ).toHaveBeenWarned()
  36. })
  37. test('INSTANCE_DESTROY', () => {
  38. new Vue({ template: 'foo' }).$mount().$destroy()
  39. expect(
  40. deprecationData[DeprecationTypes.INSTANCE_DESTROY].message
  41. ).toHaveBeenWarned()
  42. })
  43. // https://github.com/vuejs/vue/blob/dev/test/unit/features/instance/methods-events.spec.js
  44. describe('INSTANCE_EVENT_EMITTER', () => {
  45. let vm: LegacyPublicInstance
  46. let spy: jest.Mock
  47. beforeEach(() => {
  48. vm = new Vue()
  49. spy = jest.fn()
  50. })
  51. it('$on', () => {
  52. vm.$on('test', function (this: any) {
  53. // expect correct context
  54. expect(this).toBe(vm)
  55. spy.apply(this, arguments)
  56. })
  57. vm.$emit('test', 1, 2, 3, 4)
  58. expect(spy).toHaveBeenCalledTimes(1)
  59. expect(spy).toHaveBeenCalledWith(1, 2, 3, 4)
  60. expect(
  61. deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
  62. ).toHaveBeenWarned()
  63. })
  64. it('$on multi event', () => {
  65. vm.$on(['test1', 'test2'], function (this: any) {
  66. expect(this).toBe(vm)
  67. spy.apply(this, arguments)
  68. })
  69. vm.$emit('test1', 1, 2, 3, 4)
  70. expect(spy).toHaveBeenCalledTimes(1)
  71. expect(spy).toHaveBeenCalledWith(1, 2, 3, 4)
  72. vm.$emit('test2', 5, 6, 7, 8)
  73. expect(spy).toHaveBeenCalledTimes(2)
  74. expect(spy).toHaveBeenCalledWith(5, 6, 7, 8)
  75. expect(
  76. deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
  77. ).toHaveBeenWarned()
  78. })
  79. it('$off multi event', () => {
  80. vm.$on(['test1', 'test2', 'test3'], spy)
  81. vm.$off(['test1', 'test2'], spy)
  82. vm.$emit('test1')
  83. vm.$emit('test2')
  84. expect(spy).not.toHaveBeenCalled()
  85. vm.$emit('test3', 1, 2, 3, 4)
  86. expect(spy).toHaveBeenCalledTimes(1)
  87. expect(
  88. deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
  89. ).toHaveBeenWarned()
  90. })
  91. it('$off multi event without callback', () => {
  92. vm.$on(['test1', 'test2'], spy)
  93. vm.$off(['test1', 'test2'])
  94. vm.$emit('test1')
  95. expect(spy).not.toHaveBeenCalled()
  96. expect(
  97. deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
  98. ).toHaveBeenWarned()
  99. })
  100. it('$once', () => {
  101. vm.$once('test', spy)
  102. vm.$emit('test', 1, 2, 3)
  103. vm.$emit('test', 2, 3, 4)
  104. expect(spy).toHaveBeenCalledTimes(1)
  105. expect(spy).toHaveBeenCalledWith(1, 2, 3)
  106. expect(
  107. deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
  108. ).toHaveBeenWarned()
  109. })
  110. it('$off event added by $once', () => {
  111. vm.$once('test', spy)
  112. vm.$off('test', spy) // test off event and this event added by once
  113. vm.$emit('test', 1, 2, 3)
  114. expect(spy).not.toHaveBeenCalled()
  115. expect(
  116. deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
  117. ).toHaveBeenWarned()
  118. })
  119. it('$off', () => {
  120. vm.$on('test1', spy)
  121. vm.$on('test2', spy)
  122. vm.$off()
  123. vm.$emit('test1')
  124. vm.$emit('test2')
  125. expect(spy).not.toHaveBeenCalled()
  126. expect(
  127. deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
  128. ).toHaveBeenWarned()
  129. })
  130. it('$off event', () => {
  131. vm.$on('test1', spy)
  132. vm.$on('test2', spy)
  133. vm.$off('test1')
  134. vm.$off('test1') // test off something that's already off
  135. vm.$emit('test1', 1)
  136. vm.$emit('test2', 2)
  137. expect(spy).toHaveBeenCalledTimes(1)
  138. expect(spy).toHaveBeenCalledWith(2)
  139. expect(
  140. deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
  141. ).toHaveBeenWarned()
  142. })
  143. it('$off event + fn', () => {
  144. const spy2 = jasmine.createSpy('emitter')
  145. vm.$on('test', spy)
  146. vm.$on('test', spy2)
  147. vm.$off('test', spy)
  148. vm.$emit('test', 1, 2, 3)
  149. expect(spy).not.toHaveBeenCalled()
  150. expect(spy2).toHaveBeenCalledTimes(1)
  151. expect(spy2).toHaveBeenCalledWith(1, 2, 3)
  152. expect(
  153. deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
  154. ).toHaveBeenWarned()
  155. })
  156. })
  157. describe('INSTANCE_EVENT_HOOKS', () => {
  158. test('instance API', () => {
  159. const spy = jest.fn()
  160. const vm = new Vue({ template: 'foo' })
  161. vm.$on('hook:mounted', spy)
  162. vm.$mount()
  163. expect(spy).toHaveBeenCalled()
  164. expect(
  165. (
  166. deprecationData[DeprecationTypes.INSTANCE_EVENT_HOOKS]
  167. .message as Function
  168. )('hook:mounted')
  169. ).toHaveBeenWarned()
  170. })
  171. test('via template', () => {
  172. const spy = jest.fn()
  173. new Vue({
  174. template: `<child @hook:mounted="spy"/>`,
  175. methods: { spy },
  176. components: {
  177. child: {
  178. template: 'foo'
  179. }
  180. }
  181. }).$mount()
  182. expect(spy).toHaveBeenCalled()
  183. expect(
  184. (
  185. deprecationData[DeprecationTypes.INSTANCE_EVENT_HOOKS]
  186. .message as Function
  187. )('hook:mounted')
  188. ).toHaveBeenWarned()
  189. })
  190. })
  191. test('INSTANCE_EVENT_CHILDREN', () => {
  192. const vm = new Vue({
  193. template: `<child/><div><child v-for="i in 3"/></div>`,
  194. components: {
  195. child: {
  196. template: 'foo',
  197. data() {
  198. return { n: 1 }
  199. }
  200. }
  201. }
  202. }).$mount()
  203. expect(vm.$children.length).toBe(4)
  204. vm.$children.forEach((c: any) => {
  205. expect(c.n).toBe(1)
  206. })
  207. expect(
  208. deprecationData[DeprecationTypes.INSTANCE_CHILDREN].message
  209. ).toHaveBeenWarned()
  210. })
  211. test('INSTANCE_LISTENERS', () => {
  212. const foo = () => 'foo'
  213. const bar = () => 'bar'
  214. let listeners: Record<string, Function>
  215. new Vue({
  216. template: `<child @click="foo" @custom="bar" />`,
  217. methods: { foo, bar },
  218. components: {
  219. child: {
  220. template: `<div/>`,
  221. mounted() {
  222. listeners = this.$listeners
  223. }
  224. }
  225. }
  226. }).$mount()
  227. expect(Object.keys(listeners!)).toMatchObject(['click', 'custom'])
  228. expect(listeners!.click()).toBe('foo')
  229. expect(listeners!.custom()).toBe('bar')
  230. expect(
  231. deprecationData[DeprecationTypes.INSTANCE_LISTENERS].message
  232. ).toHaveBeenWarned()
  233. })
  234. describe('INSTANCE_SCOPED_SLOTS', () => {
  235. test('explicit usage', () => {
  236. let slots: Slots
  237. new Vue({
  238. template: `<child v-slot="{ msg }">{{ msg }}</child>`,
  239. components: {
  240. child: {
  241. compatConfig: { RENDER_FUNCTION: false },
  242. render() {
  243. slots = this.$scopedSlots
  244. }
  245. }
  246. }
  247. }).$mount()
  248. expect(slots!.default!({ msg: 'hi' })).toMatchObject([
  249. {
  250. type: Text,
  251. children: 'hi'
  252. }
  253. ])
  254. expect(
  255. deprecationData[DeprecationTypes.INSTANCE_SCOPED_SLOTS].message
  256. ).toHaveBeenWarned()
  257. })
  258. test('should not include legacy slot usage in $scopedSlots', () => {
  259. let normalSlots: Slots
  260. let scopedSlots: Slots
  261. new Vue({
  262. template: `<child><div>default</div></child>`,
  263. components: {
  264. child: {
  265. compatConfig: { RENDER_FUNCTION: false },
  266. render() {
  267. normalSlots = this.$slots
  268. scopedSlots = this.$scopedSlots
  269. }
  270. }
  271. }
  272. }).$mount()
  273. expect('default' in normalSlots!).toBe(true)
  274. expect('default' in scopedSlots!).toBe(false)
  275. expect(
  276. deprecationData[DeprecationTypes.INSTANCE_SCOPED_SLOTS].message
  277. ).toHaveBeenWarned()
  278. })
  279. })
  280. test('INSTANCE_ATTR_CLASS_STYLE', () => {
  281. const vm = new Vue({
  282. template: `<child class="foo" style="color:red" id="ok" />`,
  283. components: {
  284. child: {
  285. inheritAttrs: false,
  286. template: `<div><div v-bind="$attrs" /></div>`
  287. }
  288. }
  289. }).$mount()
  290. expect(vm.$el.outerHTML).toBe(
  291. `<div class="foo" style="color: red;"><div id="ok"></div></div>`
  292. )
  293. expect(
  294. (
  295. deprecationData[DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE]
  296. .message as Function
  297. )('Anonymous')
  298. ).toHaveBeenWarned()
  299. })