-
-
Notifications
You must be signed in to change notification settings - Fork 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
Testing Hooks with shallow: Invariant Violation #1938
Comments
Hooks are not yet in a non-alpha version, and are definitely not yet supported in enzyme. I'd suggest waiting to use them until they're not experimental. |
@ljharb Hooks are labeled "upcoming" now 🤔. |
Fair enough, but they’re still both not yet a thing in a real version, and enzyme doesn’t yet have support for them. |
An open issue in react facebook/react/#14091 |
Merged at facebook/react#14567 |
Reopening, since facebook/react#14679 is now merged and v16.8 seems imminent. Also tracked in #1553. |
@ljharb I'd love to help to look into what we need to do to support hooks after v16.8 release. |
@chenesan that would be great. The biggest priority is getting as many tests as possible, and mirroring those as much as possible between shallow and mount. |
Hooks have been released and this still seems to be an issue with enzyme's |
I don't know if there's any ETA for supporting hooks but I'll start to work on this in recent days :-) |
If it’s still an issue with every React package (including the test renderer) at 16.8, then a PR with tests would be quite welcome. |
I am having a possibly related issue with 16.8. I don't get the Invariant Violation, but some hooks which persist data across renders (useRef and useState) are not behaving as expected during shallow render, but work fine during mount. Versions:
Tests: import * as React from 'react';
import { shallow, mount } from 'enzyme';
class ClassInstance extends React.Component {
constructor(props) {
super(props);
this.id = Math.random().toString();
}
render() {
return <div>{this.id}</div>;
}
}
const SFCRef = () => {
const id = React.useRef(Math.random().toString());
return <div>{id.current}</div>;
};
const SFCState = () => {
const [id] = React.useState(Math.random().toString());
return <div>{id}</div>;
};
test('1 class instance property persists with shallow', () => {
const wrapper = shallow(<ClassInstance foo="a" />);
const id = wrapper.text();
wrapper.setProps({ foo: 'b' });
const id1 = wrapper.text();
expect(id).toBe(id1);
});
test('2 class instance property persists with mount', () => {
const wrapper = mount(<ClassInstance foo="a" />);
const id = wrapper.find('div').text();
wrapper.setProps({ foo: 'b' });
const id1 = wrapper.find('div').text();
expect(id).toBe(id1);
});
test('3 SFC ref persists with mount', () => {
const wrapper = mount(<SFCRef foo="a" />);
const id = wrapper.find('div').text();
wrapper.setProps({ foo: 'b' });
const id1 = wrapper.find('div').text();
expect(id).toBe(id1);
});
test('4 SFC ref persists with shallow', () => {
const wrapper = shallow(<SFCRef foo="a" />);
const id = wrapper.text();
wrapper.setProps({ foo: 'b' });
const id1 = wrapper.text();
expect(id).toBe(id1);
});
test('5 SFC state persists with mount', () => {
const wrapper = mount(<SFCState foo="a" />);
const id = wrapper.find('div').text();
wrapper.setProps({ foo: 'b' });
const id1 = wrapper.find('div').text();
expect(id).toBe(id1);
});
test('6 SFC state persists with shallow', () => {
const wrapper = shallow(<SFCState foo="a" />);
const id = wrapper.text();
wrapper.setProps({ foo: 'b' });
const id1 = wrapper.text();
expect(id).toBe(id1);
});
// Verify that an id which *should not* persist across renders in fact does not.
const SFC = () => {
const id = Math.random().toString();
return <div>{id}</div>;
}
test('7 SFC alone does not persist with mount', () => {
const wrapper = mount(<SFC foo="a" />);
const id = wrapper.find('div').text();
wrapper.setProps({ foo: 'b' });
const id1 = wrapper.find('div').text();
expect(id).not.toBe(id1);
});
test('8 SFC alone does not persist with shallow', () => {
const wrapper = shallow(<SFC foo="a" />);
const id = wrapper.text();
wrapper.setProps({ foo: 'b' });
const id1 = wrapper.text();
expect(id).not.toBe(id1);
}); Results:
|
@wodenx what version of react-test-renderer do you have? |
@ljharb lol i was just checking that - i just upgraded from 16.8.0 to 16.8.1 and have the same results. |
Has anyone managed to pull out a magic trick to use Hooks, with Enzyme, shallow or mount? |
@icyJoseph I managed to get this working by upgrading everything around react and testing:
|
@TdyP I have all of those libraries updated, and still I cannot get a simple toggle to work. In your example at the top, how do you trigger the state change when using the onClick prop? I target the prop and call the function attached to it, using the |
@icyJoseph Here's a working example with The component Test.tsx
Test file Test.test.tsx
Hope this helps! |
This works for now. You need to add
|
I think, the invariant problem goes away if you just change that arrow function in ComponentWithHooks for a |
@icyJoseph ah gotcha -- I misunderstood what was wanted based on the invariant violation issue in here (and what I was running into) |
I created a react issue for this |
@bdwain Hi :) import React, { useState } from 'react';
const TestComponent = () => {
const [myState, setMyState] = useState('1234');
return (
<>
<input onChange={({ target: { value } }) => setMyState(value)} />
<p>{myState}</p>
</>
);
};
export { TestComponent }; describe('Test Copoment', () => {
it('should change myState value on input change', () => {
// Given
const testComponent = shallow(<TestComponent />);
const { onChange } = testComponent.find('input').props();
// Then
expect(testComponent.find('p')).toHaveText('1234');
// When
act(() => {
onChange({ target: { value: '8658' } });
components.update();
});
// Then
expect(testComponent.find('p')).toHaveText('8658');
});
}); // Text is still 1234 (initial state) |
@koszatnik12 I have the same, with enzyme. I updated to lates 16.8.5 but simple unit test with |
@koszatnik12 there’s a few unreleased changes that might address your problem, but also, there’s no |
@ljharb which release is that? |
@alexanderkjeldaas the next one. |
Updating everything solved the problem for me: |
any update? |
I know it's been said a number of times above, but the main part of the suggested solutions for me was to force So I basically ended up with:
|
you don’t even have to do that if your lockfile has the right one. |
You can follow the progress here ( |
And about |
v3.10.0 has now been released. |
I am having some trouble to test with shallow render the
File test is the same used by #1938 (comment) Happy to raise a new issue if this is not the right place |
@EduardoAC a new issue would be very helpful, thanks! |
I had the same issue and the reason was multiple versions of
For some reason,
|
I was getting intermittent testing failures even after #1938 (comment) . I was able to get my specs passing consistently by doing the following:
Then using Enzyme's |
Thanks a lot @EduardoAC ! It did save me! 😄 |
updating |
@lucasmonteiro001 you are very welcome @joselcc great to hear it |
That worked for me too, thanks ! |
This solution worked for us, but we also realised we did not need yarn remove enzyme enzyme-adapter-react-16 react-test-renderer
yarn add enzyme enzyme-adapter-react-16 Test cases with Hooks still works |
@bodazhao it comes along with the react 16 enzyme adapter anyways; but it’s version still needs to be the same minor as react and react-dom. |
This are my dependencies, and I still get this error (hook should not be called outside of balblabla)
Does it matter that between my test file and the inner tested component there is a class based one? mount( <Provider><TestedClassComponent/></Provider> Where TestedClassComponent is a class component that internally uses a functional component that depends on the provider? (which is also functional) |
I just converted the middle component from class based to functional one and the problem persists. |
Current behavior
When testing component which contains newly released React Hooks using
shallow
, it crashes:Invariant Violation: Hooks can only be called inside the body of a function component.
Everything works fine at run time or when testing with
render
:My test component:
My test file:
Error stack trace:
Expected behavior
Tests should run
Your environment
Fresh create-react-app-typescript install with react 16.7.0-alpha-0
API
Version
Adapter
The text was updated successfully, but these errors were encountered: