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

Cypress types conflict with TypeScript application types #1319

Closed
shcallaway opened this issue Feb 15, 2018 · 22 comments
Closed

Cypress types conflict with TypeScript application types #1319

shcallaway opened this issue Feb 15, 2018 · 22 comments

Comments

@shcallaway
Copy link

shcallaway commented Feb 15, 2018

  • Operating System: macOS High Sierra 10.13.3
  • Cypress Version: 1.4.2
  • Browser Version: n/a

Is this a Feature or Bug?

Bug

Current behavior:

I upgrade from Cypress 1.0.3 to 1.4.2 and my TypeScript application no longer compiles. This is because the 1.4.2 dependencies include TypeScript types, which are installed by default to my node_modules/@types directory and included in my compilation step due to the following configuration setup (tsconfig.json):

{
  "compilerOptions": {
    "typeRoots": [
      "../node_modules/@types"
    ]
  }
}

Here is a relevant issue on the TypeScript repo.

My short term workaround is to use the compilerOptions.types property and enumerate each desired type instead of compilerOptions.typeRoots, which grabs everything from node_modules/@types. This is not desirable long-term as I have to now update my tsconfig.json every time I add new types.

Desired behavior:

Installing Cypress should not add anything to my node_modules/@types directory or otherwise affect how my TypeScript application compiles.

How to reproduce:

n/a

Test code:

n/a

Additional Info (images, stack traces, etc)

n/a

@jennifer-shehane
Copy link
Member

Possibly related issue: #1227

@brian-mann
Copy link
Member

@bahmutov can we get your 👀 on this plz

@bahmutov
Copy link
Contributor

bahmutov commented Feb 16, 2018

Hmm, seems when installing devDependency brings type dependencies and puts them into node_modules/@types. And I guess NPM and TypeScript freak out because something gets overwritten during this install. So right now I do not see how we can control this - seems this will be very common problem when more dependencies bring type dependencies.

@bahmutov
Copy link
Contributor

@shcallaway what do you think would work from our side in this case? We got to bring types for our code, but if NPM overwrites types from other libraries it is seems like a bug on their part. If on the other hand the TypeScript compiler gets confused by the types brought by Cypress - well it seems it is the TSC's problem

@shcallaway
Copy link
Author

It seems like Yarn and NPM install all @types to the same directory regardless of whether they are regular dependencies or dependencies-of-dependencies. So there might be nothing we can do. I think modifying tsconfig.json to only include specific packages is the right solution. However, I tried this and could not get it to work.

Side note: I noticed that those types were not in your package.json. How are they being installed as dependencies?

@salty-blue-mango
Copy link

Do we have any update on this issue?

@ro-savage
Copy link

Potential fix: #3425

@jennifer-shehane
Copy link
Member

We moved some of the type dependencies starting in Cypress 3.2.0, can anyone verify if this fixes the type conflicts? Thanks #3425

@cypress-bot cypress-bot bot added stage: awaiting response Potential fix was proposed; awaiting response and removed stage: needs investigating Someone from Cypress needs to look at this labels Mar 26, 2019
@ro-savage
Copy link

Fixed for me.

@Cubelaster
Copy link

Cubelaster commented Mar 27, 2019

Not fixed for me.
Manually installing Mocha types fixed some errors, but "Cannot find name 'cy'" still persists.
Would really like a fix :)
Edit: It seems that in my project Jest and Cypress don't like each other...

@EgonLebt
Copy link

EgonLebt commented Jun 7, 2019

Same here. I can either use cypress or jest.
Using cypress 3.3.1

@sharmilajesupaul
Copy link
Contributor

sharmilajesupaul commented Jun 13, 2019

We're running into this issue at Airbnb trying to introduce Cypress into TS projects with Jest tests. This is a minimal repro case repo: https://github.com/mohsen1/cypress-ts-issue

One workaround we're using for now is deleting the cypress/types directory in an npm prepare script.
eg:

