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

Unable to overwrite command with TS overloads #19564

Open
jaroslav-kubicek opened this issue Jan 5, 2022 · 11 comments
Open

Unable to overwrite command with TS overloads #19564

jaroslav-kubicek opened this issue Jan 5, 2022 · 11 comments
Labels
type: typings Issue related to Cypress types (for TypeScript)

Comments

@jaroslav-kubicek
Copy link

jaroslav-kubicek commented Jan 5, 2022

Current behavior

Given I override visit command as below:

Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
  // do something with URL as string
  const char = url.includes('?')

  return originalFn(url, options);
});

I'm unable to type this:

Cypress.Commands.overwrite<'visit'>('visit', (originalFn, url, options?: Partial<VisitOptions>) => {
    // do something with URL as string
  const char = url.includes('?') // TS2339: Property 'includes' does not exist on type 'Partial  & { url: string; }'

  return originalFn(url, options); // TS2554: Expected 1 arguments, but got 2.
});

... as cy.visit is defined with two type overloads, but only the latter one is taken into account:

    visit(url: string, options?: Partial<VisitOptions>): Chainable<AUTWindow>
    visit(options: Partial<VisitOptions> & { url: string }): Chainable<AUTWindow>

Desired behavior

I'm able to override visit command and use visit(url: string, options?: Partial<VisitOptions>): Chainable<AUTWindow> variant.

Test code to reproduce

Cypress.Commands.overwrite<'visit'>('visit', (originalFn, url, options?: Partial<VisitOptions>) => {
    // do something with URL as string
  const char = url.includes('?') // TS2339: Property 'includes' does not exist on type 'Partial  & { url: string; }'

  return originalFn(url, options); // TS2554: Expected 1 arguments, but got 2.
});

Cypress Version

9.2.0

Other

No response

@fugigoose
Copy link

fugigoose commented Jan 6, 2022

I just ran into this today as well, had to simply @ts-ignore for now. I wonder if it's related to how Parameters (used as the args type for CommandFnWithOriginalFn) is returning the following intersection:

