Skip to content

Commit 6f435d1

Browse files
refactor: update find matching methods
1 parent e29f288 commit 6f435d1

File tree

5 files changed

+67
-30
lines changed

5 files changed

+67
-30
lines changed

src/types.ts

+11
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,14 @@ export interface WrapperAPI {
1212
text: () => string
1313
trigger: (eventString: string) => Promise<(fn?: () => void) => Promise<void>>
1414
}
15+
16+
interface RefSelector {
17+
ref: string
18+
}
19+
20+
interface NameSelector {
21+
name: string
22+
}
23+
24+
export type FindComponentSelector = RefSelector | NameSelector | string
25+
export type FindAllComponentsSelector = NameSelector | string

src/utils/find.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { VNode, ComponentPublicInstance } from 'vue'
2+
import { FindAllComponentsSelector } from '../types'
3+
import { matchName } from './matchName'
24

3-
function matches(node: VNode, selector): boolean {
5+
function matches(node: VNode, selector: FindAllComponentsSelector): boolean {
46
if (typeof selector === 'string') {
57
return node.el?.matches?.(selector)
68
}
7-
if (typeof selector === 'object') {
8-
if (selector.name && typeof node.type === 'object') {
9-
// @ts-ignore
10-
return node.type.name === selector.name
9+
if (typeof selector === 'object' && typeof node.type === 'object') {
10+
if (selector.name && ('name' in node.type || 'displayName' in node.type)) {
11+
// match normal component definitions or functional components
12+
return matchName(selector.name, node.type.name || node.type.displayName)
1113
}
1214
}
1315
return false

src/utils/matchName.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { camelize, capitalize } from '@vue/shared'
2+
3+
export function matchName(target, sourceName) {
4+
const camelized = camelize(target)
5+
const capitalized = capitalize(camelized)
6+
7+
return (
8+
sourceName &&
9+
(sourceName === target ||
10+
sourceName === camelized ||
11+
sourceName === capitalized ||
12+
capitalize(camelize(sourceName)) === capitalized)
13+
)
14+
}

src/vue-wrapper.ts

+5-12
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,15 @@ import { ComponentPublicInstance, nextTick } from 'vue'
22
import { ShapeFlags } from '@vue/shared'
33

44
import { DOMWrapper } from './dom-wrapper'
5-
import { WrapperAPI } from './types'
5+
import {
6+
FindAllComponentsSelector,
7+
FindComponentSelector,
8+
WrapperAPI
9+
} from './types'
610
import { ErrorWrapper } from './error-wrapper'
711
import { MOUNT_ELEMENT_ID } from './constants'
812
import { find } from './utils/find'
913

10-
interface RefSelector {
11-
ref: string
12-
}
13-
14-
interface NameSelector {
15-
name: string
16-
}
17-
18-
type FindComponentSelector = RefSelector | NameSelector | string
19-
type FindAllComponentsSelector = NameSelector | string
20-
2114
export class VueWrapper implements WrapperAPI {
2215
private componentVM: ComponentPublicInstance
2316
private __emitted: Record<string, unknown[]> = {}

tests/findComponent.spec.ts

+30-13
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,45 @@
11
import { mount } from '../src'
22
import Hello from './components/Hello.vue'
33

4+
const compC = {
5+
name: 'ComponentC',
6+
template: '<div class="C">C</div>'
7+
}
8+
const compB = {
9+
name: 'component-b',
10+
template: '<div class="B">TextBefore<comp-c/>TextAfter<comp-c/></div>',
11+
components: { compC }
12+
}
13+
const compA = {
14+
template: '<div class="A"><comp-b/><hello ref="b"/></div>',
15+
components: { compB, Hello }
16+
}
17+
418
describe('findComponent', () => {
5-
it('finds deeply nested vue components', () => {
6-
const compC = {
7-
name: 'ComponentC',
8-
template: '<div class="C">C</div>'
9-
}
10-
const compB = {
11-
template: '<div class="B">TextBefore<comp-c/>TextAfter<comp-c/></div>',
12-
components: { compC }
13-
}
14-
const compA = {
15-
template: '<div class="A"><comp-b/><hello ref="b"/></div>',
16-
components: { compB, Hello }
17-
}
19+
it('finds component by ref', () => {
1820
const wrapper = mount(compA)
1921
// find by ref
2022
expect(wrapper.findComponent({ ref: 'b' })).toBeTruthy()
23+
})
24+
25+
it('finds component by dom selector', () => {
26+
const wrapper = mount(compA)
2127
// find by DOM selector
2228
expect(wrapper.findComponent('.C').$options.name).toEqual('ComponentC')
29+
})
30+
31+
it('finds component by name', () => {
32+
const wrapper = mount(compA)
2333
expect(wrapper.findComponent({ name: 'Hello' }).$el.textContent).toBe(
2434
'Hello world'
2535
)
36+
expect(wrapper.findComponent({ name: 'ComponentB' })).toBeTruthy()
37+
expect(wrapper.findComponent({ name: 'component-c' })).toBeTruthy()
38+
})
39+
40+
it('finds component by imported SFC file', () => {
41+
const wrapper = mount(compA)
2642
expect(wrapper.findComponent(Hello).$el.textContent).toBe('Hello world')
43+
expect(wrapper.findComponent(compC).$el.textContent).toBe('C')
2744
})
2845
})

0 commit comments

Comments
 (0)