cypress: Unable to compile TypeScript with "moduleResolution": "bundler" option in v5

Current behavior

Originally reported by @MasonM in #26308 and closed because of Cypress v13.0.0 - but this release does not fix this

cc @jennifer-shehane @lmiller1990 - ideally #26308 would be unlocked and reopened, if you can do that

Copied issue below:


If you have a TypeScript project using the new “moduleResolution”: “bundler” setting introduced in TypeScript 5, any attempts to run tests will cause the following error:

TSError: ⨯ Unable to compile TypeScript:
error TS5095: Option 'bundler' can only be used when 'module' is set to 'es2015' or later.

Desired behavior

Tests run successfully

Test code to reproduce

Reproduction 1

Courtesy of @MattyBalaam: https://github.com/MattyBalaam/cypress-ts-import

Reproduction 2

See error message and tsconfig.json below:

Your configFile is invalid: /home/runner/work/project/cypress.config.ts

It threw an error when required, check the stack trace below:

TSError: ⨯ Unable to compile TypeScript:
error TS5095: Option 'bundler' can only be used when 'module' is set to 'es2015' or later.

    at createTSError (/home/runner/.cache/Cypress/13.1.0/Cypress/resources/app/node_modules/ts-node/dist/index.js:311:16)
    at reportTSError (/home/runner/.cache/Cypress/13.1.0/Cypress/resources/app/node_modules/ts-node/dist/index.js:314:23)
    at /home/runner/.cache/Cypress/13.1.0/Cypress/resources/app/node_modules/ts-node/dist/index.js:686:17
    at Object.compile (/home/runner/.cache/Cypress/13.1.0/Cypress/resources/app/node_modules/ts-node/dist/index.js:743:35)
    at Module.m._compile (/home/runner/.cache/Cypress/13.1.0/Cypress/resources/app/node_modules/ts-node/dist/index.js:856:)
    at Module._extensions..js (node:internal/modules/cjs/loader:1252:10)
    at Object.require.extensions.<computed> [as .ts] (/home/runner/.cache/Cypress/13.1.0/Cypress/resources/app/node_modules/ts-node/dist/index.js:859:16)
    at Module.load (node:internal/modules/cjs/loader:1076:32)
    at Function.Module._load (node:internal/modules/cjs/loader:911:12)
    at Module.require (node:internal/modules/cjs/loader:1100:19)
    at require (node:internal/modules/cjs/helpers:108:18)
    at loadFile (/home/runner/.cache/Cypress/13.1.0/Cypress/resources/app/node_modules/@packages/server/lib/plugins/child/run_require_async_child.js:89:14)
    at EventEmitter.<anonymous> (/home/runner/.cache/Cypress/13.1.0/Cypress/resources/app/node_modules/@packages/server/lib/plugins/child/run_require_async_child.js:116:)
    at EventEmitter.emit (node:events:513:28)
    at EventEmitter.emit (node:domain:9:12)
    at process.<anonymous> (/home/runner/.cache/Cypress/13.1.0/Cypress/resources/app/node_modules/@packages/server/lib/plugins/util.js:33:22)
Test run failed, code 1

tsconfig.json

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "UpLeveled Node + React TSConfig",
  "compilerOptions": {
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "module": "ESNext",
    "target": "ES2015",
    "moduleResolution": "Bundler",
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "isolatedModules": true,
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "downlevelIteration": true,
    "forceConsistentCasingInFileNames": true,
    "jsx": "preserve",
    "noEmit": true,
    "noFallthroughCasesInSwitch": true,
    "skipLibCheck": true,
    "strict": true,
    "incremental": true,
    "noUncheckedIndexedAccess": true
  },
  "include": [
    "**/.eslintrc.cjs",
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    "**/*.js",
    "**/*.jsx",
    "**/*.cjs",
    "**/*.mjs"
  ],
  "exclude": ["node_modules", "build", "public", "scripts"]
}

Cypress Version

13.1.0

Node version

v18.17.1

Operating System

macOS Ventura 13.5 (22G74)

Debug Logs

No response

Other

No response

About this issue

  • Original URL
  • State: closed
  • Created 10 months ago
  • Reactions: 20
  • Comments: 21 (11 by maintainers)

Commits related to this issue

Most upvoted comments

I encountered this problem today while setting up a Next.JS project. To confirm the issue I created a greenfield project to test it.

Workaround

For anyone looking for a workaround who lands here before they see the other related issues (now closed), here is a workaround copied from issue #27448:

{
  // Leave this section as is.
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "bundler",
    "plugins": [],
    "paths": {}
  },
  // Add this section.
  "ts-node": {
    "compilerOptions": {
      "module": "ESNext",
      "moduleResolution": "Node"
    }
  },
}

Recreating the issue in a new project

Here are my steps and results. I hope this is helpful for whoever ends up working on a resolution.

System info

OS: macOS 14.0 Beta (23A5337a) node: v20.6.1 (I first encountered the issue on 18, then upgraded and tried again) npm: v9.8.1

Steps to reproduce

1. Create a next app using npx

% npx create-next-app@latest --typescript
✔ What is your project named? … next-cypress
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias? … No / Yes
Creating a new Next.js app in /Users/…/Developer/next-cypress.

Using npm.

Initializing project with template: app


Installing dependencies:
- react
- react-dom
- next
- typescript
- @types/react
- @types/node
- @types/react-dom
- eslint
- eslint-config-next


added 277 packages, and audited 278 packages in 10s

106 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Initialized a git repository.

Success! Created next-cypress at /Users/…/Developer/next-cypress

2. Enter the next app and install Cypress via NPM

… Developer % cd next-cypress
… next-cypress % npm i cypress -D

3. Install cypress

% npm run cypress install

> next-cypress@0.1.0 cypress
> cypress install

Installing Cypress (version: 13.1.0)

✔  Downloaded Cypress
✔  Unzipped Cypress
✔  Finished Installation /Users/zakknudsen/Library/Caches/Cypress/13.1.0

You can now open Cypress by running: node_modules/.bin/cypress open

https://on.cypress.io/installing-cypress

4. Run cypress open

% npm run cypress open

> next-cypress@0.1.0 cypress
> cypress open

It looks like this is your first time using Cypress: 13.1.0

✔  Verified Cypress! /Users/…/Library/Caches/Cypress/13.1.0/Cypress.app

Opening Cypress...

DevTools listening on ws://127.0.0.1:49466/devtools/browser/…
2023-09-12 14:25:15.233 Cypress[4606:45143] WARNING: Secure coding is not enabled for restorable state! Enable secure coding by implementing NSApplicationDelegate.applicationSupportsSecureRestorableState: and returning YES.
Missing baseUrl in compilerOptions. tsconfig-paths will be skipped
/Users/…/Library/Caches/Cypress/13.1.0/Cypress.app/Contents/Resources/app/node_modules/ts-node/dist/index.js:311
        return new TSError(diagnosticText, diagnosticCodes, diagnostics);
               ^
TSError: ⨯ Unable to compile TypeScript:
error TS5095: Option 'bundler' can only be used when 'module' is set to 'es2015' or later.

    at createTSError (/Users/…/Library/Caches/Cypress/13.1.0/Cypress.app/Contents/Resources/app/node_modules/ts-node/dist/index.js:311:16)
    at reportTSError (/Users/…/Library/Caches/Cypress/13.1.0/Cypress.app/Contents/Resources/app/node_modules/ts-node/dist/index.js:314:23)
    at /Users/…/Library/Caches/Cypress/13.1.0/Cypress.app/Contents/Resources/app/node_modules/ts-node/dist/index.js:686:17
    at Object.compile (/Users/…/Library/Caches/Cypress/13.1.0/Cypress.app/Contents/Resources/app/node_modules/ts-node/dist/index.js:743:35)
    at Module.m._compile (/Users/…/Library/Caches/Cypress/13.1.0/Cypress.app/Contents/Resources/app/node_modules/ts-node/dist/index.js:856:36)
    at Module._extensions..js (node:internal/modules/cjs/loader:1295:10)
    at Object.require.extensions.<computed> [as .js] (/Users/…/Library/Caches/Cypress/13.1.0/Cypress.app/Contents/Resources/app/node_modules/ts-node/dist/index.js:859:16)
    at Module.load (node:internal/modules/cjs/loader:1091:32)
    at Function.Module._load (node:internal/modules/cjs/loader:938:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12) {
  diagnosticCodes: [ 5095 ]
}
[4606:0912/142901.475308:ERROR:devtools_http_handler.cc(426)] GetMimeType doesn't know mime type for: browser/… text/plain will be returned
[4606:0912/142901.475478:ERROR:devtools_http_handler.cc(426)] GetMimeType doesn't know mime type for: browser/… text/plain will be returned
^C✔  Verified Cypress! /Users/…/Library/Caches/Cypress/13.1.0/Cypress.app

System information after installing Cypress

Output from % npm run cypress version:

> next-cypress@0.1.0 cypress
> cypress version

Cypress package version: 13.1.0
Cypress binary version: 13.1.0
Electron version: 21.0.0
Bundled Node version: 16.16.0

Output from npm run cypress --version:

9.8.1

Output from % npm run cypress info:

> next-cypress@0.1.0 cypress
> cypress info


DevTools listening on ws://127.0.0.1:49602/devtools/browser/…
2023-09-12 14:33:32.459 Cypress[5751:51459] WARNING: Secure coding is not enabled for restorable state! Enable secure coding by implementing NSApplicationDelegate.applicationSupportsSecureRestorableState: and returning YES.
Displaying Cypress info...

Detected 2 browsers installed:

1. Chrome
  - Name: chrome
  - Channel: stable
  - Version: 116.0.5845.187
  - Executable: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

2. Firefox
  - Name: firefox
  - Channel: stable
  - Version: 117.0
  - Executable: /Applications/Firefox.app/Contents/MacOS/firefox

