cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
47.5k stars 3.2k forks source link

Cannot consume ES module based cypress config when using Yarn 3 #22747

Open lmiller1990 opened 2 years ago

lmiller1990 commented 2 years ago

Current behavior

Does not work correctly with cypress.config.ts containing ES module syntax when using Yarn 3 (does not create node_modules). I get an error and cannot proceed.

I think the problem is we try to resolve your TS install from projectRoot but new versions of yarn install modules in some other place that isn't in <project>/node_modules.

There's a lot of information in this issue, and related ones - before working on this, spend a bit of time reading and understanding the issue. It looks like it is primarily related to Plug n Play feature.

Note: many users are excited for this fix - if you are working it, please build a pre-release binary and share it here, so users can test it out.

Test code to reproduce

https://github.com/lmiller1990/yarn-3-issue-ts

Cypress Version

10.3.0+

Other

Created from https://github.com/cypress-io/cypress/issues/22071#issuecomment-1180554866

gajus commented 2 years ago

Any chance that you've figured out a solution?

lmiller1990 commented 2 years ago

I didn't try yet, but it should be as simple as pointing Cypress at where ever Yarn PNP puts node_modules.

Happy to assist with this if you'd like to either take a stab, or even just point me in the direction - I know Cypress well, but not Yarn 3.

jefbarn commented 2 years ago

@lmiller1990 Thanks for looking into this, I'm trying to switch a project over to Yarn PNP and cypress is my last hold up.

Yarn PNP uses a custom loader and virtual filesystem, so there is not a 'node_modules' to point to. The trick should be to make sure ts-node is using the yarn loader, which is usually accomplished when loading a node script using yarn command eg 'yarn cypress run'.

But not working in this case because I suspect the cypress command is spinning off another process to run ts-node?

I'm happy to help play around with this if you have some suggestions. Also, I tried renaming my cypress.config.ts file to cypress.config.mts, which should be supported by the latest ts-node, but cypress doesn't like the mts extension yet.

lmiller1990 commented 2 years ago

Not sure where to start with this, I'll need to do some research.

I do not think we support cypress.config.mts yet - we may need to bump our ts-node version. So many extensions and module formats now 🤯

lmiller1990 commented 2 years ago

Probably need to do something around here, not sure what. I think what might be happening is this line is erroneously false, since it is attempting to resolve the user's TypeScript version using the usual node module algorithm, which doesn't work with Yarn 3.

What would be interesting is to see what happens in a Yarn 3 project without TypeScript - just using regular CJS. If that works, my suspicion is probably correct? cc @rockindahizzy

josephzidell commented 2 years ago

Running into a similar issue. Using yarn 3.2.3, cypress 10.7.0.

lmiller1990 commented 2 years ago

I think I was misleading slightly - the title should not be ES module based but TS based cypress config. I will update it.

