cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.75k stars 3.16k forks source link

TS errors with slots or/and props in Vue 3 #29799

Open florianFM opened 2 months ago

florianFM commented 2 months ago

Current behavior

Since a few days we detected "errors" when we are using slots in component tests. It was not here before. The test is working but it's annoying to have this.

Screenshot 2024-07-03 at 11 12 54

Desired behavior

No response

Test code to reproduce

FmBanner.cy.ts

  it('renders and displays title and content with default', () => {
    cy.mount(FmBanner, {
      props: {
        title: 'Test Title',
        content: 'Test content',
      },
    });

    cy.get('[data-cy="fm-banner__title"]').should('contain', 'Test Title');
    cy.get('[data-cy="fm-banner__content"]').should('contain', 'Test content');
    cy.get('.fa-circle-info').should('exist');
    cy.get('.bg-grey-50').should('exist');
  });

FmBanner.vue

<template>
  <q-banner class="fm-banner q-py-md" :class="typeClass" inline-actions>
    <template v-if="!noIcon" v-slot:avatar>
      <q-icon :name="iconName" size="sm" :class="iconColor" data-cy="fm-banner__icon" />
    </template>
    <div v-if="title || content">
      <p data-cy="fm-banner__title">{{ title }}</p>
      <p class="text-p2" data-cy="fm-banner__content">{{ content }}</p>
    </div>
    <slot />
    <template v-slot:action>
      <slot name="action" />
    </template>
  </q-banner>
</template>

<script setup lang="ts">
import { computed } from 'vue';

const props = defineProps({
  type: {
    type: String,
    default: 'info',
    validator: (value: string) => ['warning', 'error', 'success', 'info'].includes(value),
  },
  title: {
    type: String,
    required: false,
  },
  content: {
    type: String,
    required: false,
  },
  noIcon: {
    type: Boolean,
    default: false,
  },
});

const typeClass = computed(() => {
  switch (props.type) {
    case 'warning':
      return 'bg-warning-light';
    case 'error':
      return 'bg-error-light';
    case 'success':
      return 'bg-success-light';
    case 'info':
      return 'bg-grey-50';
    default:
      return 'bg-grey-50';
  }
});

const iconName = computed(() => {
  switch (props.type) {
    case 'warning':
      return 'fa-solid fa-circle-exclamation';
    case 'error':
      return 'fa-solid fa-triangle-exclamation';
    case 'success':
      return 'fa-solid fa-check';
    case 'info':
      return 'fa-solid fa-circle-info';
    default:
      return 'fa-solid fa-circle-exclamation';
  }
});

const iconColor = computed(() => {
  switch (props.type) {
    case 'warning':
      return 'text-primary-400';
    case 'error':
      return 'text-error-light';
    case 'success':
      return 'text-success-light';
    case 'info':
      return 'text-primary-400';
    default:
      return 'text-primary-400';
  }
});
</script>

<style>
.fm-banner {
  border-radius: 4px;
}
</style>

Cypress Version

13.13.0

Node version

v18.18.1

Operating System

macOS 14.5

Debug Logs

No response

Other

Full error:


  The last overload gave the following error.
    Argument of type '__VLS_WithTemplateSlots<DefineComponent<{ type: { type: StringConstructor; default: string; validator: (value: string) => boolean; }; title: { type: StringConstructor; required: false; }; content: { ...; }; noIcon: { ...; }; }, ... 11 more ..., {}>, { ...; }>' is not assignable to parameter of type 'ComponentOptionsWithObjectProps<Readonly<ComponentPropsOptions>, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, string[], string>'.
      Type '__VLS_WithTemplateSlots<DefineComponent<{ type: { type: StringConstructor; default: string; validator: (value: string) => boolean; }; title: { type: StringConstructor; required: false; }; content: { ...; }; noIcon: { ...; }; }, ... 11 more ..., {}>, { ...; }>' is not assignable to type 'ComponentOptionsBase<{ readonly [x: number]: unknown; readonly [x: on${Capitalize<string>}]: ((...args: any[]) => any) | undefined; readonly length?: number | Prop<unknown, unknown> | null | undefined; readonly concat?: Prop<unknown, unknown> | { (...items: ConcatArray<...>[]): string[]; (...items: (string | Conca...'.
        Types of property 'setup' are incompatible.
          Type '((this: void, props: LooseRequired<Readonly<ExtractPropTypes<{ type: { type: StringConstructor; default: string; validator: (value: string) => boolean; }; title: { type: StringConstructor; required: false; }; content: { ...; }; noIcon: { ...; }; }>> & {}>, ctx: { ...; }) => void | ... 2 more ... | Promise<...>) | un...' is not assignable to type '((this: void, props: LooseRequired<{ readonly [x: number]: unknown; readonly [x: on${Capitalize<string>}]: ((...args: any[]) => any) | undefined; readonly length?: number | Prop<unknown, unknown> | null | undefined; readonly concat?: Prop<unknown, unknown> | { ...; } | null | undefined; ... 27 more ...; readonly t...'.
            Type '(this: void, props: LooseRequired<Readonly<ExtractPropTypes<{ type: { type: StringConstructor; default: string; validator: (value: string) => boolean; }; title: { type: StringConstructor; required: false; }; content: { ...; }; noIcon: { ...; }; }>> & {}>, ctx: { ...; }) => void | ... 2 more ... | Promise<...>' is not assignable to type '(this: void, props: LooseRequired<{ readonly [x: number]: unknown; readonly [x: on${Capitalize<string>}]: ((...args: any[]) => any) | undefined; readonly length?: number | Prop<unknown, unknown> | null | undefined; readonly concat?: Prop<unknown, unknown> | { ...; } | null | undefined; ... 27 more ...; readonly to...'.
              Types of parameters 'props' and 'props' are incompatible.
                Type 'LooseRequired<{ readonly [x: number]: unknown; readonly [x: on${Capitalize<string>}]: ((...args: any[]) => any) | undefined; readonly length?: number | Prop<unknown, unknown> | null | undefined; readonly concat?: Prop<unknown, unknown> | { ...; } | null | undefined; ... 27 more ...; readonly toLocaleString?: strin...' is missing the following properties from type 'LooseRequired<Readonly<ExtractPropTypes<{ type: { type: StringConstructor; default: string; validator: (value: string) => boolean; }; title: { type: StringConstructor; required: false; }; content: { ...; }; noIcon: { ...; }; }>> & {}>': type, noIcon, title, contentts(2769)
index.d.ts(1377, 18): The last overload is declared here.```
jennifer-shehane commented 2 months ago

@florianFM What changed in between not seeing this and seeing this? Did you update Cypress versions?

florianFM commented 2 months ago

@jennifer-shehane I've backed up my package.json more than 4 months ago and the error is still here... So I really don't know what triggers that

florianFM commented 2 months ago

Ok I might have been wrong about the slots stuff. After other tests on my end it looks like it's about default values on props. Every time I try to add a props that has a default value (or a Boolean), it triggers an error

florianFM commented 2 months ago

I even tried declaring it with something like that and it's still doesn't work

export interface Props {
  type: 'warning' | 'error' | 'success' | 'info';
  title?: string;
  content?: string;
  noIcon?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  type: 'info',
  noIcon: false,
});