23

I've created the following custom command in my cypress/support/commands.js file.

Cypress.Commands.add("login", (username, password) => {
    cy.request({
        method: 'POST',
        form: true,
        url: '/test/login/',
        body: {'username': username, 'password': password}
    })
})

I had tests passing and login working before moving the login functionality to this custom command. I'm invoking it in my spec with cy.login(testuser, testpwd), but I'm getting the following error message: TypeError: cy.login is not a function. The docs say that /cypress/support/commands.js is loaded before any test files are evaluated, so I assumed that simply placing a custom command in there would make the command available. I'm running the tests through the local (GUI) test runner.

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Dan Swain
  • 2,910
  • 1
  • 16
  • 36

8 Answers8

27

All the code and referenced modules in index.js are loaded before your test file. So you need to refer(require) commands.js in your index.js file. You can however import commands.js module directly in your test file but then you need to include it every test file. Recommended approach is to include it in index.js file and you are not worried about explicitly refer in your test files.

Dinesh Kumar
  • 1,694
  • 15
  • 22
  • 5
    Thank you. In [this section of the docs](https://docs.cypress.io/api/cypress-api/custom-commands.html#Syntax) it says: "A great place to define or overwrite commands is in your cypress/support/commands.js file, since it is loaded before any test files are evaluated." From that it sounded like no import of commands.js is required, so it never occurred to me to try that. Similarly, for index.js they say that it is imported prior to running any spec "so you don’t have to import this file in every single one of your spec files" - but I had to import index.js and, within it, import commands.js. – Dan Swain Dec 08 '17 at 14:31
  • I also think it's not particularly clear from the docs... Will expand on this answer with a sample. – GrayedFox Aug 20 '18 at 15:53
  • Will this work with different user names and passwords in each spec file? I've used your suggestions, and updated my login to use variables so I can have the user i need in each spec, however it always logs in now as userA, it never uses userB from this other spec. I'm not sure how Command is even getting a user name and password if it's not taking it from my spec i'm running. – Daniel Aug 13 '20 at 18:52
  • Dan Swain Now the official (& updated) document says-A great place to define or overwrite commands is in your cypress/support/commands.js file, since it is loaded before any test files are evaluated via an import statement in your supportFile (cypress/support/index.js by default). – Atul KS May 13 '21 at 19:46
12

To expand on @Dinesh Kumar's excellent answer, it's also important you haven't disabled support for the default support file (I know, unfortunate naming scheme in this case) inside your cypress.json by adding the line: supportFile: false.

Delete that line from your cypress.json if it's there. You can also specify a different path if you're not happy using the default path of cypress/support/index.js.

Working index.js with commands.js file - both in the support folder:

// index.js
const customCommands = require('./commands.js')

module.exports = {
  commands: customCommands
}

And double check your settings:

// cypress.json
{
  "baseUrl": "http://demo.your-domain.test",
  "supportFile": false,  // <-- delete this line present
  ...
}
GrayedFox
  • 2,350
  • 26
  • 44
3

It may help to put a line import './commands.js' into index.js.

Teresa
  • 353
  • 1
  • 5
  • 27
Alexey Nikonov
  • 4,958
  • 5
  • 39
  • 66
  • A great place to define or overwrite commands is in your cypress/support/commands.js file, since it is loaded before any test files are evaluated via an import statement in your supportFile (cypress/support/index.js by default). – Atul KS May 13 '21 at 19:45
  • It should be `import './commands.js';` without the slash since `commands.js` is a file. – YuKitAs Oct 09 '21 at 22:50
1

For me it worked when I added the type signature of the custom command in the file cypress/support/index.d.ts. For more information visit: Cypress example - Custom Commands

declare namespace Cypress {
  interface Chainable {
    clearLocalStorageIframe(): void
  }
}

I am using 7.2.0 Cypress and command.ts and index.ts file extension I have changed it to .ts

dgraf
  • 1,084
  • 11
  • 12
1

I'm using cypress version 12.16. This is my cypress.config.js

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
    supportFile: "cypress/support/index.js",  <------ refer the index.js file into support folder
  },
})

Then the index.js file is importing my customs commands

import './commands'

My commands.js file

Cypress.Commands.add('login', (url, user) => {
    //..
})
Cypress.Commands.add('logout', () => {
    //..
})
Jaime Roman
  • 749
  • 1
  • 11
  • 26
0

TL;DR: Check if your IDE tried to resolve cy

I slipped into this problem, because my IDE's autocomplete feature added a dependency to resolve the undeclared cy object – that gets injected by cypress.

const { default: cy } = require('date-fns/esm/locale/cy/index.js');

This was very unfortunate, as there is an ongoing (in 2022) issue with the custom commands and you can find a tons of hints..

pico_prob
  • 1,105
  • 10
  • 14
0

Removing

import { cy } from "date-fns/locale";

or similar import

from the test file, resolved this. This gets added automatically to resolve undeclared cy objects

Permanent Solution: Add the following to cypress.json

"compilerOptions": {
   "types": ["cypress"]
}
0

I added at the top of commands.js.

/// <reference types="cypress" />
export{}

//CUSTOM COMMANDS...

This then exported and exposed the custom commands after cy. .

DRC
  • 1