From e0fd13145ce96978733c5c7630f295418e84d527 Mon Sep 17 00:00:00 2001 From: cexbrayat Date: Fri, 24 Apr 2020 14:09:57 +0200 Subject: [PATCH 1/2] feat: getComponent This introduces a `getComponent` which returns a `VueWrapper` or throws. It offers two benefits: - a symetric API for components/elements with `findComponent/findAllComponents/getComponent`/`find/findAll/get` - a better experience for TS users (as `findComponent` returns a union type, you can't chain certain things until you disambiguated the type manually). I also refactored the signatures of `find` to offer proper overloads (the current version breaks tests compilation in a real app, i hope this fixes it). I added TSD tests to ensure the inference is working properly. --- src/vue-wrapper.ts | 29 +++++++++++++++++++++++- test-dts/getComponent.d-test.ts | 39 +++++++++++++++++++++++++++++++++ tests/getComponent.spec.ts | 23 +++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 test-dts/getComponent.d-test.ts create mode 100644 tests/getComponent.spec.ts diff --git a/src/vue-wrapper.ts b/src/vue-wrapper.ts index c555439ed..63fbf6b5b 100644 --- a/src/vue-wrapper.ts +++ b/src/vue-wrapper.ts @@ -112,7 +112,15 @@ export class VueWrapper return result } - findComponent(selector: FindComponentSelector): VueWrapper | ErrorWrapper { + findComponent( + selector: new () => T + ): VueWrapper | ErrorWrapper + findComponent( + selector: FindComponentSelector + ): VueWrapper | ErrorWrapper + findComponent( + selector: any + ): VueWrapper | ErrorWrapper { if (typeof selector === 'object' && 'ref' in selector) { const result = this.vm.$refs[selector.ref] return result @@ -125,6 +133,25 @@ export class VueWrapper return createWrapper(null, result[0]) } + getComponent( + selector: new () => T + ): VueWrapper + getComponent( + selector: FindComponentSelector + ): VueWrapper + getComponent( + selector: any + ): VueWrapper { + const result = this.findComponent(selector) + if (result instanceof ErrorWrapper) { + throw new Error( + `Unable to find component with selector ${selector} within: ${this.html()}` + ) + } + + return result as VueWrapper + } + findAllComponents(selector: FindAllComponentsSelector): VueWrapper[] { return find(this.vm.$.subTree, selector).map((c) => createWrapper(null, c)) } diff --git a/test-dts/getComponent.d-test.ts b/test-dts/getComponent.d-test.ts new file mode 100644 index 000000000..ce59a6342 --- /dev/null +++ b/test-dts/getComponent.d-test.ts @@ -0,0 +1,39 @@ +import { expectType } from 'tsd' +import { defineComponent, ComponentPublicInstance } from 'vue' +import { mount } from '../src' + +const ComponentToFind = defineComponent({ + props: { + a: { + type: String, + required: true + } + }, + template: '' +}) + +const AppWithDefine = defineComponent({ + template: '' +}) + +const wrapper = mount(AppWithDefine) + +// get by type +const componentByType = wrapper.getComponent(ComponentToFind) +// returns a wrapper with properly typed vm +expectType(componentByType.vm.a) + +// get by name +const componentByName = wrapper.getComponent({ name: 'ComponentToFind' }) +// returns a wrapper with a generic vm (any) +expectType(componentByName.vm) + +// get by string +const componentByString = wrapper.getComponent('other') +// returns a wrapper with a generic vm (any) +expectType(componentByString.vm) + +// get by ref +const componentByRef = wrapper.getComponent({ ref: 'ref' }) +// returns a wrapper with a generic vm (any) +expectType(componentByRef.vm) diff --git a/tests/getComponent.spec.ts b/tests/getComponent.spec.ts new file mode 100644 index 000000000..05749132e --- /dev/null +++ b/tests/getComponent.spec.ts @@ -0,0 +1,23 @@ +import { defineComponent } from 'vue' +import { mount } from '../src' +import { VueWrapper } from '../src/vue-wrapper' + +const compA = defineComponent({ + template: `
` +}) + +describe('getComponent', () => { + it('should delegate to findComponent', () => { + const wrapper = mount(compA) + jest.spyOn(wrapper, 'findComponent').mockReturnThis() + wrapper.getComponent('.domElement') + expect(wrapper.findComponent).toHaveBeenCalledWith('.domElement') + }) + + it('should throw if not found', () => { + const wrapper = mount(compA) + expect(() => wrapper.getComponent('.domElement')).toThrowError( + 'Unable to find component with selector .domElement within:
' + ) + }) +}) From e1ab0d88a44e6866c1af62801bfe7251cdd194bf Mon Sep 17 00:00:00 2001 From: cexbrayat Date: Fri, 24 Apr 2020 15:47:46 +0200 Subject: [PATCH 2/2] fix: reword error message for get/getComponent --- src/vue-wrapper.ts | 4 ++-- tests/get.spec.ts | 2 +- tests/getComponent.spec.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vue-wrapper.ts b/src/vue-wrapper.ts index 63fbf6b5b..f4728f2ea 100644 --- a/src/vue-wrapper.ts +++ b/src/vue-wrapper.ts @@ -106,7 +106,7 @@ export class VueWrapper get(selector: string): DOMWrapper { const result = this.find(selector) if (result instanceof ErrorWrapper) { - throw new Error(`Unable to find ${selector} within: ${this.html()}`) + throw new Error(`Unable to get ${selector} within: ${this.html()}`) } return result @@ -145,7 +145,7 @@ export class VueWrapper const result = this.findComponent(selector) if (result instanceof ErrorWrapper) { throw new Error( - `Unable to find component with selector ${selector} within: ${this.html()}` + `Unable to get component with selector ${selector} within: ${this.html()}` ) } diff --git a/tests/get.spec.ts b/tests/get.spec.ts index 806ffe9bd..a9ac12285 100644 --- a/tests/get.spec.ts +++ b/tests/get.spec.ts @@ -23,7 +23,7 @@ describe('get', () => { const wrapper = mount(Component) expect(() => wrapper.get('#other-span')).toThrowError( - 'Unable to find #other-span within:
' + 'Unable to get #other-span within:
' ) }) }) diff --git a/tests/getComponent.spec.ts b/tests/getComponent.spec.ts index 05749132e..f64b0c124 100644 --- a/tests/getComponent.spec.ts +++ b/tests/getComponent.spec.ts @@ -17,7 +17,7 @@ describe('getComponent', () => { it('should throw if not found', () => { const wrapper = mount(compA) expect(() => wrapper.getComponent('.domElement')).toThrowError( - 'Unable to find component with selector .domElement within:
' + 'Unable to get component with selector .domElement within:
' ) }) })