diff --git a/package.json b/package.json index edfbbecdc..20b7c67f9 100644 --- a/package.json +++ b/package.json @@ -47,5 +47,9 @@ "*.ts": [ "prettier --parser=typescript --write" ] + }, + "dependencies": { + "@types/lodash": "^4.14.149", + "lodash": "^4.17.15" } } diff --git a/src/mount.ts b/src/mount.ts index 3454ea7be..9b63fcbd4 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -3,6 +3,7 @@ import { createApp, VNode, defineComponent, + transformVNodeArgs, VNodeNormalizedChildren, VNodeProps, ComponentOptions, @@ -10,6 +11,7 @@ import { Directive, Component } from 'vue' +import { isEqual, kebabCase } from 'lodash' import { VueWrapper, createWrapper } from './vue-wrapper' import { createEmitMixin } from './emitMixin' @@ -20,6 +22,7 @@ type Slot = VNode | string interface MountingOptions { data?: () => Record + shallow?: boolean props?: Props slots?: { default?: Slot @@ -61,8 +64,10 @@ export function mount

( } // create the wrapper component + const PARENT_NAME = 'VTU_PARENT' const Parent = (props?: VNodeProps) => defineComponent({ + name: PARENT_NAME, render() { return h(component, { ...props, ref: 'VTU_COMPONENT' }, slots) } @@ -99,6 +104,34 @@ export function mount

( } } + if (options?.shallow) { + transformVNodeArgs((args, instance) => { + // VTU Root node. Keep this or there won't be anything to render! + if (typeof args[0] === 'object' && args[0]['name'] === PARENT_NAME) { + return args + } + + // original component we are mounting - don't stub that! + if (isEqual(args[0], originalComponent)) { + return args + } + + // regular HTML tags + if (typeof args[0] === 'string') { + return args + } + + // don't care about comments/fragments + if (typeof args[0] === 'symbol') { + return args + } + + // must be a custom component. Stub! + const name = kebabCase(args[0]['name'] || 'anonymous') + return [`${name}-stub`] + }) + } + // add tracking for emitted events const { emitMixin, events } = createEmitMixin() vm.mixin(emitMixin) diff --git a/tests/mountingOptions/shallow.spec.ts b/tests/mountingOptions/shallow.spec.ts new file mode 100644 index 000000000..7cc8090fd --- /dev/null +++ b/tests/mountingOptions/shallow.spec.ts @@ -0,0 +1,49 @@ +import { h } from 'vue' + +import { mount } from '../../src' + +describe('mounting options: shallow', () => { + it('stubs everything with a single root node', async () => { + const Bar = { + name: 'Bar', + render() { + return h('div', { id: 'bar' }, 'Bar') + } + } + const Foo = { + name: 'Foo', + render() { + return h('div', [h('p', 'hello'), h(Bar)]) + } + } + + const wrapper = mount(Foo, { + shallow: true + }) + + expect(wrapper.html()).toBe('

hello

') + expect(wrapper.find('bar-stub').exists()).toBeTruthy() + }) + + it('stubs everything with a single root node', async () => { + const Bar = { + name: 'Bar', + render() { + return h('div', { id: 'bar' }, 'Bar') + } + } + const Foo = { + name: 'Foo', + render() { + return [h(Bar), h(Bar)] + } + } + + const wrapper = mount(Foo, { + shallow: true + }) + + expect(wrapper.html()).toBe('') + expect(wrapper.find('bar-stub').exists()).toBeTruthy() + }) +}) diff --git a/yarn.lock b/yarn.lock index 31c63e725..cf506c335 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1151,6 +1151,11 @@ dependencies: jest-diff "^24.3.0" +"@types/lodash@^4.14.149": + version "4.14.149" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" + integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ== + "@types/node@*": version "13.7.4" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.4.tgz#76c3cb3a12909510f52e5dc04a6298cdf9504ffd"