Skip to content

Commit d6bf1b8

Browse files
committed
feat(find): support functional components
1 parent 4a78737 commit d6bf1b8

File tree

6 files changed

+60
-3
lines changed

6 files changed

+60
-3
lines changed

src/lib/find-vue-components.js

+26
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@ function findAllVueComponentsFromVnode (
3131
return components
3232
}
3333

34+
function findAllFunctionalComponentsFromVnode (
35+
vnode: Component,
36+
components: Array<Component> = []
37+
): Array<Component> {
38+
if (vnode.fnOptions) {
39+
components.push(vnode)
40+
}
41+
if (vnode.children) {
42+
vnode.children.forEach((child) => {
43+
findAllFunctionalComponentsFromVnode(child, components)
44+
})
45+
}
46+
return components
47+
}
48+
3449
export function vmCtorMatchesName (vm: Component, name: string): boolean {
3550
return (vm.$vnode && vm.$vnode.componentOptions &&
3651
vm.$vnode.componentOptions.Ctor.options.name === name) ||
@@ -44,11 +59,22 @@ export function vmCtorMatchesSelector (component: Component, Ctor: Object) {
4459
return Ctors.some(c => Ctor[c] === component.__proto__.constructor)
4560
}
4661

62+
export function vmFunctionalCtorMatchesSelector (component: VNode, Ctor: Object) {
63+
const Ctors = Object.keys(component.fnOptions._Ctor)
64+
return Ctors.some(c => Ctor[c] === component.fnOptions._Ctor[c])
65+
}
66+
4767
export default function findVueComponents (
4868
root: Component,
4969
selectorType: ?string,
5070
selector: Object
5171
): Array<Component> {
72+
if (selector.functional) {
73+
const components = root._vnode
74+
? findAllFunctionalComponentsFromVnode(root._vnode)
75+
: findAllFunctionalComponentsFromVnode(root)
76+
return components.filter(component => vmFunctionalCtorMatchesSelector(component, selector._Ctor))
77+
}
5278
const components = root._isVue
5379
? findAllVueComponentsFromVm(root)
5480
: findAllVueComponentsFromVnode(root)

src/shallow.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,18 @@ import {
99
import mount from './mount'
1010
import type VueWrapper from './wrappers/vue-wrapper'
1111

12-
export default function shallow (component: Component, options: Options = {}): VueWrapper {
12+
export default function shallow (
13+
component: Component,
14+
options: Options = {}
15+
): VueWrapper {
1316
const vue = options.localVue || Vue
14-
1517
const stubbedComponents = createComponentStubsForAll(component)
16-
1718
const stubbedGlobalComponents = createComponentStubsForGlobals(vue)
1819

1920
return mount(component, {
2021
...options,
2122
components: {
23+
// stubbed components are used instead of original components components
2224
...stubbedGlobalComponents,
2325
...stubbedComponents,
2426
...options
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<template functional>
2+
<div />
3+
</template>

test/resources/test-utils.js

+4
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ export function attrsSupported () {
1313
export function listenersSupported () {
1414
return vueVersion > 2.3
1515
}
16+
17+
export function functionalSFCsSupported () {
18+
return vueVersion >= 2.5
19+
}

test/test.sh

+1
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ test_version_number "2.1.10"
1414
test_version_number "2.2.6"
1515
test_version_number "2.3.4"
1616
test_version_number "2.4.2"
17+
test_version_number "2.5.13"

test/unit/specs/mount/Wrapper/find.spec.js

+21
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import ComponentWithoutName from '~resources/components/component-without-name.v
66
import ComponentWithSlots from '~resources/components/component-with-slots.vue'
77
import ComponentWithVFor from '~resources/components/component-with-v-for.vue'
88
import Component from '~resources/components/component.vue'
9+
import FunctionalComponent from '~resources/components/functional-component.vue'
10+
import { functionalSFCsSupported } from '~resources/test-utils'
911

1012
describe('find', () => {
1113
it('returns a Wrapper matching tag selector passed', () => {
@@ -102,6 +104,25 @@ describe('find', () => {
102104
expect(wrapper.find(Component).vnode).to.be.an('object')
103105
})
104106

107+
it('returns Wrapper of Vue Component matching functional component', () => {
108+
if (!functionalSFCsSupported()) {
109+
return
110+
}
111+
const TestComponent = {
112+
template: `
113+
<div>
114+
<functional-component />
115+
</div>
116+
`,
117+
components: {
118+
FunctionalComponent
119+
}
120+
}
121+
122+
const wrapper = mount(TestComponent)
123+
expect(wrapper.find(FunctionalComponent).vnode).to.be.an('object')
124+
})
125+
105126
it('returns correct number of Vue Wrappers when component has a v-for', () => {
106127
const items = [{ id: 1 }, { id: 2 }, { id: 3 }]
107128
const wrapper = mount(ComponentWithVFor, { propsData: { items }})

0 commit comments

Comments
 (0)