React Hooks TDD satisfying quest

TDD (Test Driven Development) was something I wanted to try for a long time. As a solo-programmer dinosaur, I’m was used to storming at every task, looking at the visual side as a reference to the progress. Thioretecly, TDD made sense, but thinking about the self-discipline required to stop the eager rush, before each step, and write something that seems not related to the main goal, looked frustrating. Well, it appears I was wrong.

People don’t like writing tests. It feels like a waste of time for most of us. Especially front-end developers. Why bother if I can just go and check it in a browser? And TDD is even worse, why do I write tests before code, intentionally limiting myself? I would have it done three times quicker you say.

Well, you have a point there…

TDD your React components

The trigger was the post quoted above, reminding that there is some mythology worth checking. Ironically, the hardest part was to create a working environment with: parcel, React hooks & React testing library. After a half-day of nothing, followed by an intense week with no spare time. I restarted, and it came alive: so the TDD begone.

The challenge was simple: The good old ToDo list. Nothing more, nothing less. But this time on TDD. So the first test was trivial: getting the ToDo app title:

test('Get the todo title', () => {
  const {container} = render(<ToDoApp />)
  screen.getByText('TDD ToDo');
})

Looks funny, but loyal to the TDD methodology: before each line of code, I wrote a test that will be green only once I fulfill the described behavior.

Soon I got engaged in a mentally satisfying game: to achieving the next stage on a textual quest. Each step more complex than the previous one. Once in a while, asking a visual hint on the browser, but only if I really got stuck. The most satisfying level in the ToDo TDD quest, came where when I wrote a long test, and magically, it became green, without actually seeing the APP running, Just knowing that it can, and that I can trust the code, and it can.

test('Click done removes from todo list', () => {
  const data = [
    {title:'item one',done: false},
    {title:'item two', done:false},
    {title:'done item', done:true}];

  const {container} = render(<ToDoApp data={data}/>);
  expect(container.querySelectorAll('p').length).toBe(2);
  expect(screen.queryByLabelText(data[0].title)).toBeInTheDocument();
  expect(screen.queryByLabelText(data[0].title)).not.toBeChecked();

  screen.queryByLabelText(data[0].title).click();
  expect(container.querySelectorAll('p').length).toBe(1);
  expect(screen.queryByLabelText(data[0].title)).not.toBeInTheDocument();

  screen.getByLabelText('Show done').click();
  expect(container.querySelectorAll('p').length).toBe(3);
  expect(screen.queryByLabelText(data[0].title)).toBeInTheDocument();
  expect(screen.queryByLabelText(data[0].title)).toBeChecked();

  screen.queryByLabelText(data[0].title).click();
  screen.getByLabelText('Show done').click();
  expect(container.querySelectorAll('p').length).toBe(2);
  expect(screen.queryByLabelText(data[0].title)).toBeInTheDocument();
  expect(screen.queryByLabelText(data[2].title)).not.toBeInTheDocument();
});

Soon I felt all the good claims about the behavior-driven-selectors come alive: A very stable and reliable APP, built and documented step by step, without leaving (and sometimes forgetting) the side notes to the end. Moreover, I felt the confidence to rewrite the entire logic, knowing that there is a visual cue that will tell if something went wrong ion the way.

Moreover, sometimes, refactoring, and adding more elements broke some of the tests, pointing out towards code smell left behind, or weak section that needed rewriting for a stable APP.

On a side note, I felt the benefit of a behavior-driven-selector while writing the test over the screen and not the document. Getting a live example of the ability to totally rewrite the code, a and the HTML, without changing even one line of test. Something that came useful two days later, while the QA mentioned a video I sent here, recommending using QA selectors. As a response, I showed this TDD, and demonstrated the difference in checking the code, and not knowing if the screen actually works, checking only the bottom line, the parts the user actually sees, ignoring all the layers that don’t interest the end user.

Refrence: