Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: shallow config issue #607

Merged
merged 4 commits into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { GlobalMountOptions } from './types'
import { VueWrapper } from './vueWrapper'
import { DOMWrapper } from './domWrapper'

interface GlobalConfigOptions {
export interface GlobalConfigOptions {
global: Required<GlobalMountOptions>
plugins: {
VueWrapper: Pluggable<VueWrapper<ComponentPublicInstance>>
Expand Down
14 changes: 7 additions & 7 deletions src/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,7 @@ export function mount(
...options?.props,
ref: MOUNT_COMPONENT_REF
})

const global = mergeGlobalProperties(config.global, options?.global)
const global = mergeGlobalProperties(options?.global)
component.components = { ...component.components, ...global.components }

// create the wrapper component
Expand Down Expand Up @@ -412,10 +411,7 @@ export function mount(
// stubs
// even if we are using `mount`, we will still
// stub out Transition and Transition Group by default.
stubComponents(
global.stubs,
global.renderStubDefaultSlot ? false : options?.shallow
)
stubComponents(global.stubs, options?.shallow, global?.renderStubDefaultSlot)

// users expect stubs to work with globally registered
// components, too, such as <router-link> and <router-view>
Expand All @@ -427,7 +423,11 @@ export function mount(
if (global?.stubs) {
for (const [name, stub] of Object.entries(global.stubs)) {
if (stub === true) {
const stubbed = createStub({ name, props: {} })
const stubbed = createStub({
name,
props: {},
renderStubDefaultSlot: global?.renderStubDefaultSlot
})
// default stub.
app.component(name, stubbed)
} else {
Expand Down
23 changes: 13 additions & 10 deletions src/stubs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,27 @@ import {
} from 'vue'
import { hyphenate } from './utils/vueShared'
import { MOUNT_COMPONENT_REF, MOUNT_PARENT_NAME } from './constants'
import { config } from './config'
import { matchName } from './utils/matchName'
import { ComponentInternalInstance } from '@vue/runtime-core'

interface StubOptions {
name: string
props?: any
propsDeclaration?: any
}

function getSlots(ctx: ComponentPublicInstance): Slots | undefined {
return !config.renderStubDefaultSlot ? undefined : ctx.$slots
renderStubDefaultSlot?: boolean
Copy link
Contributor Author

@YutamaKotaro YutamaKotaro May 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In mount.ts, mergedConfig is used like this.

  const global = mergeGlobalProperties(config.global, options?.global)

So, I unified using mergetConfig.

}

export const createStub = ({
name,
props,
propsDeclaration
propsDeclaration,
renderStubDefaultSlot
}: StubOptions): ComponentOptions => {
const anonName = 'anonymous-stub'
const tag = name ? `${hyphenate(name)}-stub` : anonName

const render = (ctx: ComponentPublicInstance) => {
return h(tag, props, getSlots(ctx))
return h(tag, props, renderStubDefaultSlot ? ctx.$slots : undefined)
}

return defineComponent({
Expand Down Expand Up @@ -112,7 +109,8 @@ const isFunctionalComponent = (type: VNodeTypes): type is ComponentOptions =>

export function stubComponents(
stubs: Record<any, any> = {},
shallow: boolean = false
shallow: boolean = false,
renderStubDefaultSlot: boolean = false
) {
transformVNodeArgs((args, instance: ComponentInternalInstance | null) => {
const [nodeType, props, children, patchFlag, dynamicProps] = args
Expand Down Expand Up @@ -161,7 +159,7 @@ export function stubComponents(

// No name found?
if (!registeredName && !componentName) {
return shallow ? ['stub'] : args
return renderStubDefaultSlot || !shallow ? args : ['stub']
}

let stub = null
Expand Down Expand Up @@ -199,7 +197,12 @@ export function stubComponents(
}

const propsDeclaration = type?.props || {}
const newStub = createStub({ name, propsDeclaration, props })
const newStub = createStub({
name,
propsDeclaration,
props,
renderStubDefaultSlot
})
stubs[name] = newStub
return [newStub, props, children, patchFlag, dynamicProps]
}
Expand Down
13 changes: 8 additions & 5 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { GlobalMountOptions } from './types'
import { AppConfig } from 'vue'
import { config } from './config'

function mergeStubs(target: Record<string, any>, source: GlobalMountOptions) {
if (source.stubs) {
Expand All @@ -14,14 +15,18 @@ function mergeStubs(target: Record<string, any>, source: GlobalMountOptions) {
}

export function mergeGlobalProperties(
configGlobal: GlobalMountOptions = {},
mountGlobal: GlobalMountOptions = {}
): Required<GlobalMountOptions> {
const stubs: Record<string, any> = {}

const configGlobal: GlobalMountOptions = config?.global ?? {}
mergeStubs(stubs, configGlobal)
mergeStubs(stubs, mountGlobal)

const renderStubDefaultSlot =
mountGlobal.renderStubDefaultSlot ??
config?.renderStubDefaultSlot ??
configGlobal?.renderStubDefaultSlot

return {
mixins: [...(configGlobal.mixins || []), ...(mountGlobal.mixins || [])],
plugins: [...(configGlobal.plugins || []), ...(mountGlobal.plugins || [])],
Expand All @@ -31,9 +36,7 @@ export function mergeGlobalProperties(
mocks: { ...configGlobal.mocks, ...mountGlobal.mocks },
config: { ...configGlobal.config, ...mountGlobal.config },
directives: { ...configGlobal.directives, ...mountGlobal.directives },
renderStubDefaultSlot: !!(mountGlobal.renderStubDefaultSlot !== undefined
? mountGlobal.renderStubDefaultSlot
: configGlobal.renderStubDefaultSlot)
Copy link
Contributor Author

@YutamaKotaro YutamaKotaro May 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This library has three points where we can write renderStubDefaultSlot option.

  • mount function
  • config.global object
  • config object

The last one, I wasn't able to find in document, but it exists in GlobalConfigOptions.
So, I fixed code to use one of them (priority: mount -> config -> config.global).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or if it's for internal, I'll fix my code 🙇🏻

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense, nice job figuring this out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot !!
It's an honor to hear you say that. 🙇🏻

renderStubDefaultSlot
}
}

Expand Down
26 changes: 26 additions & 0 deletions tests/mountingOptions/global.components.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { mount } from '../../src'
import { defineComponent } from 'vue'

describe('global.components', () => {
it('registers a component to all components', () => {
Expand Down Expand Up @@ -70,4 +71,29 @@ describe('global.components', () => {
spy.mockRestore()
expect(wrapper.text()).toBe('Global')
})
it('render children with shallow and renderStubDefaultSlot', () => {
const Child = defineComponent({
template: '<div><p>child</p><slot /></div>'
})
const Component = defineComponent({
template: '<div><Child><div>hello</div></Child></div>',
components: {
Child
}
})
const wrapper = mount(Component, {
shallow: true,
global: {
renderStubDefaultSlot: true
}
})

expect(wrapper.html()).toEqual(
'<div>\n' +
' <child-stub>\n' +
' <div>hello</div>\n' +
' </child-stub>\n' +
'</div>'
)
})
})