mirror of https://github.com/vuejs/vue.git
				
				
				
			
		
			
				
	
	
		
			181 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
| import Vue from 'vue'
 | |
| import {
 | |
|   MAX_UPDATE_COUNT,
 | |
|   queueWatcher as _queueWatcher
 | |
| } from 'core/observer/scheduler'
 | |
| 
 | |
| function queueWatcher (watcher) {
 | |
|   watcher.vm = {} // mock vm
 | |
|   _queueWatcher(watcher)
 | |
| }
 | |
| 
 | |
| describe('Scheduler', () => {
 | |
|   let spy
 | |
|   beforeEach(() => {
 | |
|     spy = vi.fn()
 | |
|   })
 | |
| 
 | |
|   it('queueWatcher', done => {
 | |
|     queueWatcher({
 | |
|       run: spy
 | |
|     })
 | |
|     waitForUpdate(() => {
 | |
|       expect(spy.mock.calls.length).toBe(1)
 | |
|     }).then(done)
 | |
|   })
 | |
| 
 | |
|   it('dedup', done => {
 | |
|     queueWatcher({
 | |
|       id: 1,
 | |
|       run: spy
 | |
|     })
 | |
|     queueWatcher({
 | |
|       id: 1,
 | |
|       run: spy
 | |
|     })
 | |
|     waitForUpdate(() => {
 | |
|       expect(spy.mock.calls.length).toBe(1)
 | |
|     }).then(done)
 | |
|   })
 | |
| 
 | |
|   it('allow duplicate when flushing', done => {
 | |
|     const job = {
 | |
|       id: 1,
 | |
|       run: spy
 | |
|     }
 | |
|     queueWatcher(job)
 | |
|     queueWatcher({
 | |
|       id: 2,
 | |
|       run () { queueWatcher(job) }
 | |
|     })
 | |
|     waitForUpdate(() => {
 | |
|       expect(spy.mock.calls.length).toBe(2)
 | |
|     }).then(done)
 | |
|   })
 | |
| 
 | |
|   it('call user watchers before component re-render', done => {
 | |
|     const calls: any[] = []
 | |
|     const vm = new Vue({
 | |
|       data: {
 | |
|         a: 1
 | |
|       },
 | |
|       template: '<div>{{ a }}</div>',
 | |
|       watch: {
 | |
|         a () { calls.push(1) }
 | |
|       },
 | |
|       beforeUpdate () {
 | |
|         calls.push(2)
 | |
|       }
 | |
|     }).$mount()
 | |
|     vm.a = 2
 | |
|     waitForUpdate(() => {
 | |
|       expect(calls).toEqual([1, 2])
 | |
|     }).then(done)
 | |
|   })
 | |
| 
 | |
|   it('call user watcher triggered by component re-render immediately', done => {
 | |
|     // this happens when a component re-render updates the props of a child
 | |
|     const calls: any[] = []
 | |
|     const vm = new Vue({
 | |
|       data: {
 | |
|         a: 1
 | |
|       },
 | |
|       watch: {
 | |
|         a () {
 | |
|           calls.push(1)
 | |
|         }
 | |
|       },
 | |
|       beforeUpdate () {
 | |
|         calls.push(2)
 | |
|       },
 | |
|       template: '<div><test :a="a"></test></div>',
 | |
|       components: {
 | |
|         test: {
 | |
|           props: ['a'],
 | |
|           template: '<div>{{ a }}</div>',
 | |
|           watch: {
 | |
|             a () {
 | |
|               calls.push(3)
 | |
|             }
 | |
|           },
 | |
|           beforeUpdate () {
 | |
|             calls.push(4)
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }).$mount()
 | |
|     vm.a = 2
 | |
|     waitForUpdate(() => {
 | |
|       expect(calls).toEqual([1, 2, 3, 4])
 | |
|     }).then(done)
 | |
|   })
 | |
| 
 | |
|   it('warn against infinite update loops', function (done) {
 | |
|     let count = 0
 | |
|     const job = {
 | |
|       id: 1,
 | |
|       run () {
 | |
|         count++
 | |
|         queueWatcher(job)
 | |
|       }
 | |
|     }
 | |
|     queueWatcher(job)
 | |
|     waitForUpdate(() => {
 | |
|       expect(count).toBe(MAX_UPDATE_COUNT + 1)
 | |
|       expect('infinite update loop').toHaveBeenWarned()
 | |
|     }).then(done)
 | |
|   })
 | |
| 
 | |
|   it('should call newly pushed watcher after current watcher is done', done => {
 | |
|     const callOrder: any[] = []
 | |
|     queueWatcher({
 | |
|       id: 1,
 | |
|       user: true,
 | |
|       run () {
 | |
|         callOrder.push(1)
 | |
|         queueWatcher({
 | |
|           id: 2,
 | |
|           run () {
 | |
|             callOrder.push(3)
 | |
|           }
 | |
|         })
 | |
|         callOrder.push(2)
 | |
|       }
 | |
|     })
 | |
|     waitForUpdate(() => {
 | |
|       expect(callOrder).toEqual([1, 2, 3])
 | |
|     }).then(done)
 | |
|   })
 | |
| 
 | |
|   // GitHub issue #5191
 | |
|   it('emit should work when updated hook called', done => {
 | |
|     const el = document.createElement('div')
 | |
|     const vm = new Vue({
 | |
|       template: `<div><child @change="bar" :foo="foo"></child></div>`,
 | |
|       data: {
 | |
|         foo: 0
 | |
|       },
 | |
|       methods: {
 | |
|         bar: spy
 | |
|       },
 | |
|       components: {
 | |
|         child: {
 | |
|           template: `<div>{{foo}}</div>`,
 | |
|           props: ['foo'],
 | |
|           updated () {
 | |
|             this.$emit('change')
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }).$mount(el)
 | |
|     vm.$nextTick(() => {
 | |
|       vm.foo = 1
 | |
|       vm.$nextTick(() => {
 | |
|         expect(vm.$el.innerHTML).toBe('<div>1</div>')
 | |
|         expect(spy).toHaveBeenCalled()
 | |
|         done()
 | |
|       })
 | |
|     })
 | |
|   })
 | |
| })
 |