Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better types for wrapper.vm when the component is closed #972

Open
cexbrayat opened this issue Sep 24, 2021 · 18 comments
Open

Better types for wrapper.vm when the component is closed #972

cexbrayat opened this issue Sep 24, 2021 · 18 comments
Labels

Comments

@cexbrayat
Copy link
Member

cexbrayat commented Sep 24, 2021

Since 2.0.0-rc.15, we are now exposing $.proxy as wrapper.vm to simplify testing of script setup component,
allowing to test the following component:

<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
</script>

with expect(wrapper.vm.count).toBe(0), even if count is not exposed by the component (see PR #931 ).

This works, but for TS (vue-tsc), wrapper.vm does not have a count property, because wrapper.vm is typed as ComponentPublicInstance.

Ideally, we would like wrapper.vm type to reflect that it is actually not the component public instance, but the properties exposed to the template. Is there a way to infer that?

To reproduce, remove "exclude": ["tests/expose.spec.ts"] from tsconfig.volar.json, and run yarn vue-tsc. It fails with:

tests/expose.spec.ts:38:23 - error TS2339: Property 'count' does not exist on type '{ $: ComponentInternalInstance; $data: {}; $props: Partial<{}> & Omit<Readonly<{} & {} & {}> & VNodeProps & AllowedComponentProps & ComponentCustomProps, never>; ... 10 more ...; $watch(source: string | Function, cb: Function, options?: WatchOptions<...> | undefined): WatchStopHandle; } & ... 4 more ... & ComponentC...'.

38     expect(wrapper.vm.count).toBe(1)

For readers interested in this issue, you can workaround it with an explicit cast:
expect((wrapper.vm as unknown as { count: number }).count).toBe(1)

@cexbrayat
Copy link
Member Author

@pikax do you have an idea how we could solve that?

@pikax
Copy link
Member

pikax commented Sep 24, 2021

Currently that's not possible, I'm working on this PR vuejs/core#4465 to improve some types, I can have a look on how to also add that info there

cexbrayat added a commit to cexbrayat/vue-test-utils-next that referenced this issue Dec 22, 2021
This new option allows a better typechecking of components that expose variables.
See vuejs/language-tools#805

Refs vuejs#972 as this partially fixes it
@cexbrayat
Copy link
Member Author

For anyone keeping up with this, @johnsoncodehk released vue-tsc@0.30.0 with a new option that improves the situation. See #1170

cexbrayat added a commit to cexbrayat/vue-test-utils-next that referenced this issue Dec 24, 2021
This new option allows a better typechecking of components that expose variables.
See vuejs/language-tools#805

Refs vuejs#972 as this partially fixes it
cexbrayat added a commit to cexbrayat/vue-test-utils-next that referenced this issue Dec 24, 2021
This new option allows a better typechecking of components that expose variables.
See vuejs/language-tools#805

Refs vuejs#972 as this partially fixes it
@felixzapata
Copy link

The explicit cast solution stops working with the last Vue release (3.2.45).

@cexbrayat
Copy link
Member Author

@felixzapata are you using VTU v2.2.2 ? There was a breaking change in Vue v3.2.45, but the latest VTU release should work around it.

@felixzapata
Copy link

felixzapata commented Nov 14, 2022

sorry, I forgot to mention that with VTU 2.2.2 also fails. I mean, I tested with Vue 3.2.45 and VTU 2.2.2

@cexbrayat
Copy link
Member Author

@felixzapata In that case, can you open an issue with a small repro using https://stackblitz.com/edit/vitest-dev-vitest-a961ap?file=package.json&initialPath=__vitest__ please? We'll take a look

@felixzapata
Copy link

felixzapata commented Nov 14, 2022

I will try because, besides the standard packages, we have some custom configurations and TypeScript typing rules.

I am reviewing the tests that are failing; all the ones we have using casting in order to spy methods.

@felixzapata
Copy link

Is there a way to allow this mocking? Is similar to this one but the problem I think is because of mount and because I am late setting the mock. I think it should be during the mounting process.

@cexbrayat
Copy link
Member Author

@felixzapata It is not possible, as this is not possible in vanilla JS. See #1798 (comment) for more explanation.

@felixzapata
Copy link

@felixzapata It is not possible, as this is not possible in vanilla JS. See #1798 (comment) for more explanation.

ok, maybe I have some thoughts of something similar I did in the past regarding the framework/library.

@matthew-dean
Copy link

This may have been improved for vue-tsc, but it still fails with Volar AFAIK.

@pm0u
Copy link

pm0u commented Nov 14, 2023

Is there any related issues for vue or volar that we could chime in on since this is an external issue?

@cexbrayat
Copy link
Member Author

@pm0u I don't think there are such issues upstream (but maybe there are, I haven't checked recently).
@pikax was working on a PR to improve the situation if I remember correctly, but I'm not sure of its status

@pm0u
Copy link

pm0u commented Nov 14, 2023

I saw that, however it looks like that has been untouched since 9/2021. The TS version referenced in the package json is a major version behind, so probably safe to say it is stale

@ulfgebhardt
Copy link

In component:

const slide = ref(0)

defineExpose({ slide })

In test:

it('has slide value 0', () => {
  expect(wrapper.vm.slide).toBe(0)
})

Not sure if proper solution, but solves the typing without any casts.

@cexbrayat
Copy link
Member Author

@ulfgebhardt Thanks, but your solution is expected to work: this issue is for the cases where you don't want to expose the variable.

@pikax
Copy link
Member

pikax commented Dec 19, 2023

This will require a few changes from https://github.com/vuejs/language-tools, since the SFC types are generated by it, I recommend creating a cross issue over there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants