Skip to content

Commit

Permalink
fix(find): do not find DOM node by ref if it is not inside element
Browse files Browse the repository at this point in the history
  • Loading branch information
xanf committed Nov 30, 2021
1 parent 125ea2f commit b118e9a
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 13 deletions.
15 changes: 9 additions & 6 deletions src/baseWrapper.ts
Expand Up @@ -45,9 +45,8 @@ export default abstract class BaseWrapper<ElementType extends Node>
find<K extends keyof SVGElementTagNameMap>(
selector: K
): DOMWrapper<SVGElementTagNameMap[K]>
find<T extends Element>(selector: string | RefSelector): DOMWrapper<T>
find(selector: string): DOMWrapper<Element>
find(selector: RefSelector): DOMWrapper<Node>
find<T extends Element = Element>(selector: string): DOMWrapper<T>
find<T extends Node = Node>(selector: string | RefSelector): DOMWrapper<T>
find(selector: string | RefSelector): DOMWrapper<Node> {
// allow finding the root element
if (!isElement(this.element)) {
Expand Down Expand Up @@ -227,9 +226,13 @@ export default abstract class BaseWrapper<ElementType extends Node>
get<K extends keyof SVGElementTagNameMap>(
selector: K
): Omit<DOMWrapper<SVGElementTagNameMap[K]>, 'exists'>
get<T extends Element>(selector: string): Omit<DOMWrapper<T>, 'exists'>
get(selector: RefSelector): Omit<DOMWrapper<Node>, 'exists'>
get(selector: string | RefSelector): Omit<DOMWrapper<Element>, 'exists'> {
get<T extends Element = Element>(
selector: string
): Omit<DOMWrapper<T>, 'exists'>
get<T extends Node = Node>(
selector: string | RefSelector
): Omit<DOMWrapper<T>, 'exists'>
get(selector: string | RefSelector): Omit<DOMWrapper<Node>, 'exists'> {
const result = this.find(selector)
if (result.exists()) {
return result
Expand Down
14 changes: 14 additions & 0 deletions src/domWrapper.ts
Expand Up @@ -3,6 +3,9 @@ import BaseWrapper from './baseWrapper'
import WrapperLike from './interfaces/wrapperLike'
import { isElement } from './utils/isElement'
import { registerFactory, WrapperType } from './wrapperFactory'
import { RefSelector } from './types'
import { isRefSelector } from './utils'
import { createWrapperError } from './errorWrapper'

export class DOMWrapper<NodeType extends Node> extends BaseWrapper<NodeType> {
constructor(element: NodeType) {
Expand All @@ -21,6 +24,17 @@ export class DOMWrapper<NodeType extends Node> extends BaseWrapper<NodeType> {
: this.element.toString()
}

find(selector: string | RefSelector): DOMWrapper<any> {
const result = super.find(selector)
if (result.exists() && isRefSelector(selector)) {
return this.element.contains(result.element)
? result
: createWrapperError('DOMWrapper')
}

return result
}

findAllComponents(selector: any): any {
const results = super.findAllComponents(selector)
return results.filter((r: WrapperLike) => this.element.contains(r.element))
Expand Down
14 changes: 8 additions & 6 deletions src/interfaces/wrapperLike.ts
Expand Up @@ -17,9 +17,8 @@ export default interface WrapperLike {
find<K extends keyof SVGElementTagNameMap>(
selector: K
): DOMWrapper<SVGElementTagNameMap[K]>
find<T extends Element>(selector: string | RefSelector): DOMWrapper<T>
find(selector: string): DOMWrapper<Element>
find(selector: RefSelector): DOMWrapper<Node>
find<T extends Element = Element>(selector: string): DOMWrapper<T>
find<T extends Node = Node>(selector: string | RefSelector): DOMWrapper<T>

findAll<K extends keyof HTMLElementTagNameMap>(
selector: K
Expand Down Expand Up @@ -68,9 +67,12 @@ export default interface WrapperLike {
get<K extends keyof SVGElementTagNameMap>(
selector: K
): Omit<DOMWrapper<SVGElementTagNameMap[K]>, 'exists'>
get<T extends Element>(selector: string): Omit<DOMWrapper<T>, 'exists'>
get(selector: RefSelector): Omit<DOMWrapper<Node>, 'exists'>
get(selector: string): Omit<DOMWrapper<Element>, 'exists'>
get<T extends Element = Element>(
selector: string
): Omit<DOMWrapper<T>, 'exists'>
get<T extends Node = Node>(
selector: string | RefSelector
): Omit<DOMWrapper<T>, 'exists'>

getComponent<T extends never>(selector: string): Omit<WrapperLike, 'exists'>
getComponent<T extends DefinedComponent>(
Expand Down
8 changes: 7 additions & 1 deletion src/utils.ts
@@ -1,4 +1,4 @@
import { GlobalMountOptions } from './types'
import { GlobalMountOptions, RefSelector } from './types'
import { ComponentOptions, ConcreteComponent, FunctionalComponent } from 'vue'
import { config } from './config'

Expand Down Expand Up @@ -107,3 +107,9 @@ export function hasOwnProperty<O extends {}, P extends PropertyKey>(
): obj is O & Record<P, unknown> {
return obj.hasOwnProperty(prop)
}

export function isRefSelector(
selector: string | RefSelector
): selector is RefSelector {
return typeof selector === 'object' && 'ref' in selector
}
15 changes: 15 additions & 0 deletions tests/find.spec.ts
Expand Up @@ -38,6 +38,21 @@ describe('find', () => {
expect(wrapper.find({ ref: 'plain' }).exists()).toBe(true)
expect(wrapper.find({ ref: 'plain' }).element).toBeInstanceOf(Text)
})

it('does not find ref located in the same component but not in current DOM wrapper', () => {
const Component = defineComponent({
render() {
return h('div', [
h('span', { ref: 'span', id: 'my-span' }),
h('div', { class: 'search-target' })
])
}
})
const wrapper = mount(Component)
expect(
wrapper.find('.search-target').find({ ref: 'span' }).exists()
).toBe(false)
})
})

it('find using multiple root nodes', () => {
Expand Down

0 comments on commit b118e9a

Please sign in to comment.