Cypress doesn't see custom cy. commands

Viewed 22950

Cypress can't import custom command

commands.js

Cypress.Commands.add('generateToken', ({secret}) => {
    const totp = require('totp-generator');
    const token = totp(secret); 
    });

support/index.js

import './commands'

test.spec.ts

/// <reference types="Cypress" />

context('Actions', () => {
    beforeEach(() => {})
  })
    it('Main test', () => {
        cy.generateToken('XXXX');
    })

All the time generateToken() is underlined in test.spec.ts and error appears:

Property 'generateToken' does not exist on type 'cy'.

index.js and commands.js were not moved from original directories. cypress.json file is empty.

8 Answers

Since your spec is a typescript file, did you add a new types definition for the support/index.js?

Their documentation seems to outline it pretty well here. Only thing that is different with their example though is that you're not returning anything from generateToken so I don't think you can place it into the global Chainable interface.

You could try adding this in a support/index.d.ts file and see if it yells at you

declare namespace Cypress {
  interface Chainable {
    generateToken({secret}: {secret: string}): void
  }
}

Since the proposed answer of nshirley did not work for me, I found this comment. It is very similar but adds declare global at the top, to declare these custom commands on a global scope.

Here is a working example:

cypress/support/commands.ts:

declare global {
  namespace Cypress {
    interface Chainable<Subject> {
      /**
       * Provides a working example
       */
      generateToken(secret: any): Cypress.Chainable<Element>;
    }
  }
}

const generateToken = (secret: any) => {
  // Your Code
};

Cypress.Commands.add("generateToken", generateToken);

And in your test you can just use it:

cy.generateToken("Example");

As you can see, you can even provide some documentation for your methods, but that is completely optional.

Fully working in 2021.

for support/index.ts file

import './commands'

for support/commands.ts file

Cypress.Commands.add('generateToken', generateToken);
function generateToken({secret}): void {
    const totp = require('totp-generator');
    const token = totp(secret); 
}

// this is another example.
Cypress.Commands.add('login', login);
function login(username: string, password: string): void {
    // steps for login 
}

declare namespace Cypress {
    interface Chainable<Subject> {
       generateToken({secret}): void;

       /**
        * This will log user in
        * @param email string
        * @param password string
        */
       login(email: string, password: string): void;
    }
}

for test.spec.ts file

cy.login("somebody@domain.com", "something");
cy.generateToken("Example");

None of the other answers worked for me. I wanted to have type support in the VS Code as well as I didn't want to face cypress Property does not exist on type 'cy & EventEmitter' runtime error.

I have added another example of login with JSDoc support.

Here is how I get TypeScript to see my custom commands:

commands.ts

declare namespace Cypress {
  interface Chainable<Subject> {
    generateToken(secret: any): Cypres.Chainable<void>;
  }
}

function generateToken(secret: any): void {
  // Generate token
}

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

test.spec.ts

cy.generateToken(secret);

add the path in tsconfig.json

{
  "include": [
    "integration/*.ts",
    "support/*.ts"
  ]
}

Try to call Cypress.generateToken('XXXX'); Does that work?

Also, try to remove unnecessary parentheses while adding the command. Try this:

Cypress.Commands.add('generateToken', secret => {
    const totp = require('totp-generator');
    const token = totp(secret); 
});

Do something like this in support/command.js

Cypress.Commands.add('generateToken', (secret) => {

       const totp = require('totp-generator');
       const token = totp(secret);
  };
  cy.request(options)

});

Then in your js code

    /// <reference types="Cypress" />

context('Actions', () => {
    beforeEach(() => {})
  })
    it('Main test', () => {
        const token ='XXXX'
        cy.generateToken(token);
    })

Edit 1

Can you add this and can add more iterative waits as per the test you have

describe('check the tokens', function() 
{
// on 30 seconds 
it('first token ',()=> {
    cy.wait(30000).then(()=>{
        const token = getToken();   // You're waiting here for 30 sec before you get token
        console.log('first token: ' + token);
    })
})
// on 60 seconds 
it('second token', ()=>{
    cy.wait(60000).then(()=>{
        const token = getToken();
        console.log('second token: '+ token);
    });
})
})

function getToken () {
    const totp = require('totp-generator');
    const token = totp('ABCD');
    return token;
  }

Try below and see if it works.

Cypress.Commands.add('generateToken', { prevSubject: false }, ({secret}) => {

// Your code.

});

Related