Miqdad
Miqdad

Reputation: 5

Enzyme: Value returns undefined when simulating onSubmit

I'm trying to simulate the way the form was submitted. So to summarize when the user types in the textarea 'field, the component must be updated, then the user presses the submit button and the component is updated again. I expect that the value filled in the textarea will be empty after the user successfully submit. But unexpectedly the returned value is undefined.

CommentBox.js

import React from 'react';

class CommentBox extends React.Component {
    state = {
        comment: ''
    }

    handleChange = event => {
        this.setState({
            comment: event.target.value
        })
    }

    handleSubmit = event => {
        event.preventDefault();
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <h4>Add a comment</h4>
                <textarea onChange={this.handleChange} value={this.state.comment} />
                <div>
                    <button>Submit Comment</button>
                </div>
            </form>
        )
    }
}

export default CommentBox;

CommentBox.text.js

import React from 'react';
import { mount } from 'enzyme';
import CommentBox from 'components/CommentBox';

let wrapped;

beforeEach(() => {
    wrapped = mount(<CommentBox />);
})

afterEach(() => {
    wrapped.unmount();
})

it('when form is submitted, text area gets emptied', () => {
    wrapped.find('textarea').simulate('change', {
        target: { value: 'new comment' }
    })

    wrapped.update();
    wrapped.find('form').simulate('submit', {
        preventDefault: () => {}
    });
    wrapped.update();

    expect(wrapped.find('textarea').prop('value')).toEqual('');
})

I expect the output will be passed but the actual output is value returns undefined so test is failed.

Upvotes: 0

Views: 357

Answers (3)

Kanak
Kanak

Reputation: 26

You may try this:

import React from 'react';

class CommentBox extends React.Component {
    //adding initVal for setting initial value in textbox
    // and playing with it until the form submits
    state = {
        comment: '',
        initVal: ''
    }

    handleChange = event => {
        //on change in textfield, updating initVal with the typed text
        this.setState({
            initVal: event.target.value
        })
    }

    handleSubmit = event => {
        //finally on submission comment is updated with entered value
        //which you may use it for further operations
        //and initVal is set back to empty '' for setting textfield value as empty 
        //field
        this.setState({
            comment: this.state.initVal
            initVal: ''
        })
        //event.preventDefault();
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <h4>Add a comment</h4>
                //changes here
                <textarea onChange={this.handleChange} value={this.state.initVal} />
                <div>
                    <button>Submit Comment</button>
                </div>
            </form>
        )
    }
}

export default CommentBox;

Upvotes: 0

Matt Carlotta
Matt Carlotta

Reputation: 19762

I don't see anything that would make the test fail... other than not including this.setState({ comment: "" }); in the handleSubmit callback.

If you utilize state, then you have to manually reset it (or if the component unmounts, then it loses state automatically). React works by manipulating a virtual DOM. Then, you utilize state to manipulate the elements within this virtual DOM. Since you're preventing a page refresh (e.preventDefault) the state persists as intended.

Working example (click the Tests tab -- next to the Browser tab -- to run the test):

Edit CommentBox Testing


components/CommentBox

import React, { Component } from "react";

class CommentBox extends Component {
  state = { comment: "" };

  handleChange = ({ target: { value } }) => {
    this.setState({ comment: value });
  };

  handleSubmit = e => {
    e.preventDefault();

    console.log("submitted comment: ", this.state.comment);

    this.setState({ comment: "" });
  };

  render = () => (
    <div className="app">
      <form onSubmit={this.handleSubmit}>
        <h4>Add a comment</h4>
        <textarea
          className="uk-textarea"
          onChange={this.handleChange}
          value={this.state.comment}
        />
        <div className="button-container">
          <button type="submit" className="uk-button uk-button-primary">
            Submit Comment
          </button>
        </div>
      </form>
    </div>
  );
}

export default CommentBox;

components/CommentBox/__tests__/CommentBox.test.js

import React from "react";
import { mount } from "enzyme";
import CommentBox from "../index";

describe("Comment Box", () => {
  let wrapper;
  beforeEach(() => {
    wrapper = mount(<CommentBox />);
  });

  afterEach(() => {
    wrapper.unmount();
  });

  it("when form is submitted, text area gets emptied", () => {
    wrapper.find("textarea").simulate("change", {
      target: { value: "new comment" }
    });

    expect(wrapper.find("textarea").prop("value")).toEqual("new comment");

    wrapper.find("form").simulate("submit", {
      preventDefault: () => {}
    });

    expect(wrapper.find("textarea").prop("value")).toEqual("");
  });
});

Upvotes: 1

Kishan Jaiswal
Kishan Jaiswal

Reputation: 664

handleChange = (e) => {
 if(e.keyCode == 13 && e.shiftKey == false) {
  e.preventDefault();
  this.myFormRef.submit();
  }
}

render() {
  return (
    <form ref={el => this.myFormRef = el}  >
            <h4>Add a comment</h4>
            <textarea onKeyDown={this.handleChange} value={this.state.comment} 
             />
            <div>
                <button type="submit">Submit Comment</button>
            </div>
        </form>

 );
}

you can do like this on enter

Upvotes: 0

Related Questions