Vibe coding with AI course · Module 11: Spotify Clone

Testing - Jest & React Testing Library

1 min read
In this lesson2

Writing tests for React components.

Setup

npm install --save-dev @testing-library/react @testing-library/jest-dom jest

Component Tests

// Button.tsx
export function Button({ onClick, children }: {
  onClick: () => void;
  children: React.ReactNode
}) {
  return (
    <button onClick={onClick} className="btn">
      {children}
    </button>
  );
}

// Button.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from './Button';

describe('Button', () => {
  it('renders children', () => {
    render(<Button onClick={() => {}}>Click me</Button>);
    expect(screen.getByText('Click me')).toBeInTheDocument();
  });

  it('calls onClick when clicked', () => {
    const handleClick = jest.fn();
    render(<Button onClick={handleClick}>Click</Button>);

    fireEvent.click(screen.getByText('Click'));
    expect(handleClick).toHaveBeenCalledTimes(1);
  });
});

See you soon!

Code for this lesson: App.tsx
'use client';

import { useState } from 'react';

export default function CreatePlaylistModal() {
  const [isOpen, setIsOpen] = useState(true);
  const [name, setName] = useState('');
  const [description, setDescription] = useState('');
  const [isPublic, setIsPublic] = useState(true);

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (name.trim()) {
      alert(`Created playlist: ${name}`);
      setIsOpen(false);
    }
  };

  if (!isOpen) {
    return (
      <div className="min-h-screen bg-black text-white flex items-center justify-center">
        <button
          onClick={() => setIsOpen(true)}
          className="px-6 py-3 bg-green-500 text-black font-semibold rounded-full hover:bg-green-400"
        >
          Create Playlist
        </button>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-black/75 flex items-center justify-center p-4">
      <div className="bg-gray-900 rounded-lg max-w-md w-full p-6 text-white">
        <h2 className="text-2xl font-bold mb-6">Create Playlist</h2>

        <form onSubmit={handleSubmit}>
          <div className="mb-4">
            <label className="block text-sm font-semibold mb-2">
              Name
            </label>
            <input
              type="text"
              value={name}
              onChange={(e) => setName(e.target.value)}
              placeholder="My Playlist"
              className="w-full bg-gray-800 text-white px-4 py-3 rounded outline-none focus:ring-2 focus:ring-green-500"
              autoFocus
            />
          </div>

          <div className="mb-4">
            <label className="block text-sm font-semibold mb-2">
              Description (Optional)
            </label>
            <textarea
              value={description}
              onChange={(e) => setDescription(e.target.value)}
              placeholder="Add a description..."
              className="w-full bg-gray-800 text-white px-4 py-3 rounded outline-none resize-none focus:ring-2 focus:ring-green-500"
              rows={3}
            />
          </div>

          <div className="mb-6">
            <label className="flex items-center gap-3 cursor-pointer">
              <input
                type="checkbox"
                checked={isPublic}
                onChange={(e) => setIsPublic(e.target.checked)}
                className="w-5 h-5"
              />
              <span>Make playlist public</span>
            </label>
          </div>

          <div className="flex gap-3">
            <button
              type="button"
              onClick={() => setIsOpen(false)}
              className="flex-1 py-3 border border-gray-700 rounded-full font-semibold hover:border-white"
            >
              Cancel
            </button>
            <button
              type="submit"
              disabled={!name.trim()}
              className="flex-1 py-3 bg-green-500 rounded-full text-black font-semibold hover:bg-green-400 disabled:bg-gray-700 disabled:text-gray-500"
            >
              Create
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. Which libraries do we install to test React components?

  2. 2. What is fireEvent.click() used for in a test?

Hands-on tasks in the game

  • Click in order

    Click the elements to build the testing utilities import:

  • Vertical ordering

    Order the steps of a test that checks a button click:

Useful articles