Note: to run these browsers, pass <name>:<channel> to the '--browser' field

Examples:
- cypress run --browser firefox
- cypress run --browser chrome

Learn More: https://on.cypress.io/launching-browsers

Proxy Settings: none detected
Environment Variables: none detected

Application Data: /Users/…/Library/Application Support/cypress/cy/development
Browser Profiles: /Users/…/Library/Application Support/cypress/cy/development/browsers
Binary Caches: /Users/…/Library/Caches/Cypress

Cypress Version: 13.1.0 (stable)
System Platform: darwin (23.0.0)
System Memory: 8.59 GB free 472 MB

+1 on this. I am having the same issue.

This needs to be resolved as a fresh default installation of Next.js 14.0.1 with

npx create-next-app

also causes the error

TSError: ⨯ Unable to compile TypeScript: error TS5095: Option ‘bundler’ can only be used when ‘module’ is set to ‘es2015’ or later.

when running Cypress 13.4.0.

I am able to reproduce this issue error with the slimmed types configuration:

{
  "compilerOptions": {
    "module": "es2015",
    "moduleResolution": "bundler",
  }
}

I have only been able to produce this error when the Cypress configuration is using typescript, i.e. cypress.config.ts. When other files (src, test files) are using .ts it seems to be working as expected.

I do not see this error when the Cypress configuration is cypress.config.js, which is what the config-with-module-resolution-bundler system test project was leveraging.

The config-with-module-resolution-bundler project was not using the correct types version and was testing a .js spec, so it wasn’t actually running anything through the ts compiler to indicate the wrong version was installed given the configuration provided. So it was a false-positive test. Sorry guys!

I have been able to make a few tweaks to our setup and it seems resolves the moduleResolution: bundler error with the reproduction I have. I want to do some more testing locally, but hoping to have something ready quick!

Also facing the same issue on next.js 14. “moduleResolution”: “node” fixes it but it can have side effects on Next.js code.

@AtofStryker I upgraded to https://cdn.cypress.io/beta/npm/13.6.3/linux-x64/fix/set_module_resolution_with_commonjs-0481c7af5d4085004b91dd644d7a4c8d97ea1b00/cypress.tgz (linux x64 version from the commit) and can confirm that this is allowing moduleResolution: "Bundler" in our tsconfig.json 🎉

package.json

{
  "devDependencies": {
    "cypress": "https://cdn.cypress.io/beta/npm/13.6.3/linux-x64/fix/set_module_resolution_with_commonjs-0481c7af5d4085004b91dd644d7a4c8d97ea1b00/cypress.tgz"
  }
}

I was able to remove my workaround lines below from tsconfig.json:

tsconfig.json

{
-  // Old "moduleResolution": "Node" option required for Cypress
-  // https://github.com/cypress-io/cypress/issues/26308#issuecomment-1663592648
-  //
-  // TODO: Remove this when Cypress supports "moduleResolution": "Bundler"
-  // https://github.com/cypress-io/cypress/issues/27448
-  // https://github.com/cypress-io/cypress/issues/27731
-  "ts-node": {
-    "compilerOptions": {
-      "module": "es2015",
-      "moduleResolution": "node"
-    }
-  },
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "Bundler"
  }
}

@ahmadbilaldev @arbuznik can either of you try TS_NODE_COMPILER=1 npx cypress open as a workaround?

@AtofStryker FYI, I gave this a try and it resolved the issue for me.

@ahmadbilaldev @arbuznik can either of you try TS_NODE_COMPILER=1 npx cypress open as a workaround?

Does this issue means it’s not possible to use cypress with Next.js?

Or is there a working workaround?

“next”: “13.5.6”, “cypress”: “^13.6.1”, “typescript”: “^5”

So in Cypress 13.5.0 we still need to use workaround with ts-node? Cypress complains on usage of “module”: “ESNext”, “moduleResolution”: “Bundler”,

Okay - while working through how any changes would impact the existing expectations, I have found a few possible option that may work for a few of you depending on your current setup…

  1. skip the ts-node project check for the Cypress configuration via TS_NODE_SKIP_PROJECT=true

or

  1. override your compile options via the the command line to force commonJS / node resolution for the configuration child process:
TS_NODE_COMPILER_OPTIONS="{\"module\":\"CommonJS\",\"moduleResolution\":\"node\"}"

or

  1. specify ts-node configuration in your typescript configuration file. This options requires updating the generated cypress.config.ts file to be compatible with these compile options. The updates I made actually lost the types from the defineConfig helper we provide.
  "ts-node": {
    "compilerOptions": {
      "esm": true,
      "module": "esnext",
      "moduleResolution": "bundler",
    },
  },
module.exports = {
  e2e: {
    setupNodeEvents(on, config) {
      // implement node event listeners here
    },
  },
};

If anyone tries these options out and they work, that’d be helpful to know if any of these are reasonable paths forward given the various project setups someone can have with various typescript versions & needs.