1

My test fail because I don't know what to declare in the onChange value,

describe("App", function() {
  const wrapper = shallow(<App />);

  it("should have an input", function() {
    expect(
      wrapper.contains(<input type="text" onChange={null} />)
    ).toBeTruthy();
  });
});

I just have this in my component

<input type="text" onChange={this.changeInput} />
skyboyer
  • 22,209
  • 7
  • 57
  • 64
Hoknimo
  • 533
  • 2
  • 6
  • 15
  • You can try onChange={() => jest.fn()} – Ana Liza Pandac Dec 12 '18 at 13:32
  • how about really straightforward `expect(wrapper).toMatchSnapshot()`? it checked much more attributes/components you can hard-code in your `expect(wrapper.find(...)).to` – skyboyer Dec 12 '18 at 13:37
  • @skyboyer I try to convince myself even that make sense, test ui is strange to me, because once ui is there, means it will be there, I'm ok to test functionality but test ui existence seems too much work. – Hoknimo Dec 12 '18 at 13:42
  • that's why you definitely should take a look into [testing with snapshots](https://jestjs.io/docs/en/snapshot-testing) :) – skyboyer Dec 12 '18 at 14:20

3 Answers3

1

What I would do here is to firstly check that the input element exists:

it('verifies that an input element is rendered', () => {
  expect(wrapper.exists('input')).toBeTruthy();
});

Then, with that verified, separately verify the onChange function exists. I'm not someone who supports having multiple verifications in a single it statement simply because if any of the expect statements trigger a failure, then all expect statements below that are never carried out. So I'd use a separate it as follows:

it('verifies that an onChange function is set`, () => {
  expect(typeof wrapper.find('input').prop('onChange')).toBe('function');
});

Another option is to set a mock function for your onChange prop and verify that it's invoked correctly as follows:

const testOnChange = jest.fn();
const wrapper = mount(<App onChange={testOnChange} />);

it('verifies that the onChange function is invoked', () => {
  wrapper.find('input').prop('onChange')();
  expect(testOnChange.mock.calls).toHaveLength(1);
});
AJC24
  • 3,280
  • 2
  • 19
  • 30
  • I see. Good you seperate it out, but this test `verifies that an "onChange" function is set ` is needed? I usually only test if it's called, why that's the point of testing thing that will 100% work? – Hoknimo Dec 12 '18 at 13:47
  • Well this was just an example of one way you can verify that `onChange` has, indeed, been passed down. The OP could also test that it's invoked using a mocked function. That is a better option. I've updated my answer to include that. – AJC24 Dec 12 '18 at 14:02
  • any reason not using toHaveBeenCalled? – Hoknimo Dec 12 '18 at 14:05
  • 1
    None whatsoever. You can use either one. – AJC24 Dec 12 '18 at 14:07
  • another question, why not use stimulate('onChange')? – Hoknimo Dec 12 '18 at 14:09
  • See this comment - it's not recommended to use `simulate`: https://github.com/airbnb/enzyme/issues/1081#issuecomment-323866479 – AJC24 Dec 12 '18 at 14:16
1

should have an input test shouldn't involve onChange at all. It can be tested similarly to how the reference suggests:

expect(wrapper.find('input[type="text"]')).to.have.lengthOf(1);

onChange can be tested in another test, similarly to how is shown in this question.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • what if input is wrapped by a higher order component says ``? – Hoknimo Dec 12 '18 at 13:46
  • Then you assert that there's `wrapper.find(MyInput)` and test how `MyInput` works in another test. That's proper unit testing strategy. – Estus Flask Dec 12 '18 at 14:40
  • what if MyInput is just a stateless component, do we even need to test those? – Hoknimo Dec 12 '18 at 15:44
  • Yes. It can be seen as a unit, and *unit* testing implies that units are tested one by one in isolation. – Estus Flask Dec 12 '18 at 15:49
  • Do you do that personally? – Hoknimo Dec 12 '18 at 15:50
  • Yes. That's how unit testing is done. This approach isn't specific to React, it would be the same for any kind of components. – Estus Flask Dec 12 '18 at 15:56
  • isn't it tedious to do so? write so much code just to make sure the ui is there, isn't it easier to assert it with eyes? – Hoknimo Dec 12 '18 at 16:00
  • 1
    *Automated* tests are intended to replace human eyes with machine work. Writing unit tests is supposed to be tedious. It saves time on the large scale when you're bashing your head for hours trying to figure out why tests fail and debugging them - that's when this becomes really tedious. The more detailed unit tests are, the more efficient troubleshooting is. I'd suggest to read more on unit tests and how they differ from other kinds of tests. – Estus Flask Dec 12 '18 at 16:10
  • I know what it is but what if requirement change often in an organization? – Hoknimo Dec 13 '18 at 02:10
  • 1
    @Hoknimo Then tests are fixed often to pass. It's much easier to fix red test that should be green than to fix green test that should be red. You can balance between unit and e2e tests and make unit tests less or more restrictive for specific project, but this depends on the project. – Estus Flask Dec 13 '18 at 06:56
0

you can just expect(wrapper.find('input').length).toBe(1)

not sure about syntax or function names but it's there :)

Doğancan Arabacı
  • 3,934
  • 2
  • 17
  • 25