Full Stack Development

Introduction to Testing



by Tomas Trescak t.trescak@westernsydney.edu.au

Testing

/

Introduction

  • Testing saves the day
  • Three heroes: Unit, Integration, E2E
  • Fits into CI/CD

Testing

/

Unit Testing - Tiny Titans

  • Tests one piece in isolation
  • Example: Formatting a post’s date
    // utils/date.ts
export function formatDate(date: Date): string {
  return date.toLocaleDateString("en-US", { 
    month: "long", day: "numeric", year: "numeric" 
  });
}

// tests/date.test.ts
import { describe, it, expect } from "vitest";
import { formatDate } from "../utils/date";

describe("formatDate", () => {
  it("formats a valid date", () => {
    const date = new Date("2025-04-07");
    expect(formatDate(date)).toBe("April 7, 2025");
  });
});
  

Testing

/

Integration Testing - Team Work

  • Tests pieces together
  • Example: Post list with API
    // components/PostList.tsx
import { useEffect, useState } from "react";
import { formatDate } from "../utils/date";

export function PostList() {
  const [posts, setPosts] = useState<{ title: string; date: Date }[]>([]);
  useEffect(() => {
    fetch("/api/posts")
      .then((res) => res.json())
      .then((data) => setPosts(data.map((p: any) => ({ ...p, date: new Date(p.date) }))));
  }, []);
  return (
    <div>{posts.map((p) => <div key={p.title}>{p.title} - {formatDate(p.date)}</div>)}</div>
  );
}

// tests/PostList.test.tsx
import { render, screen } from "@testing-library/react";
import { describe, it, expect, vi } from "vitest";
import { PostList } from "../components/PostList";

describe("PostList", () => {
  it("fetches and renders posts", async () => {
    vi.spyOn(global, "fetch").mockResolvedValue({
      json: () => Promise.resolve([{ title: "Test Post", date: "2025-04-07" }]),
    } as any);
    render(<PostList />);
    expect(
      await screen.findByText("Test Post - April 7, 2025")
    ).toBeDefined();
  });
});
  

Testing

/

E2E Testing - Full Adventure

  • Tests the whole app
  • Example: Browsing and adding postsI
    // tests/e2e/blog.spec.ts
import { test, expect } from "@playwright/test";

test("user views and admin adds post", async ({ page }) => {
  await page.goto("http://localhost:3000");
  await expect(page.getByText("Test Post")).toBeVisible();

  await page.goto("http://localhost:3000/admin");
  await page.fill("#title", "New Post");
  await page.fill("#date", "2025-04-08");
  await page.click("button[type='submit']");
  await page.goto("http://localhost:3000");
  await expect(page.getByText("New Post")).toBeVisible();
});
  

Testing

/

Which one?

Test Type Description Speed CI/CD When to Execute
Unit Tests one piece in isolation (e.g., formatDate ) Lightning fast (ms) Every commit
Integration Tests multiple pieces together (e.g., fetch + render) Moderate (100s of ms) Pull requests
End-to-End (E2E) Tests the full app like a user (e.g., browsing posts) Slow (seconds) Before deployment

Testing

/

Case Study

  • Problem: Posts don’t show
  • Check Unit Tests ✅
  • Test fetch + render ✅
  • E2E Fails ❌