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

Not able to use Component Testing with Vite/Vue after upgrade to TypeScript 5 #26628

Open
mbp opened this issue Apr 28, 2023 · 16 comments · May be fixed by #29441
Open

Not able to use Component Testing with Vite/Vue after upgrade to TypeScript 5 #26628

mbp opened this issue Apr 28, 2023 · 16 comments · May be fixed by #29441
Labels
CT Issue related to component testing npm: @cypress/vue @cypress/vue package issues topic: typescript Triaged Issue has been routed to backlog. This is not a commitment to have it prioritized by the team.

Comments

@mbp
Copy link

mbp commented Apr 28, 2023

Current behavior

I am using Vue 3.2.47, Vite 4.3.3, TypeScript 5.0.4 and I get TypeScript error message after upgrade. It seems similar as the issue that was fixed in #25538

Desired behavior

No error message

Test code to reproduce

MyComponent.ts:

<template>
    <span>
      <slot name="item" v-bind="{ item: item }"></slot>
    </span>
</template>

<script setup lang="ts">
interface Props {
  item: any;
}

defineProps<Props>();
</script>

MyComponent.cypress.ts:

import { mount } from 'cypress/vue';
import { h } from 'vue';
import MyComponent from './MyComponent .vue';

describe('MyComponent ', () => {
  it('should render', () => {
    mount(MyComponent , {
      props: {
        item: {
          id: 1,
          text: 'First element',
        }
      },
      slots: {
        item: ({ item }: { item: any }) =>
          h('div', {}, `${item.id} - ${item.text}`),
      },
    });
  });
});

Error is:

MyComponent.cypress.ts:7:11 - error TS2769: No overload matches this call.
  The last overload gave the following error.
    Argument of type '__VLS_WithTemplateSlots<DefineComponent<__VLS_TypePropsToRuntimeProps<Props>, {}, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 4 more ..., {}>, { ...; }>' is not assignable to parameter of type 'ComponentOptionsWithObjectProps<__VLS_TypePropsToRuntimeProps<Props>, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, string[], string>'.
      Type '__VLS_WithTemplateSlots<DefineComponent<__VLS_TypePropsToRuntimeProps<Props>, {}, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 4 more ..., {}>, { ...; }>' is not assignable to type 'ComponentOptionsBase<Readonly<ExtractPropTypes<__VLS_TypePropsToRuntimeProps<Props>>> & { [x: `on${Capitalize<string>}`]: ((...args: any[]) => any) | undefined; }, ... 10 more ..., string>'.
        Types of property 'emits' are incompatible.
          Type 'ThisType<void> | (string[] & ThisType<void>) | undefined' is not assignable to type '(string[] & ThisType<void>) | undefined'.
            Type 'ThisType<void>' is not assignable to type 'string[] & ThisType<void>'.
              Type 'ThisType<void>' is missing the following properties from type 'string[]': length, pop, push, concat, and 31 more.

7     mount(ListInteractive, {
            ~~~~~~~~~~~~~~~

  node_modules/cypress/vue/dist/index.d.ts:1339:18
    1339 declare function mount<PropsOptions extends Readonly<ComponentPropsOptions>, RawBindings, D extends {}, C extends ComputedOptions = {}, M extends Record<string, Function> = {}, E extends EmitsOptions = Record<string, any>, 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<ExtractPropTypes<PropsOptions> & PublicProps, D>): Cypress.Chainable<{
                          ~~~~~
    The last overload is declared here.


Found 1 error in MyComponent.cypress.ts:7

Cypress Version

12.11.0

Node version

v18

Operating System

Windows

Debug Logs

No response

Other

No response

@lmiller1990 lmiller1990 added npm: @cypress/vue @cypress/vue package issues CT Issue related to component testing labels May 1, 2023
@warrensplayer
Copy link
Contributor

@mbp I am not able to reproduce the same error using those versions of the libraries you mention, but I might not have setup my project the same as you. Please provide a reproducible example of the issue you're encountering. Here are some tips for providing a Short, Self Contained, Correct, Example and our own Troubleshooting Cypress guide.

@lmiller1990
Copy link
Contributor

#26633 may solve the issue.

@mbp
Copy link
Author

mbp commented May 3, 2023

@warrensplayer the issue can be reproduced by the same repro that is in #25538

So steps to reproduce:

  1. Clone https://github.com/lmiller1990/cypress-issue-23653
  2. Update cypress dependency to latest 12.11.0
  3. Call npm run build - confirm it still compiles (TypeScript 4.9)
  4. Now update remaining dependencies to latest versions (find list below)
  5. Call npm run build. Compilation error occurs
> [email protected] build
          Type 'ThisType<void> | (string[] & ThisType<void>) | undefined' is not assignable to type '(string[] & ThisType<void>) | undefined'.
            Type 'ThisType<void>' is not assignable to type 'string[] & ThisType<void>'.
              Type 'ThisType<void>' is missing the following properties from type 'string[]': length, pop, push, concat, and 31 more.

6     cy.mount(HelloWorld, {})               ~~~~~~~~~~
  node_modules/cypress/vue/dist/index.d.ts:1339:18
    1339 declare function mount<PropsOptions extends Readonly<ComponentPropsOptions>, RawBindings, D extends {}, C extends ComputedOptions = {}, M extends Record<string, Function> = {}, E extends EmitsOptions = Record<string, any>, 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<ExtractPropTypes<PropsOptions> & PublicProps, D>): Cypress.Chainable<{
                          ~~~~~
    The last overload is declared here.


Found 1 error in src/components/HelloWorld.cy.ts:6
  "dependencies": {
    "vue": "3.2.47"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "4.2.1",
    "cypress": "12.11.0",
    "typescript": "5.0.4",
    "vite": "4.3.3",
    "vue-tsc": "1.6.3"
  }

I don't know how to test if #26633 fixes the issue

@mbp
Copy link
Author

mbp commented May 10, 2023

Now that #26633 is part of 12.12.0, I tested again with the updated dependency. But it still does not compile. Line numbers changed a little though:

src/components/HelloWorld.cy.ts:6:14 - error TS2769: No overload matches this call.
  The last overload gave the following error.
    Argument of type '__VLS_WithTemplateSlots<DefineComponent<__VLS_TypePropsToRuntimeProps<{ label: string; }>, {}, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 4 more ..., {}>, { ...; }>' is not assignable to parameter of type 'ComponentOptionsWithObjectProps<__VLS_TypePropsToRuntimeProps<{ label: string; }>, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, string[], string>'.
      Type '__VLS_WithTemplateSlots<DefineComponent<__VLS_TypePropsToRuntimeProps<{ label: string; }>, {}, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 4 more ..., {}>, { ...; }>' is not assignable to type 'ComponentOptionsBase<Readonly<ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{ label: string; }>>> & { [x: `on${Capitalize<string>}`]: ((...args: any[]) => any) | undefined; }, ... 10 more ..., string>'.
        Types of property 'emits' are incompatible.
          Type 'ThisType<void> | (string[] & ThisType<void>) | undefined' is not assignable to type '(string[] & ThisType<void>) | undefined'.
            Type 'ThisType<void>' is not assignable to type 'string[] & ThisType<void>'.
              Type 'ThisType<void>' is missing the following properties from type 'string[]': length, pop, push, concat, and 31 more.

6     cy.mount(HelloWorld, {})
               ~~~~~~~~~~

  node_modules/cypress/vue/dist/index.d.ts:1377:18
    1377 declare function mount<PropsOptions extends Readonly<ComponentPropsOptions>, RawBindings, D extends {}, C extends ComputedOptions = {}, M extends Record<string, Function> = {}, E extends EmitsOptions = Record<string, any>, 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<ExtractPropTypes<PropsOptions> & PublicProps, D>): Cypress.Chainable<{
                          ~~~~~
    The last overload is declared here.


Found 1 error in src/components/HelloWorld.cy.ts:6

@marktnoonan
Copy link
Contributor

Thanks for the updated info @mbp, we'll look into this some more.

@xmatthias
Copy link

xmatthias commented May 12, 2023

I'm having the same error on a project of mine
Interestingly, it's only impacting one component - but not 2 others, which are similarly simple (the only difference is that the other components also have a computed value, which the "failing" one doesn't.
As such, i think that my setup is correct - but something else is messing with that specific component.

for now, i've @ts-expect-error'ed this ... but having this correct would be great

@warrensplayer
Copy link
Contributor

I was able to confirm this type error still exists when updating dependencies in the sample repo as documented in the comment above here: #26628 (comment)

The issue is with the slot in the button. If that is removed, then the typing is fine. Look at updating the mount types appropriately in the built-in Vue adaptor in Cypress.

@warrensplayer warrensplayer added the Triaged Issue has been routed to backlog. This is not a commitment to have it prioritized by the team. label May 31, 2023
@mbp
Copy link
Author

mbp commented Jun 1, 2023

I am just guessing here - but I believe there is chance this could be fixed with latest type file from @vue/test-utils. Please see related issue, which is also about combination of slots and props: vuejs/test-utils#2054

This fix is coming in @vue/test-utils 2.4.0, but not released yet.

@warrensplayer warrensplayer removed their assignment Jun 13, 2023
@WaldemarEnns
Copy link

Very similar error, here is my reproduction:

Setup

  • cypress 12.17.4
  • vue 3.2.41
  • typescript 5.0.2
  • tailwind 3.2.1 (since my example tests include tailwind)
  • vuetify 3.3.14 (since my app is based on vuetify and I have a custom mount() function implementation)

package.json

{
    "private": true,
    "type": "module",
    "scripts": {
        "dev": "vite",
        "build": "vue-tsc && vite build",
        "test:e2e": "cypress open"
    },
    "devDependencies": {
        "@fortawesome/fontawesome-free": "^6.4.2",
        "@inertiajs/vue3": "^1.0.0",
        "@tailwindcss/forms": "^0.5.3",
        "@types/ziggy-js": "^1.3.2",
        "@vitejs/plugin-vue": "^4.0.0",
        "autoprefixer": "^10.4.12",
        "axios": "^1.1.2",
        "cypress": "^12.17.4",
        "laravel-vite-plugin": "^0.7.5",
        "postcss": "^8.4.18",
        "tailwindcss": "^3.2.1",
        "typescript": "^5.0.2",
        "vite": "^4.0.0",
        "vue": "^3.2.41",
        "vue-tsc": "^1.2.0"
    },
    "dependencies": {
        "vuetify": "^3.3.14"
    }
}

InputLabel.vue

<script setup lang="ts">
defineProps<{
    value?: string;
}>();
</script>

<template>
    <label class="block font-medium text-sm text-gray-700 dark:text-gray-300">
        <span v-if="value">{{ value }}</span>
        <span v-else><slot /></span>
    </label>
</template>

InputLabel.cy.ts

import InputLabel from '../../../resources/js/Components/InputLabel.vue'

describe('<InputLabel />', () => {
  it('renders', () => {
    cy.mount(InputLabel, {
      props: {
        value: 'Test Label'
      }
    })
  })
})

Error for InputLabel.cy.ts (sorry it's german)

Der Typ "{ value: string; }" kann dem Typ "VNodeProps & { __v_isVNode?: undefined; [Symbol.iterator]?: undefined; } & Record<string, any> & { [x: number]: unknown; } & { readonly filter?: Prop<unknown, unknown> | { <S extends string>(predicate: (value: string, index: number, array: readonly string[]) => value is S, thisArg?: any): S[]; (predicate: (value: st..." nicht zugewiesen werden.
  Der Typ "{ value: string; }" kann dem Typ "{ readonly filter?: Prop<unknown, unknown> | { <S extends string>(predicate: (value: string, index: number, array: readonly string[]) => value is S, thisArg?: any): S[]; (predicate: (value: string, index: number, array: readonly string[]) => unknown, thisArg?: any): string[]; } | null | undefined; ... 22 more ...; r..." nicht zugewiesen werden.
    Die Typen der Eigenschaft "toString" sind nicht kompatibel.
      Der Typ "() => string" kann dem Typ "string" nicht zugewiesen werden.ts(2322)

PChip.vue (bunch of vuetify components)

<script setup lang="ts">
defineProps<{
  value?: string;
}>()
</script>

<template>
  <v-container class="pa-4">
    <v-chip class="mb-6">
      {{ value }}
    </v-chip>

    <v-text-field label="Label"></v-text-field>

    <v-avatar
      color="brown"
    >
      <span class="text-h5">WE</span>
    </v-avatar>
    
    <div class="mt-2">
      <v-btn color="error" class="mb-2 mr-2">Test</v-btn>
      <v-btn color="warning" class="mb-2 mr-2">Test</v-btn>
      <v-btn color="success" class="mb-2 mr-2">Test</v-btn>
    </div>
  </v-container>
</template>

PChip.cy.ts

import PChip from '../../../resources/js/Components/PChip.vue'

describe('<PChip />', () => {
  it('renders', () => {
    cy.mount(PChip, {
      props: {
        value: 'Test Chip'
      }
    })
  })
})

Error for PChip.cy.ts

Der Typ "{ value: string; }" kann dem Typ "VNodeProps & { __v_isVNode?: undefined; [Symbol.iterator]?: undefined; } & Record<string, any> & { [x: number]: unknown; } & { readonly filter?: Prop<unknown, unknown> | { <S extends string>(predicate: (value: string, index: number, array: readonly string[]) => value is S, thisArg?: any): S[]; (predicate: (value: st..." nicht zugewiesen werden.
  Der Typ "{ value: string; }" kann dem Typ "{ readonly filter?: Prop<unknown, unknown> | { <S extends string>(predicate: (value: string, index: number, array: readonly string[]) => value is S, thisArg?: any): S[]; (predicate: (value: string, index: number, array: readonly string[]) => unknown, thisArg?: any): string[]; } | null | undefined; ... 22 more ...; r..." nicht zugewiesen werden.
    Die Typen der Eigenschaft "toString" sind nicht kompatibel.
      Der Typ "() => string" kann dem Typ "string" nicht zugewiesen werden.ts(2322)

component.ts

// ***********************************************************
// This example support/component.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import './commands'

// Import styles
import '../../../resources/css/app.css'
import 'vuetify/styles'
import '@fortawesome/fontawesome-free/css/all.css'

// Alternatively you can use CommonJS syntax:
// require('./commands')

import { mount } from 'cypress/vue'
import { h } from 'vue'
import { VApp } from 'vuetify/components'
import vuetify from '../../../resources/js/plugins/vuetify'

Cypress.Commands.add('mount', (component, options = {}) => {
  options.global = options.global || {}
  options.global.plugins = options.global.plugins || []

  options.global.plugins.push({
    install(app) {
      app.use(vuetify)
    },
  })
  
  return mount(() => {
    return h(VApp, [h(component, options.props)])
  }, options)
})

// Example use:
// cy.mount(MyComponent)

type MountParams = Parameters<typeof mount>
type OptionsParam = MountParams[1]

declare global {
  namespace Cypress {
    interface Chainable {
      /**
       * Helper mount function for Vue Components
       * @param component Vue Component or JSX Element to mount
       * @param options Options passed to Vue Test Utils
       */
      mount(component: any, options?: OptionsParam): Chainable<any>
    }
  }
}

Results

The components get rendered correctly within cypress but I get the mentioned TS errors. Also, my component is labeled in Cypress as undefined:

InputLabel.cy.ts

unknown component

PChip.cy.ts

unknown component vuetify

@Jicmou
Copy link

Jicmou commented Nov 16, 2023

We had a very similar error, when having a slot in a tested component. In the end we could silence the error by setting strictFunctionTypes: false in tsconfig.json. We consider this a workaround rather than a fix though, and it could be nice not to be forced to have a less strict typescript configuration while using cypress and vue 🙏

@yhanssens
Copy link

I am just guessing here - but I believe there is chance this could be fixed with latest type file from @vue/test-utils. Please see related issue, which is also about combination of slots and props: vuejs/test-utils#2054

This fix is coming in @vue/test-utils 2.4.0, but not released yet.

This still seems to be the issue. Did you manage to find a workaround?

@mbp
Copy link
Author

mbp commented Feb 14, 2024

This still seems to be the issue. Did you manage to find a workaround?

I use this ugly workaround:

mount(MyComponent as any, { ... });

@lmiller1990
Copy link
Contributor

lmiller1990 commented Feb 15, 2024

It may be the type definitions in cypress/vue need updating to sync with the latest version of Test Utils. You can see here it is on 2.3.2 still

"@vue/test-utils": "2.3.2",

I think someone needs to make a PR to update that.

Note that cypress/vue bundles Test Utils - it will not slurp up the one in your node_modules, so you can't just install the latest Test Utils, Cypress must update the one they are using (just need to do the dependency update and wait for the next Cypress release).

@WaldemarEnns
Copy link

Has anything happened so far?

@lmiller1990
Copy link
Contributor

Not sure, check to see if the internal version of Test Utils was updated, if not you could submit a PR! See above post for more info.

@WaldemarEnns
Copy link

WaldemarEnns commented Mar 28, 2024

Not sure, check to see if the internal version of Test Utils was updated, if not you could submit a PR! See above post for more info.

I am giving this a try right now. Also, the docs might have to be updated or even extended for Vuetify specifically since the example there is not really working for me and my setup rather looks something like this (not that it is not fully TypeScript compliant and still errors at VLayout etc.):

import { h } from 'vue'
import { mount } from 'cypress/vue'
import { VLayout } from 'vuetify/components'
import vuetify from '@/plugins/vuetify'

type MountParams = Parameters<typeof mount>
type OptionsParam = MountParams[1]

declare global {
  namespace Cypress {
    interface Chainable {
      mount(
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        component: any,
        options?: OptionsParam
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      ): Chainable<any>
    }
  }
}

Cypress.Commands.add('mount', (component, options = {}) => {
  options.global = options.global || {}
  options.global.plugins = options.global.plugins || []

  options.global.plugins.push({
    install (app) {
      app.use(vuetify)
    }
  })

  return mount(VLayout, {
    ...options,
    slots: {
      default: h(component, options.props, {
        ...options.slots
      })
    }
  })
})

Note that I use VLayout since the latest version of Vuetify ships changes to the VApp wrapper that messed with my components (e.g. stretched them etc. due to display: flex on the v-applciation wrapper element).

Looking into the official Cypress repo, I noticed that they are using pure JS in component.js instead of TypeScript as it would be in a component.ts setup. So opening a PR that will fix TS, would also require changing the setup to TS as well.

@mbp mbp linked a pull request Apr 30, 2024 that will close this issue
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CT Issue related to component testing npm: @cypress/vue @cypress/vue package issues topic: typescript Triaged Issue has been routed to backlog. This is not a commitment to have it prioritized by the team.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants