Closed MasonM closed 10 months ago
@MasonM thanks for including the reproduction, routing this to our e2e team
This seems to fix it: https://github.com/cypress-io/cypress/compare/develop...MasonM:cypress:fix-26308
But I only tested by manually applying this change to /Users/mmalone/Library/Caches/Cypress/12.8.1/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/ts_node.js
and following the reproduction steps, so I don't know if it'll have any unwanted effects
"moduleResolution": "node"
is the default: https://www.typescriptlang.org/docs/handbook/module-resolution.html#module-resolution-strategies. I wonder why that fixes it.
@lmiller1990 Probably because it's getting overridden to "module"
by the tsconfig.json
in the project
@lmiller1990 That's odd. The reproduction repository doesn't have "allowImportingTsExtensions"
at all, so how is it getting that?
@MasonM I removed my post, I was on the wrong branch. The reproduction does indeed exhibit the issue.
Let's open a PR and see if the test suite passes!
@lmiller1990 Okay, done: https://github.com/cypress-io/cypress/pull/26415
Seems the tests aren't running, probably because I didn't sign the CLA. But I can't do that without permission from my employer, and that process generally takes several months, so would you or @MattyBalaam mind entering the PR instead?
Actually, this is a little confusing - the issue is that moduleResolution: bundler
does not work, so setting moduleResolution: node
is the fix?
What is the goal here, exactly? Just to clarify -- If it's just to make it work, this will be just fine. The concern I have is looking at the tsconfig.json
, a lot of users might assume moduleResolution: bundler
is applied to cypress.config.ts
, which it won't be -- we will be overriding that for ts-node
, which is what is used to transpile and execute the cypress.config.ts
. moduleResolution: bundler
will be applied to your Next.js code, which I think is the intention here - the side effect is that it conflicts with our ts-node
defaults.
Is this correct? Or do you want to enforce moduleResolution: bundler
for the Node.js execution of cypress.config.ts
, too? (I don't think that makes too much sense - moduleResolution: bundler
is for bundlers, which generally bundler code for browser usage, not Node.js usage).
I think your fix is probably okay, since the goal is just to have things work as you'd generally expect, and I'd say most people expect cypress.config.ts
to run in Node.js.
@MasonM right, I see - once we clarify the goal here, I can force commit with and override your contribution (and CLA requirement). I can still tag you in the commit message to give some attribution.
In my project, we don't have any tests written in TypeScript, only application code. In other words, the mere presence of a tsconfig.json
with "moduleResolution": "bundler"
triggers this bug, even though we aren't actually using TypeScript with Cypress. That's why setting the environment variable CYPRESS_INTERNAL_NO_TYPESCRIPT=1
is an acceptable workaround for us. It disables TypeScript entirely, but we don't care about TypeScript in our tests.
I wrote the original reproduction because in our codebase we do use TypeScript in a monorepo and we explicitly want to use the bundler
option.
The horrible workaround we have at the moment is to put a tsconfig with node
moduleResolution in the root of our UI app packages (we are using component testing here not e2e), and then adding extra tsconfig files inside other folders so they use the correct moduleResolution.
If the goal is what @MattyBalaam wrote, then I am not sure the proposed fix of hard-coding resolution: node
is correct. We probably need to make sure all the options are correctly set.
@MattyBalaam to help drive this forward, can you offer insight into why you are choosing to use moduleResolution: bundler
for cypress.config
, which is just executed (not bundled)? Or do you want to use bundler
for everything else (like Vite, etc) and this bug is just a side effect of that?
Hi, I'm on holiday at the moment so can't do a big deep dive, but the moduleResolution is set in tsconfig
not cypress.config
.
This test case is maybe a little inaccurate for our use case which is component tests, and I've just noticed the config here is for e2e (I forked off someone else's example)
We are building out apps using remix which uses esbuild, however out component tests are using a webpack config. The bundler config allows us to export a stricter set of files from our shared UI packages using exports rather than main in our package.json.
Sure no problem - no rush on this.
I think there's a bit of confusion here - if the project has cypress.config.ts
(not the TS extension) we will use typescript to transpile the cypress.config
when we execute it. That will automatically grab tsconfig.json
- I don't think this is obvious at all to the majority of users, which is why there is a lot of confusion.
A lot of projects I've seen have started doing tsconfig.json
and tsconfig.node.json
since they use TS on the back and front ends.
I think we should come up with a better general solution so this entire process is less confusing. When you've got some bandwidth, we can look to explore some solutions. I wonder if we can adopt esbuild too - it's fast, and a lot more simple to use.
We're also experiencing this problem. Is there a recommended workaround until "moduleResolution": "bundler" is supported?
Oh you know what, I think I do have a good solution. Let me clarify, to make sure it's clear what's going on.
Most users want the tsconfig.json
in their project for use with their bundler (webpack, Vite) or framework (Next.js, using webpack, SvelteKit, with Vite, etc...). These are bundlers, so using the new moduleResolution: bundler makes sense.
The side effect is Cypress uses ts-node
under the hood to execute cypress.config.ts
. This also grabs the tsconfig.json
. Most likely, users do not want to use moduleResolution: bundler here - it's not bundling any code, just transpiling the TS to JS to execute in a one-off fashion.
Assume this use case, what you can do is specify a ts-node.compilerOptions
in tsconfig.json
that will only be used for your cypress.config.ts
transpilation. Here is how to do that using the OP's reproduction (and it works):
https://github.com/MattyBalaam/cypress-ts-import/pull/1/files
For completeness, the code:
{
+ "ts-node": {
+ "compilerOptions": {
+ "module": "es2015",
+ "moduleResolution": "node"
+ }
+ },
"compilerOptions": {
"module": "es2015",
"moduleResolution": "bundler"
}
}
cc @filiptammergard @MattyBalaam @MasonM - this should help! I think this is more correct, actually. You have complete control over how both TS pipelines (your Node.js for cypress.config
and for your bundler) behave.
https://github.com/cypress-io/cypress/pull/26415/files is still probably relevant and makes sense, we can get this PR ready, too. The only non-solved use case is actually using moduleResolution: bundler
for the cypress.config
process, but I really don't think many people want this - you'd be using a moduleResolution strategy that doesn't really line up with what is actually happening when cypress.config.ts
is executed. I could be missing something here, though.
@lmiller1990 Looks like a good workaround!
While it might be more correct, it also adds extra config to maintain and it's not obvious it's related to cypress.config.ts
.
I don't see why someone would want to use bundler
for cypress.config.ts
despite it not being accurate. You just want it to work out of the box, and Cypress knows best what options it needs for that.
I'd love to see https://github.com/cypress-io/cypress/pull/26415 happening to make it possible to keep the project's tsconfig.json
unchanged.
But good workaround in the meantime!
https://github.com/cypress-io/cypress/pull/26415 probably still makes sense, main concern is it might break some existing workflows. I'll look into it and see if it can merge as-is, or if it'll need to wait for a major.
you can do is specify a
ts-node.compilerOptions
intsconfig.json
that will only be used for yourcypress.config.ts
transpilation. Here is how to do that using the OP's reproduction (and it works):
I just took a look at our code again and noticed since I created the original test case here we had also added a ts-node.compilerOptions
in our repo to cover running some other ts-node tasks and no longer have the original issue.
Any news on that? The PR seems to be stall?
I don't think anyone is actively working on this. The proper solution doesn't seem clear, either (any recommendation)?
Does https://github.com/cypress-io/cypress/issues/26308#issuecomment-1499724602 work for you?
@philipp-serfling The PR is stalled because I can't sign the CLA, so the Cypress team can't accept it. If you can sign the CLA, then feel free to open an identical PR.
@MasonM Oh gosh what a pitty. I could fix it by updating to TypeScript 5.x and VS Code to 1.80.0 See https://stackoverflow.com/questions/76071355/vite-default-template-giving-error-in-vscode-moduleresolution-bundler
I managed to resolve it by running yarn install
or npm equivalent 🙄
I think Next.js is broken now too https://github.com/cypress-io/cypress/issues/27448
I will look at picking this one up.
Thanks @lmiller1990 ! For background, it was changed in https://github.com/vercel/next.js/pull/51957, so broken since a few versions now.
Also, just generally, would be great to get Cypress a bit more stable with TypeScript and ESM, there's a few longer-running bugs which have no good solution to them :) Can feel pretty broken for new users, and we have been suggesting more users switch to Playwright now because of this.
Maybe the leadership would agree with you spending a few days / weeks fixing everything.
For people looking for a temporary workaround, the workaround posted above by @lmiller1990 worked for us too:
Adding the following (old, obsolete) ts-node
options for Cypress:
tsconfig.json
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "Bundler"
},
+ // Old "moduleResolution": "Node" option required for Cypress
+ // https://github.com/cypress-io/cypress/issues/26308#issuecomment-1663592648
+ //
+ // TODO: Remove when issue is resolved https://github.com/cypress-io/cypress/issues/27448
+ "ts-node": {
+ "compilerOptions": {
+ "module": "ESNext",
+ "moduleResolution": "Node"
+ }
+ }
}
Workaround
For people looking for a temporary workaround, the workaround posted above by @lmiller1990 worked for us too:
Adding the following (old, obsolete)
ts-node
options for Cypress:
tsconfig.json
{ "compilerOptions": { "module": "ESNext", "moduleResolution": "Bundler" }, + // Old "moduleResolution": "Node" option required for Cypress + // https://github.com/cypress-io/cypress/issues/26308#issuecomment-1663592648 + // + // TODO: Remove when issue is resolved https://github.com/cypress-io/cypress/issues/27448 + "ts-node": { + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Node" + } + } }
This works for me
I too was having the same issue, so decided to try with a freshly created Vite app. To my surprise, I was not able to recreate the issue with the fresh Vite app, although it uses "moduleResolution": "bundler"
. I wonder what is the difference.
This is how I created the Vite app:
npm create vite@latest # choose options react and typescript
npm install cypress --save-dev
npx cypress open
Workaround
For people looking for a temporary workaround, the workaround posted above by @lmiller1990 worked for us too: Adding the following (old, obsolete)
ts-node
options for Cypress:tsconfig.json
{ "compilerOptions": { "module": "ESNext", "moduleResolution": "Bundler" }, + // Old "moduleResolution": "Node" option required for Cypress + // https://github.com/cypress-io/cypress/issues/26308#issuecomment-1663592648 + // + // TODO: Remove when issue is resolved https://github.com/cypress-io/cypress/issues/27448 + "ts-node": { + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Node" + } + } }
This works for me
Also using this workaround
Working on this in #27484
@lmiller1990 Is this available to use? If so, what version?
@filiptammergard from the changelog changes in #27484 it seems that 12.17.5 will include this change, to be released on 29 August 2023:
## 12.17.5
_Released 08/29/2023 (PENDING)_
**Bugfixes:**
- Only force CommonJS when running `ts-node` with a `TS_NODE_COMPILER` environment variable, such as when Cypress uses `ts-node` internally. This solves an issue where Cypress' internal `tsconfig` conflicts with properties set in the user's `tsconfig.json` such as `module` and `moduleResolution`. Fixes [#26308](https://github.com/cypress-io/cypress/issues/26308) and [#27448](https://github.com/cypress-io/cypress/issues/27448).
Released in Cypress 13.0.0.
Reopened due to the issue being re-reported and the fix not fully resolving the issue. Please see this comment for workaround suggestions: https://github.com/cypress-io/cypress/issues/27731#issuecomment-1796430350.
Going to actually close this as a duplicate of https://github.com/cypress-io/cypress/issues/27731. Please follow that issue if you're encountering this error.
Current behavior
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:Desired behavior
Tests run successfully
Test code to reproduce
Courtesy of @MattyBalaam: https://github.com/MattyBalaam/cypress-ts-import
Cypress Version
12.8.1
Node version
18.11.0
Operating System
macOS 12.6
Debug Logs
Expand
```shell $ DEBUG='cypress:*' ./node_modules/.bin/cypress run | tee debug.log cypress:cli:cli cli starts with arguments ["/opt/homebrew/Cellar/node/18.11.0/bin/node","/Users/mmalone/src/cypress-ts-import/node_modules/.bin/cypress","run"] +0ms cypress:cli NODE_OPTIONS is not set +0ms cypress:cli:cli program parsing arguments +1ms cypress:cli:cli running Cypress with args [ Command { _events: [Object: null prototype] { 'option:auto-cancel-after-failures': [Function (anonymous)], 'option:browser': [Function (anonymous)], 'option:ci-build-id': [Function (anonymous)], 'option:component': [Function (anonymous)], 'option:config': [Function (anonymous)], 'option:config-file': [Function (anonymous)], 'option:e2e': [Function (anonymous)], 'option:env': [Function (anonymous)], 'option:group': [Function (anonymous)], 'option:key': [Function (anonymous)], 'option:headed': [Function (anonymous)], 'option:headless': [Function (anonymous)], 'option:no-exit': [Function (anonymous)], 'option:parallel': [Function (anonymous)], 'option:port': [Function (anonymous)], 'option:project': [Function (anonymous)], 'option:quiet': [Function (anonymous)], 'option:record': [Function (anonymous)], 'option:reporter': [Function (anonymous)], 'option:reporter-options': [Function (anonymous)], 'option:spec': [Function (anonymous)], 'option:tag': [Function (anonymous)], 'option:dev': [Function (anonymous)] }, _eventsCount: 23, _maxListeners: undefined, commands: [], options: [ [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option], [Option] ], parent: Command { _events: [Object: null prototype], _eventsCount: 1, _maxListeners: undefined, commands: [Array], options: [Array], parent: null, _allowUnknownOption: false, _args: [], rawArgs: [Array], _scriptPath: '/Users/mmalone/src/cypress-ts-import/node_modules/.bin/cypress', _name: 'cypress', _optionValues: {}, _storeOptionsAsProperties: true, _passCommandToAction: true, _actionResults: [], _actionHandler: null, _executableHandler: false, _executableFile: null, _defaultCommandName: null, _exitCallback: null, _aliases: [], _hidden: false, _helpFlags: '-h, --help', _helpDescription: 'display help for command', _helpShortFlag: '-h', _helpLongFlag: '--help', _hasImplicitHelpCommand: undefined, _helpCommandName: 'help', _helpCommandnameAndArgs: 'help [command]', _helpCommandDescription: 'display help for command', _usage: 'Other
This was originally reported in https://github.com/cypress-io/cypress/issues/26148, but was determined to be a separate issue. From looking at the code, I believe the following line is causing this behavior: https://github.com/cypress-io/cypress/blob/e6b2466f7b219a86da46c1ac720432ef75193ca4/packages/server/lib/plugins/child/ts_node.js#L25
There is a workaround, but it only works if you don't have any tests written in TypeScript: set the environment variable
CYPRESS_INTERNAL_NO_TYPESCRIPT=1
to disable TypeScript entirely: https://github.com/cypress-io/cypress/blob/74ada1157c1bf1b184e09873edb6868ae7a67f43/packages/server/lib/util/resolve.js#L12-L14