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: '
{{ a }}
', 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: '
', components: { test: { props: ['a'], template: '
{{ a }}
', 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: `
`, data: { foo: 0 }, methods: { bar: spy }, components: { child: { template: `
{{foo}}
`, props: ['foo'], updated() { this.$emit('change') } } } }).$mount(el) vm.$nextTick(() => { vm.foo = 1 vm.$nextTick(() => { expect(vm.$el.innerHTML).toBe('
1
') expect(spy).toHaveBeenCalled() done() }) }) }) })