From: Evan You Date: Wed, 11 Sep 2019 15:09:16 +0000 (-0400) Subject: test: more tests for suspense X-Git-Tag: v3.0.0-alpha.0~783 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ccfcdb8746a92a5bc006a7682fdef06eba9a13de;p=thirdparty%2Fvuejs%2Fcore.git test: more tests for suspense --- diff --git a/packages/runtime-core/__tests__/rendererSuspense.spec.ts b/packages/runtime-core/__tests__/rendererSuspense.spec.ts index 16953bee44..c5d2ad4154 100644 --- a/packages/runtime-core/__tests__/rendererSuspense.spec.ts +++ b/packages/runtime-core/__tests__/rendererSuspense.spec.ts @@ -6,47 +6,50 @@ import { render, nodeOps, serializeInner, - nextTick + nextTick, + onMounted, + watch, + onUnmounted } from '@vue/runtime-test' describe('renderer: suspense', () => { - it('basic usage (nested + multiple deps)', async () => { - const msg = ref('hello') - const deps: Promise[] = [] + const deps: Promise[] = [] + + beforeEach(() => { + deps.length = 0 + }) - const createAsyncComponent = (loader: () => Promise) => ({ + // a simple async factory for testing purposes only. + function createAsyncComponent( + comp: T, + delay: number = 0 + ) { + return { async setup(props: any, { slots }: any) { - const p = loader() + const p: Promise = new Promise(r => setTimeout(() => r(comp), delay)) deps.push(p) const Inner = await p return () => h(Inner, props, slots) } - }) + } + } - const AsyncChild = createAsyncComponent( - () => - new Promise(resolve => { - setTimeout(() => { - resolve({ - setup(props: { msg: string }) { - return () => h('div', props.msg) - } - }) - }, 0) - }) - ) + it('basic usage (nested + multiple deps)', async () => { + const msg = ref('hello') + + const AsyncChild = createAsyncComponent({ + setup(props: { msg: string }) { + return () => h('div', props.msg) + } + }) const AsyncChild2 = createAsyncComponent( - () => - new Promise(resolve => { - setTimeout(() => { - resolve({ - setup(props: { msg: string }) { - return () => h('div', props.msg) - } - }) - }, 10) - }) + { + setup(props: { msg: string }) { + return () => h('div', props.msg) + } + }, + 10 ) const Mid = { @@ -77,12 +80,89 @@ describe('renderer: suspense', () => { }) test('fallback content', async () => { + const Async = createAsyncComponent({ + render() { + return h('div', 'async') + } + }) + + const Comp = { + setup() { + return () => + h(Suspense, null, { + default: h(Async), + fallback: h('div', 'fallback') + }) + } + } + + const root = nodeOps.createElement('div') + render(h(Comp), root) + expect(serializeInner(root)).toBe(`
fallback
`) + + await Promise.all(deps) + await nextTick() + expect(serializeInner(root)).toBe(`
async
`) + }) + + test('onResolve', async () => { + const Async = createAsyncComponent({ + render() { + return h('div', 'async') + } + }) + + const onResolve = jest.fn() + + const Comp = { + setup() { + return () => + h( + Suspense, + { + onResolve + }, + { + default: h(Async), + fallback: h('div', 'fallback') + } + ) + } + } + + const root = nodeOps.createElement('div') + render(h(Comp), root) + expect(serializeInner(root)).toBe(`
fallback
`) + expect(onResolve).not.toHaveBeenCalled() + + await Promise.all(deps) + await nextTick() + expect(serializeInner(root)).toBe(`
async
`) + expect(onResolve).toHaveBeenCalled() + }) + + test('buffer mounted/updated hooks & watch callbacks', async () => { const deps: Promise[] = [] + const calls: string[] = [] + const toggle = ref(true) const Async = { async setup() { const p = new Promise(r => setTimeout(r, 1)) deps.push(p) + + watch(() => { + calls.push('watch callback') + }) + + onMounted(() => { + calls.push('mounted') + }) + + onUnmounted(() => { + calls.push('unmounted') + }) + await p // test resume for returning bindings return { @@ -98,7 +178,7 @@ describe('renderer: suspense', () => { setup() { return () => h(Suspense, null, { - default: h(Async), + default: toggle.value ? h(Async) : null, fallback: h('div', 'fallback') }) } @@ -107,22 +187,30 @@ describe('renderer: suspense', () => { const root = nodeOps.createElement('div') render(h(Comp), root) expect(serializeInner(root)).toBe(`
fallback
`) + expect(calls).toEqual([]) await Promise.all(deps) await nextTick() expect(serializeInner(root)).toBe(`
async
`) - }) - - test.todo('buffer mounted/updated hooks & watch callbacks') + expect(calls).toEqual([`watch callback`, `mounted`]) - test.todo('onResolve') + // effects inside an already resolved suspense should happen at normal timing + toggle.value = false + await nextTick() + expect(serializeInner(root)).toBe(``) + expect(calls).toEqual([`watch callback`, `mounted`, 'unmounted']) + }) + // should receive updated props/slots when resolved test.todo('content update before suspense resolve') + // mount/unmount hooks should not even fire test.todo('unmount before suspense resolve') test.todo('nested suspense') + test.todo('new async dep after resolve should cause suspense to restart') + test.todo('error handling') test.todo('portal inside suspense')