Skip to content

Commit

Permalink
✨ add pendingDelay prop
Browse files Browse the repository at this point in the history
Closes #6
  • Loading branch information
posva committed Mar 14, 2018
1 parent e9ef996 commit 7ad5fa3
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 4 deletions.
25 changes: 24 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@ export default {
props: {
promise: Promise,
promises: Array,
pendingDelay: {
type: [Number, String],
default: 200,
},
},

data: () => ({
resolved: false,
data: null,
error: null,

isDelayElapsed: false,
}),

render (h) {
Expand All @@ -27,14 +33,17 @@ export default {
'Provide exactly one default/then scoped slot for the resolved promise'
)
return slot.call(this, this.data)
} else {
} else if (this.isDelayElapsed) {
assert(
(this.$slots.default && this.$slots.default.length === 1) ||
(this.$slots.pending && this.$slots.pending.length === 1),
'Provide exactly one default/pending slot with no `slot-scope` for the pending promise'
)
return this.$slots.default ? this.$slots.default[0] : this.$slots.pending[0]
}

// do not render anything
return h()
},

watch: {
Expand All @@ -43,6 +52,7 @@ export default {
if (!promise) return
this.resolved = false
this.error = null
this.setupDelay()
promise
.then(data => {
if (this.promise === promise) {
Expand All @@ -63,6 +73,7 @@ export default {
this.resolved = false
this.error = []
this.data = []
this.setupDelay()
promises.forEach(p => {
p
.then(data => {
Expand All @@ -79,4 +90,16 @@ export default {
immediate: true,
},
},

methods: {
setupDelay () {
if (this.pendingDelay > 0) {
this.isDelayElapsed = false
if (this.timerId) clearTimeout(this.timerId)
this.timerId = setTimeout(() => this.isDelayElapsed = true, this.pendingDelay)
} else {
this.isDelayElapsed = true
}
},
},
}
87 changes: 85 additions & 2 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import NoError from './utils/NoError'
import NoResolve from './utils/NoResolve'
import NoPending from './utils/NoPending'

const tick = () => new Promise(resolve => setTimeout(resolve, 0))
// keep a real setTimeout
const timeout = setTimeout
const tick = () => new Promise(resolve => timeout(resolve, 0))
jest.useFakeTimers()

describe('Promised', () => {
let wrapper
Expand All @@ -17,6 +20,7 @@ describe('Promised', () => {
wrapper = mount(Helper, {
propsData: {
promise,
pendingDelay: 0,
},
})
})
Expand Down Expand Up @@ -70,6 +74,7 @@ describe('Promised', () => {
wrapper = mount(Helper, {
propsData: {
promises,
pendingDelay: 0,
},
})
})
Expand Down Expand Up @@ -133,6 +138,7 @@ describe('Promised', () => {
wrapper = mount(NoError, {
propsData: {
promise,
pendingDelay: 0,
},
})
expect(errorSpy).not.toHaveBeenCalled()
Expand All @@ -146,6 +152,7 @@ describe('Promised', () => {
wrapper = mount(NoResolve, {
propsData: {
promise,
pendingDelay: 0,
},
})
expect(errorSpy).not.toHaveBeenCalled()
Expand All @@ -160,6 +167,7 @@ describe('Promised', () => {
wrapper = mount(NoPending, {
propsData: {
promise,
pendingDelay: 0,
},
})
expect(errorSpy).toHaveBeenCalledTimes(2)
Expand All @@ -172,7 +180,10 @@ describe('Promised', () => {
beforeEach(() => {
[promise, resolve, reject] = fakePromise()
wrapper = mount(NamedSlots, {
propsData: { promise },
propsData: {
promise,
pendingDelay: 0,
},
})
})

Expand All @@ -192,4 +203,76 @@ describe('Promised', () => {
expect(wrapper.text()).toBe('nope')
})
})

describe('pendingDelay', () => {
describe('single promise', () => {
let promise
beforeEach(() => {
clearTimeout.mockClear()
;[promise] = fakePromise()
wrapper = mount(Helper, {
propsData: {
promise,
pendingDelay: 300,
},
})
})

test('displays nothing before the delay', async () => {
expect(wrapper.text()).toBe('')
jest.runAllTimers()
await tick()
expect(wrapper.text()).toBe('loading')
})

test('custom pendingDelay', async () => {
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 300)
;[promise] = fakePromise()
wrapper.setProps({
promise,
pendingDelay: 100,
})
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 100)
})

test('cancels previous timeouts', () => {
expect(clearTimeout).not.toHaveBeenCalled()
;[promise] = fakePromise()
wrapper.setProps({
promise,
pendingDelay: 100,
})
expect(clearTimeout).toHaveBeenCalled()
})
})

describe('multiple promises', () => {
let fakedPromises
beforeEach(async () => {
fakedPromises = Array.from({ length: 3 }, () => fakePromise()).map(
([promise, resolve, reject]) => ({
promise,
resolve,
reject,
})
)

const promises = fakedPromises.map(({ promise }) => promise)

wrapper = mount(Helper, {
propsData: {
promises,
pendingDelay: 300,
},
})
})

test('displays nothing before the delay', async () => {
expect(wrapper.text()).toBe('')
jest.runAllTimers()
await tick()
expect(wrapper.text()).toBe('loading')
})
})
})
})
2 changes: 1 addition & 1 deletion test/utils/common.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Promised from '../../src'

export default {
props: ['promise', 'promises'],
props: ['promise', 'promises', 'pendingDelay'],
filters: {
text (data) {
return Array.isArray(data) ? data.join(',') : data
Expand Down

0 comments on commit 7ad5fa3

Please sign in to comment.