Skip to content

Commit

Permalink
fix(warn): avoid warning on empty children with Suspense (#3962)
Browse files Browse the repository at this point in the history
  • Loading branch information
posva authored Nov 6, 2023
1 parent b39fa1f commit 405f345
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 1 deletion.
74 changes: 74 additions & 0 deletions packages/runtime-core/__tests__/components/Suspense.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ import {
onUnmounted,
onErrorCaptured,
shallowRef,
SuspenseProps,
resolveDynamicComponent,
Fragment
} from '@vue/runtime-test'
import { createApp, defineComponent } from 'vue'
import { type RawSlots } from 'packages/runtime-core/src/componentSlots'

describe('Suspense', () => {
const deps: Promise<any>[] = []
Expand Down Expand Up @@ -1523,4 +1526,75 @@ describe('Suspense', () => {
expected = `<div>outerB</div><div>innerB</div>`
expect(serializeInner(root)).toBe(expected)
})

describe('warnings', () => {
// base function to check if a combination of slots warns or not
function baseCheckWarn(
shouldWarn: boolean,
children: RawSlots,
props: SuspenseProps | null = null
) {
const Comp = {
setup() {
return () => h(Suspense, props, children)
}
}

const root = nodeOps.createElement('div')
render(h(Comp), root)

if (shouldWarn) {
expect(`<Suspense> slots expect a single root node.`).toHaveBeenWarned()
} else {
expect(
`<Suspense> slots expect a single root node.`
).not.toHaveBeenWarned()
}
}

// actual function that we use in tests
const checkWarn = baseCheckWarn.bind(null, true)
const checkNoWarn = baseCheckWarn.bind(null, false)

test('does not warn on single child', async () => {
checkNoWarn({
default: h('div'),
fallback: h('div')
})
})

test('does not warn on null', async () => {
checkNoWarn({
default: null,
fallback: null
})
})

test('does not warn on <component :is="null" />', async () => {
checkNoWarn({
default: () => [resolveDynamicComponent(null)],
fallback: () => null
})
})

test('does not warn on empty array', async () => {
checkNoWarn({
default: [],
fallback: () => []
})
})

test('warns on multiple children in default', async () => {
checkWarn({
default: [h('div'), h('div')]
})
})

test('warns on multiple children in fallback', async () => {
checkWarn({
default: h('div'),
fallback: [h('div'), h('div')]
})
})
})
})
7 changes: 6 additions & 1 deletion packages/runtime-core/src/components/Suspense.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
assertNumber
} from '../warning'
import { handleError, ErrorCodes } from '../errorHandling'
import { NULL_DYNAMIC_COMPONENT } from '../helpers/resolveAssets'

export interface SuspenseProps {
onResolve?: () => void
Expand Down Expand Up @@ -795,7 +796,11 @@ function normalizeSuspenseSlot(s: any) {
}
if (isArray(s)) {
const singleChild = filterSingleRoot(s)
if (__DEV__ && !singleChild) {
if (
__DEV__ &&
!singleChild &&
s.filter(child => child !== NULL_DYNAMIC_COMPONENT).length > 0
) {
warn(`<Suspense> slots expect a single root node.`)
}
s = singleChild
Expand Down
1 change: 1 addition & 0 deletions packages/runtime-core/src/vnode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export type VNodeProps = {

type VNodeChildAtom =
| VNode
| typeof NULL_DYNAMIC_COMPONENT
| string
| number
| boolean
Expand Down

0 comments on commit 405f345

Please sign in to comment.