11// @flow
22
33import Vue from 'vue'
4- import { isValidSelector } from '../lib/validators '
4+ import getSelectorTypeOrThrow , { selectorTypes } from '../lib/get-selector-type '
55import findVueComponents , { vmCtorMatchesName } from '../lib/find-vue-components'
6- import findMatchingVNodes from '../lib/find-matching-vnodes'
6+ import findVNodesBySelector from '../lib/find-vnodes-by-selector'
7+ import findVNodesByRef from '../lib/find-vnodes-by-ref'
78import VueWrapper from './vue-wrapper'
89import WrapperArray from './wrapper-array'
910import ErrorWrapper from './error-wrapper'
@@ -36,16 +37,22 @@ export default class Wrapper implements BaseWrapper {
3637 * Checks if wrapper contains provided selector.
3738 */
3839 contains ( selector : Selector ) {
39- if ( ! isValidSelector ( selector ) ) {
40- throwError ( 'wrapper.contains() must be passed a valid CSS selector or a Vue constructor' )
41- }
40+ const selectorType = getSelectorTypeOrThrow ( selector , 'contains' )
4241
43- if ( typeof selector === 'object' ) {
42+ if ( selectorType === selectorTypes . VUE_COMPONENT ) {
4443 const vm = this . vm || this . vnode . context . $root
4544 return findVueComponents ( vm , selector . name ) . length > 0
4645 }
4746
48- if ( typeof selector === 'string' && this . element instanceof HTMLElement ) {
47+ if ( selectorType === selectorTypes . OPTIONS_OBJECT ) {
48+ if ( ! this . isVueComponent ) {
49+ throwError ( '$ref selectors can only be used on Vue component wrappers' )
50+ }
51+ const nodes = findVNodesByRef ( this . vnode , selector . ref )
52+ return nodes . length > 0
53+ }
54+
55+ if ( selectorType === selectorTypes . DOM_SELECTOR && this . element instanceof HTMLElement ) {
4956 return this . element . querySelectorAll ( selector ) . length > 0
5057 }
5158
@@ -174,12 +181,10 @@ export default class Wrapper implements BaseWrapper {
174181 /**
175182 * Finds first node in tree of the current wrapper that matches the provided selector.
176183 */
177- find ( selector : string ) : Wrapper | ErrorWrapper | VueWrapper {
178- if ( ! isValidSelector ( selector ) ) {
179- throwError ( 'wrapper.find() must be passed a valid CSS selector or a Vue constructor' )
180- }
184+ find ( selector : Selector ) : Wrapper | ErrorWrapper | VueWrapper {
185+ const selectorType = getSelectorTypeOrThrow ( selector , 'find' )
181186
182- if ( typeof selector === 'object' ) {
187+ if ( selectorType === selectorTypes . VUE_COMPONENT ) {
183188 if ( ! selector . name ) {
184189 throwError ( '.find() requires component to have a name property' )
185190 }
@@ -191,7 +196,18 @@ export default class Wrapper implements BaseWrapper {
191196 return new VueWrapper ( components [ 0 ] , this . options )
192197 }
193198
194- const nodes = findMatchingVNodes ( this . vnode , selector )
199+ if ( selectorType === selectorTypes . OPTIONS_OBJECT ) {
200+ if ( ! this . isVueComponent ) {
201+ throwError ( '$ref selectors can only be used on Vue component wrappers' )
202+ }
203+ const nodes = findVNodesByRef ( this . vnode , selector . ref )
204+ if ( nodes . length === 0 ) {
205+ return new ErrorWrapper ( `ref="${ selector . ref } "` )
206+ }
207+ return new Wrapper ( nodes [ 0 ] , this . update , this . options )
208+ }
209+
210+ const nodes = findVNodesBySelector ( this . vnode , selector )
195211
196212 if ( nodes . length === 0 ) {
197213 return new ErrorWrapper ( selector )
@@ -203,11 +219,9 @@ export default class Wrapper implements BaseWrapper {
203219 * Finds node in tree of the current wrapper that matches the provided selector.
204220 */
205221 findAll ( selector : Selector ) : WrapperArray {
206- if ( ! isValidSelector ( selector ) ) {
207- throwError ( 'wrapper.findAll() must be passed a valid CSS selector or a Vue constructor' )
208- }
222+ const selectorType = getSelectorTypeOrThrow ( selector , 'findAll' )
209223
210- if ( typeof selector === 'object' ) {
224+ if ( selectorType === selectorTypes . VUE_COMPONENT ) {
211225 if ( ! selector . name ) {
212226 throwError ( '.findAll() requires component to have a name property' )
213227 }
@@ -216,11 +230,19 @@ export default class Wrapper implements BaseWrapper {
216230 return new WrapperArray ( components . map ( component => new VueWrapper ( component , this . options ) ) )
217231 }
218232
233+ if ( selectorType === selectorTypes . OPTIONS_OBJECT ) {
234+ if ( ! this . isVueComponent ) {
235+ throwError ( '$ref selectors can only be used on Vue component wrappers' )
236+ }
237+ const nodes = findVNodesByRef ( this . vnode , selector . ref )
238+ return new WrapperArray ( nodes . map ( node => new Wrapper ( node , this . update , this . options ) ) )
239+ }
240+
219241 function nodeMatchesSelector ( node , selector ) {
220242 return node . elm && node . elm . getAttribute && node . elm . matches ( selector )
221243 }
222244
223- const nodes = findMatchingVNodes ( this . vnode , selector )
245+ const nodes = findVNodesBySelector ( this . vnode , selector )
224246 const matchingNodes = nodes . filter ( node => nodeMatchesSelector ( node , selector ) )
225247
226248 return new WrapperArray ( matchingNodes . map ( node => new Wrapper ( node , this . update , this . options ) ) )
@@ -237,20 +259,23 @@ export default class Wrapper implements BaseWrapper {
237259 * Checks if node matches selector
238260 */
239261 is ( selector : Selector ) : boolean {
240- if ( ! isValidSelector ( selector ) ) {
241- throwError ( 'wrapper.is() must be passed a valid CSS selector or a Vue constructor' )
242- }
262+ const selectorType = getSelectorTypeOrThrow ( selector , 'is' )
243263
244- if ( typeof selector === 'object' ) {
245- if ( ! this . isVueComponent ) {
246- return false
247- }
264+ if ( selectorType === selectorTypes . VUE_COMPONENT && this . isVueComponent ) {
248265 if ( typeof selector . name !== 'string' ) {
249266 throwError ( 'a Component used as a selector must have a name property' )
250267 }
251268 return vmCtorMatchesName ( this . vm , selector . name )
252269 }
253270
271+ if ( selectorType === selectorTypes . OPTIONS_OBJECT ) {
272+ throwError ( '$ref selectors can not be used with wrapper.is()' )
273+ }
274+
275+ if ( typeof selector === 'object' ) {
276+ return false
277+ }
278+
254279 return ! ! ( this . element &&
255280 this . element . getAttribute &&
256281 this . element . matches ( selector ) )
0 commit comments