// package.json
"scripts" {
  ...
 "patch:bad:types": "rimraf ./node_modules/cypress/types",
 "prepare": "npm run patch:bad:types && npm run build",
  ...
}

@bahmutov
Copy link
Contributor

I have created a Jest + Cypress example repo that separates their types from each other https://github.com/cypress-io/cypress-and-jest-typescript-example. In general, it shows how to create tsconfig.json in cypress folder. I believe this is the best repo TS option if there are conflicting types.

@jennifer-shehane jennifer-shehane removed the stage: awaiting response Potential fix was proposed; awaiting response label Jul 23, 2019
@wachunga
Copy link

wachunga commented Jul 27, 2019

Our team prefers to keep tests alongside the code they're testing, not isolated in a cypress folder. Has anyone managed to do this without conflicting type issues? Maybe @bahmutov would know best if this possible.

@sharmilajesupaul
Copy link
Contributor

@bahmutov when you have a large monorepo with multiple projects that are using Jest/Mocha/Chai and Cypress, sharing the global namespace is an issue. Having to have double the amount of tsconfigs is not the best solution imo.

Would it be possible to export Cypress globals from a package entrypoint? We could get around this issue if we can import the conflicting modules directly from Cypress.

i.e.

import { cy, it, describe } from "cypress"

cc. @lencioni

@bahmutov
Copy link
Contributor

bahmutov commented Aug 2, 2019

Why do you need to double the number of tsconfigs - just have a tsconfig in Cypress folder, extending your main tsconfig and just adjusting the types.

We were thinking how to move from globals like "cy", "it" but this is a big breaking change and we are not ready to do it yet.

@lencioni
Copy link

lencioni commented Aug 2, 2019

Hi @bahmutov, thanks for the fast response!

Why do you need to double the number of tsconfigs - just have a tsconfig in Cypress folder, extending your main tsconfig and just adjusting the types.

I think this makes a lot of sense for smaller projects where they only have a single cypress folder.

At Airbnb, we have a fairly large and quickly growing monorepo with hundreds of projects, which will eventually turn into thousands. Each project can be thought of as a fairly standalone piece of software. Some of these projects are entire apps that are individually built and deployed. While cypress won't be useful for every single project, we hope to enable it it for a bunch of them and we want to keep the overhead of adopting cypress for maintainers of these projects to a minimum. I hope this helps contextualize @sharmilajesupaul's question!

We were thinking how to move from globals like "cy", "it" but this is a big breaking change and we are not ready to do it yet.

Would it be possible to keep the globals around for folks who want to continue using them, and also add some exports for people who want to be more explicit? I believe that would be a semver minor change.

@bahmutov
Copy link
Contributor

bahmutov commented Aug 5, 2019 via email

@bahmutov
Copy link
Contributor

bahmutov commented Aug 6, 2019

@lencioni just so we are discussing the same thing, can you create a public repo and show example apps there set up in the same way as you would like to have at AirBnb, please? Then we can definitely see how to better configure Cypress and TypeScript and this would benefit a lot of users

@sharmilajesupaul
Copy link
Contributor

sharmilajesupaul commented Mar 2, 2020

@bahmutov just an update, at Airbnb, we use use nested tsconfigs in our project cypress directories. Which is what I think you originally recommended.

The base that all projects inherit from:

// projects/typescript/tsconfig.base.json
{
 ...
    "isolatedModules": true
  },
  "exclude": [
    "../*/server/**/*",
    "../*/cypress/**/*"
  ]
}

The base config that all cypress directories inherit from:

// projects/cypress/tsconfig.cypress.json
// override any options that can't be used in /cypress
{
  "extends": "../typescript/tsconfig.base.json",
  "compilerOptions": {
    "isolatedModules": false
  },
  "exclude": []
}

then in every project cypress/:

// projects/some-ui-project/cypress/tsconfig.json
{
  "extends": "../../cypress/tsconfig.cypress.json",
  "include": [".", "../../../node_modules/cypress"]
}

