2
\$\begingroup\$

This is my first unit testing and also my first React project. I'm coming from an AngularJS background, but in terms of testing, this is my first try.

I spent some time reading about tests and I got even more confused than before. Some say to test only the basic functionality, so you don't overkill your code. Some say to make a solid test, so you make sure your code will not break.

I've created a component to go on the footer, where users can insert their e-mail to subscribe to a newsletter. The input should accept only a valid e-mail and show a valid/invalid class.

I don't know if my tests are okay, if I'm missing something or if I ended up "overkilling" my component with tests and its structure in general. I would really appreciate some feedback since this is my very first time testing.

newsletter.component.js

import React from "react";

export class Newsletter extends React.Component {
    constructor() {
        super();

        this.state = {
            valid:   null,
            sending: false
        }

        this.validateEmail = this.validateEmail.bind(this);
        this.submitForm    = this.submitForm.bind(this);
    }

    validateEmail() {
        const self = this;
        let emailData = this.refs.email.value;

        if ( emailData.includes('@') && emailData.indexOf('.') > -1 ) {
            if ( !self.state.valid ) {
                self.setState({
                    valid: true
                })
            }
        } else {
            if ( self.state.valid || self.state.valid === null ) {
                self.setState({
                    valid: false
                })
            }
        }
    }

    submitForm(event) {
        event.preventDefault();

        if ( !this.state.valid ) {
            return false;
        }

        this.setState({
            sending: true
        })

        // Send data to the database
    }

    render() {
        const state = this.state;
        let inputClass;

        if ( state.valid === false ) {
            inputClass = 'invalid';
        } else if ( state.valid === true ) {
            inputClass = 'valid'
        }

        return (
            <form>
                <input type="email" className={inputClass} onChange={this.validateEmail} ref="email" name="email" placeholder="E-mail" required />
                <button disabled={state.sending} onClick={this.submitForm}>Subscribe</button>
            </form>
        );
    }
}

newsletter.test.js

import React from "react";

import { mount } from "enzyme";
import toJson from "enzyme-to-json";

import { Newsletter } from "./Newsletter";

describe("Teste newsletter footer component", () => {
    it("Should render as expected", () => {
        const tree = toJson(mount(<Newsletter />));

        expect(tree).toMatchSnapshot();
    });

    describe("Input class", () => {
        let wrapper, input;

        beforeEach(function() {
            wrapper = mount(<Newsletter />);
            input = wrapper.find("input");
        })

        it("Should be empty", () => {
            expect( wrapper.find('.valid').length ).toBe(0);
            expect( wrapper.find('.invalid').length ).toBe(0);
        });

        it("Should be 'invalid'", () => {
            input.node.value = "name@email";
            input.simulate("change");

            expect( wrapper.find('.invalid').length ).toBe(1);
        });

        it("Should be 'valid'", () => {
            input.node.value = "name@email.com.br";
            input.simulate("change");

            expect( wrapper.find('.valid').length ).toBe(1);
        });
    });

    describe("Validate e-mail", () => {
        let wrapper, input;

        beforeEach(function() {
            wrapper = mount(<Newsletter />);
            input = wrapper.find("input");
        })

        it("Should be invalid", () => {
            input.node.value = "name";
            input.simulate("change");
            expect( wrapper.state().valid ).toBeFalsy();

            input.node.value = "name@email";
            input.simulate("change");
            expect( wrapper.state().valid ).toBeFalsy();
        });

        it("Should be valid", () => {
            input.node.value = "name@email.com";
            input.simulate("change");
            expect( wrapper.state().valid ).toBeTruthy();

            input.node.value = "name@email.com.br";
            input.simulate("change");
            expect( wrapper.state().valid ).toBeTruthy();
        });
    });

    describe("Submit the form", () => {
        let wrapper, input;

        beforeEach(function() {
            wrapper = mount(<Newsletter />);
            input = wrapper.find("input");
        })

        it("Should not be submiting", () => {
            input.node.value = "name@email";
            input.simulate("change");
            wrapper.find("button").simulate("click", {
                preventDefault: () => {}
            });

            expect( wrapper.state().sending ).toBeFalsy();
        });

        it("Should be submiting", () => {
            input.node.value = "name@email.com";
            input.simulate("change");
            wrapper.find("button").simulate("click", {
                preventDefault: () => {}
            });

            expect( wrapper.state().sending ).toBeTruthy();
        });
    });
});
\$\endgroup\$
1
\$\begingroup\$

The test for state.sending overlaps with the test for state.valid in the test. Since you are not resetting state.sending to false in the code, the case should not be submitting depends on the order that the tests are executed, and will fail if the order changes.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.