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

Stubbing ES modules (imports) does not work for component testing #17048

Closed
twhoff opened this issue Jun 22, 2021 · 13 comments
Closed

Stubbing ES modules (imports) does not work for component testing #17048

twhoff opened this issue Jun 22, 2021 · 13 comments
Labels
stage: needs information Not enough info to reproduce the issue

Comments

@twhoff
Copy link

twhoff commented Jun 22, 2021

Current behavior

using cy.stub on an ES module does not work as expected, see example code below:

// Person.js
export const getName = () => 'Bob'
// Test which stubs person
import * as person from './Person'

it('Stubs person', () => {
    cy.stub(person, 'getName').callsFake(() => 'Billy')

    console.log(person.getName()) // Expects 'Billy', gets 'Bob'
})

Cypress 7.5.0

@jennifer-shehane
Copy link
Member

I'm getting Billy when I run this code. Could you provide a repo that reproduces the issue?

cypress/integration/persons.js

export const getName = () => 'Bob'

cypress/integration/spec.js

// Test which stubs person
import * as person from './person'

it('Stubs person', () => {
  cy.stub(person, 'getName').callsFake(() => 'Billy')

  expect(person.getName()).to.eq('Billy') // Expects 'Billy', gets 'Bob'
})

Screen Shot 2021-06-22 at 12 49 25 PM

@jennifer-shehane jennifer-shehane added the stage: needs information Not enough info to reproduce the issue label Jun 22, 2021
@Dorious
Copy link

Dorious commented Jun 25, 2021

I'm getting the same problem. @jennifer-shehane but do you get the result inside the app that is using person? What configuration do you have? browserify or webpack?
I'm using component test runner with webpack dev server (maybe that is correlated).
Want to stub library that is outside of my control and doing import * as Grr from 'grr' doesn't do the trick unfortunately.

@twhoff
Copy link
Author

twhoff commented Jun 30, 2021

Apologies, I forgot to mention this is when unit testing using @cypress/react and with the command yarn cypress run-ct.

For a bit more information, the app is bootstrapped with create-react-app and is not ejected (so webpack under the hood).

Let me know if you need more information.

image

@twhoff
Copy link
Author

twhoff commented Jul 16, 2021

@jennifer-shehane just wanted to bump this as essentially stubbing / spying does not work in the context of unit testing.

@twhoff twhoff changed the title Stubbing ES modules (imports) does not work Stubbing ES modules (imports) does not work for component testing Aug 31, 2021
@twhoff
Copy link
Author

twhoff commented Aug 31, 2021

So just bumping this again - essentially stubbing module imports (import * as Redux from 'react-redux' for example) doesn't work for component tests (yarn cypress run-ct) but DOES work for regular tests (yarn cypress run) - this is a pretty major issue if you ask me, surprised it has been broken for over a year??

@twhoff
Copy link
Author

twhoff commented Sep 3, 2021

Update - I finally managed to get this working reasonably with component tests (unit testing).

The core concepts are actually in a code example I didn't find until now (my bad):
https://github.com/cypress-io/cypress/tree/master/npm/react/cypress/component/advanced/mocking-imports

@twhoff twhoff closed this as completed Sep 3, 2021
@bvandercar-vt
Copy link

I do not think this is resolved, Cypress should have a viable solution builtin

@bvandercar-vt
Copy link

I am getting the error from cypress "ES Modules cannot be stubbed" when I attempt this.

@binvb
Copy link

binvb commented Oct 8, 2022

I am getting the error from cypress "ES Modules cannot be stubbed" when I attempt this.

same to me

@SIGSTACKFAULT
Copy link

SIGSTACKFAULT commented Jun 25, 2023

same problem.

for me, it's much easier to stub the function that retrieves values from localStorage than to fill localStorage

@mike-plummer
Copy link
Contributor

To anyone stumbling on this issue the latest information on this topic can be found in #22355

The TL;DR is that ESM mocking is very different than CommonJS mocking - the ESM spec makes it almost impossible to use standard mocking mechanisms which makes things difficult for Cypress (and any other tool that runs in the browser). We have recently released an experimental plugin that can be applied to your test Vite config to enable common mocking scenarios, but it is an early Alpha release so there will likely be hiccups and customization necessary to get it working in your project. The linked issue above has several suggestions for ways to either restructure your code or restructure your tests to mitigate the need for mocking/spying.

@dwilt
Copy link

dwilt commented Aug 24, 2023

@mike-plummer we've got a NextJS application and are trying to do ESM mocking.. that issue is referencing a vite plugin. Any thoughts for NextJS?

@mike-plummer
Copy link
Contributor

@dwilt It should be relatively simple to update your Next application's Webpack Config to specify the module output format. Have you customized it to output ESM modules? I thought Webpack was still outputting commonjs by default, but maybe that's changing.

Take a look at the output fields - IIRC you can tweak output.chunkFormat and/or output.module to control what module format Webpack publishes. You can either update the base config for your project, or customize it just for your Cypress tests using this pattern via the webpackConfig prop (example references a react project but it should work for next as well)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stage: needs information Not enough info to reproduce the issue
Projects
None yet
Development

No branches or pull requests

8 participants