Open dudewad opened 4 years ago
This repo is only for bug reports and feature requests relating to the Cypress product. If you want to open an issue on our documentation, you can open it here.
This issue will be transferred to our cypress-documentation repo.
cc @bahmutov
Having the same issue, tests do work, but the IntelliJ won't recognize the typings (custom commands are red undersquiggled). Something is still amiss but I'm wasting too much time trying to find out :( Tried everything in https://github.com/cypress-io/cypress/issues/1065 I guess it has to do with a conflicting monorepo setup :| Maybe better docs could help me too.
cc @CypressJoseph 😅
@bahmutov @jennifer-shehane @CypressJoseph it's impossible to get types working when following the official guide given here https://docs.cypress.io/api/cypress-api/custom-commands.html#5-Write-TypeScript-definitions
Could you please check this topic?
Hi folks, this issue comment helped me work around the issue: https://github.com/cypress-io/add-cypress-custom-command-in-typescript/issues/2#issuecomment-389870033
Fix seems to be declaring Cypress in the global namespace, and your custom command definitions in there (copied from ☝️ ):
declare global {
namespace Cypress {
interface Chainable {
customCommand: typeof customCommand;
}
}
}
function customCommand(input: MyCustomClass) {
// ...
}
Cypress.Commands.add('customCommand', customCommand);
But agree that the solution suggested in the docs doesn't work
In the RWA the types are declared the same way as in the docs. I'm thinking this may be related to the config. Will continue to investigate.
https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/global.d.ts
Hi @jennifer-shehane, is there any progress on this topic? It has been reported months ago and backed up with examples.
I finally got my commands working in a lib like you have @dudewad
The trick was to have the following line at the top of the file:
/// <reference types="cypress" />
combined with @jamie--stewart solution (https://github.com/cypress-io/cypress-documentation/issues/2565#issuecomment-651251129)
So my file looks like this:
/// <reference types="cypress" />
declare global {
namespace Cypress {
interface Chainable {
customCommand: typeof customCommand;
}
}
}
function customCommand(input: MyCustomClass) {
// ...
}
Cypress.Commands.add('customCommand', customCommand);
With that everything works fine. Typings are ok when running Cypress, and I finally get completion for my added commands in my project.
@jamie--stewart thank you for your global namespace suggestion! That was what I was missing in my case. Once I added it, all the commands that were highlighted as syntax errors were automatically resolved.
Also, to add my 2 cents to the whole thread, I found out that other plugins like cypress-axe
that also augment the cy
Chainable interface, had to be also referenced via triple slash statement in the same place where the main cypress
types were also referenced.
So for example, in my commands.ts
I have at the top:
/// <reference types="cypress" />
/// <reference types="@types/cypress-axe" />
declare global {
namespace Cypress {
interface Chainable<Subject> {
register(email: string, password: string): Cypress.Chainable<null>;
}
}
}
function register(email: string, password: string) {
// implementation
}
Cypress.Commands.add('register', register);
Strangely enough, despite the fact that I am using applitools as well, their typings are automatically resolved without the need to include a respective triple slash reference.
Following the docs here: https://docs.cypress.io/api/cypress-api/custom-commands.html#See-also Doesn't work.
Getting a Property 'customAction' does not exist on type 'cy & EventEmitter'
None of the suggestions here have worked.
Going to switch back to JS 🤷🏻♂️
We're open to pull requests to improve this doc. There are examples of definitions of custom commands in both https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/global.d.ts and https://github.com/cypress-io/cypress-example-recipes/pull/540
Had a similar issue and was able to fix it by placing the custom index.d.ts
file in the root directory in types folder of the cypress project and not in the support folder.
File: index.d.ts 💊
// in cypress/index.d.ts
// load type definitions that come with Cypress module
/// <reference types="cypress" />
declare namespace Cypress {
interface Chainable {
dataCy(value: string): Chainable<any>;
};
}
Worked ✅
.cypress/
+---- support/
| +---- commands.ts
.types/
+---- index.d.ts
Didn't work ⛔
.cypress/
+---- support/
| +---- commands.ts
| +---- index.d.ts
TS Config 🚗
{
"include": ["./**/*.ts", "types/**/*.d.ts"]
}
I still have this problem, that all my custom commands result with TS2339: Property 'When' does not exist on type 'cy & EventEmitter'.
My tscondif.json
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"baseUrl": "src",
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": false,
"noEmit": true,
"jsx": "react",
"types": [
"node",
"jest",
"@testing-library/jest-dom",
"cypress",
"cypress-file-upload",
"@testing-library/cypress"
]
},
"include": [
"src/**/*",
"../node_modules/cypress",
"test/cypress/acceptance/*.ts"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
in commands.ts
/// <reference types="cypress" />
require('@testing-library/cypress/add-commands');
require('cypress-file-upload');
// eslint-disable-next-line @typescript-eslint/no-namespace
declare namespace Cypress {
interface Chainable {
/**
* Logs a BDD Given statement
* @example
* cy.given('I open the user list')
*/
Given(title: string): Chainable<any>;
/**
* Logs a BDD When statement
* @example
* cy.when('I create a user')
*/
When(title: string): Chainable<any>;
/**
* Logs a BDD Then statement
* @example
* cy.then('I see a user')
*/
Then(title: string): Chainable<any>;
/**
* Logs a BDD And statement
* @example
* cy.and('I see an updated user count')
*/
And(title: string): Chainable<any>;
/**
* Logs a BDD Finally statement
* @example
* cy.finally('I delete the user again')
*/
Finally(title: string): Chainable<any>;
/**
* Logs in
* @example
* cy.login()
*/
login(): Chainable<any>;
}
}
Cypress.Commands.add('Given', (message) => cy.log(`**GIVEN ${message}**`));
Cypress.Commands.add('When', (message) => cy.log(`**WHEN ${message}**`));
Cypress.Commands.add('Then', (message) => cy.log(`**THEN ${message}**`));
Cypress.Commands.add('And', (message) => cy.log(`**AND ${message}**`));
Cypress.Commands.add('Finally', (message) => cy.log(`**FINALLY ${message}**`));
Cypress.Commands.add('login', () => {
cy.visit('/login');
cy.findByPlaceholderText(/e-mail/i).type(Cypress.env('EMAIL'));
cy.findByPlaceholderText(/password/i).type(Cypress.env('PASSWORD'));
cy.findByRole('button', { name: /ready/i }).click();
});
also, this setup made my unit tests broken, I've added jest to typesc in tsconfig, but it now requires typescript on unit tests, which is what I don't want 👎 the setup is really confusing and error prone.
The following configuration works for me:
Typescript Version 4.2.3 Cypress package version: 5.6.0 Cypress binary version: 5.6.0
web_app/cypress/support/commands.ts
:
import { tag } from './tag';
declare global {
// eslint-disable-next-line no-redeclare
namespace Cypress {
interface Chainable {
tag: typeof tag;
}
}
}
Cypress.Commands.add('tag', tag);
web_app/cypress/.eslintrc
:
{
"plugins": [
"cypress"
],
"env": {
"cypress/globals": true
},
"extends": [
"plugin:cypress/recommended"
],
"globals": {
"tag": "readonly"
}
}
web_app/cypress/tsconfig.json
:
{
"extends": "../tsconfig.json",
"include": ["./**/*.ts"],
"exclude": [],
"compilerOptions": {
"types": ["cypress"],
"lib": ["esnext", "dom.iterable", "dom"],
"isolatedModules": false,
"allowJs": true,
"noEmit": true
}
}
TypeScript picks up the function signature from the imported file:
Thank you @shwarcu,
There is a change you have to do to your example for the types to work. You are missing the extension of the declaration file you triple slash reference.
It is counter intuitive (and seriously backwards) but triple slash comments are not exactly node related. They do not use node commonjs resolution. So if you omit the extension, the resolution are simply ignored.
The good news is there is a better solution: merge the script and the type declaration. Look at this example repo https://github.com/cypress-io/add-cypress-custom-command-in-typescript.
I will make a PR to the docs to explain that better.
I hope it helps
[EDIT] I made the PR
Thanks @toniton this helped in my case.
none of the above suggestions worked for me, though what worked for me was
/// <reference path="../../../cypress/global.d.ts" />
in one of my spec files.
I'm using create-react-app
The problem is that create-react-app
by default has turned isolatedModules
to true
in tsconfig.json
file. Therefore, without this line, typescript considers
global.d.ts
as an isolated module and won't consider its content. However with this line,
Typescript has a reference to global.d.ts
and then will consider it as a module.
Current behavior:
I am completely unable to get cypress typings to register for commands created using
Cypress.Commands.add
. I've got a repo that has several e2e projects within it that share a set of testing code (this shared lib lives at./tools/testing
)../tools/testing/e2e/support/commands.ts
is where we run severalCypress.Commands.add
calls.Alongside that file I placed a
global.d.ts
file (I've also moved it around and tried naming itindex.d.ts
, etc). Runningtsc -p tsconfig.json --listFiles
shows that theglobal.d.ts
is included, yet it appears to have no effect. That file contains the following:This is following this discussion (and many others that I've found) here
I've also tried wrapping the namespace declaration in a
global
but that doesn't seem to help, either.It's clear that
tsc
has included my global file but I can't discern if this is a Cypress issue or a Typescript issue.The above commands that are created using Cypress example recipes. However, given linting, I can't access them without using array notation or
tsc
will choke on them at dev time. Using dot notation to access them then throws the error:TS2339: Property 'getIframeWindow' does not exist on type 'cy & EventEmitter'.
Desired behavior:
Improve documentation on how to add typings. It doesn't seem realistic that there's a whole page on how to create these commands but no expectation that people will not want typings to be supported for them.
Test code to reproduce
As this is a typings issue not a test issue I'm going to add the reproduction inline here.
Add a command:
Type the command:
Versions
Cypress 3.8.2 TS 3.4.5