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

Unable to mock React useState #2069

Closed
JamesIves opened this issue Jul 26, 2019 · 9 comments
Closed

Unable to mock React useState #2069

JamesIves opened this issue Jul 26, 2019 · 9 comments

Comments

@JamesIves
Copy link

JamesIves commented Jul 26, 2019

Describe the bug
I'm unable to use Sinon to mock the React hook useState. I've tried multiple different ways but always end up with it not being mocked.

My code looks like this:

import React, { useState } from 'react';

function Expand() {
  const [expanded, setExpanded] = useState(null);

  return (
    <div>
      <button onClick={() => setExpanded(true)}>
        Expand
      </button>
    </div>
  );
}

And using Sinon in my test I've tried to stub it like so:

import * as React from 'react'; 
import {stub} from 'sinon';

const setExpandedStub = stub();
const setStateStub = stub(React, 'useState').returns([
  null,
  setExpandedStub,
]);
const component = mount(<Expand />);

component
  .find('button')
  .prop('onClick')();

t.equals(
  setExpandedStub.args,
  true,
  'Should set the state to true.'
);

Logging out useState in my function when my test runs seems to reveal that it never actually gets mocked by Sinon: [Function: useState] and I'm unable to call setExpandedStub.args etc.

To Reproduce
Steps to reproduce the behavior:

  1. Attempt to mock React.useState.
  2. It never mocks.

Expected behavior
I expect the function to be stubbed so I can tell when it has been called.

Context (please complete the following information):

  • Library version: 7.3.2
  • Environment: Mac OSX
  • Other libraries you are using: React, Enzyme, Tape

Additional context
https://reactjs.org/docs/hooks-state.html

@fatso83
Copy link
Contributor

fatso83 commented Jul 26, 2019

We are trying to keep the GitHub issues list tidy and focused on bugs and feature discussions. This ticket looks like a usage question; please post it to StackOverflow and tag it with sinon, so the bigger community can help answer your questions.

If you feel that your topic is an issue with Sinon, please open a new ticket and follow the guidelines for reporting an issue.

@fatso83 fatso83 closed this as completed Jul 26, 2019
@JamesIves
Copy link
Author

JamesIves commented Jul 27, 2019

I did - but I don't understand how this doesn't fall under the guidelines for reporting issue? From my understanding Sinon isn't working as intended in this use case based on the stubbing documentation and previous cases where similar code works fine for stubbing. If it's working as intended it's unclear as to why.

@fatso83
Copy link
Contributor

fatso83 commented Jul 28, 2019

There is nothing that says Sinon is doing anything wrong here. And there are multiple ways the example could go wrong and they all relate to binding. Meaning that you probably bind the reference to useState in your client code before you stub out the export in the test.

This relates to module binding, probably using Babel and/or Webpack, which is not what this library is about.

We do have multiple guides though, and I would try out the link levels replacement strategy first ("link seams"):
https://sinonjs.org/how-to/.

This should work fine when running through Babel-Node, but if you also employ Webpack you'll encounter complications, which is out of scope (as the various Webpack versions have different ways of exporting modules).

@fatso83
Copy link
Contributor

fatso83 commented Jul 28, 2019

P.S. Post a link to the stackoverflow question and I'll try to find time in making a runnable example project.

@fatso83
Copy link
Contributor

fatso83 commented Jul 28, 2019

Here's a runnable demo where I stub out useState using only Sinon and React:
https://repl.it/@fatso83/React-library-stubbing-demo-sinon-only

You don't strictly need Sinon to demonstrate this, though. Just overwriting the exported reference would be enough.

I don't have access to a development environment on holiday, so I just coded it up in the browser using repl.it, and as I don't know how to configure it using Babel and all that jazz it is purely standard EcmaScript, but you should be able to follow as it's pretty close to the original JSX.

@JamesIves
Copy link
Author

Really appreciate the example and the explanation!

@fatso83
Copy link
Contributor

fatso83 commented Jul 28, 2019

No worries - at least now we can refer people to an example :)

BUT should it for some reason NOT work in your case, I assume it's due to some bundler/packer configuration issue, most probably Webpack. In that case, you might be interested in reading #1762 or the associated webpack thread webpack/webpack#6979 (comment) to understand why Sinon is not responsible for this and what options you have to achieve your target.

Izhaki has some good input.

@littleh322
Copy link

littleh322 commented Jun 23, 2020

How would you handle multiple useState instances using different types in your functional component?
For example:
const [open, setOpen] = useState<boolean>(false);
const [name, setName] = useState<string>('Enter name here...');
const [object, setObject] = useState<SomeObject[]>('Enter name here...');

I bet if you mock out useState for a boolean value, it'll set name to the boolean value. Then, it'll also fail when attempting to use the object, because SomeObject[] != boolean type.

Still haven't found out how to mock useState effectively.

@fatso83

@fatso83
Copy link
Contributor

fatso83 commented Jun 25, 2020

@littleh322 That's a usage question and we are not equipped (i.e. payed) to handle general support.; please post it to StackOverflow and tag it with sinon, so the bigger community can help answer your questions. They are usually very quick (and I am often one of them, just not in my parental leave).

@sinonjs sinonjs locked and limited conversation to collaborators Jun 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants