Skip to content

Commit d2b7142

Browse files
committed
tests for advanced async component features
1 parent e7a066f commit d2b7142

File tree

2 files changed

+156
-10
lines changed

2 files changed

+156
-10
lines changed

src/core/vdom/helpers/resolve-async-component.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,30 +75,42 @@ export function resolveAsyncComponent (
7575
res.then(resolve, reject)
7676
}
7777
} else if (isDef(res.component) && typeof res.component.then === 'function') {
78+
res.component.then(resolve, reject)
79+
7880
if (isDef(res.error)) {
7981
factory.errorComp = ensureCtor(res.error, baseCtor)
8082
}
8183

8284
if (isDef(res.loading)) {
8385
factory.loadingComp = ensureCtor(res.loading, baseCtor)
84-
setTimeout(() => {
85-
if (isUndef(factory.resolved) && isUndef(factory.error)) {
86-
factory.loading = true
87-
forceRender()
88-
}
89-
}, res.delay || 200)
86+
if (res.delay === 0) {
87+
factory.loading = true
88+
} else {
89+
setTimeout(() => {
90+
if (isUndef(factory.resolved) && isUndef(factory.error)) {
91+
factory.loading = true
92+
forceRender()
93+
}
94+
}, res.delay || 200)
95+
}
9096
}
9197

9298
if (isDef(res.timeout)) {
93-
setTimeout(reject, res.timeout)
99+
setTimeout(() => {
100+
reject(
101+
process.env.NODE_ENV !== 'production'
102+
? `timeout (${res.timeout}ms)`
103+
: null
104+
)
105+
}, res.timeout)
94106
}
95-
96-
res.component.then(resolve, reject)
97107
}
98108
}
99109

100110
sync = false
101111
// return in case resolved synchronously
102-
return factory.resolved
112+
return factory.loading
113+
? factory.loadingComp
114+
: factory.resolved
103115
}
104116
}

test/unit/features/component/component-async.spec.js

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,138 @@ describe('Component async', () => {
159159
done()
160160
}
161161
})
162+
163+
describe('loading/error/timeout', () => {
164+
it('with loading component', done => {
165+
const vm = new Vue({
166+
template: `<div><test/></div>`,
167+
components: {
168+
test: () => ({
169+
component: new Promise(resolve => {
170+
setTimeout(() => {
171+
resolve({ template: '<div>hi</div>' })
172+
// wait for promise resolve and then parent update
173+
Promise.resolve().then(() => {
174+
Vue.nextTick(next)
175+
})
176+
}, 5)
177+
}),
178+
loading: { template: `<div>loading</div>` },
179+
delay: 1
180+
})
181+
}
182+
}).$mount()
183+
184+
expect(vm.$el.innerHTML).toBe('<!---->')
185+
186+
let loadingAsserted = false
187+
setTimeout(() => {
188+
Vue.nextTick(() => {
189+
loadingAsserted = true
190+
expect(vm.$el.textContent).toBe('loading')
191+
})
192+
}, 1)
193+
194+
function next () {
195+
expect(loadingAsserted).toBe(true)
196+
expect(vm.$el.textContent).toBe('hi')
197+
done()
198+
}
199+
})
200+
201+
it('with loading component (0 delay)', done => {
202+
const vm = new Vue({
203+
template: `<div><test/></div>`,
204+
components: {
205+
test: () => ({
206+
component: new Promise(resolve => {
207+
setTimeout(() => {
208+
resolve({ template: '<div>hi</div>' })
209+
// wait for promise resolve and then parent update
210+
Promise.resolve().then(() => {
211+
Vue.nextTick(next)
212+
})
213+
}, 0)
214+
}),
215+
loading: { template: `<div>loading</div>` },
216+
delay: 0
217+
})
218+
}
219+
}).$mount()
220+
221+
expect(vm.$el.textContent).toBe('loading')
222+
223+
function next () {
224+
expect(vm.$el.textContent).toBe('hi')
225+
done()
226+
}
227+
})
228+
229+
it('with error component', done => {
230+
const vm = new Vue({
231+
template: `<div><test/></div>`,
232+
components: {
233+
test: () => ({
234+
component: new Promise((resolve, reject) => {
235+
setTimeout(() => {
236+
reject()
237+
// wait for promise resolve and then parent update
238+
Promise.resolve().then(() => {
239+
Vue.nextTick(next)
240+
})
241+
}, 0)
242+
}),
243+
loading: { template: `<div>loading</div>` },
244+
error: { template: `<div>error</div>` },
245+
delay: 0
246+
})
247+
}
248+
}).$mount()
249+
250+
expect(vm.$el.textContent).toBe('loading')
251+
252+
function next () {
253+
expect(`Failed to resolve async component`).toHaveBeenWarned()
254+
expect(vm.$el.textContent).toBe('error')
255+
done()
256+
}
257+
})
258+
259+
it('with error component + timeout', done => {
260+
const vm = new Vue({
261+
template: `<div><test/></div>`,
262+
components: {
263+
test: () => ({
264+
component: new Promise((resolve, reject) => {
265+
setTimeout(() => {
266+
resolve({ template: '<div>hi</div>' })
267+
// wait for promise resolve and then parent update
268+
Promise.resolve().then(() => {
269+
Vue.nextTick(next)
270+
})
271+
}, 5)
272+
}),
273+
loading: { template: `<div>loading</div>` },
274+
error: { template: `<div>error</div>` },
275+
delay: 0,
276+
timeout: 1
277+
})
278+
}
279+
}).$mount()
280+
281+
expect(vm.$el.textContent).toBe('loading')
282+
283+
setTimeout(() => {
284+
Vue.nextTick(() => {
285+
expect(`Failed to resolve async component`).toHaveBeenWarned()
286+
expect(vm.$el.textContent).toBe('error')
287+
})
288+
}, 1)
289+
290+
function next () {
291+
expect(vm.$el.textContent).toBe('error') // late resolve ignored
292+
done()
293+
}
294+
})
295+
})
162296
})

0 commit comments

Comments
 (0)