At first, we essentially did this #1319 (comment). We created our own cypress module that re-exported all the cypress globals -- everyone imported from our local module vs the cypress node module. But we were still seeing issues with the typing especially for custom commands and some of the globals.

So we fell back on the recommended route and that has been working well so far.


Also, in any test files where the Cypress - Chai expect conflicts with Jest's expect, adding this line to redeclare expect and explicitly setting it to jest.Expect will fix the conflict for that test file.

// Cypress brings in Chai types for the global expect, but we want to use jest
// expect here so we need to re-declare it.
declare const expect: jest.Expect;

^ @wachunga this could be a workaround for your colocated test files

In our case, we have Jest tests for a CLI tool that uses the Cypress module API and needed to use this method. The nested tsconfig.json should work for all other cases.

@jrwebdev
Copy link

jrwebdev commented Mar 7, 2020

I have created a Jest + Cypress example repo that separates their types from each other https://github.com/cypress-io/cypress-and-jest-typescript-example. In general, it shows how to create tsconfig.json in cypress folder. I believe this is the best repo TS option if there are conflicting types.

Maybe I'm missing something, but with that setup you run into compilation errors if running tsc at the root as there are still conflicting global types, and Cypress's types aren't loaded via that tsconfig file.

Like others, I prefer colocation rather than a separate directory; the only workaround I've been able to come up with for that is to have the main tsconfig exclude the Cypress test files, then have a separate tsconfig for Cypress that includes them and the global Cypress types. Then it should just be a matter of adding import 'cypress/types'; (or /// <reference types="cypress" />) in each Cypress file so the IDE doesn't complain. Example here:

https://github.com/jrwebdev/typescript-jest-cypress

I think you'd need to do something similar regardless if you had all Cypress tests in a separate directory with a tsconfig.json file, just probably wouldn't need the import part.

In general though, I agree with others that testing libraries should just export everything through modules rather than globally, but I think this TS issue could help a lot with problems like this too.

@brybrophy
Copy link

@bahmutov just an update, at Airbnb, we use use nested tsconfigs in our project cypress directories. Which is what I think you originally recommended.

The base that all projects inherit from:

// projects/typescript/tsconfig.base.json
{
 ...
    "isolatedModules": true
  },
  "exclude": [
    "../*/server/**/*",
    "../*/cypress/**/*"
  ]
}

The base config that all cypress directories inherit from:

// projects/cypress/tsconfig.cypress.json
// override any options that can't be used in /cypress
{
  "extends": "../typescript/tsconfig.base.json",
  "compilerOptions": {
    "isolatedModules": false
  },
  "exclude": []
}

then in every project cypress/:

// projects/some-ui-project/cypress/tsconfig.json
{
  "extends": "../../cypress/tsconfig.cypress.json",
  "include": [".", "../../../node_modules/cypress"]
}

@bahmutov Your comment helped me get this working in our monorepo. However, all we had to do was add "../*/cypress/**/*" to the exclude in tsconfig.base.json. We didn't need to do anything with isolatedModules.

In tsconfig.base.json

{
  "compilerOptions": {
    "module": "esnext",
    "target": "es2018",
    "lib": ["es2018", "es2019.array", "dom"],
    "moduleResolution": "node",
    "baseUrl": "./packages",
    "jsx": "react",
    "esModuleInterop": true,
    "strict": true,
    "allowJs": false,
    "allowUnreachableCode": false,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "importHelpers": true,
    "composite": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "useDefineForClassFields": true,
    "resolveJsonModule": true,
    "typeRoots": ["./node_modules/@types", "./typings"]
  },
  "exclude": ["node_modules", "../*/cypress/**/*"]
}

In tsconfig.cypress.json

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

In all /cypress directories (inside of individual packages in the monorepo)

{
  "extends": "path/to/tsconfig.cypress.json"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests