import { queueJob, nextTick, queuePostFlushCb, invalidateJob } from '../src/scheduler' describe('scheduler', () => { it('nextTick', async () => { const calls: string[] = [] const dummyThen = Promise.resolve().then() const job1 = () => { calls.push('job1') } const job2 = () => { calls.push('job2') } nextTick(job1) job2() expect(calls.length).toBe(1) await dummyThen // job1 will be pushed in nextTick expect(calls.length).toBe(2) expect(calls).toMatchObject(['job2', 'job1']) }) describe('queueJob', () => { it('basic usage', async () => { const calls: string[] = [] const job1 = () => { calls.push('job1') } const job2 = () => { calls.push('job2') } queueJob(job1) queueJob(job2) expect(calls).toEqual([]) await nextTick() expect(calls).toEqual(['job1', 'job2']) }) it('should dedupe queued jobs', async () => { const calls: string[] = [] const job1 = () => { calls.push('job1') } const job2 = () => { calls.push('job2') } queueJob(job1) queueJob(job2) queueJob(job1) queueJob(job2) expect(calls).toEqual([]) await nextTick() expect(calls).toEqual(['job1', 'job2']) }) it('queueJob while flushing', async () => { const calls: string[] = [] const job1 = () => { calls.push('job1') // job2 will be executed after job1 at the same tick queueJob(job2) } const job2 = () => { calls.push('job2') } queueJob(job1) await nextTick() expect(calls).toEqual(['job1', 'job2']) }) }) describe('queuePostFlushCb', () => { it('basic usage', async () => { const calls: string[] = [] const cb1 = () => { calls.push('cb1') } const cb2 = () => { calls.push('cb2') } const cb3 = () => { calls.push('cb3') } queuePostFlushCb([cb1, cb2]) queuePostFlushCb(cb3) expect(calls).toEqual([]) await nextTick() expect(calls).toEqual(['cb1', 'cb2', 'cb3']) }) it('should dedupe queued postFlushCb', async () => { const calls: string[] = [] const cb1 = () => { calls.push('cb1') } const cb2 = () => { calls.push('cb2') } const cb3 = () => { calls.push('cb3') } queuePostFlushCb([cb1, cb2]) queuePostFlushCb(cb3) queuePostFlushCb([cb1, cb3]) queuePostFlushCb(cb2) expect(calls).toEqual([]) await nextTick() expect(calls).toEqual(['cb1', 'cb2', 'cb3']) }) it('queuePostFlushCb while flushing', async () => { const calls: string[] = [] const cb1 = () => { calls.push('cb1') // cb2 will be executed after cb1 at the same tick queuePostFlushCb(cb2) } const cb2 = () => { calls.push('cb2') } queuePostFlushCb(cb1) await nextTick() expect(calls).toEqual(['cb1', 'cb2']) }) }) describe('queueJob w/ queuePostFlushCb', () => { it('queueJob inside postFlushCb', async () => { const calls: string[] = [] const job1 = () => { calls.push('job1') } const cb1 = () => { // queueJob in postFlushCb calls.push('cb1') queueJob(job1) } queuePostFlushCb(cb1) await nextTick() expect(calls).toEqual(['cb1', 'job1']) }) it('queueJob & postFlushCb inside postFlushCb', async () => { const calls: string[] = [] const job1 = () => { calls.push('job1') } const cb1 = () => { calls.push('cb1') queuePostFlushCb(cb2) // job1 will executed before cb2 // Job has higher priority than postFlushCb queueJob(job1) } const cb2 = () => { calls.push('cb2') } queuePostFlushCb(cb1) await nextTick() expect(calls).toEqual(['cb1', 'job1', 'cb2']) }) it('postFlushCb inside queueJob', async () => { const calls: string[] = [] const job1 = () => { calls.push('job1') // postFlushCb in queueJob queuePostFlushCb(cb1) } const cb1 = () => { calls.push('cb1') } queueJob(job1) await nextTick() expect(calls).toEqual(['job1', 'cb1']) }) it('queueJob & postFlushCb inside queueJob', async () => { const calls: string[] = [] const job1 = () => { calls.push('job1') // cb1 will executed after job2 // Job has higher priority than postFlushCb queuePostFlushCb(cb1) queueJob(job2) } const job2 = () => { calls.push('job2') } const cb1 = () => { calls.push('cb1') } queueJob(job1) await nextTick() expect(calls).toEqual(['job1', 'job2', 'cb1']) }) it('nested queueJob w/ postFlushCb', async () => { const calls: string[] = [] const job1 = () => { calls.push('job1') queuePostFlushCb(cb1) queueJob(job2) } const job2 = () => { calls.push('job2') queuePostFlushCb(cb2) } const cb1 = () => { calls.push('cb1') } const cb2 = () => { calls.push('cb2') } queueJob(job1) await nextTick() expect(calls).toEqual(['job1', 'job2', 'cb1', 'cb2']) }) }) test('invalidateJob', async () => { const calls: string[] = [] const job1 = () => { calls.push('job1') invalidateJob(job2) job2() } const job2 = () => { calls.push('job2') } const job3 = () => { calls.push('job3') } const job4 = () => { calls.push('job4') } // queue all jobs queueJob(job1) queueJob(job2) queueJob(job3) queuePostFlushCb(job4) expect(calls).toEqual([]) await nextTick() // job2 should be called only once expect(calls).toEqual(['job1', 'job2', 'job3', 'job4']) }) test('sort job based on id', async () => { const calls: string[] = [] const job1 = () => calls.push('job1') // job1 has no id const job2 = () => calls.push('job2') job2.id = 2 const job3 = () => calls.push('job3') job3.id = 1 queueJob(job1) queueJob(job2) queueJob(job3) await nextTick() expect(calls).toEqual(['job3', 'job2', 'job1']) }) // #1595 test('avoid duplicate postFlushCb invocation', async () => { const calls: string[] = [] const cb1 = () => { calls.push('cb1') queuePostFlushCb(cb2) } const cb2 = () => { calls.push('cb2') } queuePostFlushCb(cb1) queuePostFlushCb(cb2) await nextTick() expect(calls).toEqual(['cb1', 'cb2']) }) })