Basically, yarn 3 + TS isn't working? I think it's because we try to load your local TS from node_modules, which is not a thing in Yarn 3... digging into the various module problems now (eg https://github.com/cypress-io/cypress/issues/22795) so hopefully can look into this, too.

sarah96wang commented 1 year ago

Running into the same error with Yarn 3.2.3 and TS during migration from Cypress 9 to 10. Any updates?

lmiller1990 commented 1 year ago

I haven't had a chance to look at this in more depth yet. I'm sorry. I don't think I can look at this during Dec, but I would like to see this triaged and fixed in January. Let me try and bump this one up in priority.

baus commented 1 year ago

Hey team! Please add your planning poker estimate with Zenhub @astone123 @lmiller1990 @marktnoonan @mike-plummer @rockindahizzy @warrensplayer @ZachJW34

gusgard commented 1 year ago

This is the workaround I found to run it with yarn v3 https://github.com/cypress-io/cypress/issues/22699#issuecomment-1370861099

jefbarn commented 1 year ago

@gusgard That workaround is not working in my environment. Are you using typescript for your cypress config?

francisu commented 1 year ago

@lmiller1990 - this might help

This remains an issue in Cypress 12.3.0

I have this as well. I think the problem is in the code of ProjectConfigIpc in forkConfigProcess where it launches a plain node instance to do things. As this node instance was not launched via yarn, it does not get the required patching to resolve packages according to the Yarn 2/3 (PNP) rules. If the NODE_OPTIONS were set to require the .pnp-cjs file then it should work. I have not been able to test this because I don't have time to figure out how to build a cypress distribution from source and try it.

I also wanted to try it by patching cypress as it was installed on my machine, but the cypress npm dist does not seem to contain this code.

I'm happy to help test any proposed solution. And if I can get help in patching the cypress dist as it's installed (via yarn), then I can make the patch and try it.

francisu commented 1 year ago

This is the workaround I found to run it with yarn v3 #22699 (comment)

This seems to only apply to the webpack-dev-server. Some (including me) are using vite.

lmiller1990 commented 1 year ago

Hello @francisu, good suggestion! I didn't know that the process needed to be launched via yarn to make it "know" about the pnp config. I will try this trick with NODE_OPTIONS (hopefully this week).

I think we need to solve Yarn 3 PnP once and for all, this has dragged out for way too long. I will try and get this into our sprint work in the near future.

francisu commented 1 year ago

Hello @francisu, good suggestion! I didn't know that the process needed to be launched via yarn to make it "know" about the pnp config. I will try this trick with NODE_OPTIONS (hopefully this week).

I think we need to solve Yarn 3 PnP once and for all, this has dragged out for way too long. I will try and get this into our sprint work in the near future.

LMK if you want any help testing this with Yarn 3 (effectively the same as Yarn 2 for this purpose)

hugobarragon commented 1 year ago

Any solution lately?

lmiller1990 commented 1 year ago

I am unable to prioritize this right now, I'm sorry. If anyone else would like to take a look and give it a try, a PR would be much appreciated!

matthias-pichler commented 1 year ago

As a workaround one can forego some of the benefits of PnP and set

nodeLinker: node-modules

in the .yarnrc.yml file. That will prompt yarn to generate node_modules folders. Manually setting NODE_OPTIONS="--require $(pwd)/.pnp.cjs" didn't work for me.

hugobarragon commented 1 year ago

This works for the major of projects, but does not work for monorepos, for monorepos only cypress individual on each project is kinda working

matthias-pichler commented 1 year ago

This works for the major of projects, but does not work for monorepos, for monorepos only cypress individual on each project is kinda working

That I don't know. The project I configured this in is using yarn workspaces and the node_modules are deduplicated and hoisted to the root folder by yarn and in this setup it's working fine.

jmgate commented 1 year ago

Any movement on this? We're at risk of throwing away ~2 years of Cypress test development if this isn't resolved by the end of March.

lmiller1990 commented 1 year ago

Hiya @jmgate, are you having issues for Component Testing or just general Cypress usage w/ Yarn 3?

Will try and get some resources on this before end of Q1 (end of March).

jmgate commented 1 year ago

Just general Cypress usage w/ Yarn 3 zero installs.

lmiller1990 commented 1 year ago

Gotcha. I will try and get this into our next sprint of work. I don't know much about the scope of the problem, but it looks like there is a good chunk of information in this issue to help with debugging it.

@jmgate are you using the Plug n Play feature? Or is this a general issue across Yarn 3? I'm learning about Yarn 3 now, looks like I've got a bit of exploration to do.

francisu commented 1 year ago

I'm happy to try an experimental distribution if you want. And if you have questions about how to do it, we can correspond.

On Tue, Feb 21, 2023 at 3:35 PM Lachlan Miller @.***> wrote:

Gotcha. I will try and get this into our next sprint of work. I don't know much about the scope of the problem, but it looks like there is a good chunk of information in this issue to help with debugging it.

— Reply to this email directly, view it on GitHub https://github.com/cypress-io/cypress/issues/22747#issuecomment-1437846785, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHGWNM7CTTIW73Y3DRE3ILWYRAZDANCNFSM53JHH6TQ . You are receiving this because you were mentioned.Message ID: @.***>

--

CTO, Founder SnapStrat http://www.snapstrat.com | +1 510 432 1589

lmiller1990 commented 1 year ago

@francisu are you using the Plug n Play feature? I'm trying to get a grasp on what the scope of the problem is - I don't know much about Yarn 3 (yet) except I couldn't get it working with any of my projects 😓

francisu commented 1 year ago

Yes, I'm not using node-modules at all, just standard Yarn 3. It should be pretty easy for you to test, just create a new project, install yarn as normal, and then do a 'yarn set version berry' and you will be on yarn3 pnp.

Hopefully the suggested fix[1] will work.

https://github.com/cypress-io/cypress/issues/22747#issuecomment-1377993283

On Tue, Feb 21, 2023 at 3:37 PM Lachlan Miller @.***> wrote:

@francisu https://github.com/francisu are you using the Plug n Play feature? I'm trying to get a grasp on what the scope of the problem is - I don't know much about Yarn 3 (yet) except I couldn't get it working with any of my projects 😓

— Reply to this email directly, view it on GitHub https://github.com/cypress-io/cypress/issues/22747#issuecomment-1437848099, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHGWNI5YBT2BQNNJDAY6I3WYRBCPANCNFSM53JHH6TQ . You are receiving this because you were mentioned.Message ID: @.***>

--

CTO, Founder SnapStrat http://www.snapstrat.com | +1 510 432 1589

dyabol commented 1 year ago

We have exactly same problem. When you use yarn berry with nodeLinker: node-modules everything works, problem is when you change config to nodeLinker: pnp, install dependecies and run cypress tests. We use cypress with typescript.

hchho commented 1 year ago

We tried the NODE_OPTIONS option and that didn't resolve the issue. Looking into a bit more, the issue begins when the pnp-loader sees that a node instance outside of the project root is loading a config.ts file under the project, and when that happens pnp-loader defaults to a Commonjs interpreter, which results in the type error. The NODE_OPTIONS persists to the child node that Cypress spins up, but Yarn automatically unplugs Cypress when it downloads, so I don't think the pnp-loader setting actually works?? It's been a while since I looked at this so my memory is a bit fuzzy, but my team is really eager to get this working.

francisu commented 1 year ago

When you say you tried the NODE_OPTIONS, do you mean you modified the code in Cypress to modify the NODE_OPTIONS when it was spawning the node process? Changing the NODE_OPTIONS when calling Cypress would had no effect for me, and I could not get to the source code of Cypress when I unplugged it. The unplugged version of the package had very little code and not the code that does the spawning. I still don't know where to find this (otherwise I would have just patched it).

On Tue, Feb 21, 2023 at 5:09 PM Henry @.***> wrote:

We tried the NODE_OPTIONS option and that didn't resolve the issue. Looking into a bit more, the issue begins when the pnp-loader sees that a node instance outside of the project root is loading a config.ts file under the project, and when that happens pnp-loader defaults to a Commonjs interpreter, which results in the type error. The NODE_OPTIONS persists to the child node that Cypress spins up, but Yarn automatically unplugs Cypress when it downloads, so I don't think the pnp-loader setting actually works?? It's been a while since I looked at this so my memory is a bit fuzzy, but my team is really eager to get this working.

— Reply to this email directly, view it on GitHub https://github.com/cypress-io/cypress/issues/22747#issuecomment-1437910545, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHGWNKCQBRMPMM3VXM5VPDWYRL2HANCNFSM53JHH6TQ . You are receiving this because you were mentioned.Message ID: @.***>

--

CTO, Founder SnapStrat http://www.snapstrat.com | +1 510 432 1589

hchho commented 1 year ago

When you say you tried the NODE_OPTIONS, do you mean you modified the code in Cypress to modify the NODE_OPTIONS when it was spawning the node process? Changing the NODE_OPTIONS when calling Cypress would had no effect for me, and I could not get to the source code of Cypress when I unplugged it. The unplugged version of the package had very little code and not the code that does the spawning. I still don't know where to find this (otherwise I would have just patched it). … On Tue, Feb 21, 2023 at 5:09 PM Henry @.> wrote: We tried the NODE_OPTIONS option and that didn't resolve the issue. Looking into a bit more, the issue begins when the pnp-loader sees that a node instance outside of the project root is loading a config.ts file under the project, and when that happens pnp-loader defaults to a Commonjs interpreter, which results in the type error. The NODE_OPTIONS persists to the child node that Cypress spins up, but Yarn automatically unplugs Cypress when it downloads, so I don't think the pnp-loader setting actually works?? It's been a while since I looked at this so my memory is a bit fuzzy, but my team is really eager to get this working. — Reply to this email directly, view it on GitHub <#22747 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHGWNKCQBRMPMM3VXM5VPDWYRL2HANCNFSM53JHH6TQ . You are receiving this because you were mentioned.Message ID: @.> -- CTO, Founder SnapStrat http://www.snapstrat.com | +1 510 432 1589

Yes, thanks for helping me clarify. There's a snippet of code that spawns an instance, I'll take a look tomorrow but I believe (could be wrong, I'm recalling this from memory) it points to the directory where Cypress is installed to spawn a child. The main dist for Cypress is located in a separate folder (at least on a Mac) and I was able to fiddle around with it there, but didn't get too much headway because it would've taken too much time to self-onboard myself with the project.

francisu commented 1 year ago

I have a Mac too. Can you tell me where the code is and I will try my fix there?

jmgate commented 1 year ago

@lmiller1990

@jmgate are you using the Plug n Play feature?

Yes.

MartinN3 commented 1 year ago

I also use typescript, and I can only add that issue remains whether you use vite or webpack for running cypress e2e tests. Nodelinker solution mentioned lately, that unpacks files to node_modules fixes the issue for me.

btw: transition to yarn 3 using migration guide on yarn website was far better experience than i expected and benefits in resolution and package managing are remarkable.

jmgate commented 1 year ago

BTW, the exact problem we were having was captured in #24209, which was closed in favor of this issue.

hchho commented 1 year ago

@francisu I found the dist code here (example) /Users//Library/Caches/Cypress/10.11.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child

lmiller1990 commented 1 year ago

This is going to be worked on in our next block of work (between 28th Feb and 13th March). Assuming we solve the problem, we can ship the fix in the following release. There will definitely be pre-release binaries that can be tested, whoever picks up this issue will post here. Thanks for your patience!

ZachJW34 commented 1 year ago

I looked into this a bit and this is what I found (and reiterate what we've found so far in this discussion):

Takeaway from my findings is if we tweak the ESM error detection we can get yarn pnp to work for projects using type="module". Projects utilizing Typescript will require further work. A workaround for TS project could be to just use a javascript config file in the meantime.

Note: With the tweak mentioned above I was able to get a yarn pnp project to work with CT testing. The launchpad walkthrough is borked due to all of the dependency detection we do not working with yarn pnp, but the suggestion of running the dep detection in a child process could be the fix here.

I've never used yarn pnp so this is just a summary of what I found as a yarn pnp newb!

kubijo commented 1 year ago

Some code has been merged adding the ability to stack loaders to work with pnp but not sure what Node version contains this change.

According to the changelog, that would be 2023-02-02, Version 19.6.0.

I've had to update to get my yarn PnP + typescript project off the ground… as a sidenote, I've settled on tsx as a replacement for ts-node

lmiller1990 commented 1 year ago

Some code has been merged adding the ability to stack loaders to work with pnp but not sure what Node version contains this change.

According to the changelog, that would be 2023-02-02, Version 19.6.0.

I've had to update to get my yarn PnP + typescript project off the ground… as a sidenote, I've settled on tsx as a replacement for ts-node

Good info - ts-node is used pretty heavily in Cypress, I don't think we can change our default implementation easily, especially just for Yarn 3 support.

Based on @ZachJW34's info, this might going to be hard (impossible?) without significant changes. Is this normal for complex projects looking to work with Yarn 3? It seems unusual for a mature project like Yarn to introduce a feature something that requires so many major changes to known projects to work.

A workaround for TS project could be to just use a javascript config file in the meantime.

If it turns out this is major amount of work, another alternative might be cypress.config.js and // @check-ts at the top. I don't think there's ever a reason to actually compile cypress.config.ts with strict mode - it's more for convenient hints when configuring a project.

To be clear - I think the goal is "be able to USE Cypress CT with Yarn 3", not "have 100% perfect support for every possible use case out of the box". If we can get mostly working, an have a known solution for the remaining project configurations, that'd probably be okay - as long as it's not too disruptive.

kubijo commented 1 year ago

Is this normal for complex projects looking to work with Yarn 3

Well... AFAIK esm and loaders are pretty much still experimental in node and then you have yarn with its seriously cool but involved PnP plus typescript that is on its own a hard enough thing to resolve... And then you apparently want/need to support other standards that go against each other (cjs)...

Nothing is impossible, this is an engineering problem, not a problem... but it surely gets very annoying very fast.

From what I've seen and did on my projects so far I have a feeling that the biggest road block is trying to solve everything on one code path with mixed module systems in use... You might find it somewhat more doable were you able to split cjs into a separate path and share the utilities around it...

lmiller1990 commented 1 year ago

@ZachJW34 I went over this, thanks for the info -- I think you might have made one mistake, let me clarify.

yarn pnp projects using cypress.config.js with type="module" or cypress.config.mjs won't work

I found Yarn PnP projects with cypress.config.mjs work just fine - regardless of the value of "module" in package.json.

I created three separate issues to make it easier to debug and fix this.

  1. Yarn 3 + cypress.config.ts does not work https://github.com/cypress-io/cypress/issues/25958
  2. Yarn 3 does not work with type=module and cypress.config.js https://github.com/cypress-io/cypress/issues/25959
  3. Dependencies are not detected during onboarding when using Yarn 3 #25960

I think (1) is the biggest main problem. type=module and cypress.config.js has an easy fix - change to cypress.config.mjs.

If you need this to work right now, here are the options:

1. cypress.config.ts does not work

Right now, it will not work with TypeScript.

Before

import { defineConfig } from 'cypress'

export default defineConfig({
  e2e: { /*...*/ }
});

After

const { defineConfig } = require("cypress");

module.exports = defineConfig({
   e2e: { /*...*/ }
});

If you are in VS Code, you can still get type hints via defineConfig.

2. Not working with type: module and cypress.config.js

Fix: Just rename cypress.config.js to cypress.config.mjs, and it should work.

Before

// cypress.config.js
import { defineConfig } from 'cypress'

export default defineConfig({
  e2e: {}
});

After

Just rename cypress.config.js to cypress.config.mjs, and it should work.

3. In Component Testing setup, modules are flagged as "not installed (like webpack, vite etc) even if they are.

Just skip/ignore warnings - it actually works. The UI is incorrect, we need to ensure we resolve yarn pnp modules correctly when checking.

francisu commented 1 year ago

I found Yarn PnP projects with cypress.config.mjs work just fine - regardless of the value of "module" in package.json.

We use setupNodeEvents() in our cypress.config.ts, which used to be in the plugins file. Because of this, it's difficult to convert the cypress.config.ts file to cypress.config.mjs file. We would have to provide the compiled .js files for everything, and also the package.json files so that Yarn 3 knows where to find all of the dependencies. Is there some kind of workaround for this situation? Perhaps having the plugins defined in a separate typescript file (as was done in the past)?

So we are still stuck.

lmiller1990 commented 1 year ago

I learned a lot about Yarn PnP recently and am knocking out issues, one by one. https://github.com/cypress-io/cypress/issues/25960 is closed, the ones https://github.com/cypress-io/cypress/issues/22747#issuecomment-1445788919 should be next.

nemonemi commented 1 year ago

I am experiencing the same issue. New NX project with Yarn 3 PnP mode and Cypress@12.17.1.

I have tried converting it to .js or .mjs but nothing worked.

As far as I understand, Cypress is trying to reference the Typescript from the node_modules and it doesn't know that it should actually search in the .yarn/cache folder. Would this be a correct assessment?

Your configFile is invalid: /home/app/frontend/apps/qualification/cypress.config.ts

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

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /home/app/frontend/apps/qualification/cypress.config.ts
    at new NodeError (node:internal/errors:399:5)
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:79:11)
    at defaultGetFormat (node:internal/modules/esm/get_format:121:38)
    at defaultLoad (node:internal/modules/esm/load:81:20)
    at nextLoad (node:internal/modules/esm/loader:163:28)
    at ESMLoader.load (node:internal/modules/esm/loader:605:26)
    at ESMLoader.moduleProvider (node:internal/modules/esm/loader:457:22)
    at new ModuleJob (node:internal/modules/esm/module_job:64:26)
    at #createModuleJob (node:internal/modules/esm/loader:480:17)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:434:34)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
lmiller1990 commented 1 year ago

I don't think that is the issue here

Your configFile is invalid: /home/app/frontend/apps/qualification/cypress.config.ts

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

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for 
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:79:11)
    at defaultGetFormat (node:internal/modules/esm/get_format:121:38)
    at defaultLoad (node:internal/modules/esm/load:81:20)

It is using the native ESM loader which means the file must be .js to my understanding.

What's the minimal setup to repro this, I can take a look. Are you doing "type": "module" in your package.json by any chance?

kubijo commented 1 year ago

Cypress@13 has just been released and this still seems to be an issue… I have tried ts and mjs extensions to no avail. Is there a chance that this will get revisited soon?

Edit:

I might have gotten a little ahead of myself here, as the following change allowed me to open cypress@13 without that "invalid config file" error.

image

lmiller1990 commented 1 year ago

If you are using type: module you need to include file extensions for Node.js to resolve the files correctly

wiegell commented 1 year ago

@lmiller1990 i have two do-what-you-want days next week at work and thought about looking into this, do you have any more pointers at where to start or maybe some general advice about this part of the codebase? I have read the overall contributors guideline.