Test-Driven Development in frontend applications

In 2024, I wrote brefly about the differences in tdd for backend and frontend development. Now, I want to share a more detailed account of my experience implementing Test-Driven Development (TDD) in a recent frontend project. This post will walk you through the process, the challenges I faced, and the lessons learned along the way. Whether you’re new to TDD or looking to refine your approach, I hope this will provide valuable insights into how TDD can enhance your frontend development workflow.

Introduction

TDD as a practice does not differentiate client-side applications from server-side applications, writing test first is a practice that goes beyond that. Investigating the literature on that topic shows that the first books that came about were in Java, which is also known as a server-side language that happens to support some of the client-side features. However, as TDD became ubiquitous to other stacks the differences between server and client started to become more apparent.

For some, the idea of testing client-side applications is a waste of time and there is no need to invest time on it as the user interface that is built is just an “implementation detail”. I would attribute such misunderstanding to one of the books that is a reference in software architecture: Clean Architecture by Uncle Bob. In the book, the UI is treated as something not important and doesn´t deserve attention. The book was released in 2017 and since then the industry has evolved the reality is that the client-side applications started to have a set of tools to write tests first just for them.

QUnit for example is the testing framework for jQuery one of the libraries most popular to date. jest/mocha for more recent applications and jasmine for the angular ecosystem. ReactJs and testing-library became the power duet for writing testable code in the front end. VueJs and Angular also have a representative ecosystem.

It is also necessary to understand that server-side applications have different roles and responsibilities in comparison with client-side applications. The client side is often interested in responsiveness, browser APIs, async state and avoiding freezing, whereas server-side applications are interested in the interaction with the storage system, HTTP requests, queues and queues.

Global state

Like server-side applications, client-side applications also have a global state. The global state is often managed by libraries such as Redux, MobX, or even the Context API in React. This global state can be tested using unit tests, integration tests, and end-to-end tests. The key is to ensure that the global state is predictable and maintainable, which is where TDD comes into play.

I intend to prefer refactoring over specilized test in regards to global state. The reason is that the global state is often a reflection of the application’s business logic, and writing tests for it can lead to a more complex and fragile codebase. Instead, I prefer to focus on writing tests for the individual components that interact with the global state.

An example of this is the json-tool source code, which is a simple application that allows users to convert JSON data to various formats. The application uses React Context to manage the global state, and the tests are focused on the functionality at hand, not the implementation detail.

An example of that is the test setup, that is done building all the contexts needed for the application to run, at this stage, there is no special initialization for the global state, just the contexts that are needed for the application to run. In other words, the focus is on the functionality and the feedback is as close as possible to what the user would see.

Mocks

Project Overview

  • Briefly Describe the Project: What was the app? (e.g., a single-page application, a React component library, etc.). What were its core features?
  • Why TDD Was Chosen: “We decided to try TDD to address [specific problems – e.g., maintainability, bug reduction, improved code quality].”
  • Tech Stack: (Quickly list the key technologies – e.g., React, TypeScript, Jest, etc.)

III. The TDD Process – Walkthrough (Approx. 200-250 words)

  • Cycle 1: Write a Test: Show an example of a test you wrote first. Illustrate the test’s purpose clearly. “This test ensures that the component renders correctly.” (Include the test code).
  • Cycle 2: Write the Minimal Code: Explain the rationale behind the minimal code you wrote to pass the test. “We focused on getting the bare minimum to work.” (Include the code).
  • Cycle 3: Refactor: (Optional – briefly explain how you refactored the code while keeping the tests passing). “We refactored to improve readability but only after rigorously testing.”

IV. Challenges & Lessons Learned (Approx. 150-200 words)

  • Common Challenges: Share your struggles – e.g., “Initially, writing the first tests felt counterintuitive.” or “It was challenging to write tests that accurately reflected the desired behavior.”
  • Key Lessons: What did you learn? (e.g., “TDD forces you to think about requirements,” “It’s okay to start small,” “Don’t be afraid to refactor.”)
  • Specific takeaway: “One of the biggest takeaways was focusing on the intent of the code, not just the implementation.”

V. Conclusion (Approx. 50-75 words)

  • Recap: Briefly summarize the benefits of TDD.
  • Call to Action: Encourage readers to try TDD themselves – “Give TDD a shot – you might be surprised!” or “Resources to get started…” (Link to relevant documentation, tutorials, etc.)

You also might like

About this post

This post was written by a human with AI assistance, which was used for research, outlining, editing and code suggestions. Claims, code samples and references were reviewed before publication, and the sources are cited so you can judge them yourself.