misc.spec.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. import Vue from '@vue/compat'
  2. import { nextTick } from '../../runtime-core/src/scheduler'
  3. import {
  4. DeprecationTypes,
  5. deprecationData,
  6. toggleDeprecationWarning,
  7. } from '../../runtime-core/src/compat/compatConfig'
  8. import { triggerEvent } from './utils'
  9. import { h } from '@vue/runtime-core'
  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('mode as function', () => {
  22. const Foo = {
  23. name: 'Foo',
  24. render: (h: any) => h('div', 'foo'),
  25. }
  26. const Bar = {
  27. name: 'Bar',
  28. data: () => ({ msg: 'bar' }),
  29. render: (ctx: any) => h('div', ctx.msg),
  30. }
  31. toggleDeprecationWarning(false)
  32. Vue.configureCompat({
  33. MODE: comp => (comp && comp.name === 'Bar' ? 3 : 2),
  34. })
  35. const vm = new Vue({
  36. components: { Foo, Bar },
  37. template: `<div><foo/><bar/></div>`,
  38. }).$mount()
  39. expect(vm.$el).toBeInstanceOf(HTMLDivElement)
  40. expect(vm.$el.innerHTML).toBe(`<div>foo</div><div>bar</div>`)
  41. })
  42. test('WATCH_ARRAY', async () => {
  43. const spy = vi.fn()
  44. const vm = new Vue({
  45. data() {
  46. return {
  47. foo: [],
  48. }
  49. },
  50. watch: {
  51. foo: spy,
  52. },
  53. }) as any
  54. expect(
  55. deprecationData[DeprecationTypes.WATCH_ARRAY].message,
  56. ).toHaveBeenWarned()
  57. expect(spy).not.toHaveBeenCalled()
  58. vm.foo.push(1)
  59. await nextTick()
  60. expect(spy).toHaveBeenCalledTimes(1)
  61. })
  62. test('PROPS_DEFAULT_THIS', () => {
  63. let thisCtx: any
  64. const Child = {
  65. customOption: 1,
  66. inject: ['provided'],
  67. props: {
  68. foo: null,
  69. bar: {
  70. default(this: any) {
  71. // copy values since injection must be sync
  72. thisCtx = {
  73. foo: this.foo,
  74. $options: this.$options,
  75. provided: this.provided,
  76. }
  77. return this.foo + 1
  78. },
  79. },
  80. },
  81. template: `{{ bar }}`,
  82. }
  83. const vm = new Vue({
  84. components: { Child },
  85. provide: {
  86. provided: 2,
  87. },
  88. template: `<child :foo="0" />`,
  89. }).$mount()
  90. expect(vm.$el.textContent).toBe('1')
  91. // other props
  92. expect(thisCtx.foo).toBe(0)
  93. // $options
  94. expect(thisCtx.$options.customOption).toBe(1)
  95. // injections
  96. expect(thisCtx.provided).toBe(2)
  97. expect(
  98. (deprecationData[DeprecationTypes.PROPS_DEFAULT_THIS].message as Function)(
  99. 'bar',
  100. ),
  101. ).toHaveBeenWarned()
  102. })
  103. test('V_ON_KEYCODE_MODIFIER', () => {
  104. const spy = vi.fn()
  105. const vm = new Vue({
  106. template: `<input @keyup.1="spy">`,
  107. methods: { spy },
  108. }).$mount()
  109. expect(vm.$el).toBeInstanceOf(HTMLInputElement)
  110. triggerEvent(vm.$el, 'keyup', e => {
  111. e.key = '_'
  112. e.keyCode = 1
  113. })
  114. expect(spy).toHaveBeenCalled()
  115. expect(
  116. deprecationData[DeprecationTypes.V_ON_KEYCODE_MODIFIER].message,
  117. ).toHaveBeenWarned()
  118. })
  119. test('CUSTOM_DIR', async () => {
  120. const myDir = {
  121. bind: vi.fn(),
  122. inserted: vi.fn(),
  123. update: vi.fn(),
  124. componentUpdated: vi.fn(),
  125. unbind: vi.fn(),
  126. } as any
  127. const getCalls = () =>
  128. Object.keys(myDir).map(key => myDir[key].mock.calls.length)
  129. const vm = new Vue({
  130. data() {
  131. return {
  132. ok: true,
  133. foo: 1,
  134. }
  135. },
  136. template: `<div v-if="ok" v-my-dir="foo"/>`,
  137. directives: {
  138. myDir,
  139. },
  140. }).$mount() as any
  141. expect(getCalls()).toMatchObject([1, 1, 0, 0, 0])
  142. expect(
  143. (deprecationData[DeprecationTypes.CUSTOM_DIR].message as Function)(
  144. 'bind',
  145. 'beforeMount',
  146. ),
  147. ).toHaveBeenWarned()
  148. expect(
  149. (deprecationData[DeprecationTypes.CUSTOM_DIR].message as Function)(
  150. 'inserted',
  151. 'mounted',
  152. ),
  153. ).toHaveBeenWarned()
  154. vm.foo++
  155. await nextTick()
  156. expect(getCalls()).toMatchObject([1, 1, 1, 1, 0])
  157. expect(
  158. (deprecationData[DeprecationTypes.CUSTOM_DIR].message as Function)(
  159. 'update',
  160. 'updated',
  161. ),
  162. ).toHaveBeenWarned()
  163. expect(
  164. (deprecationData[DeprecationTypes.CUSTOM_DIR].message as Function)(
  165. 'componentUpdated',
  166. 'updated',
  167. ),
  168. ).toHaveBeenWarned()
  169. })
  170. test('ATTR_FALSE_VALUE', () => {
  171. const vm = new Vue({
  172. template: `<div :id="false" :foo="false"/>`,
  173. }).$mount()
  174. expect(vm.$el).toBeInstanceOf(HTMLDivElement)
  175. expect(vm.$el.hasAttribute('id')).toBe(false)
  176. expect(vm.$el.hasAttribute('foo')).toBe(false)
  177. expect(
  178. (deprecationData[DeprecationTypes.ATTR_FALSE_VALUE].message as Function)(
  179. 'id',
  180. ),
  181. ).toHaveBeenWarned()
  182. expect(
  183. (deprecationData[DeprecationTypes.ATTR_FALSE_VALUE].message as Function)(
  184. 'foo',
  185. ),
  186. ).toHaveBeenWarned()
  187. })
  188. test('ATTR_FALSE_VALUE with false on input value', () => {
  189. const vm = new Vue({
  190. template: `<input :value="false"/>`,
  191. }).$mount()
  192. expect(vm.$el).toBeInstanceOf(HTMLInputElement)
  193. expect(vm.$el.hasAttribute('value')).toBe(true)
  194. expect(vm.$el.getAttribute('value')).toBe('false')
  195. expect(
  196. (deprecationData[DeprecationTypes.ATTR_FALSE_VALUE].message as Function)(
  197. 'value',
  198. ),
  199. ).not.toHaveBeenWarned()
  200. })
  201. test("ATTR_FALSE_VALUE with false value shouldn't throw warning", () => {
  202. const vm = new Vue({
  203. template: `<div :id="false" :foo="false"/>`,
  204. compatConfig: {
  205. ATTR_FALSE_VALUE: false,
  206. },
  207. }).$mount()
  208. expect(vm.$el).toBeInstanceOf(HTMLDivElement)
  209. expect(vm.$el.hasAttribute('id')).toBe(true)
  210. expect(vm.$el.getAttribute('id')).toBe('false')
  211. expect(vm.$el.hasAttribute('foo')).toBe(true)
  212. expect(vm.$el.getAttribute('foo')).toBe('false')
  213. expect(
  214. (deprecationData[DeprecationTypes.ATTR_FALSE_VALUE].message as Function)(
  215. 'id',
  216. ),
  217. ).not.toHaveBeenWarned()
  218. expect(
  219. (deprecationData[DeprecationTypes.ATTR_FALSE_VALUE].message as Function)(
  220. 'foo',
  221. ),
  222. ).not.toHaveBeenWarned()
  223. })
  224. test('ATTR_ENUMERATED_COERCION', () => {
  225. const vm = new Vue({
  226. template: `<div :draggable="null" :spellcheck="0" contenteditable="foo" />`,
  227. }).$mount()
  228. expect(vm.$el).toBeInstanceOf(HTMLDivElement)
  229. expect(vm.$el.getAttribute('draggable')).toBe('false')
  230. expect(vm.$el.getAttribute('spellcheck')).toBe('true')
  231. expect(vm.$el.getAttribute('contenteditable')).toBe('true')
  232. expect(
  233. (
  234. deprecationData[DeprecationTypes.ATTR_ENUMERATED_COERCION]
  235. .message as Function
  236. )('draggable', null, 'false'),
  237. ).toHaveBeenWarned()
  238. expect(
  239. (
  240. deprecationData[DeprecationTypes.ATTR_ENUMERATED_COERCION]
  241. .message as Function
  242. )('spellcheck', 0, 'true'),
  243. ).toHaveBeenWarned()
  244. expect(
  245. (
  246. deprecationData[DeprecationTypes.ATTR_ENUMERATED_COERCION]
  247. .message as Function
  248. )('contenteditable', 'foo', 'true'),
  249. ).toHaveBeenWarned()
  250. })
  251. test('ATTR_ENUMERATED_COERCION, coercing "false"', () => {
  252. const vm = new Vue({
  253. template: `<div><div draggable="false" :spellcheck="false">hello</div></div>`,
  254. }).$mount()
  255. expect(vm.$el.innerHTML).toBe(
  256. `<div draggable="false" spellcheck="false">hello</div>`,
  257. )
  258. expect(
  259. (
  260. deprecationData[DeprecationTypes.ATTR_ENUMERATED_COERCION]
  261. .message as Function
  262. )('draggable', 'false', 'false'),
  263. ).toHaveBeenWarned()
  264. expect(
  265. (
  266. deprecationData[DeprecationTypes.ATTR_ENUMERATED_COERCION]
  267. .message as Function
  268. )('spellcheck', 'false', 'false'),
  269. ).toHaveBeenWarned()
  270. })