[string, (Partial<VisitOptions> | undefined)] & [(Partial<VisitOptions> & {url: string})

@mjhenkes
Copy link
Member

mjhenkes commented Jan 7, 2022

@jaroslav-kubicek, thanks for logging the issue and providing the reproducible example. Based on your provided code i was able to reproduce this issue locally.

@mjhenkes mjhenkes added type: typings Issue related to Cypress types (for TypeScript) stage: ready for work The issue is reproducible and in scope labels Jan 7, 2022
@alexniculae
Copy link

alexniculae commented Jan 10, 2022

Same in my case, but for adding a custom (dual) command with multiple definitions, not for overwriting an existing one - error and details copied below.

I also added a // @ts-ignore for Cypress.Commands.add and it's now ignoring the issue; but I think it's safer to stay on 8.3.0, as it seems to be the last stable version of Cypress.

Great features added in version(s) 9.x, but too many issues and breaking changes that were not considered or not documented; looking forward for a reliable release 🙂

(property) Cypress.Cypress.Commands: {
    add<T extends keyof Cypress.Chainable<any>>(name: T, fn: Cypress.CommandFn<T>): void;
    add<T extends keyof Cypress.Chainable<any>>(name: T, options: Cypress.CommandOptions & {
        ...;
    }, fn: Cypress.CommandFn<...>): void;
    add<T extends keyof Cypress.Chainable<...>, S extends keyof Cypress.PrevSubjectMap<...>>(name: T, options: Cypress.CommandOptions & {
        ...;
    }, fn: Cypress.CommandFnWithSubject<...>): void;
    add<T extends keyof Cypress.Chainable<...>, S extends keyof Cypress.PrevSubjectMap<...>>(name: T, options: Cypress.CommandOptions & {
        ...;
    }, fn: Cypress.CommandFnWithSubject<...>): void;
    overwrite<T extends keyof Cypress.Chainable<...>>(name: T, fn: Cypress.CommandFnWithOriginalFn<...>): void;
    overwrite<T extends keyof Cypress.Chainable<...>, S extends keyof Cypress.PrevSubjectMap<...>>(name: T, fn: Cypress.CommandFnWithOriginalFnAndSubject<...>): void;
}
@see — https://on.cypress.io/api/commands

No overload matches this call.
  Overload 1 of 4, '(name: "testCustomCommandCy9.2", options: CommandOptions & { prevSubject: false; }, fn: CommandFn<"testCustomCommandCy9.2">): void', gave the following error.
    Type 'string' is not assignable to type '(boolean | keyof PrevSubjectMap<unknown> | (keyof PrevSubjectMap<unknown>)[]) & false'.
  Overload 2 of 4, '(name: "testCustomCommandCy9.2", options: CommandOptions & { prevSubject: true | "optional" | ["optional"]; }, fn: CommandFnWithSubject<"testCustomCommandCy9.2", unknown>): void', gave the following error.
    Argument of type '(this: Context, $prevSubject: unknown, selector: string, content: Parameters<ChainableMethods<any>[T]>[1], options?: Parameters<ChainableMethods<any>[T]>[2]) => Chainable<...>' is not assignable to parameter of type 'CommandFnWithSubject<"testCustomCommandCy9.2", unknown>'.
  Overload 3 of 4, '(name: "testCustomCommandCy9.2", options: CommandOptions & { prevSubject: (keyof PrevSubjectMap<unknown>)[]; }, fn: CommandFnWithSubject<"testCustomCommandCy9.2", void | Document | JQuery<...> | Window>): void', gave the following error.
    Type '"optional"' is not assignable to type '(boolean | keyof PrevSubjectMap<unknown> | (keyof PrevSubjectMap<unknown>)[]) & (keyof PrevSubjectMap<unknown>)[]'.ts(2769)
cypress.d.ts(22, 5): The expected type comes from property 'prevSubject' which is declared here on type 'CommandOptions & { prevSubject: false; }'
cypress.d.ts(22, 5): The expected type comes from property 'prevSubject' which is declared here on type 'CommandOptions & { prevSubject: (keyof PrevSubjectMap<unknown>)[]; }'

@edufarre
Copy link

edufarre commented Mar 1, 2022

Do we have any updates on this? I am using the version 9.5.0 and I am still having this issue when trying to Cypress.Commands.overwrite the original visit command

@dclowd9901
Copy link

dclowd9901 commented Apr 28, 2022

One workaround for this that we used until the Cypress devs release a fix was simply swapping the visit function types in our own type definition file:

declare namespace Cypress {
  interface Chainable {
    ...
    visit(
      options: Partial<Cypress.VisitOptions & PopulatePreloadsOptions> & { url: string }
    ): Cypress.Chainable<Cypress.AUTWindow>;
    visit(
      url: string,
      options?: Partial<Cypress.VisitOptions & PopulatePreloadsOptions>
    ): Cypress.Chainable<Cypress.AUTWindow>;
    ...
  }
}

It's janky, but at least we still get type assertions.

Does anyone know what the canonical way to resolve something like this in Typescript? It seems like it's probably not solvable using the string literal generic mechanism for overwrite. Maybe a predicate?

Edit: Looks like it goes back to this question: microsoft/TypeScript#47540

@cypress-bot cypress-bot bot added stage: backlog and removed stage: ready for work The issue is reproducible and in scope labels Apr 29, 2022
@nikepol
Copy link

nikepol commented Mar 8, 2023

This one helped me to fix TS2554: Expected 1 arguments, but got 2.
YourCommand(value: string, any?: string, any2?:string): Chainable<JQuery<HTMLElement>>

@cypress-app-bot
Copy link
Collaborator

This issue has not had any activity in 180 days. Cypress evolves quickly and the reported behavior should be tested on the latest version of Cypress to verify the behavior is still occurring. It will be closed in 14 days if no updates are provided.

@cypress-app-bot cypress-app-bot added the stale no activity on this issue for a long period label Sep 5, 2023
@cypress-app-bot
Copy link
Collaborator

This issue has been closed due to inactivity.

@cypress-app-bot cypress-app-bot closed this as not planned Won't fix, can't repro, duplicate, stale Sep 19, 2023
@unikitty37
Copy link

…and yet, the issue persists and is still present in Cypress 13.7.3.

The auto-generated support/commands.ts has this example

// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })

but if I add this to the file:

Cypress.Commands.add('login', (email, password) => { return true })

I get

Argument of type '"login"' is not assignable to parameter of type 'keyof Chainable<any>'.

Surely if Cypress is auto-generating a .ts file, the examples it gives should have valid types?

@jennifer-shehane jennifer-shehane removed the stale no activity on this issue for a long period label Apr 16, 2024
@tfrijsewijk
Copy link

Still a problem in 13.10.0:

image

It's a cleaned up copy/paste from the Cypress documentation: https://docs.cypress.io/api/cypress-api/custom-commands#Overwrite-visit-command

nunogois added a commit to Unleash/unleash that referenced this issue Sep 26, 2024
Some e2e Cypress tests were failing due to the Vercel live feedback
toolbar covering interactive elements, preventing test actions from
completing:
https://github.com/Unleash/unleash/actions/runs/11048512034/job/30692949711#step:4:136

This PR addresses the issue by disabling the Vercel toolbar specifically
during Cypress tests. This is done by setting the
`x-vercel-skip-toolbar` header, which Vercel provides to prevent the
toolbar from interfering with automated tests. You can find more
information about this feature in the Vercel documentation: [Disable
Toolbar for
Automation](https://vercel.com/docs/workflow-collaboration/vercel-toolbar/managing-toolbar#disable-toolbar-for-automation).

Specific type declarations were needed due to
cypress-io/cypress#19564
@maks-io
Copy link

maks-io commented Oct 15, 2024

Just a little "push" from my side: still a problem in version 13.15.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: typings Issue related to Cypress types (for TypeScript)
Projects
None yet
Development

No branches or pull requests