█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/JavaScript (Standalone Deep Dive)/Testing JavaScript
45 minIntermediate

Testing JavaScript

After this lesson, you will be able to: Use Jest or Vitest for unit tests, React Testing Library for components, Playwright for end-to-end.

Testing in JS uses the same three-layer pyramid as Python. Tools are language-specific.

Prerequisites:JavaScript Tooling

Vitest — the modern default

Faster than Jest, Jest-compatible API, native ESM.

python
// math.test.ts
import { describe, it, expect } from "vitest";
import { add, divide } from "./math";
describe("add", () => {
it("sums two numbers", () => {
expect(add(2, 3)).toBe(5);
});
it.each([
[1, 1, 2],
[0, 0, 0],
[-1, 1, 0],
])("add(%i, %i) = %i", (a, b, expected) => {
expect(add(a, b)).toBe(expected);
});
it("throws on divide by zero", () => {
expect(() => divide(10, 0)).toThrow(/zero/);
});
});

React Testing Library — test behavior, not implementation

Render the component; interact like a user.

python
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { LoginForm } from "./LoginForm";
describe("<LoginForm />", () => {
it("submits with email and password", async () => {
const onSubmit = vi.fn();
const user = userEvent.setup();
render(<LoginForm onSubmit={onSubmit} />);
await user.type(screen.getByLabelText(/email/i), "[email protected]");
await user.type(screen.getByLabelText(/password/i), "pw1234");
await user.click(screen.getByRole("button", { name: /sign in/i }));
expect(onSubmit).toHaveBeenCalledWith({
email: "[email protected]",
password: "pw1234",
});
});
});

Playwright — end-to-end in real browsers

Drives a real browser; tests real user flows.

python
// e2e/login.spec.ts
import { test, expect } from "@playwright/test";
test("user can log in", async ({ page }) => {
await page.goto("/login");
await page.getByLabel("Email").fill("[email protected]");
await page.getByLabel("Password").fill("pw1234");
await page.getByRole("button", { name: "Sign in" }).click();
await expect(page).toHaveURL("/dashboard");
await expect(page.getByText("Welcome")).toBeVisible();
});
// Run: npx playwright test
// Debug: npx playwright test --debug

Common mistakes only experienced JS testers avoid

Testing implementation (state shape, method names) instead of behavior (what user sees). Brittle to refactors. Mocking everything until tests pass but app broken. Mock at boundaries only (network, DB). Coverage as the only metric. 100% coverage on trivial getters is worthless. Slow e2e suites that nobody runs. Aim for <5 min total e2e in CI.

Quick Check

Why prefer `getByRole` over `getByTestId` in React Testing Library?

Pick the philosophy.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←JavaScript Tooling
Back to JavaScript (Standalone Deep Dive)
JavaScript Security→