Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cypress Custom TypeScript Command is not a Function

I am implementing a custom Cypress command in TypeScript:

// support/commands.ts
const login = () => {
    console.log('Logging in...');
};

Cypress.Commands.add('login', login);

declare namespace Cypress {
    interface Chainable {
        login: typeof login;
    }
}

I try to call it using:

describe('Login Scenario', () => {
    it('should allow a user to login', () => {
        cy.visit('/');
        cy.login();
    });
});

Yet, it seems the command is not set up:

TypeError: cy.login is not a function

If I write the command in pure JavaScript (removing the namespace declaration and updating the call to (cy as any).login();, it works.

What am I missing?

like image 588
Jonathan Petitcolas Avatar asked Aug 05 '18 12:08

Jonathan Petitcolas


People also ask

Can I use TypeScript with Cypress?

Cypress ships with official type declarations for TypeScript. This allows you to write your tests in TypeScript.

What is custom command in Cypress?

Cypress custom commands are described by users and not the default commands from Cypress. These customized commands are used to create the test steps that are repeated in an automation flow. We can add and overwrite an already pre-existing command. They should be placed in the commands.

Where do I put custom commands in Cypress?

The best place to define the custom commands is in the cypress/support/commands. js file, as it loads before any of the test-script files.


2 Answers

I fixed it by adding index.d.ts file in my commands folder. In this file I added something like this:

import { MyCustomType } from '../Types';

declare global {
  namespace Cypress {
    interface Chainable<Subject = any> {
      login(): Chainable<MyCustomType>;
    }
  }
}

If you don't import or export anything, just omit global namespace declaration:

declare namespace Cypress {
  interface Chainable<Subject = any> {
    login(): Chainable<MyCustomType>;
  }
}

Keep in mind that it won't work with Typesciprt < 2.3, because default generics type has to be supported.

like image 167
Krzysztof Grzybek Avatar answered Sep 18 '22 13:09

Krzysztof Grzybek


Here is what I use and I do not have to add

/// <reference types="cypress" />

at the top of every file.

I have my custom typings under <projectroot>/cypress/support/index.d.ts

/// <reference types="cypress" />

declare namespace Cypress {
  interface Chainable<Subject> {
    getByDataTest(tag: string): Chainable<any>
  }
}

And my <projectroot>/cypress/tsconfig.json looks like

{
  "compilerOptions": {
    "strict": true,
    "baseUrl": "../node_modules",
    "target": "es5",
    "lib": ["es5", "dom"],
    "typeRoots": ["./support"]
  },
  "include": ["**/*.ts"]
}

And TypeScript is finally happy

describe('when I want to select by data test tag', () => {
  it('should select by data test tag', () => {
    cy.getByDataTest('yolo').should('exist')
  });
});
like image 28
GentryRiggen Avatar answered Sep 17 '22 13:09

GentryRiggen