-
-
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
Setting text value of input #76
Comments
@jackfranklin the purpose of enzyme is mostly to assert things about rendered react components and their behavior.... by manipulating input values you are manipulating the behavior of the component in an unpredictable way... Some things you can do:
|
@lelandrichardson understood, thanks. I quite like the idea of simulating key presses as a replacement. Would you consider a method to help input lots of keypresses? Eg |
I think that's an interesting idea! The fact that simulating typing is so difficult has been something that's bothered me... |
OK - I might have a play and ping a PR if I get anywhere? :) |
@lelandrichardson I had a go at this and ended up with something like this: simulateKeyPresses(characters, ...args) {
for(let i = 0; i < characters.length; i++) {
this.simulate('keyPress', extend({
which: characters.charCodeAt(i),
key: characters[i],
keyCode: characters.charCodeAt(i)
}, args));
}
} This works in terms of calling an Additionally, the React test util docs do suggest you should set
So I would come back again to the point that it would be nice to have a syntactic method for setting the input value and triggering a change - although I can see why you want to avoid that. I'd love to come up with a Thanks for a great library :) |
Thanks so much for these examples. It'd be great if you could add |
I feel like a better approach here would be making a generic and entirely separate library that provided an API, that generated a stream of simulated browser events. Then, enzyme could simply use that library, and could delegate any API decisions to that other module. That other module would then be useful for a number of other projects. I don't know what that API would look like, but I think solving it in a generic way, for all events and element types, is a hard enough problem that it shouldn't be attempted directly inside a larger project. |
@vesln have you made any progress on a capybara like library? |
@SpencerCDixon i've built something that we use internally, but truth to be told, it's far away from ready. i was really hoping for some input from the community on potential API and feature set before i open source it if you have any suggestions/ideas please let me know |
gotcha. Yeah I havn't really spent much time thinking about it but I think it would be cool to mimic capybara's API as much as possible so the library would be very intuitive for people to learn who are coming from a Rails/Ruby background. I'd definitely be down to put some time into it/help you work on it if you were interested in open sourcing what you did for your company. |
@SpencerCDixon sounds awesome, let's join forces! i will ping u when i have something up, even if it's only the initial boilerplate. then we can discuss the api/features publicly and make it happen |
👍 sounds great! |
In regards to the original topic (not specific to keypress events) this does seem unintuitive. I just started using enzyme today so maybe there is a easier way of writing this out... Currently if I wanted to test some event on a input, let's say change event, it looks like this:
Versus the TestUtils way:
The unintuitive part is using 2 different types to do 1 action. Where as with the React TestUtils you're only having to get and deal with the node. Again new to this, so is there a more streamlined way of doing this common testing task? Right now I'm doing it the TestUtils way. |
Not sure if this helps, but personally I've been using: wrapper.find('input').simulate('change', {target: {value: 'My new value'}}); to test |
@levibuzolic your method worked great for me. |
@hnry Are you still using the TestUtils way? |
I feel like this could be related to the bug mentioned in this blog post: |
It's not working for textarea element |
It also doesn't work for components using currentTarget instead of target, (you cannot pass custom data to currentTarget the way you do it for target, currentTarget will ignore it) |
@levibuzolic Is there a way if i could only set value , i dont have any Onchange or on Blur methods , its just i just need to set value to the input |
How about below? const wrapper = mount(<input />);
wrapper.find('input').node.value = 'Test'; |
Anyone agrees that @levibuzolic solution should be added to documentation? One has to dig trough all the comments here, to find a how to properly simulate input change .. Something this trivial should feel like more fun to accomplish. |
I didn't think @levibuzolic's solution was working, but I had to swap import { reducer as formReducer } from 'redux-form'
...
let commentCreate
let form
beforeEach(() => {
commentCreate = sinon.spy()
form = mount(
- <Provider store={mockStore({ form: formReducer })}>
+ <Provider store={createStore(combineReducers({ form: formReducer }))}>
<Container commentCreate={commentCreate} />
</Provider>
).find('form')
})
it('valid and calls commentCreate', () => {
const textarea = form.find('textarea').first()
textarea.simulate('change', { target: { value: 'foo' } })
form.simulate('submit')
expect(commentCreate.callCount).to.equal(1)
})
it('invalid so does not call commentCreate', () => {
form.simulate('submit')
expect(commentCreate.callCount).to.equal(0)
}) I used Redux-Form Test to troubleshoot. |
not working for me..
http://stackoverflow.com/questions/41732318/test-setting-text-value-with-react-and-enzyme |
Indeed; in v3, all sub-wrappers must be re-found from the root to see updates. |
I managed to simulate setting a value for textarea.
|
The solution I found for having a input with
is to use
|
This is working for me to test filling out the password field on a login form const passwordInput = component.find('input').at(1);
passwordInput.instance().value = 'y';
passwordInput.simulate('change');
component.find('form').first().simulate('submit'); |
this works for me: wrapper.find('#input-value').simulate('change', { target: { '10' } }) then, to check if the value was changed: expect(wrapper.find('#input-value').props().value).toEqual('10') |
It seems like a number of people have working solutions. @jackfranklin happy to reopen if this is still an issue for you on latest enzyme. |
@jsonmaur, how did you clear the mock on the afterEach / afterAll block? |
@yuritoledo I get @timbroder, your version works however I'm unable to |
@CWSites Sorry, my bad. The correct is: |
here is my code..
I have update my DOM with |
@anupammaurya can you create a codesandbox ? |
@CWSites I haven't tried expecting before changing it. The value at that point is a known assumption from the test setup |
@timbroder what I'm running into is that it only updates the value of
These are the different ways that I've tried to update the input, but none of them pass the value to the function which is called onChange.
|
I currently have tested this approach and works flawlessly |
I tried this out and typescript would complain about value not existing in instance() const attribute = document.createAttribute("value");
attribute.value = "[email protected]";
const emailInput = wrapper.find('input').at(0);
emailInput.getDOMNode().setAttributeNode(attribute);
emailInput.simulate('change');
wrapper.update(); |
This is what worked for me for simulating text entry into a textarea and testing for a secondary component that was loaded after text entry. RTFM simulate. Also note that simulate is on the wrapper (the result of
|
For anyone who failed to get the value right with Here is what I did and it is working const SomeInputComponent = ({onChangeCallback}) => {
const inputRef = useRef(null);
const handleOnChange = useCallback(()=>{
onChangeCallback(inputRef.current.value)
}, [])
return <div><input ref={inputRef} onChange={handleOnChange} /></div>
} it('Should change the value ', () => {
let value = '';
const wrapper = mount(
<SomeInputComponent
onChangeCallback={res => {
value = res;
}}
/>,
);
const $input = wrapper.find('input');
$input.at(0).instance().value = 'Changed';
$input.simulate('change');
expect(value).toEqual('Changed');
}); |
This is the only thing that seems to work at all with a password input type -- thank you! |
This is the only thing that worked for me on a controlled input. Thanks! |
I've been using this too, but I want to ask that what if I'm passing data in the onChange like this
Now, I'm confused about how can I pass data in the onChange on the test? |
@Puneet1796 that depends on where |
@ljharb How does it matter?, According to the documentation simulate on mounted components can't let data pass through it, now here what enzyme fails to test the onChange. |
@Puneet1796 i'm not sure what you mean - it matters because the way the JS language works prevents any interception of |
@ljharb I have an array of values and I'm iterating over each value and renders a component everytime, say list item, but I want to pass index in the change so that I'll know which list item is updated. But in the case of testing, I found out that there's no way mentioned in the documentation to pass the value in |
Based on the code you passed, it's impossible via any means. |
What i had to do to update the value of a form field that was only referenced with a ref. const inputField = wrapper.find('input[type="text"]');
inputField.getDOMNode().value = "my updated value";
inputField.simulate('whatever you are listening for'); |
this one actually worked for me; All other solutions in this thread gave different errors of the |
I have tried all the methods mentioned above but none of them worked for me. |
To set the value of an input currently I have to do:
It would be really nice in my opinion if I could instead do something akin to jQuery:
What are your thoughts on that? I'd be happy to attempt to work on the PR :)
The text was updated successfully, but these errors were encountered: