From 9a03ad3c22213b706de1f18b7e50c85b26fbbc5f Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Mon, 10 Apr 2023 02:39:25 +0800 Subject: [PATCH 01/18] feat: use vue-component-type-helpers --- package.json | 3 +- pnpm-lock.yaml | 52 ++++++++++------- src/index.ts | 2 - src/mount.ts | 138 +++++--------------------------------------- src/vueWrapper.ts | 8 +-- tests/props.spec.ts | 5 +- 6 files changed, 50 insertions(+), 158 deletions(-) diff --git a/package.json b/package.json index 9e64d5561..de6502541 100644 --- a/package.json +++ b/package.json @@ -60,8 +60,9 @@ "vitest": "0.29.8", "vue": "3.2.47", "vue-class-component": "8.0.0-rc.1", + "vue-component-type-helpers": "1.3.14", "vue-router": "4.1.6", - "vue-tsc": "1.2.0", + "vue-tsc": "1.3.14", "vuex": "4.1.0" }, "peerDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c9948e3e9..bf6ff295d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -113,12 +113,15 @@ devDependencies: vue-class-component: specifier: 8.0.0-rc.1 version: 8.0.0-rc.1(vue@3.2.47) + vue-component-type-helpers: + specifier: 1.3.14 + version: 1.3.14 vue-router: specifier: 4.1.6 version: 4.1.6(vue@3.2.47) vue-tsc: - specifier: 1.2.0 - version: 1.2.0(typescript@4.9.5) + specifier: 1.3.14 + version: 1.3.14(typescript@4.9.5) vuex: specifier: 4.1.0 version: 4.1.0(vue@3.2.47) @@ -1283,29 +1286,29 @@ packages: pretty-format: 27.5.1 dev: true - /@volar/language-core@1.3.0-alpha.0: - resolution: {integrity: sha512-W3uMzecHPcbwddPu4SJpUcPakRBK/y/BP+U0U6NiPpUX1tONLC4yCawt+QBJqtgJ+sfD6ztf5PyvPL3hQRqfOA==} + /@volar/language-core@1.4.0-alpha.7: + resolution: {integrity: sha512-kn/xA+RANXogFHv8Md7lmM4BsVcV51EmgROPiiE1km0PtZ7Po8VFj0Y5B5MNd3RZO/DLWiNfUtXC8MKmHGeDgA==} dependencies: - '@volar/source-map': 1.3.0-alpha.0 + '@volar/source-map': 1.4.0-alpha.7 dev: true - /@volar/source-map@1.3.0-alpha.0: - resolution: {integrity: sha512-jSdizxWFvDTvkPYZnO6ew3sBZUnS0abKCbuopkc0JrIlFbznWC/fPH3iPFIMS8/IIkRxq1Jh9VVG60SmtsdaMQ==} + /@volar/source-map@1.4.0-alpha.7: + resolution: {integrity: sha512-JV5LAe7kgjM8l9yvnve15M2rAJnJ+1hi4G7AbkfMvfn9IkH/BFeSwJo/aIFSRMH0m67BMbP30Ao03NQvCgqOcQ==} dependencies: muggle-string: 0.2.2 dev: true - /@volar/typescript@1.3.0-alpha.0: - resolution: {integrity: sha512-5UItyW2cdH2mBLu4RrECRNJRgtvvzKrSCn2y3v/D61QwIDkGx4aeil6x8RFuUL5TFtV6QvVHXnsOHxNgd+sCow==} + /@volar/typescript@1.4.0-alpha.7: + resolution: {integrity: sha512-tf7n/bNW9aTLbCpgi3E4VUpxgkOjECWRCgd4O+TLxBro1QaBzsjad2fakX4Gp9EwkhFD/WqeeHrgVpeLh5FCRw==} dependencies: - '@volar/language-core': 1.3.0-alpha.0 + '@volar/language-core': 1.4.0-alpha.7 dev: true - /@volar/vue-language-core@1.2.0: - resolution: {integrity: sha512-w7yEiaITh2WzKe6u8ZdeLKCUz43wdmY/OqAmsB/PGDvvhTcVhCJ6f0W/RprZL1IhqH8wALoWiwEh/Wer7ZviMQ==} + /@volar/vue-language-core@1.3.14: + resolution: {integrity: sha512-qXRoOe/B3lWYrbKHw5YInGxoIbBoFSKxVJjLML3RGE/nL1+b0CtqGD+TO9pfwMnjuhHAqzvTm7Hw2l5sLxjbYA==} dependencies: - '@volar/language-core': 1.3.0-alpha.0 - '@volar/source-map': 1.3.0-alpha.0 + '@volar/language-core': 1.4.0-alpha.7 + '@volar/source-map': 1.4.0-alpha.7 '@vue/compiler-dom': 3.2.47 '@vue/compiler-sfc': 3.2.47 '@vue/reactivity': 3.2.47 @@ -1315,11 +1318,11 @@ packages: vue-template-compiler: 2.7.14 dev: true - /@volar/vue-typescript@1.2.0: - resolution: {integrity: sha512-zjmRi9y3J1EkG+pfuHp8IbHmibihrKK485cfzsHjiuvJMGrpkWvlO5WVEk8oslMxxeGC5XwBFE9AOlvh378EPA==} + /@volar/vue-typescript@1.3.14: + resolution: {integrity: sha512-dguC5lEnZdqV5kY+6NZvzuoUN1CeIfTUNArrw6XD49xZUHPXpA3w4EYDqPdEEiLe6Oqg/DGLKwW9IjepJzYGyw==} dependencies: - '@volar/typescript': 1.3.0-alpha.0 - '@volar/vue-language-core': 1.2.0 + '@volar/typescript': 1.4.0-alpha.7 + '@volar/vue-language-core': 1.3.14 dev: true /@vue/babel-helper-vue-transform-on@1.0.2: @@ -4000,6 +4003,10 @@ packages: vue: 3.2.47 dev: true + /vue-component-type-helpers@1.3.14: + resolution: {integrity: sha512-PxCcuUB4KIkyMnr8dgiOzDkCNdeMltC9gWheniEHBXENpQpAGpmHQK08IVr9l4hY5GOVsRHWD8NSTsWM58KvRw==} + dev: true + /vue-router@4.1.6(vue@3.2.47): resolution: {integrity: sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==} peerDependencies: @@ -4016,14 +4023,15 @@ packages: he: 1.2.0 dev: true - /vue-tsc@1.2.0(typescript@4.9.5): - resolution: {integrity: sha512-rIlzqdrhyPYyLG9zxsVRa+JEseeS9s8F2BbVVVWRRsTZvJO2BbhLEb2HW3MY+DFma0378tnIqs+vfTzbcQtRFw==} + /vue-tsc@1.3.14(typescript@4.9.5): + resolution: {integrity: sha512-gSiFmSAIE64VxYIXsMD50spQ5wS3p+RmXItYrQC35oZaWCMfllvtLgCFKeP/lrTrjwvbLryshKF54Jgh/cH30g==} hasBin: true peerDependencies: typescript: '*' dependencies: - '@volar/vue-language-core': 1.2.0 - '@volar/vue-typescript': 1.2.0 + '@volar/vue-language-core': 1.3.14 + '@volar/vue-typescript': 1.3.14 + semver: 7.3.8 typescript: 4.9.5 dev: true diff --git a/src/index.ts b/src/index.ts index 5a2402460..7985faf29 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,5 +25,3 @@ export { MountingOptions, createWrapperError } - -export type { ComponentMountingOptions } from './mount' diff --git a/src/mount.ts b/src/mount.ts index 0fe8ce4e8..bf897470e 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -1,5 +1,4 @@ import { - FunctionalComponent, ComponentPublicInstance, ComponentOptionsWithObjectProps, ComponentOptionsWithArrayProps, @@ -7,144 +6,35 @@ import { ExtractPropTypes, VNodeProps, ComponentOptionsMixin, - DefineComponent, - MethodOptions, AllowedComponentProps, ComponentCustomProps, - ExtractDefaultPropTypes, EmitsOptions, ComputedOptions, ComponentPropsOptions, - Prop + VNode } from 'vue' -import { MountingOptions } from './types' +import { GlobalMountOptions, MountingOptions } from './types' import { VueWrapper } from './vueWrapper' import { trackInstance } from './utils/autoUnmount' import { createVueWrapper } from './wrapperFactory' import { createInstance } from './createInstance' +import type { ComponentProps, ComponentSlots, ComponentExposed } from 'vue-component-type-helpers' // NOTE this should come from `vue` type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps -export type ComponentMountingOptions = T extends DefineComponent< - infer PropsOrPropOptions, - any, - infer D, - any, - any -> - ? MountingOptions< - Partial> & - Omit< - Readonly> & PublicProps, - keyof ExtractDefaultPropTypes - >, - D - > & - Record - : MountingOptions - -// Class component (without vue-class-component) - no props -export function mount( - originalComponent: { - new (...args: any[]): V - __vccOpts: any - }, - options?: MountingOptions & Record -): VueWrapper> - -// Class component (without vue-class-component) - props -export function mount( - originalComponent: { - new (...args: any[]): V - __vccOpts: any - defaultProps?: Record> | string[] - }, - options?: MountingOptions

