| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- 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()
- })
- })
- })
- })
|