diff --git a/src/mount.ts b/src/mount.ts index ec5e08332..141fb8571 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -45,7 +45,7 @@ import { attachEmitListener } from './emit' import { createVNodeTransformer } from './vnodeTransformers/util' import { createStubComponentsTransformer, - addToDoNotStubComponents + CreateStubComponentsTransformerConfig } from './vnodeTransformers/stubComponentsTransformer' import { createStubDirectivesTransformer } from './vnodeTransformers/stubDirectivesTransformer' import { @@ -315,6 +315,9 @@ export function mount( let component: ConcreteComponent const instanceOptions = getInstanceOptions(options ?? {}) + const rootComponents: CreateStubComponentsTransformerConfig['rootComponents'] = + {} + if ( isFunctionalComponent(originalComponent) || isLegacyFunctionalComponent(originalComponent) @@ -335,15 +338,14 @@ export function mount( h(originalComponent, { ...props, ...attrs }, slots), ...instanceOptions }) - addToDoNotStubComponents(originalComponent) + rootComponents.legacy = originalComponent } else if (isObjectComponent(originalComponent)) { component = { ...originalComponent, ...instanceOptions } } else { component = originalComponent } - // Don't stub component only on root level, but still stub if used inside - addToDoNotStubComponents(component, true) + rootComponents.component = component // We've just replaced our component with its copy // Let's register it as a stub so user can find it registerStub({ source: originalComponent, stub: component }) @@ -465,11 +467,6 @@ export function mount( // create the app const app = createApp(Parent) - // the Parent type must not be stubbed - // but we can't add it directly, as createApp creates a copy - // and store it in app._component (since v3.2.32) - // So we store this one instead - addToDoNotStubComponents(app._component) // add tracking for emitted events // this must be done after `createApp`: https://github.com/vuejs/test-utils/issues/436 @@ -577,6 +574,7 @@ export function mount( createVNodeTransformer({ transformers: [ createStubComponentsTransformer({ + rootComponents, stubs: getComponentsFromStubs(global.stubs), shallow: options?.shallow, renderStubDefaultSlot: global.renderStubDefaultSlot diff --git a/src/vnodeTransformers/stubComponentsTransformer.ts b/src/vnodeTransformers/stubComponentsTransformer.ts index 75da6b513..6ade69577 100644 --- a/src/vnodeTransformers/stubComponentsTransformer.ts +++ b/src/vnodeTransformers/stubComponentsTransformer.ts @@ -36,15 +36,6 @@ interface StubOptions { renderStubDefaultSlot?: boolean } -const doNotStubComponents = new WeakMap() -const shouldNotStub = (type: ConcreteComponent) => doNotStubComponents.has(type) -const shouldNotStubRoot = (type: ConcreteComponent) => - !!doNotStubComponents.get(type) -export const addToDoNotStubComponents = ( - type: ConcreteComponent, - onlyRoot?: boolean -) => doNotStubComponents.set(type, !!onlyRoot) - const normalizeStubProps = (props: ComponentPropsOptions) => { // props are always normalized to object syntax const $props = props as unknown as ComponentObjectPropsOptions @@ -106,13 +97,18 @@ const resolveComponentStubByName = ( } } -interface CreateStubComponentsTransformerConfig { +export interface CreateStubComponentsTransformerConfig { + rootComponents: { + legacy?: Component + component?: Component + } stubs?: Record shallow?: boolean renderStubDefaultSlot: boolean } export function createStubComponentsTransformer({ + rootComponents, stubs = {}, shallow = false, renderStubDefaultSlot = false @@ -166,11 +162,15 @@ export function createStubComponentsTransformer({ }) } - if (shouldNotStub(type)) { - // Either don't stub everytime or only on root level - if (!instance?.parent || !shouldNotStubRoot(type)) { - return type - } + if ( + // Don't stub VTU_ROOT component + !instance || + // Don't stub mounted component on root level + (rootComponents.component === type && !instance?.parent) || + // Don't stub component with compat wrapper + (rootComponents.legacy && rootComponents.legacy === type) + ) { + return type } const registeredName = getComponentRegisteredName(instance, type) @@ -225,7 +225,7 @@ export function createStubComponentsTransformer({ // Set name when using shallow without stub const stubName = name || registeredName || componentName - const newStub = + return ( config.plugins.createStubs?.({ name: stubName, component: type @@ -235,7 +235,7 @@ export function createStubComponentsTransformer({ type, renderStubDefaultSlot }) - return newStub + ) } return type