& Record -): VueWrapper> - -// Class component - no props -export function mount( - originalComponent: { - new (...args: any[]): V - registerHooks(keys: string[]): void - }, - options?: MountingOptions & Record -): VueWrapper> - -// Class component - props -export function mount( - originalComponent: { - new (...args: any[]): V - props(Props: P): any - registerHooks(keys: string[]): void - }, - options?: MountingOptions

& Record -): VueWrapper> - -// Functional component with emits -export function mount( - originalComponent: FunctionalComponent, - options?: MountingOptions & Record -): VueWrapper> +type WithVueWrapper = T extends ComponentPublicInstance ? VueWrapper : VueWrapper -// Component declared with defineComponent -export function mount< - PropsOrPropOptions = {}, - RawBindings = {}, - D = {}, - C extends ComputedOptions = ComputedOptions, - M extends MethodOptions = MethodOptions, - Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, - Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - E extends EmitsOptions = Record, - EE extends string = string, - PP = PublicProps, - Props = Readonly>, - Defaults extends {} = ExtractDefaultPropTypes ->( - component: DefineComponent< - PropsOrPropOptions, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - PP, - Props, - Defaults - >, - options?: MountingOptions< - Partial & Omit, - D - > & - Record -): VueWrapper< - InstanceType< - DefineComponent< - PropsOrPropOptions, - RawBindings, - D, - C, - M, - Mixin, - Extends, - EmitsOptions, - EE, - PP, - Props, - Defaults - > - > -> -// component declared by vue-tsc ScriptSetup -export function mount>( - component: T, - options?: ComponentMountingOptions -): VueWrapper> +export function mount any) | (new (...args: any) => any)>( + originalComponent: T, + options?: Record & { + props?: ComponentProps; + slots?: { + [K in keyof ComponentSlots]: string | VNode[]; + }; + global?: GlobalMountOptions; + } +): WithVueWrapper>; // Component declared with no props export function mount< diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 4f53f8987..8064dbe7f 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -1,7 +1,6 @@ import { nextTick, App, - ComponentCustomProperties, ComponentPublicInstance, VNode } from 'vue' @@ -75,12 +74,7 @@ function createVMProxy( } export class VueWrapper< - T extends Omit< - ComponentPublicInstance, - '$emit' | keyof ComponentCustomProperties - > & { - $emit: (event: any, ...args: any[]) => void - } & ComponentCustomProperties = ComponentPublicInstance + T extends ComponentPublicInstance = ComponentPublicInstance > extends BaseWrapper { private readonly componentVM: T private readonly rootVM: ComponentPublicInstance | undefined | null diff --git a/tests/props.spec.ts b/tests/props.spec.ts index 77b73c03a..690b7700e 100644 --- a/tests/props.spec.ts +++ b/tests/props.spec.ts @@ -108,8 +108,9 @@ describe('props', () => { const wrapper = mount(component, { props: { modelValue: 1, - 'onUpdate:modelValue': async (modelValue: number) => - wrapper.setProps({ modelValue }) + 'onUpdate:modelValue': async (modelValue: number) => { + await wrapper.setProps({ modelValue }) + } } }) From b2a5343cce5fdddda8bb81b9885fc0caf923f7c8 Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Mon, 10 Apr 2023 02:44:19 +0800 Subject: [PATCH 02/18] chore: fix lint --- src/mount.ts | 24 ++++++++++++++++-------- src/vueWrapper.ts | 7 +------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/mount.ts b/src/mount.ts index bf897470e..80d068b3a 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -18,23 +18,31 @@ import { VueWrapper } from './vueWrapper' import { trackInstance } from './utils/autoUnmount' import { createVueWrapper } from './wrapperFactory' import { createInstance } from './createInstance' -import type { ComponentProps, ComponentSlots, ComponentExposed } from 'vue-component-type-helpers' +import type { + ComponentProps, + ComponentSlots, + ComponentExposed +} from 'vue-component-type-helpers' // NOTE this should come from `vue` type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps -type WithVueWrapper = T extends ComponentPublicInstance ? VueWrapper : VueWrapper +type WithVueWrapper = T extends ComponentPublicInstance + ? VueWrapper + : VueWrapper -export function mount any) | (new (...args: any) => any)>( +export function mount< + T extends ((...args: any) => any) | (new (...args: any) => any) +>( originalComponent: T, options?: Record & { - props?: ComponentProps; + props?: ComponentProps slots?: { - [K in keyof ComponentSlots]: string | VNode[]; - }; - global?: GlobalMountOptions; + [K in keyof ComponentSlots]: string | VNode[] + } + global?: GlobalMountOptions } -): WithVueWrapper>; +): WithVueWrapper> // Component declared with no props export function mount< diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 8064dbe7f..121ccdbe5 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -1,9 +1,4 @@ -import { - nextTick, - App, - ComponentPublicInstance, - VNode -} from 'vue' +import { nextTick, App, ComponentPublicInstance, VNode } from 'vue' import { config } from './config' import domEvents from './constants/dom-events' From b5a10eedf088bd63d52e87a1a90821f3dcb73976 Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Mon, 10 Apr 2023 02:56:30 +0800 Subject: [PATCH 03/18] fix: simplify VueWrapper --- src/mount.ts | 6 +----- src/vueWrapper.ts | 12 +++++------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/mount.ts b/src/mount.ts index 80d068b3a..f210becc9 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -27,10 +27,6 @@ import type { // NOTE this should come from `vue` type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps -type WithVueWrapper = T extends ComponentPublicInstance - ? VueWrapper - : VueWrapper - export function mount< T extends ((...args: any) => any) | (new (...args: any) => any) >( @@ -42,7 +38,7 @@ export function mount< } global?: GlobalMountOptions } -): WithVueWrapper> +): VueWrapper> // Component declared with no props export function mount< diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 121ccdbe5..b8676364f 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -68,10 +68,8 @@ function createVMProxy( }) } -export class VueWrapper< - T extends ComponentPublicInstance = ComponentPublicInstance -> extends BaseWrapper { - private readonly componentVM: T +export class VueWrapper T) | (new (...args: any) => T) = any> extends BaseWrapper { + private readonly componentVM: T & ComponentPublicInstance private readonly rootVM: ComponentPublicInstance | undefined | null private readonly __app: App | null private readonly __setProps: @@ -81,7 +79,7 @@ export class VueWrapper< constructor( app: App | null, - vm: T, + vm: T & ComponentPublicInstance, setProps?: (props: Record) => void ) { super(vm?.$el) @@ -97,7 +95,7 @@ export class VueWrapper< // or for components with a setup that returns a render function (as they have an empty proxy) // in both cases, we return `vm` directly instead if (hasSetupState(vm)) { - this.componentVM = createVMProxy(vm, vm.$.setupState) + this.componentVM = createVMProxy(vm, vm.$.setupState) } else { this.componentVM = vm } @@ -206,7 +204,7 @@ export class VueWrapper< return this.hasMultipleRoots ? this.parentElement : this.vm.$el } - get vm(): T { + get vm(): T & ComponentPublicInstance { return this.componentVM } From b87329e1833d89e184edaad33e0a634d155e3dc7 Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Mon, 10 Apr 2023 02:57:28 +0800 Subject: [PATCH 04/18] chore: fix lint --- src/vueWrapper.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index b8676364f..3480799d5 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -68,7 +68,10 @@ function createVMProxy( }) } -export class VueWrapper T) | (new (...args: any) => T) = any> extends BaseWrapper { +export class VueWrapper< + T = any, + C extends ((...args: any) => T) | (new (...args: any) => T) = any +> extends BaseWrapper { private readonly componentVM: T & ComponentPublicInstance private readonly rootVM: ComponentPublicInstance | undefined | null private readonly __app: App | null @@ -95,7 +98,10 @@ export class VueWrapper T) | (new (...args // or for components with a setup that returns a render function (as they have an empty proxy) // in both cases, we return `vm` directly instead if (hasSetupState(vm)) { - this.componentVM = createVMProxy(vm, vm.$.setupState) + this.componentVM = createVMProxy( + vm, + vm.$.setupState + ) } else { this.componentVM = vm } From 72203e1231b7bf0d6d1e96282ef24898bf614eff Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Mon, 10 Apr 2023 03:09:57 +0800 Subject: [PATCH 05/18] fix: allow extra props --- src/mount.ts | 2 +- test-dts/mount.d-test.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mount.ts b/src/mount.ts index f210becc9..753ea79c6 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -32,7 +32,7 @@ export function mount< >( originalComponent: T, options?: Record & { - props?: ComponentProps + props?: Record & ComponentProps slots?: { [K in keyof ComponentSlots]: string | VNode[] } diff --git a/test-dts/mount.d-test.ts b/test-dts/mount.d-test.ts index 4c5b47753..2091f777a 100644 --- a/test-dts/mount.d-test.ts +++ b/test-dts/mount.d-test.ts @@ -141,7 +141,7 @@ expectError((props: { a: 1 }) => {}, { }) expectType( - mount((props: { a: number }, ctx) => {}, { + mount((props: { a: number }, ctx: { expose(exposed: { a: number }) }) => {}, { props: { a: 22 } @@ -278,16 +278,16 @@ class WithPropCustomClassComponent extends CustomClassComponent( + mount( // @ts-expect-error should has props error - WithPropCustomClassComponent, + WithPropCustomClassComponent as typeof WithPropCustomClassComponent & (new () => { $props: CustomClassComponentProps }), { props: {} } ) ) -mount( - WithPropCustomClassComponent, +mount( + WithPropCustomClassComponent as typeof WithPropCustomClassComponent & (new () => { $props: CustomClassComponentProps }), { props: { size: 'small' } } From 4ae64d36595b2f11a8f60a7f17d7cc014bb7b6bf Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Mon, 10 Apr 2023 03:16:29 +0800 Subject: [PATCH 06/18] fix: expose props --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- src/mount.ts | 2 +- test-dts/mount.d-test.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index de6502541..9113f694b 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "vitest": "0.29.8", "vue": "3.2.47", "vue-class-component": "8.0.0-rc.1", - "vue-component-type-helpers": "1.3.14", + "vue-component-type-helpers": "1.3.14-patch.1", "vue-router": "4.1.6", "vue-tsc": "1.3.14", "vuex": "4.1.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf6ff295d..646523b3e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -114,8 +114,8 @@ devDependencies: specifier: 8.0.0-rc.1 version: 8.0.0-rc.1(vue@3.2.47) vue-component-type-helpers: - specifier: 1.3.14 - version: 1.3.14 + specifier: 1.3.14-patch.1 + version: 1.3.14-patch.1 vue-router: specifier: 4.1.6 version: 4.1.6(vue@3.2.47) @@ -4003,8 +4003,8 @@ packages: vue: 3.2.47 dev: true - /vue-component-type-helpers@1.3.14: - resolution: {integrity: sha512-PxCcuUB4KIkyMnr8dgiOzDkCNdeMltC9gWheniEHBXENpQpAGpmHQK08IVr9l4hY5GOVsRHWD8NSTsWM58KvRw==} + /vue-component-type-helpers@1.3.14-patch.1: + resolution: {integrity: sha512-v+03MWlsDYdXse6psH8Ch13d0RDJN1htPcwfK631W7y4fUpcMezzPruCW9+4kH92QGFiXvmyUSiNB6TDwZoNZg==} dev: true /vue-router@4.1.6(vue@3.2.47): diff --git a/src/mount.ts b/src/mount.ts index 753ea79c6..fb623b892 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -38,7 +38,7 @@ export function mount< } global?: GlobalMountOptions } -): VueWrapper> +): VueWrapper & ComponentProps> // Component declared with no props export function mount< diff --git a/test-dts/mount.d-test.ts b/test-dts/mount.d-test.ts index 2091f777a..fb55303de 100644 --- a/test-dts/mount.d-test.ts +++ b/test-dts/mount.d-test.ts @@ -141,7 +141,7 @@ expectError((props: { a: 1 }) => {}, { }) expectType( - mount((props: { a: number }, ctx: { expose(exposed: { a: number }) }) => {}, { + mount((props: { a: number }, ctx) => {}, { props: { a: 22 } From 61727dc2e5cd7a0585d5972cb9b055615d97e189 Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Mon, 10 Apr 2023 04:03:26 +0800 Subject: [PATCH 07/18] fix: pass vue-tsc --- src/mount.ts | 12 +++++++++++- tests/components/ComponentWithSlots.vue | 17 ++++------------- tests/components/WithTeleportEmitsComp.vue | 4 +++- tests/features/compat.spec.ts | 3 ++- tests/mountingOptions/mocks.spec.ts | 4 ++-- 5 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/mount.ts b/src/mount.ts index fb623b892..d6a0c41ec 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -27,6 +27,10 @@ import type { // NOTE this should come from `vue` type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps +type PatchSlot = T extends (...args: infer P) => any + ? (...args: P) => any + : T + export function mount< T extends ((...args: any) => any) | (new (...args: any) => any) >( @@ -34,7 +38,13 @@ export function mount< options?: Record & { props?: Record & ComponentProps slots?: { - [K in keyof ComponentSlots]: string | VNode[] + [K in keyof ComponentSlots]: + | PatchSlot[K]> + | string + | VNode + | VNode[] + | (new () => any) + | { template: string } } global?: GlobalMountOptions } diff --git a/tests/components/ComponentWithSlots.vue b/tests/components/ComponentWithSlots.vue index e5353d127..8b3b89f6b 100644 --- a/tests/components/ComponentWithSlots.vue +++ b/tests/components/ComponentWithSlots.vue @@ -29,17 +29,8 @@ - diff --git a/tests/components/WithTeleportEmitsComp.vue b/tests/components/WithTeleportEmitsComp.vue index 04b1f8af7..53a055327 100644 --- a/tests/components/WithTeleportEmitsComp.vue +++ b/tests/components/WithTeleportEmitsComp.vue @@ -1,6 +1,8 @@ diff --git a/tests/features/compat.spec.ts b/tests/features/compat.spec.ts index 3fb175088..469ecb95b 100644 --- a/tests/features/compat.spec.ts +++ b/tests/features/compat.spec.ts @@ -5,7 +5,7 @@ import { mount } from '../../src' vi.mock('vue', () => mockVue) const { configureCompat, defineComponent, h } = mockVue // @ts-expect-error @vue/compat does not expose default export in types -const Vue = mockVue.default +const Vue = mockVue.default as typeof mockVue describe('@vue/compat build', () => { describe.each(['suppress-warning', false])( @@ -221,6 +221,7 @@ describe('@vue/compat build', () => { GLOBAL_PROTOTYPE: 'suppress-warning' }) + // @ts-expect-error Vue.prototype.$test = 1 const Component = { template: 'hello ' } diff --git a/tests/mountingOptions/mocks.spec.ts b/tests/mountingOptions/mocks.spec.ts index c07bb5937..722418e33 100644 --- a/tests/mountingOptions/mocks.spec.ts +++ b/tests/mountingOptions/mocks.spec.ts @@ -42,10 +42,10 @@ describe('mocks', () => { `, computed: { url(): string { - return `/posts/${this.$route.params.id}` + return `/posts/${this.$router.currentRoute.value.params.id}` }, id(): string | string[] { - return this.$route.params.id + return this.$router.currentRoute.value.params.id } }, methods: { From 3f661bfa00fff7ba98250cdd09bb0ed5a269eca8 Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Mon, 10 Apr 2023 04:09:21 +0800 Subject: [PATCH 08/18] Update mocks.spec.ts --- tests/mountingOptions/mocks.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/mountingOptions/mocks.spec.ts b/tests/mountingOptions/mocks.spec.ts index 722418e33..c07bb5937 100644 --- a/tests/mountingOptions/mocks.spec.ts +++ b/tests/mountingOptions/mocks.spec.ts @@ -42,10 +42,10 @@ describe('mocks', () => { `, computed: { url(): string { - return `/posts/${this.$router.currentRoute.value.params.id}` + return `/posts/${this.$route.params.id}` }, id(): string | string[] { - return this.$router.currentRoute.value.params.id + return this.$route.params.id } }, methods: { From 23bd67c433623166ad4a295c7528974ea4bf2851 Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Mon, 10 Apr 2023 04:16:40 +0800 Subject: [PATCH 09/18] fix vue-tsc --- types/testing.d.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/testing.d.ts b/types/testing.d.ts index 130e22330..f20fafd0e 100644 --- a/types/testing.d.ts +++ b/types/testing.d.ts @@ -1,7 +1,8 @@ -import type { Router } from 'vue-router' +import type { Router, RouteLocation } from 'vue-router' declare module 'vue' { interface ComponentCustomProperties { + $route: RouteLocation $router: Router $t: (key: string) => string } From 719549ddea62917629f7bc172a04694f8bde49d2 Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Mon, 10 Apr 2023 04:17:29 +0800 Subject: [PATCH 10/18] drop node 14 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1eb7c1755..c68aba2ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: - node: [14, 16, 18] + node: [16, 18] steps: - uses: actions/checkout@v3 From c198f6f992c9e47359c365b475f5ac7426b83339 Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Tue, 11 Apr 2023 05:42:06 +0800 Subject: [PATCH 11/18] feat: redo ComponentMountingOptions --- src/index.ts | 2 ++ src/mount.ts | 35 +++++++++++++++++++---------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/index.ts b/src/index.ts index 7985faf29..5a2402460 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,3 +25,5 @@ export { MountingOptions, createWrapperError } + +export type { ComponentMountingOptions } from './mount' diff --git a/src/mount.ts b/src/mount.ts index d6a0c41ec..bd7133fd9 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -13,7 +13,7 @@ import { ComponentPropsOptions, VNode } from 'vue' -import { GlobalMountOptions, MountingOptions } from './types' +import { MountingOptions } from './types' import { VueWrapper } from './vueWrapper' import { trackInstance } from './utils/autoUnmount' import { createVueWrapper } from './wrapperFactory' @@ -27,27 +27,30 @@ import type { // NOTE this should come from `vue` type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps -type PatchSlot = T extends (...args: infer P) => any +type ShimSlotReturnType = T extends (...args: infer P) => any ? (...args: P) => any - : T + : never + +export type ComponentMountingOptions = Omit< + MountingOptions>, + 'slots' +> & { + slots?: { + [K in keyof ComponentSlots]: + | ShimSlotReturnType[K]> + | string + | VNode + | VNode[] + | (new () => any) + | { template: string } + } +} & Record export function mount< T extends ((...args: any) => any) | (new (...args: any) => any) >( originalComponent: T, - options?: Record & { - props?: Record & ComponentProps - slots?: { - [K in keyof ComponentSlots]: - | PatchSlot[K]> - | string - | VNode - | VNode[] - | (new () => any) - | { template: string } - } - global?: GlobalMountOptions - } + options?: ComponentMountingOptions ): VueWrapper & ComponentProps> // Component declared with no props From b2787e4aaa1914a7705954dd0d832f2375cb51da Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Tue, 11 Apr 2023 06:01:58 +0800 Subject: [PATCH 12/18] refactor: sync renderToString with mount --- src/renderToString.ts | 127 +++++------------------------------------- 1 file changed, 14 insertions(+), 113 deletions(-) diff --git a/src/renderToString.ts b/src/renderToString.ts index 9d2250852..afa60e5bf 100644 --- a/src/renderToString.ts +++ b/src/renderToString.ts @@ -1,132 +1,33 @@ import { renderToString as baseRenderToString } from '@vue/server-renderer' import { - FunctionalComponent, - ComponentOptionsWithObjectProps, - ComponentOptionsWithArrayProps, - ComponentOptionsWithoutProps, - ExtractPropTypes, - VNodeProps, - ComponentOptionsMixin, - DefineComponent, - MethodOptions, AllowedComponentProps, ComponentCustomProps, - ExtractDefaultPropTypes, - EmitsOptions, - ComputedOptions, + ComponentOptionsMixin, + ComponentOptionsWithArrayProps, + ComponentOptionsWithObjectProps, + ComponentOptionsWithoutProps, ComponentPropsOptions, - Prop + ComputedOptions, + EmitsOptions, + ExtractPropTypes, + VNodeProps } from 'vue' -import { RenderMountingOptions } from './types' import { createInstance } from './createInstance' +import { ComponentMountingOptions } from './mount' +import { RenderMountingOptions } from './types' // NOTE this should come from `vue` type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps -type ComponentMountingOptions = T extends DefineComponent< - infer PropsOrPropOptions, - any, - infer D, - any, - any -> - ? RenderMountingOptions< - Partial> & - Omit< - Readonly> & PublicProps, - keyof ExtractDefaultPropTypes - >, - D - > & - Record - : RenderMountingOptions - -// Class component (without vue-class-component) - no props -export function renderToString( - originalComponent: { - new (...args: any[]): V - __vccOpts: any - }, - options?: RenderMountingOptions & Record -): Promise - -// Class component (without vue-class-component) - props -export function renderToString( - originalComponent: { - new (...args: any[]): V - __vccOpts: any - defaultProps?: Record> | string[] - }, - options?: RenderMountingOptions

