TDD for Frontend Engineers (Test Driven Development)

TDD for Frontend Engineers (Test Driven Development)

Posted 2023-05-14

Test-Driven Development (TDD) for Frontend Engineers: An In-depth Guide

Test-Driven Development - also known as TDD - is a methodology to write (failing) tests before your write the code for the feature you're developing.

At its core, this is all TDD involves

  • Write a test that fails, for the smallest feature possible (e.g. 'when button is clicked, a counter appears')
  • Write the production code so the test passes. Don't worry about code quality.
  • Now you have passing tests, refactor the code to be nicer quality.
  • Then repeat, with the next smallest feature

I remember trying it years ago, and deciding that it resulted in messy code and horrible tests. I think I just missed the core part of TDD.

TDD isn't about getting test coverage.

TDD is about writing your code in a way that makes it easy to test. And if it is easy to test, it is much more maintainable.

Of course, it does help that as you build features with TDD they almost always have good code coverage. You also tend to come up with more edge cases to account for, as you're writing the failing tests first.methodology

In a non TDD workflow (write code, then write tests) it is much easier to fall into pattern of mostly testing the happy path. But what if you click twice? What if you use a keyboard to trigger the on-click on the button? etc

Quick note about TDD & Frontend applications

In this blog post I'm going to give examples of tools to use with React. But TDD in frontend applies to any frontend framework - such as VueJS, Angular, Svelte, etc. I'm picking mostly on React as it is by far the most popular.

Red/Green/Refactor

As mentioned, the core part of TDD is to write a failing test, write the smallest amount of code so it passes, then refactor.

This is known as red/green/refactor.

Setting up your local dev environment for best DX for TDD

You really want to aim for fast running unit/integration tests (every company has their own definition of what these mean).

Ideally with a reliable test runner. I always use jest. I know some love mocha but it seems quite rare now in 2023 to see new projects use mocha.

E2E (end-to-end) tests which use Cypress or Playwright can be useful, but they tend to be quite slow. The slower your feedback while doing TDD, the worse experience you will have writing TDD code.

Unit vs Integration vs E2E

Unit tests (frontend)

Unit tests are testing a single 'unit' of code. In a frontend application this almost always refers to

  • a single JSX React component
  • or a single function (running some business logic)

For component tests in a React application

Integration tests (frontend)

Integration tests are testing that several 'units' of code work together. In a frontend application this normally means a larger component built up of several other components. An example would be:

  • a multi step wizard checkout flow
  • a NextJS 'page', which loads different components within it

E2E (End to end) tests

E2E tend to test the entire application, as a real user.

They will tend to use tools such as Cypress or Playwright. They run a real version of a browser (often Chrome, and often 'headless') and interact like a real user.

They are slow, harder to maintain. But you get a lot of confidence that your application is really working like it should. Even more so if you do real API calls.

Best practices when doing TDD

Treat your test code (after refactoring/cleaning up) to the same level of quality as production code.

I think you can sometimes get away with more duplication (makes tests easier to read), but generally test code should be as good quality as your main application code.

But make good use of utility functions and fixtures for tests

Create helper functions to generate mock data, or do common actions. For example if you have a component that pops up a modal, you probably want to interact with elements inside the modal. Instead of writing the code to trigger the modal, it could be useful to have a helper function to trigger this common action.

Subscribe to my
Full Stack Typescript Developer
newsletter

If you enjoyed my content and want more Full Stack Typescript content, then enter your email below.

I send a few links every couple of weeks, that I personally found useful from around the web.

Focusing on Testing, Typescript, NextJS, and also
engineering soft skills posts.

Welcome to my site and blog - Code Driven Development.

This is where I dive topics relating to modern software engineering - with a focus on Typescript, React, web accessibility and Agile practices

I pick topics that I think are interesting, that I think others might find interesting, or write up guides that I wish I had read before learning a topic.