mirror of https://github.com/vuejs/core.git
Merge cc9e5f4d75
into 56be3dd4db
This commit is contained in:
commit
80ce1ccb65
|
@ -0,0 +1,157 @@
|
||||||
|
import {
|
||||||
|
type ComponentInternalInstance,
|
||||||
|
getCurrentInstance,
|
||||||
|
h,
|
||||||
|
nodeOps,
|
||||||
|
render,
|
||||||
|
} from '@vue/runtime-test'
|
||||||
|
import { formatComponentName } from '../src/component'
|
||||||
|
|
||||||
|
describe('formatComponentName', () => {
|
||||||
|
test('default name', () => {
|
||||||
|
let instance: ComponentInternalInstance | null = null
|
||||||
|
const Comp = {
|
||||||
|
setup() {
|
||||||
|
instance = getCurrentInstance()
|
||||||
|
return () => null
|
||||||
|
},
|
||||||
|
}
|
||||||
|
render(h(Comp), nodeOps.createElement('div'))
|
||||||
|
|
||||||
|
expect(formatComponentName(null, Comp)).toBe('Anonymous')
|
||||||
|
expect(formatComponentName(null, Comp, true)).toBe('App')
|
||||||
|
expect(formatComponentName(instance, Comp)).toBe('Anonymous')
|
||||||
|
expect(formatComponentName(instance, Comp, true)).toBe('App')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('name option', () => {
|
||||||
|
let instance: ComponentInternalInstance | null = null
|
||||||
|
const Comp = {
|
||||||
|
name: 'number-input',
|
||||||
|
setup() {
|
||||||
|
instance = getCurrentInstance()
|
||||||
|
return () => null
|
||||||
|
},
|
||||||
|
}
|
||||||
|
render(h(Comp), nodeOps.createElement('div'))
|
||||||
|
|
||||||
|
expect(formatComponentName(null, Comp)).toBe('NumberInput')
|
||||||
|
expect(formatComponentName(instance, Comp, true)).toBe('NumberInput')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('self recursive name', () => {
|
||||||
|
let instance: ComponentInternalInstance | null = null
|
||||||
|
const Comp = {
|
||||||
|
components: {} as any,
|
||||||
|
setup() {
|
||||||
|
instance = getCurrentInstance()
|
||||||
|
return () => null
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Comp.components.ToggleButton = Comp
|
||||||
|
render(h(Comp), nodeOps.createElement('div'))
|
||||||
|
|
||||||
|
expect(formatComponentName(instance, Comp)).toBe('ToggleButton')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('name from parent', () => {
|
||||||
|
let instance: ComponentInternalInstance | null = null
|
||||||
|
const Comp = {
|
||||||
|
setup() {
|
||||||
|
instance = getCurrentInstance()
|
||||||
|
return () => null
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const Parent = {
|
||||||
|
components: {
|
||||||
|
list_item: Comp,
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
return h(Comp)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
render(h(Parent), nodeOps.createElement('div'))
|
||||||
|
|
||||||
|
expect(formatComponentName(instance, Comp)).toBe('ListItem')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('functional components', () => {
|
||||||
|
const UserAvatar = () => null
|
||||||
|
expect(formatComponentName(null, UserAvatar)).toBe('UserAvatar')
|
||||||
|
UserAvatar.displayName = 'UserPicture'
|
||||||
|
expect(formatComponentName(null, UserAvatar)).toBe('UserPicture')
|
||||||
|
expect(formatComponentName(null, () => null)).toBe('Anonymous')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Name from file', () => {
|
||||||
|
const Comp = {
|
||||||
|
__file: './src/locale-dropdown.vue',
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(formatComponentName(null, Comp)).toBe('LocaleDropdown')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('inferred name', () => {
|
||||||
|
const Comp = {
|
||||||
|
__name: 'MainSidebar',
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(formatComponentName(null, Comp)).toBe('MainSidebar')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('global component', () => {
|
||||||
|
let instance: ComponentInternalInstance | null = null
|
||||||
|
const Comp = {
|
||||||
|
setup() {
|
||||||
|
instance = getCurrentInstance()
|
||||||
|
return () => null
|
||||||
|
},
|
||||||
|
}
|
||||||
|
render(h(Comp), nodeOps.createElement('div'))
|
||||||
|
|
||||||
|
instance!.appContext.components.FieldLabel = Comp
|
||||||
|
|
||||||
|
expect(formatComponentName(instance, Comp)).toBe('FieldLabel')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('name precedence', () => {
|
||||||
|
let instance: ComponentInternalInstance | null = null
|
||||||
|
const Dummy = () => null
|
||||||
|
const Comp: Record<string, any> = {
|
||||||
|
components: { Dummy },
|
||||||
|
setup() {
|
||||||
|
instance = getCurrentInstance()
|
||||||
|
return () => null
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const Parent = {
|
||||||
|
components: { Dummy } as any,
|
||||||
|
render() {
|
||||||
|
return h(Comp)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
render(h(Parent), nodeOps.createElement('div'))
|
||||||
|
|
||||||
|
expect(formatComponentName(instance, Comp)).toBe('Anonymous')
|
||||||
|
expect(formatComponentName(instance, Comp, true)).toBe('App')
|
||||||
|
|
||||||
|
instance!.appContext.components.CompA = Comp
|
||||||
|
expect(formatComponentName(instance, Comp)).toBe('CompA')
|
||||||
|
expect(formatComponentName(instance, Comp, true)).toBe('CompA')
|
||||||
|
|
||||||
|
Parent.components.CompB = Comp
|
||||||
|
expect(formatComponentName(instance, Comp)).toBe('CompB')
|
||||||
|
|
||||||
|
Comp.components.CompC = Comp
|
||||||
|
expect(formatComponentName(instance, Comp)).toBe('CompC')
|
||||||
|
|
||||||
|
Comp.__file = './CompD.js'
|
||||||
|
expect(formatComponentName(instance, Comp)).toBe('CompD')
|
||||||
|
|
||||||
|
Comp.__name = 'CompE'
|
||||||
|
expect(formatComponentName(instance, Comp)).toBe('CompE')
|
||||||
|
|
||||||
|
Comp.name = 'CompF'
|
||||||
|
expect(formatComponentName(instance, Comp)).toBe('CompF')
|
||||||
|
})
|
||||||
|
})
|
|
@ -894,7 +894,7 @@ function setupStatefulComponent(
|
||||||
// bail here and wait for re-entry.
|
// bail here and wait for re-entry.
|
||||||
instance.asyncDep = setupResult
|
instance.asyncDep = setupResult
|
||||||
if (__DEV__ && !instance.suspense) {
|
if (__DEV__ && !instance.suspense) {
|
||||||
const name = Component.name ?? 'Anonymous'
|
const name = formatComponentName(instance, Component)
|
||||||
warn(
|
warn(
|
||||||
`Component <${name}>: setup function returned a promise, but no ` +
|
`Component <${name}>: setup function returned a promise, but no ` +
|
||||||
`<Suspense> boundary was found in the parent component tree. ` +
|
`<Suspense> boundary was found in the parent component tree. ` +
|
||||||
|
@ -1226,9 +1226,11 @@ export function formatComponentName(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!name && instance && instance.parent) {
|
if (!name && instance) {
|
||||||
// try to infer the name based on reverse resolution
|
// try to infer the name based on reverse resolution
|
||||||
const inferFromRegistry = (registry: Record<string, any> | undefined) => {
|
const inferFromRegistry = (
|
||||||
|
registry: Record<string, any> | undefined | null,
|
||||||
|
) => {
|
||||||
for (const key in registry) {
|
for (const key in registry) {
|
||||||
if (registry[key] === Component) {
|
if (registry[key] === Component) {
|
||||||
return key
|
return key
|
||||||
|
@ -1236,10 +1238,12 @@ export function formatComponentName(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
name =
|
name =
|
||||||
|
inferFromRegistry(instance.components) ||
|
||||||
|
(instance.parent &&
|
||||||
inferFromRegistry(
|
inferFromRegistry(
|
||||||
instance.components ||
|
|
||||||
(instance.parent.type as ComponentOptions).components,
|
(instance.parent.type as ComponentOptions).components,
|
||||||
) || inferFromRegistry(instance.appContext.components)
|
)) ||
|
||||||
|
inferFromRegistry(instance.appContext.components)
|
||||||
}
|
}
|
||||||
|
|
||||||
return name ? classify(name) : isRoot ? `App` : `Anonymous`
|
return name ? classify(name) : isRoot ? `App` : `Anonymous`
|
||||||
|
|
Loading…
Reference in New Issue