& Record -): Promise - -// Class component - no props -export function renderToString( - originalComponent: { - new (...args: any[]): V - registerHooks(keys: string[]): void - }, - options?: RenderMountingOptions & Record -): Promise - -// Class component - props -export function renderToString( - originalComponent: { - new (...args: any[]): V - props(Props: P): any - registerHooks(keys: string[]): void - }, - options?: RenderMountingOptions

& Record -): Promise - -// Functional component with emits -export function renderToString( - originalComponent: FunctionalComponent, - options?: RenderMountingOptions & Record -): Promise - -// Component declared with defineComponent export function renderToString< - PropsOrPropOptions = {}, - RawBindings = {}, - D = {}, - C extends ComputedOptions = ComputedOptions, - M extends MethodOptions = MethodOptions, - Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, - Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - E extends EmitsOptions = Record, - EE extends string = string, - PP = PublicProps, - Props = Readonly>, - Defaults extends {} = ExtractDefaultPropTypes + T extends ((...args: any) => any) | (new (...args: any) => any) >( - component: DefineComponent< - PropsOrPropOptions, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - PP, - Props, - Defaults - >, - options?: RenderMountingOptions< - Partial & Omit, - D - > & - Record + originalComponent: T, + options?: ComponentMountingOptions & + Pick, 'attachTo'> ): Promise -// component declared by vue-tsc ScriptSetup -export function renderToString< - T extends DefineComponent ->(component: T, options?: ComponentMountingOptions): Promise - // Component declared with no props export function renderToString< Props = {}, From 1b6cf217360ca86850ced0699a4c300a6ff7eeb7 Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Tue, 11 Apr 2023 06:16:40 +0800 Subject: [PATCH 13/18] chore: add issue link --- tests/components/WithTeleportEmitsComp.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/WithTeleportEmitsComp.vue b/tests/components/WithTeleportEmitsComp.vue index 53a055327..fae24099b 100644 --- a/tests/components/WithTeleportEmitsComp.vue +++ b/tests/components/WithTeleportEmitsComp.vue @@ -1,7 +1,7 @@ From 2f15e55788078141ab33783a9ce2f9e2163289d0 Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Tue, 11 Apr 2023 06:22:42 +0800 Subject: [PATCH 14/18] refactor: simplify VueWrapper type args --- src/vueWrapper.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 3480799d5..e2c2ff96c 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -69,10 +69,10 @@ function createVMProxy( } export class VueWrapper< - T = any, - C extends ((...args: any) => T) | (new (...args: any) => T) = any + VM = unknown, + T extends VM & ComponentPublicInstance = VM & ComponentPublicInstance > extends BaseWrapper { - private readonly componentVM: T & ComponentPublicInstance + private readonly componentVM: T private readonly rootVM: ComponentPublicInstance | undefined | null private readonly __app: App | null private readonly __setProps: @@ -82,7 +82,7 @@ export class VueWrapper< constructor( app: App | null, - vm: T & ComponentPublicInstance, + vm: T, setProps?: (props: Record) => void ) { super(vm?.$el) @@ -98,10 +98,7 @@ export class VueWrapper< // or for components with a setup that returns a render function (as they have an empty proxy) // in both cases, we return `vm` directly instead if (hasSetupState(vm)) { - this.componentVM = createVMProxy( - vm, - vm.$.setupState - ) + this.componentVM = createVMProxy(vm, vm.$.setupState) } else { this.componentVM = vm } @@ -210,7 +207,7 @@ export class VueWrapper< return this.hasMultipleRoots ? this.parentElement : this.vm.$el } - get vm(): T & ComponentPublicInstance { + get vm(): T { return this.componentVM } From 322833427ce455dc5115b40283964313bd581397 Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Tue, 11 Apr 2023 07:43:42 +0800 Subject: [PATCH 15/18] refactor: remove raw options overloads --- src/mount.ts | 151 +++++------------------------- src/renderToString.ts | 118 +++-------------------- test-dts/mount.d-test.ts | 12 +-- test-dts/renderToString.d-test.ts | 2 +- test-dts/shallowMount.d-test.ts | 18 ++-- tests/config.spec.ts | 4 +- tests/features/compat.spec.ts | 2 +- tests/renderToString.spec.ts | 2 +- tests/setData.spec.ts | 4 +- 9 files changed, 57 insertions(+), 256 deletions(-) diff --git a/src/mount.ts b/src/mount.ts index bd7133fd9..5047df961 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -1,154 +1,51 @@ -import { - ComponentPublicInstance, - ComponentOptionsWithObjectProps, - ComponentOptionsWithArrayProps, - ComponentOptionsWithoutProps, - ExtractPropTypes, - VNodeProps, - ComponentOptionsMixin, - AllowedComponentProps, - ComponentCustomProps, - EmitsOptions, - ComputedOptions, - ComponentPropsOptions, - VNode -} from 'vue' -import { MountingOptions } from './types' -import { VueWrapper } from './vueWrapper' -import { trackInstance } from './utils/autoUnmount' -import { createVueWrapper } from './wrapperFactory' -import { createInstance } from './createInstance' +import { ComponentPublicInstance, DefineComponent, VNode } from 'vue' import type { + ComponentExposed, ComponentProps, - ComponentSlots, - ComponentExposed + ComponentSlots } from 'vue-component-type-helpers' - -// NOTE this should come from `vue` -type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps +import { createInstance } from './createInstance' +import { MountingOptions } from './types' +import { trackInstance } from './utils/autoUnmount' +import { VueWrapper } from './vueWrapper' +import { createVueWrapper } from './wrapperFactory' type ShimSlotReturnType = T extends (...args: infer P) => any ? (...args: P) => any : never +type WithArray = T | T[] + export type ComponentMountingOptions = Omit< MountingOptions>, 'slots' > & { slots?: { - [K in keyof ComponentSlots]: + [K in keyof ComponentSlots]: WithArray< | ShimSlotReturnType[K]> | string | VNode - | VNode[] | (new () => any) | { template: string } + > } } & Record export function mount< - T extends ((...args: any) => any) | (new (...args: any) => any) + T, + C = T extends ((...args: any) => any) | (new (...args: any) => any) + ? T + : T extends { props?: infer Props } + ? DefineComponent< + Props extends Readonly<(infer PropNames)[]> | (infer PropNames)[] + ? { [key in PropNames extends string ? PropNames : string]?: any } + : Props + > + : DefineComponent >( originalComponent: T, - options?: ComponentMountingOptions -): VueWrapper & ComponentProps> - -// Component declared with no props -export function mount< - Props = {}, - RawBindings = {}, - D extends {} = {}, - C extends ComputedOptions = {}, - M extends Record = {}, - E extends EmitsOptions = Record, - Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, - Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - EE extends string = string ->( - componentOptions: ComponentOptionsWithoutProps< - Props, - RawBindings, - D, - C, - M, - E, - Mixin, - Extends, - EE - >, - options?: MountingOptions -): VueWrapper< - ComponentPublicInstance -> & - Record - -// Component declared with { props: [] } -export function mount< - PropNames extends string, - RawBindings, - D extends {}, - C extends ComputedOptions = {}, - M extends Record = {}, - E extends EmitsOptions = Record, - Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, - Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - EE extends string = string, - Props extends Readonly<{ [key in PropNames]?: any }> = Readonly<{ - [key in PropNames]?: any - }> ->( - componentOptions: ComponentOptionsWithArrayProps< - PropNames, - RawBindings, - D, - C, - M, - E, - Mixin, - Extends, - EE, - Props - >, - options?: MountingOptions -): VueWrapper> - -// Component declared with { props: { ... } } -export function mount< - // the Readonly constraint allows TS to treat the type of { required: true } - // as constant instead of boolean. - PropsOptions extends Readonly, - RawBindings, - D extends {}, - C extends ComputedOptions = {}, - M extends Record = {}, - E extends EmitsOptions = Record, - Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, - Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - EE extends string = string ->( - componentOptions: ComponentOptionsWithObjectProps< - PropsOptions, - RawBindings, - D, - C, - M, - E, - Mixin, - Extends, - EE - >, - options?: MountingOptions & PublicProps, D> -): VueWrapper< - ComponentPublicInstance< - ExtractPropTypes, - RawBindings, - D, - C, - M, - E, - VNodeProps & ExtractPropTypes - > -> + options?: ComponentMountingOptions +): VueWrapper & ComponentProps> // implementation export function mount( diff --git a/src/renderToString.ts b/src/renderToString.ts index afa60e5bf..0e666e8b9 100644 --- a/src/renderToString.ts +++ b/src/renderToString.ts @@ -1,120 +1,26 @@ import { renderToString as baseRenderToString } from '@vue/server-renderer' -import { - AllowedComponentProps, - ComponentCustomProps, - ComponentOptionsMixin, - ComponentOptionsWithArrayProps, - ComponentOptionsWithObjectProps, - ComponentOptionsWithoutProps, - ComponentPropsOptions, - ComputedOptions, - EmitsOptions, - ExtractPropTypes, - VNodeProps -} from 'vue' - +import { DefineComponent } from 'vue' import { createInstance } from './createInstance' import { ComponentMountingOptions } from './mount' import { RenderMountingOptions } from './types' -// NOTE this should come from `vue` -type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps - export function renderToString< - T extends ((...args: any) => any) | (new (...args: any) => any) + T, + C = T extends ((...args: any) => any) | (new (...args: any) => any) + ? T + : T extends { props?: infer Props } + ? DefineComponent< + Props extends Readonly<(infer PropNames)[]> | (infer PropNames)[] + ? { [key in PropNames extends string ? PropNames : string]?: any } + : Props + > + : DefineComponent >( originalComponent: T, - options?: ComponentMountingOptions & + options?: ComponentMountingOptions & Pick, 'attachTo'> ): Promise -// Component declared with no props -export function renderToString< - Props = {}, - RawBindings = {}, - D extends {} = {}, - C extends ComputedOptions = {}, - M extends Record = {}, - E extends EmitsOptions = Record, - Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, - Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - EE extends string = string ->( - componentOptions: ComponentOptionsWithoutProps< - Props, - RawBindings, - D, - C, - M, - E, - Mixin, - Extends, - EE - >, - options?: RenderMountingOptions -): Promise - -// Component declared with { props: [] } -export function renderToString< - PropNames extends string, - RawBindings, - D extends {}, - C extends ComputedOptions = {}, - M extends Record = {}, - E extends EmitsOptions = Record, - Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, - Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - EE extends string = string, - Props extends Readonly<{ [key in PropNames]?: any }> = Readonly<{ - [key in PropNames]?: any - }> ->( - componentOptions: ComponentOptionsWithArrayProps< - PropNames, - RawBindings, - D, - C, - M, - E, - Mixin, - Extends, - EE, - Props - >, - options?: RenderMountingOptions -): Promise - -// Component declared with { props: { ... } } -export function renderToString< - // the Readonly constraint allows TS to treat the type of { required: true } - // as constant instead of boolean. - PropsOptions extends Readonly, - RawBindings, - D extends {}, - C extends ComputedOptions = {}, - M extends Record = {}, - E extends EmitsOptions = Record, - Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, - Extends extends ComponentOptionsMixin = ComponentOptionsMixin, - EE extends string = string ->( - componentOptions: ComponentOptionsWithObjectProps< - PropsOptions, - RawBindings, - D, - C, - M, - E, - Mixin, - Extends, - EE - >, - options?: RenderMountingOptions< - ExtractPropTypes & PublicProps, - D - > -): Promise - export function renderToString(component: any, options?: any): Promise { if (options?.attachTo) { console.warn('attachTo option is not available for renderToString') diff --git a/test-dts/mount.d-test.ts b/test-dts/mount.d-test.ts index fb55303de..2bcd15d6e 100644 --- a/test-dts/mount.d-test.ts +++ b/test-dts/mount.d-test.ts @@ -56,8 +56,8 @@ mount(AppWithDefine, { }) expectError( - // @ts-expect-error wrong prop type should not compile mount(AppWithDefine, { + // @ts-expect-error wrong prop type should not compile props: { a: 2 } }) ) @@ -134,14 +134,14 @@ mount(AppWithoutProps, { // Functional tests // @ts-expect-error wrong props -expectError((props: { a: 1 }) => {}, { +expectError((props: { a: 1 }) => { }, { props: { a: '222' } }) expectType( - mount((props: { a: number }, ctx) => {}, { + mount((props: { a: number }, ctx: any) => { }, { props: { a: 22 } @@ -245,7 +245,7 @@ class CustomClassComponent { return this.props } context: SetupContext - render(): VNodeChild {} + render(): VNodeChild { } } class NoPropCustomClassComponent extends CustomClassComponent { count = ref(0) @@ -279,9 +279,9 @@ class WithPropCustomClassComponent extends CustomClassComponent { $props: CustomClassComponentProps }), { + // @ts-expect-error should has props error props: {} } ) @@ -318,7 +318,6 @@ mount(Foo, { expectError( mount( - // @ts-expect-error defineComponent({ props: { baz: String, @@ -329,6 +328,7 @@ expectError( } }), { + // @ts-expect-error props: { baz: 'hello' } diff --git a/test-dts/renderToString.d-test.ts b/test-dts/renderToString.d-test.ts index 12c950ec8..d0eee2526 100644 --- a/test-dts/renderToString.d-test.ts +++ b/test-dts/renderToString.d-test.ts @@ -27,8 +27,8 @@ renderToString(AppWithDefine, { }) expectError( - // @ts-expect-error wrong prop type should not compile renderToString(AppWithDefine, { + // @ts-expect-error wrong prop type should not compile props: { a: 2 } }) ) diff --git a/test-dts/shallowMount.d-test.ts b/test-dts/shallowMount.d-test.ts index e11507bc2..ce33d451d 100644 --- a/test-dts/shallowMount.d-test.ts +++ b/test-dts/shallowMount.d-test.ts @@ -15,11 +15,10 @@ const AppWithDefine = defineComponent({ }) // accept props -let wrapper = shallowMount(AppWithDefine, { - props: { a: 'Hello', b: 2 } -}) // vm is properly typed -expectType(wrapper.vm.a) +expectType(shallowMount(AppWithDefine, { + props: { a: 'Hello', b: 2 } +}).vm.a) // allow extra props, like using `h()` shallowMount(AppWithDefine, { @@ -27,8 +26,8 @@ shallowMount(AppWithDefine, { }) expectError( - // @ts-expect-error wrong prop type should not compile shallowMount(AppWithDefine, { + // @ts-expect-error wrong prop type should not compile props: { a: 2 } }) ) @@ -69,11 +68,10 @@ const AppWithArrayProps = { } // accept props -wrapper = shallowMount(AppWithArrayProps, { - props: { a: 'Hello' } -}) // vm is properly typed -expectType(wrapper.vm.a) +expectType(shallowMount(AppWithArrayProps, { + props: { a: 'Hello' } +}).vm.a) // can receive extra props // as they are declared as `string[]` @@ -86,7 +84,7 @@ const AppWithoutProps = { } // allow extra props, like using `h()` -wrapper = shallowMount(AppWithoutProps, { +shallowMount(AppWithoutProps, { props: { b: 'Hello' } }) diff --git a/tests/config.spec.ts b/tests/config.spec.ts index 159d25006..8002f2854 100644 --- a/tests/config.spec.ts +++ b/tests/config.spec.ts @@ -113,20 +113,20 @@ describe('config', () => { components: { Child }, template: '

