forked from vuejs/vue-test-utils
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfind.js
123 lines (109 loc) · 2.84 KB
/
find.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// @flow
import findDOMNodes from './find-dom-nodes'
import {
DOM_SELECTOR,
REF_SELECTOR,
COMPONENT_SELECTOR,
VUE_VERSION
} from 'shared/consts'
import { throwError } from 'shared/util'
import { matches } from './matches'
export function findAllInstances (rootVm: any) {
const instances = [rootVm]
let i = 0
while (i < instances.length) {
const vm = instances[i]
;(vm.$children || []).forEach(child => {
instances.push(child)
})
i++
}
return instances
}
function findAllVNodes (
vnode: VNode,
selector: any
): Array<VNode> {
const matchingNodes = []
const nodes = [vnode]
while (nodes.length) {
const node = nodes.shift()
if (node.children) {
const children = [...node.children].reverse()
children.forEach((n) => {
nodes.unshift(n)
})
}
if (node.child) {
nodes.unshift(node.child._vnode)
}
if (matches(node, selector)) {
matchingNodes.push(node)
}
}
return matchingNodes
}
function removeDuplicateNodes (vNodes: Array<VNode>): Array<VNode> {
const vNodeElms = vNodes.map(vNode => vNode.elm)
return vNodes.filter(
(vNode, index) => index === vNodeElms.indexOf(vNode.elm)
)
}
export default function find (
root: VNode | Element,
vm?: Component,
selector: Selector
): Array<VNode | Component> {
if ((root instanceof Element) && selector.type !== DOM_SELECTOR) {
throwError(
`cannot find a Vue instance on a DOM node. The node ` +
`you are calling find on does not exist in the ` +
`VDom. Are you adding the node as innerHTML?`
)
}
if (
selector.type === COMPONENT_SELECTOR &&
(
selector.value.functional ||
(selector.value.options &&
selector.value.options.functional)
) &&
VUE_VERSION < 2.3
) {
throwError(
`find for functional components is not supported ` +
`in Vue < 2.3`
)
}
if (root instanceof Element) {
return findDOMNodes(root, selector.value)
}
if (!root && selector.type !== DOM_SELECTOR) {
throwError(
`cannot find a Vue instance on a DOM node. The node ` +
`you are calling find on does not exist in the ` +
`VDom. Are you adding the node as innerHTML?`
)
}
if (!vm && selector.type === REF_SELECTOR) {
throwError(
`$ref selectors can only be used on Vue component ` + `wrappers`
)
}
if (
vm &&
vm.$refs &&
selector.value.ref in vm.$refs
) {
const refs = vm.$refs[selector.value.ref]
return Array.isArray(refs) ? refs : [refs]
}
const nodes = findAllVNodes(root, selector)
const dedupedNodes = removeDuplicateNodes(nodes)
if (nodes.length > 0 || selector.type !== DOM_SELECTOR) {
return dedupedNodes
}
// Fallback in case element exists in HTML, but not in vnode tree
// (e.g. if innerHTML is set as a domProp)
return findDOMNodes(root.elm, selector.value)
}