Day Five
TDD-Driven Development: The Reels Module
Section titled “TDD-Driven Development: The Reels Module”Welcome to Day Five! Today, we will build the backend for our Reels feature using the same Test-Driven Development (TDD) discipline we learned on Day Two. This will solidify the Red-Green-Refactor pattern. We will also perform a “TDD-safe refactor” to add a feature we missed, demonstrating how tests provide a safety net when changing existing code.
Backend Milestones (Repo 1: insta-clone-fastify-backend) ✅
Section titled “Backend Milestones (Repo 1: insta-clone-fastify-backend) ✅”Our first task is to add a missing endpoint for posts, and we will do it using TDD principles to guide our refactoring.
Red Phase: Write a Failing Test for Reels
Section titled “Red Phase: Write a Failing Test for Reels”We’ll now build the reels module, starting with a failing test for the GET /reels/grid endpoint.
-
Create the
reelstest fileTerminal window mkdir -p src/modules/reelstouch src/modules/reels/reels.test.ts -
Write the integration test This test describes what we want: an endpoint that returns an array of reels and a
200 OKstatus.src/modules/reels/reels.test.ts import Fastify from "fastify";import { reelsRoutes } from "./reels.routes";describe("GET /reels/grid", () => {it("should return a list of reels with a 200 status code", async () => {const app = Fastify();const mockReels = [{id: 1,video_url: "http://example.com/video1.mp4",thumbnail_url: "http://example.com/thumb1.png",caption: "Reel 1",views: 100,},{id: 2,video_url: "http://example.com/video2.mp4",thumbnail_url: "http://example.com/thumb2.png",caption: "Reel 2",views: 200,},];// To satisfy TypeScript, our mock must match the full shape of the// 'transactions' dependency, including all methods on 'posts'.app.decorate("transactions", {posts: {create: jest.fn(),getAll: jest.fn(),getById: jest.fn(),},reels: {getAll: jest.fn().mockReturnValue(mockReels),},});app.register(reelsRoutes);const response = await app.inject({method: "GET",url: "/reels/grid",});expect(response.statusCode).toBe(200);expect(JSON.parse(response.payload)).toEqual(mockReels);});}); -
Run the test and watch it fail
Terminal window npm testIt will fail because
reels.routes.tsdoesn’t exist. This is our Red light. Perfect.
Green Phase: Make the Test Pass
Section titled “Green Phase: Make the Test Pass”Now, we write the minimum amount of code required to make our new test pass. This includes creating the types, updating the database, implementing the service and routes, and loading the module in the server.
-
Create
reels.types.ts -
Update
database.plugin.tsanddatabase.transactions.ts -
Implement
reels.service.tsandreels.routes.ts -
Load the Reels Module in
server.ts -
Run the test again
Terminal window npm testWith all the pieces in place, the
reels.test.tssuite should now pass. This is our Green light.
Refactor Phase: Make It Real
Section titled “Refactor Phase: Make It Real”Our test is green, and the feature is “functionally” complete—it gets data from the database to the browser. But it doesn’t look or feel like Instagram yet. This is the Refactor phase.
The goal as we go is to take the working-but-basic implementation and polish it into a pixel-perfect clone of the real Instagram..
TDD gives us the confidence to make these UI and functionality changes, knowing that our tests will immediately tell us if we’ve broken the core data-fetching logic.
This is where you show what you’ve learned and use the patterns we have been building to create new features and polish!
Frontend Milestones (Repo 2: insta-clone-react-frontend) ✅
Section titled “Frontend Milestones (Repo 2: insta-clone-react-frontend) ✅”- Create the Reels Schema (
app/schemas/reel.schema.ts) - Create the Reel Grid Item Component (
app/components/ReelGridItem.tsx) - Create the Reels Grid Route (
app/routes/profile.reels.grid.tsx)
Verification
Section titled “Verification”- Restart both your backend and frontend servers to apply all changes.
- Navigate to
http://localhost:5173/. You should be redirected to the posts grid at/profile/posts/grid. - Click the “Reels” tab in the sub-navigation.
- The URL should change to
/profile/reels/grid, and you should now see the grid of reel thumbnails fetched from your backend.
Conclusions
Section titled “Conclusions”Look at how quickly you added a new feature! This is the direct benefit of the architecture you built on Day Four.
- Leveraging Existing Layouts: You didn’t need to create any new navigation or layout components. You simply created a new route file (
profile.reels.grid.tsx), and it was automatically rendered within the correct context by the parentprofile.tsxlayout. This is the power of nested routing. - A Predictable, Repeatable Pattern: The process for adding a new data-driven page is now crystal clear:
- Create the backend module (types, db, service, routes).
- Create a Zod schema on the frontend.
- Build the small, reusable UI components.
- Assemble them in a new route file with a
loader. This pattern makes development fast and predictable.
- The Importance of Seeding: Manually creating data via
curlis fine for one-off tests, but for developing a UI, having a reliable set of seed data that loads automatically saves a tremendous amount of time and effort. - Continuous Improvement: The “Housekeeping” task at the beginning shows that development is an iterative process. We often need to go back and improve or fix previous work as new requirements come to light.