' }) - // @ts-expect-error let comp = mount(Component, { shallow: true, global: { + // @ts-expect-error renderStubDefaultSlot: 'truthy' } }) expect(comp.find('#default-slot').exists()).toBe(true) - // @ts-expect-error let comp2 = mount(Component, { shallow: true, global: { + // @ts-expect-error renderStubDefaultSlot: 0 } }) diff --git a/tests/features/compat.spec.ts b/tests/features/compat.spec.ts index 469ecb95b..6984a3e35 100644 --- a/tests/features/compat.spec.ts +++ b/tests/features/compat.spec.ts @@ -227,7 +227,7 @@ describe('@vue/compat build', () => { const Component = { template: 'hello ' } const wrapper = mount(Component) - // @ts-expect-error $test "magically" appears from "Vue.prototype" in compat build + // $test "magically" appears from "Vue.prototype" in compat build expect(wrapper.vm.$test).toBe(1) }) }) diff --git a/tests/renderToString.spec.ts b/tests/renderToString.spec.ts index 7a8166c73..f844fd35f 100644 --- a/tests/renderToString.spec.ts +++ b/tests/renderToString.spec.ts @@ -70,8 +70,8 @@ describe('renderToString', () => { }) expect( - // @ts-expect-error `attachTo` property is not allowed await renderToString(Component, { + // @ts-expect-error `attachTo` property is not allowed attachTo: 'body' }) ).toBe('
foo
') diff --git a/tests/setData.spec.ts b/tests/setData.spec.ts index 30cfabd55..e965b1e05 100644 --- a/tests/setData.spec.ts +++ b/tests/setData.spec.ts @@ -190,13 +190,13 @@ describe('setData', () => { it('should keep Date object on setData', async () => { const wrapper = mount( - { + defineComponent({ template: '
', props: { modelValue: Date }, data() { return { value: this.modelValue } } - }, + }), { props: { modelValue: new Date('2022-08-10T12:15:54Z') From 143744041c5e1df8aa14130c5aa58ff1fc895cff Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Tue, 11 Apr 2023 07:54:31 +0800 Subject: [PATCH 16/18] fix: fixed wrong test case --- test-dts/mount.d-test.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test-dts/mount.d-test.ts b/test-dts/mount.d-test.ts index 2bcd15d6e..446d4075f 100644 --- a/test-dts/mount.d-test.ts +++ b/test-dts/mount.d-test.ts @@ -133,12 +133,14 @@ mount(AppWithoutProps, { // Functional tests -// @ts-expect-error wrong props -expectError((props: { a: 1 }) => { }, { - props: { - a: '222' - } -}) +expectError( + mount((props: { a: 1 }) => { }, { + props: { + // @ts-expect-error wrong props + a: '222' + } + }) +) expectType( mount((props: { a: number }, ctx: any) => { }, { From 686a5d6359078c9230e8ee0290eedc262194f60c Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Tue, 11 Apr 2023 08:13:43 +0800 Subject: [PATCH 17/18] chore: format --- test-dts/shallowMount.d-test.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/test-dts/shallowMount.d-test.ts b/test-dts/shallowMount.d-test.ts index ce33d451d..044aa058c 100644 --- a/test-dts/shallowMount.d-test.ts +++ b/test-dts/shallowMount.d-test.ts @@ -16,9 +16,11 @@ const AppWithDefine = defineComponent({ // accept props // vm is properly typed -expectType(shallowMount(AppWithDefine, { - props: { a: 'Hello', b: 2 } -}).vm.a) +expectType( + shallowMount(AppWithDefine, { + props: { a: 'Hello', b: 2 } + }).vm.a +) // allow extra props, like using `h()` shallowMount(AppWithDefine, { @@ -69,9 +71,11 @@ const AppWithArrayProps = { // accept props // vm is properly typed -expectType(shallowMount(AppWithArrayProps, { - props: { a: 'Hello' } -}).vm.a) +expectType( + shallowMount(AppWithArrayProps, { + props: { a: 'Hello' } + }).vm.a +) // can receive extra props // as they are declared as `string[]` From f2be9d575a8cf3bb3d80318a016850c592526b20 Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Tue, 11 Apr 2023 16:01:19 +0800 Subject: [PATCH 18/18] fix: take data option into account --- src/mount.ts | 6 ++++-- src/vueWrapper.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/mount.ts b/src/mount.ts index 5047df961..e4450c25a 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -16,8 +16,10 @@ type ShimSlotReturnType = T extends (...args: infer P) => any type WithArray = T | T[] +type ComponentData = T extends { data?(...args: any): infer D } ? D : {} + export type ComponentMountingOptions = Omit< - MountingOptions>, + MountingOptions, ComponentData>, 'slots' > & { slots?: { @@ -45,7 +47,7 @@ export function mount< >( originalComponent: T, options?: ComponentMountingOptions -): VueWrapper & ComponentProps> +): VueWrapper & ComponentProps & ComponentData> // implementation export function mount( diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index e2c2ff96c..c00310405 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -70,7 +70,7 @@ function createVMProxy( export class VueWrapper< VM = unknown, - T extends VM & ComponentPublicInstance = VM & ComponentPublicInstance + T extends ComponentPublicInstance = VM & ComponentPublicInstance > extends BaseWrapper { private readonly componentVM: T private readonly rootVM: ComponentPublicInstance | undefined | null