Skip to content

Commit

Permalink
fix(find): finding by ref may return Node, not just Element
Browse files Browse the repository at this point in the history
  • Loading branch information
xanf committed Nov 30, 2021
1 parent bfce74d commit 125ea2f
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 24 deletions.
18 changes: 12 additions & 6 deletions src/baseWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ export default abstract class BaseWrapper<ElementType extends Node>
selector: K
): DOMWrapper<SVGElementTagNameMap[K]>
find<T extends Element>(selector: string | RefSelector): DOMWrapper<T>
find(selector: string | RefSelector): DOMWrapper<Element>
find(selector: string | RefSelector): DOMWrapper<Element> {
find(selector: string): DOMWrapper<Element>
find(selector: RefSelector): DOMWrapper<Node>
find(selector: string | RefSelector): DOMWrapper<Node> {
// allow finding the root element
if (!isElement(this.element)) {
return createWrapperError('DOMWrapper')
Expand All @@ -61,7 +62,7 @@ export default abstract class BaseWrapper<ElementType extends Node>

const result = currentComponent.refs[selector.ref]

if (result instanceof HTMLElement) {
if (result instanceof Node) {
return createDOMWrapper(result)
} else {
return createWrapperError('DOMWrapper')
Expand Down Expand Up @@ -110,8 +111,9 @@ export default abstract class BaseWrapper<ElementType extends Node>
selector: T | Exclude<FindComponentSelector, FunctionalComponent>
): VueWrapper<InstanceType<T>>
// searching for functional component results in DOMWrapper
findComponent<T extends FunctionalComponent>(selector: T): DOMWrapper<Node>
findComponent<T extends FunctionalComponent>(
selector: T | string
selector: string
): DOMWrapper<Element>
// searching by name or ref always results in VueWrapper
findComponent<T extends never>(
Expand Down Expand Up @@ -154,7 +156,10 @@ export default abstract class BaseWrapper<ElementType extends Node>
selector: T | Exclude<FindAllComponentsSelector, FunctionalComponent>
): VueWrapper<InstanceType<T>>[]
findAllComponents<T extends FunctionalComponent>(
selector: T | string
selector: T
): DOMWrapper<Node>[]
findAllComponents<T extends FunctionalComponent>(
selector: string
): DOMWrapper<Element>[]
findAllComponents<T extends never>(selector: NameSelector): VueWrapper[]
findAllComponents<T extends ComponentPublicInstance>(
Expand Down Expand Up @@ -223,7 +228,8 @@ export default abstract class BaseWrapper<ElementType extends Node>
selector: K
): Omit<DOMWrapper<SVGElementTagNameMap[K]>, 'exists'>
get<T extends Element>(selector: string): Omit<DOMWrapper<T>, 'exists'>
get(selector: string): Omit<DOMWrapper<Element>, 'exists'> {
get(selector: RefSelector): Omit<DOMWrapper<Node>, 'exists'>
get(selector: string | RefSelector): Omit<DOMWrapper<Element>, 'exists'> {
const result = this.find(selector)
if (result.exists()) {
return result
Expand Down
2 changes: 1 addition & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface Plugin<Instance, O> {
options: O
}

class Pluggable<Instance = DOMWrapper<Element>> {
class Pluggable<Instance = DOMWrapper<Node>> {
installedPlugins: Plugin<Instance, any>[] = []

install<O>(handler: (instance: Instance) => Record<string, any>): void
Expand Down
13 changes: 7 additions & 6 deletions src/interfaces/wrapperLike.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export default interface WrapperLike {
selector: K
): DOMWrapper<SVGElementTagNameMap[K]>
find<T extends Element>(selector: string | RefSelector): DOMWrapper<T>
find(selector: string | RefSelector): DOMWrapper<Element>
find(selector: string): DOMWrapper<Element>
find(selector: RefSelector): DOMWrapper<Node>

findAll<K extends keyof HTMLElementTagNameMap>(
selector: K
Expand Down Expand Up @@ -50,8 +51,11 @@ export default interface WrapperLike {
selector: T | Exclude<FindAllComponentsSelector, FunctionalComponent>
): VueWrapper<InstanceType<T>>[]
findAllComponents<T extends FunctionalComponent>(
selector: T | string
selector: string
): DOMWrapper<Element>[]
findAllComponents<T extends FunctionalComponent>(
selector: T
): DOMWrapper<Node>[]
findAllComponents<T extends never>(selector: NameSelector): VueWrapper[]
findAllComponents<T extends ComponentPublicInstance>(
selector: T | FindAllComponentsSelector
Expand All @@ -65,6 +69,7 @@ export default interface WrapperLike {
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'>

getComponent<T extends never>(selector: string): Omit<WrapperLike, 'exists'>
Expand All @@ -75,10 +80,6 @@ export default interface WrapperLike {
getComponent<T extends FunctionalComponent>(
selector: T | string
): Omit<DOMWrapper<Element>, 'exists'>
// searching by name or ref always results in VueWrapper
getComponent<T extends never>(
selector: NameSelector | RefSelector
): Omit<VueWrapper, 'exists'>
getComponent<T extends ComponentPublicInstance>(
selector: T | FindComponentSelector
): Omit<VueWrapper<T>, 'exists'>
Expand Down
2 changes: 1 addition & 1 deletion src/wrapperFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export enum WrapperType {
VueWrapper
}

type DOMWrapperFactory = <T extends Element>(element: T) => DOMWrapperType<T>
type DOMWrapperFactory = <T extends Node>(element: T) => DOMWrapperType<T>
type VueWrapperFactory = <T extends ComponentPublicInstance>(
app: App | null,
vm: T,
Expand Down
2 changes: 1 addition & 1 deletion test-dts/findComponent.d-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ expectType<VueWrapper<InstanceType<typeof ComponentWithEmits>>>(

// find by type - functional
const functionalComponentByType = wrapper.findComponent(FuncComponent)
expectType<DOMWrapper<Element>>(functionalComponentByType)
expectType<DOMWrapper<Node>>(functionalComponentByType)

// find by string
const componentByString = wrapper.findComponent('.foo')
Expand Down
32 changes: 23 additions & 9 deletions tests/find.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineComponent, h, nextTick } from 'vue'
import { defineComponent, h, nextTick, Fragment } from 'vue'

import { mount, VueWrapper } from '../src'
import SuspenseComponent from './components/Suspense.vue'
Expand All @@ -15,15 +15,29 @@ describe('find', () => {
expect(wrapper.find('#my-span').exists()).toBe(true)
})

it('find DOM element by ref', () => {
const Component = defineComponent({
render() {
return h('div', {}, [h('span', { ref: 'span', id: 'my-span' })])
}
describe('find DOM element by ref', () => {
it('works for root element', () => {
const Component = defineComponent({
render() {
return h('div', {}, [h('span', { ref: 'span', id: 'my-span' })])
}
})
const wrapper = mount(Component)
expect(wrapper.find({ ref: 'span' }).exists()).toBe(true)
expect(wrapper.find({ ref: 'span' }).attributes('id')).toBe('my-span')
})

it('works when ref is pointing to non-element node', () => {
const Component = defineComponent({
render() {
return h('div', null, h(Fragment, { ref: 'plain' }, ['hello']))
}
})

const wrapper = mount(Component)
expect(wrapper.find({ ref: 'plain' }).exists()).toBe(true)
expect(wrapper.find({ ref: 'plain' }).element).toBeInstanceOf(Text)
})
const wrapper = mount(Component)
expect(wrapper.find({ ref: 'span' }).exists()).toBe(true)
expect(wrapper.find({ ref: 'span' }).attributes('id')).toBe('my-span')
})

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

0 comments on commit 125ea2f

Please sign in to comment.