-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Allow ESM stubbing for functions in Vite #22355
Comments
@JessicaSachs @lmiller1990 let me know if I can provide any additional info |
Thanks for opening this issue. We should be doing what the Vitest plugin does to enable ESM mocking. |
The Vitest code doesn't look too bad. It might be a good solution for now (to help A dev-server specific mock/stub doesn't seem ideal, although happy to look into this in the short term until we better know how to handle the general problem of ESM module mock/stubs. We will discuss internally and figure out the logistics/prioritization of this! |
Can we include allowing esm stubbing functions in NextJS as well? That's the only thing preventing us to use the new SWC compiler on NextJS. Currently, we're using the following .babelrc to make stubbing work.
|
Is there any update for the latest version of Cypress? When trying something similar with a composable I get the error |
@illegalnumbers as a workaround, I export the composables from another file, then stub. // composables/index.ts
import useOrg from './useOrg'
export {
useOrg
}
// Component file (usage example)
import composables from '../composables'
const org = composables.useOrg()
// Test spec file
import composables from '../composables'
cy.stub(composables, 'useOrg').returns({ data: [] }) |
Sorry fam, we did not work on ESM stubbing yet. I'd really like to see this implemented, I hope we can look at it soon. Vitest supports this but they run everything in a Node.js context. I think the first step is looking at what they do and finding out if we can do the same thing. Is there any other runners supporting ESM stubs? Jest now has ESM support natively - I wonder how they implement it? I'm thinking the most likely rely on the Node.js module resolution, too - I don't know of any browser runners that support ESM and stubs. If anyone wants to explore this, I can definitely help out or make some suggestions. Especially if someone can find a reference implementation, I can assist with the "here is where you need to put the code in Cypress". |
I'm interested in adding browser support to esmock. it would be awesome if someone would add a cypress test folder alongside esmock's other test folders, and inside the test folder, add a passing test and a broken/failing test that uses esmock in the right place to try and browser-import a module with mock import tree. |
Oh nice! Hadn't seen this project, this looks promising. |
I think it's time to tackle this, going to get some resources into this in our next sprint. Not sure on the complexity or how best to solve this, but we can at least start investigating. |
This comment was marked as outdated.
This comment was marked as outdated.
There is a nice repo we can test this on once delivered: https://github.com/muratkeremozcan/tour-of-heroes-react-vite-cypress-ts. Enable the lines with the comment |
This comment was marked as outdated.
This comment was marked as outdated.
Update on ESM stubbingUnfortunately this is a non-trivial problem due to how ES Modules are designed. The ESM spec requires modules to have an immutable namespace, and since Cypress component tests run inside the browser and use the browser's module loader to ensure spec compliance it isn't possible to do something like this: import MyModule from './module.js'
// `MyModule` is a sealed namespace, can't resassign/add/delete direct members
MyModule.something = 'somethingElse' Other testing tools like Jest & Vitest work around this in a couple different ways:
What are your options today?Rest assured, we are working on a way to support this in a way that doesn't have a massive breaking change and doesn't change the way your code runs. In the interim, there are a couple workarounds that I'll try to outline here:
Is Cypress considering any changes?Short answer - we aren't sure yet. We're kicking around a few ideas, and if you know of another we'd love to hear about it. To get the same sort of behavior as Jest and others we could introduce a new API like Another option we're considering is a plugin that rewrites ES Modules as they're served by your dev server so that they're mutable. This is a fairly complex thing to get right, and we aren't 100% sold on this being the right thing to do. One of the major principles of Cypress is that we try to be as standards-compliant as possible so we don't accidentally hide problems in your code. We'd love to hear your thoughts on this approach, and if anyone knows of a tool that already does this (or is interested in writing one) let us know! |
This is published now: https://www.npmjs.com/package/@cypress/vite-plugin-cypress-esm |
I found this is not working for some basic cases: https://github.com/lmiller1990/esm-bug I will file an issue. |
@marktnoonan how would I go about using mocking ESM modules with a NextJS project? |
@dwilt you could try: https://www.npmjs.com/package/@cypress/vite-plugin-cypress-esm Are you actually using ESM (eg If you have a specific reproduction of something not working, happy to take a look. |
@lmiller1990 Trying out the plugin returns this error: We just use the import/export syntax. We don't have
|
Will need a minimal reproduction to give any useful advice! |
@andyhqtran I ran into this the other day and created an issue with a reproduction #28696 |
Hi @lmiller1990, we've been struggling to make the @cypress/vite-plugin-cypress-esm plugin work without success for component tests in a Vue 3 + Typescript project. An easy way to reproduce is to just scaffold the example Vue 3 app with: The error we are getting is this one: We tried to add Vue to the ignoreModuleList as:
But the problem persists. Any ideas on how to approach it? |
Hmm can you try I am guessing you cannot stub something defined at runtime, which could be After a lot of time/effort from many people in many projects, there is still no solution to stub/mock for ESM modules. They are sealed and immutable at the implementation level, I can't really imagine if this will ever be fully solvable. I am not entirely sure what is the actual issue here. It looks like on line 8 of your code it does: setup(props, {expose: __expose)` And for some reason, the object it is trying to destructure is null. I can't think why that would be or how it's caused by this plugin. Please try the |
Hi @lmiller1990 same problem with Keep in mind that the |
Hey @lmiller1990 I just created one for you: https://github.com/mverdaguer/cypress-vue3-esm-stubs-error/tree/main |
It's great to see the effort on such an important topic. I think once there is an option to mock modules on real environments all my wishes come true. Unfortunately using the plugin on our React-Typescript-vite setup fails.
and a readable error like:
I have the plugin configured with The plugin seems to fail on some basic step of our project even though it is quite common and nothing unorthodox happens in our build process therefore it is difficult to attempt a repro case. Is there anything I can do? What is the state of the plugin currently. Does someone has a working example except the PR where it got merged? |
@Crismon96 The plugin is an alpha-stage experiment so instability and errors are to be expected, but I can say for certain that it is being used successfully on several very large complex projects. The plugin relies on fairly basic methods to transform code (regexes rather than an AST) for now, so it's very possible a particular string or magic variable name in a unique third-party dependency or newer babel transform is tripping things up. Without a reproduction case I can't provide much direct assistance, but I would recommend the following flow:
If you are able to narrow it down and get something working hopefully that may give you enough info to report back and open an issue with a reproduction case. Good luck! |
Just adding for future reference, someone pointed out you could experiment with using MSW to intercept a module and return mocked one. From: vitest-dev/vitest#3046 (comment) |
I was interested in this issue a while back and thought I'd play around with MSW after @lmiller1990 pointed out the viability of using MSW. I was able to get something to work (with some quirks...) if anyone is interested in checking it out cypress-vite-esm-msw-mocker and giving it a go. The package allows you to intercept network requests and replace a modules contents with another file on disk or just a string. Works with esm modules and default exports (since the entire file gets replaced). The package is rough around the edges but could be useful! |
Is there a solution for webpack for the same issue? |
@matthias-deschoenmacker The solution most people have used is modifying Webpack to not generate ESM modules when bundling for your Component Tests. There is a config option that allows you to customize the Webpack config applied to your project. That would cover situations where your code is bundled as ESM - if you're somehow pulling in third-party libs that are prebundled as ESM then you have a more complex problem that is a bit outside of Cypress - you'd either need to stub a higer-level wrapper that is under your control, or restructure the import to be dynamic and use something like |
Is the consensus here that vitest will not support this then? |
Outside of the plugin (with works for a good amount of cases, did you try it?) and various other suggestions that are suggested here there is no ongoing work to enable ESM mocking/stubbing in Cypress / Vite integration. Does Vitest (eg, the Node.js test runner powered by Vite: https://vitest.dev/) even support this? My understanding is the ESM is designed specifically to not be mutable - the core issue is we are all trying to do something the spec specifically disallows (tinkering with modules). |
Any progress on this? Is this even planned to be worked on? |
Thanks for all of the feedback! We're going to close this specific issue as resolved. We recommend using https://www.npmjs.com/package/@cypress/vite-plugin-cypress-esm to achieve this requested feature. If you encounter bugs with the plugin, want more features in the plugin, or have another use case that is not covered by the plugin, please open a new issue in the cypress repo. |
What would you like?
Utilizing Vite + Vue and Cypress Component Test Runner, how would you stub a composable function since you can't stub the default export?
I can't find a decent example that doesn't utilize Babel, and the only solution we have come up with is exporting an object with methods that can be stubbed, which, to be honest, would be a large refactor.
When stubbing the default export, as shown below, an error is thrown:
ESModules cannot be stubbed
. I know this is a valid error (here's a great write-up for reference); however, we need the ability to stub the default exports of imported modules.Why is this needed?
It's a standard in Vue 3 to move stateful logic into composable functions. Composables typically export a default function (not an object) and devs need the ability to stub the outputs of a composable.
There is currently a workaround; however, it would require refactoring large blocks of code within our (and most) application whereby the composable exports a utility function that is used to set the returned values. This workaround (shown below) is a bit cumbersome and requires a very explicit, non-standard way of writing composable functions.
Here is the same composable provided above, rewritten for the workaround (not ideal):
Other
No response
The text was updated successfully, but these errors were encountered: