From d3e50f9e64b547cc5aaf8577fec3b1f4875d2748 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Sun, 16 Apr 2023 00:38:15 +0800 Subject: [PATCH] feat: integrated `vue-component-type-helpers` (#2026) This commit also drops node 14 from the build The public signatures of `mount` and `renderToString` are now simplified, and should be more accurate. Fixes #1973 --- .github/workflows/ci.yml | 2 +- package.json | 3 +- pnpm-lock.yaml | 52 ++-- src/mount.ts | 278 ++++----------------- src/renderToString.ts | 225 ++--------------- src/vueWrapper.ts | 16 +- test-dts/mount.d-test.ts | 32 +-- test-dts/renderToString.d-test.ts | 2 +- test-dts/shallowMount.d-test.ts | 22 +- tests/components/ComponentWithSlots.vue | 17 +- tests/components/WithTeleportEmitsComp.vue | 4 +- tests/config.spec.ts | 4 +- tests/features/compat.spec.ts | 5 +- tests/props.spec.ts | 5 +- tests/renderToString.spec.ts | 2 +- tests/setData.spec.ts | 4 +- types/testing.d.ts | 3 +- 17 files changed, 144 insertions(+), 532 deletions(-) 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 diff --git a/package.json b/package.json index 47e6f1b04..89166bccc 100644 --- a/package.json +++ b/package.json @@ -60,8 +60,9 @@ "vitest": "0.30.1", "vue": "3.2.47", "vue-class-component": "8.0.0-rc.1", + "vue-component-type-helpers": "1.3.14-patch.1", "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 ef977392f..3e556a088 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-patch.1 + version: 1.3.14-patch.1 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) @@ -1291,29 +1294,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 @@ -1323,11 +1326,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: @@ -4051,6 +4054,10 @@ packages: vue: 3.2.47 dev: true + /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): resolution: {integrity: sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==} peerDependencies: @@ -4067,14 +4074,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/mount.ts b/src/mount.ts index 0fe8ce4e8..e4450c25a 100644 --- a/src/mount.ts +++ b/src/mount.ts @@ -1,247 +1,53 @@ -import { - FunctionalComponent, - ComponentPublicInstance, - ComponentOptionsWithObjectProps, - ComponentOptionsWithArrayProps, - ComponentOptionsWithoutProps, - ExtractPropTypes, - VNodeProps, - ComponentOptionsMixin, - DefineComponent, - MethodOptions, - AllowedComponentProps, - ComponentCustomProps, - ExtractDefaultPropTypes, - EmitsOptions, - ComputedOptions, - ComponentPropsOptions, - Prop -} from 'vue' +import { ComponentPublicInstance, DefineComponent, VNode } from 'vue' +import type { + ComponentExposed, + ComponentProps, + ComponentSlots +} from 'vue-component-type-helpers' +import { createInstance } from './createInstance' import { MountingOptions } from './types' -import { VueWrapper } from './vueWrapper' import { trackInstance } from './utils/autoUnmount' +import { VueWrapper } from './vueWrapper' import { createVueWrapper } from './wrapperFactory' -import { createInstance } from './createInstance' - -// 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> - -// 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 +type ShimSlotReturnType = T extends (...args: infer P) => any + ? (...args: P) => any + : never + +type WithArray = T | T[] + +type ComponentData = T extends { data?(...args: any): infer D } ? D : {} + +export type ComponentMountingOptions = Omit< + MountingOptions, ComponentData>, + 'slots' +> & { + slots?: { + [K in keyof ComponentSlots]: WithArray< + | ShimSlotReturnType[K]> + | string + | VNode + | (new () => any) + | { template: string } > - > -> -// component declared by vue-tsc ScriptSetup -export function mount>( - component: T, - options?: ComponentMountingOptions -): VueWrapper> - -// 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> + } +} & Record -// 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 + 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 >( - 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 - > -> + originalComponent: T, + options?: ComponentMountingOptions +): VueWrapper & ComponentProps & ComponentData> // implementation export function mount( diff --git a/src/renderToString.ts b/src/renderToString.ts index 9d2250852..0e666e8b9 100644 --- a/src/renderToString.ts +++ b/src/renderToString.ts @@ -1,217 +1,24 @@ import { renderToString as baseRenderToString } from '@vue/server-renderer' -import { - FunctionalComponent, - ComponentOptionsWithObjectProps, - ComponentOptionsWithArrayProps, - ComponentOptionsWithoutProps, - ExtractPropTypes, - VNodeProps, - ComponentOptionsMixin, - DefineComponent, - MethodOptions, - AllowedComponentProps, - ComponentCustomProps, - ExtractDefaultPropTypes, - EmitsOptions, - ComputedOptions, - ComponentPropsOptions, - Prop -} from 'vue' - -import { RenderMountingOptions } from './types' +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 - -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 ->( - component: DefineComponent< - PropsOrPropOptions, - RawBindings, - D, - C, - M, - Mixin, - Extends, - E, - EE, - PP, - Props, - Defaults - >, - options?: RenderMountingOptions< - Partial & Omit, - D - > & - Record -): 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 = {}, - 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 + 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 >( - componentOptions: ComponentOptionsWithObjectProps< - PropsOptions, - RawBindings, - D, - C, - M, - E, - Mixin, - Extends, - EE - >, - options?: RenderMountingOptions< - ExtractPropTypes & PublicProps, - D - > + originalComponent: T, + options?: ComponentMountingOptions & + Pick, 'attachTo'> ): Promise export function renderToString(component: any, options?: any): Promise { diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 4f53f8987..c00310405 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -1,10 +1,4 @@ -import { - nextTick, - App, - ComponentCustomProperties, - ComponentPublicInstance, - VNode -} from 'vue' +import { nextTick, App, ComponentPublicInstance, VNode } from 'vue' import { config } from './config' import domEvents from './constants/dom-events' @@ -75,12 +69,8 @@ function createVMProxy( } export class VueWrapper< - T extends Omit< - ComponentPublicInstance, - '$emit' | keyof ComponentCustomProperties - > & { - $emit: (event: any, ...args: any[]) => void - } & ComponentCustomProperties = ComponentPublicInstance + VM = unknown, + T extends ComponentPublicInstance = VM & ComponentPublicInstance > extends BaseWrapper { private readonly componentVM: T private readonly rootVM: ComponentPublicInstance | undefined | null diff --git a/test-dts/mount.d-test.ts b/test-dts/mount.d-test.ts index 4c5b47753..446d4075f 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 } }) ) @@ -133,15 +133,17 @@ 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) => {}, { + mount((props: { a: number }, ctx: any) => { }, { props: { a: 22 } @@ -245,7 +247,7 @@ class CustomClassComponent { return this.props } context: SetupContext - render(): VNodeChild {} + render(): VNodeChild { } } class NoPropCustomClassComponent extends CustomClassComponent { count = ref(0) @@ -278,16 +280,16 @@ class WithPropCustomClassComponent extends CustomClassComponent( - // @ts-expect-error should has props error - WithPropCustomClassComponent, + mount( + WithPropCustomClassComponent as typeof WithPropCustomClassComponent & (new () => { $props: CustomClassComponentProps }), { + // @ts-expect-error should has props error props: {} } ) ) -mount( - WithPropCustomClassComponent, +mount( + WithPropCustomClassComponent as typeof WithPropCustomClassComponent & (new () => { $props: CustomClassComponentProps }), { props: { size: 'small' } } @@ -318,7 +320,6 @@ mount(Foo, { expectError( mount( - // @ts-expect-error defineComponent({ props: { baz: String, @@ -329,6 +330,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..044aa058c 100644 --- a/test-dts/shallowMount.d-test.ts +++ b/test-dts/shallowMount.d-test.ts @@ -15,11 +15,12 @@ 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 +28,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 +70,12 @@ 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 +88,7 @@ const AppWithoutProps = { } // allow extra props, like using `h()` -wrapper = shallowMount(AppWithoutProps, { +shallowMount(AppWithoutProps, { props: { b: 'Hello' } }) 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..fae24099b 100644 --- a/tests/components/WithTeleportEmitsComp.vue +++ b/tests/components/WithTeleportEmitsComp.vue @@ -1,6 +1,8 @@ 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 3fb175088..6984a3e35 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,12 +221,13 @@ describe('@vue/compat build', () => { GLOBAL_PROTOTYPE: 'suppress-warning' }) + // @ts-expect-error Vue.prototype.$test = 1 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/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 }) + } } }) 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') 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 }