Skip to content

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

Open

Description

@cexbrayat

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)

Activity

  1. cexbrayat commented on Sep 24, 2021

    @cexbrayat
    MemberAuthor

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

  2. pikax commented on Sep 24, 2021

    @pikax
    Member

    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

  3. cexbrayat commented on Dec 22, 2021

    @cexbrayat
    MemberAuthor

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

  4. felixzapata commented on Nov 14, 2022

    @felixzapata

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

  5. cexbrayat commented on Nov 14, 2022

    @cexbrayat
    MemberAuthor

    @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.

  6. felixzapata commented on Nov 14, 2022

    @felixzapata

    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

  7. cexbrayat commented on Nov 14, 2022

    @cexbrayat
    MemberAuthor

    @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

  8. felixzapata commented on Nov 14, 2022

    @felixzapata

    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.

  9. felixzapata commented on Nov 30, 2022

    @felixzapata

    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.

  10. cexbrayat commented on Nov 30, 2022

    @cexbrayat
    MemberAuthor

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

  11. felixzapata commented on Nov 30, 2022

    @felixzapata

    @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.

  12. matthew-dean commented on Feb 25, 2023

    @matthew-dean

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

  13. pm0u commented on Nov 14, 2023

    @pm0u

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

  14. cexbrayat commented on Nov 14, 2023

    @cexbrayat
    MemberAuthor

    @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

  15. pm0u commented on Nov 14, 2023

    @pm0u

    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

  16. ulfgebhardt commented on Dec 13, 2023

    @ulfgebhardt

    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.

  17. cexbrayat commented on Dec 13, 2023

    @cexbrayat
    MemberAuthor

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

  18. pikax commented on Dec 19, 2023

    @pikax
    Member

    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.

  19. alexanderschikora commented on Apr 1, 2025

    @alexanderschikora

    Can't we just expose everything, when the component is mounted in test-utils? That would fix all issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions