You don't have access to this class

Keep learning! Join and start boosting your career

Aprovecha el precio especial y haz tu profesi贸n a prueba de IA

Antes: $249

Currency
$209
Suscr铆bete

Termina en:

0 D铆as
21 Hrs
53 Min
21 Seg
Curso de React Testing Library

Curso de React Testing Library

Wilmer Javier Garzon Cabezas

Wilmer Javier Garzon Cabezas

Desarrollo Guiado por Pruebas (TDD) en React

6/20
Resources

What is Test Driven Development (TDD)?

Test Driven Development (TDD) is a software development methodology that changes the traditional order of component creation. Instead of starting with the development of software components, TDD begins with writing tests. This strategy ensures that when it comes time to refactor, there are tests in place to ensure that modifications do not introduce errors.

How does the TDD cycle work?

The Test Driven Development cycle goes through three clear stages:

  1. Red: In this step, the initial tests are created. Since the component does not yet exist, these tests must fail.
  2. Green: The component is developed to pass the previously configured tests.
  3. Refactor: This phase allows the code to be improved and optimized with the assurance that the tests will protect the system against unexpected errors.

It is important to note that this methodology shines in well-defined software, where the use cases are clear. It is not as effective in software in experimental or constantly changing phases.

How to implement TDD?

Creating initial tests

  1. Create a folder for the component, for example, counter.

  2. Inside, start a test file, counter.test.tsx.

  3. Set up the key vitest imports, such as describe, it and expect.

  4. Define the main test cases:

    • The counter should initially display the value "0".
    • When a button is clicked, the counter should increment to "1".

Here the rendering of the component is simulated (although it does not exist yet) and the expected behavior is ensured by testing library/react.

import { describe, it, expect } from "vitest";import { render, screen, fireEvent } from "@testing-library/react";import { Counter } from './Counter';
describe("Counter", () => { it("should show initial value", () => { render(<Counter />); const counter = screen.getByText("Counter: 0"); expect(counter).toBeInTheDocument(); });  
 it("should increment counter", async () => { render(<Counter />); const button = screen.getByText("Increment"); fireEvent.click(button); const counter = screen.getByText("Counter: 1"); expect(counter).toBeInTheDocument(); });});

Component development

  1. Creates or modifies the counter.tsx component.
  2. Defines its initial state and expected behavior:
import { useState } from 'react';
export const Counter = () => { const [counter, setCounter] = useState(0);  
 const handleIncrement = () => setCounter(counter + 1);
 return ( <div>
        <p>Counter: {counter}</p>
        <buttononClick={handleIncrement}>Increment</button>
     </div> );};

Refactoring with confidence

Once the tests pass successfully, you can refactor the code with confidence that the tests will protect your system against introducing bugs.

Why implement TDD?

  • Code Quality: Provides a strong testing foundation that allows changes without fear of breaking existing functionality.
  • Fast Feedback: Reports immediately if a change introduces a bug.
  • Efficient Design: Encourages clear and concise test writing, resulting in cleaner, more understandable code.

Proposed Challenge

Create a new component using TDD. Some ideas are:

  • An "todo list" that displays items when they are added.
  • A timer that switches to the "paused" state when stopped.

Constant practice of TDD not only strengthens your skills, but prepares you to create robust and secure systems. Come share your achievements!

Contributions 4

Questions 0

Sort by:

Want to see more contributions, questions and answers from the community?

Usando TDD lo cree as铆: 1. src/TodoList/TodoList.test.tsx ```js import { describe, it, expect } from 'vitest'; import { render, screen, fireEvent, act } from '@testing-library/react'; import TodoList from './TodoList'; describe('<TodoList />', () => { it('should display input to enter Todo activity ', () => { render(<TodoList />); const input = screen.getByPlaceholderText('Enter Todo Activity'); expect(input).toBeInTheDocument(); }); it('should display button to add Todo', () => { render(<TodoList />); const button = screen.getByText('Add Todo'); expect(button).toBeInTheDocument(); }); it('should display ul empty at the begin', () => { render(<TodoList />); const ul = screen.getByRole('list'); expect(ul).toBeEmptyDOMElement(); }); it('should add todo to the list', async () => { render(<TodoList />); const input = screen.getByPlaceholderText('Enter Todo Activity'); fireEvent.change(input, { target: { value: 'Learn Vitest' } }); const button = screen.getByText('Add Todo'); await act(async () => { fireEvent.click(button); }); const ul = screen.getByRole('list'); expect(ul).not.toBeEmptyDOMElement(); expect(ul).toContainHTML('
  • Learn Vitest
  • '); expect(screen.getByText('Learn Vitest')).toBeInTheDocument(); }); }); ```import { describe, it, expect } from 'vitest';import { render, screen, fireEvent, act } from '@testing-library/react';import TodoList from './TodoList';describe('\<TodoList />', () => { it('should display input to enter Todo activity ', () => { render(*\<TodoList* */>*); const input = screen.getByPlaceholderText('Enter Todo Activity'); expect(input).toBeInTheDocument(); }); it('should display button to add Todo', () => { render(*\<TodoList* */>*); const button = screen.getByText('Add Todo'); expect(button).toBeInTheDocument(); }); it('should display ul empty at the begin', () => { render(*\<TodoList* */>*); const ul = screen.getByRole('list'); expect(ul).toBeEmptyDOMElement(); }); it('should add todo to the list', async () => { render(*\<TodoList* */>*); const input = screen.getByPlaceholderText('Enter Todo Activity'); fireEvent.change(input, { target: { value: 'Learn Vitest' } }); const button = screen.getByText('Add Todo'); await act(async () => { fireEvent.click(button); }); const ul = screen.getByRole('list'); expect(ul).not.toBeEmptyDOMElement(); expect(ul).toContainHTML('\
  • Learn Vitest\
  • '); expect(screen.getByText('Learn Vitest')).toBeInTheDocument(); }); }); 1. src/TodoList/TodoList.tsx ```js import React, {useState} from 'react'; const TodoList = () => { const [todoValue, setTodoValue] = useState(""); const [list, setList] = useState<string[]>([]); const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { setTodoValue(e.target.value); } const addTodo = () => { setList([...list, "Learn Vitest"]); } return (
    <input type="text" placeholder="Enter Todo Activity" value={todoValue} onChange={handleChange}/> <button onClick={addTodo}>Add Todo</button>
      { list.map((item, index) => (
    • {item}
    • )) }
    ); } export default TodoList; ```import React, {useState} from 'react'; const TodoList = () => { const \[todoValue, setTodoValue] = useState(""); const \[list, setList] = useState\<string\[]>(\[]); const handleChange = (e: React.ChangeEvent\<HTMLInputElement>) => { setTodoValue(e.target.value); } const addTodo = () => { setList(\[...list, "Learn Vitest"]); } return ( *<*div*>* *<*input type="text" placeholder="Enter Todo Activity" value={todoValue} onChange={handleChange}*/>* *<*button onClick={addTodo}*>*Add Todo*\</*button*>* *<*ul*>* { list.map((item, index) => ( *<*li key={index}*>*{item}*\</*li*>* )) } *\</*ul*>* *\</*div*>* );} export default TodoList;
    Los comportamientos no deterministas se refieren a situaciones en las que el resultado de una operaci贸n puede variar en diferentes ejecuciones, incluso con los mismos datos de entrada. Esto puede ocurrir, por ejemplo, en sistemas que dependen de la fecha y hora actual o en conexiones a servicios externos que pueden fallar o comportarse de manera inconsistente. Estos comportamientos son problem谩ticos en testing, ya que pueden llevar a resultados inesperados. Por eso, se recomienda usar mocks para simular estos comportamientos y garantizar la fiabilidad de las pruebas.
    Otra refactorizaci贸n que podr铆a ser en el componente <u>Contador </u>es reutilizar el **Button** que se cre贸 en la `clase 4` 馃槑 ![](https://static.platzi.com/media/user_upload/image-d269e2da-54da-4874-a1ea-df8c9244e461.jpg)
    Relacionado al setState, siempre que se tenga en cuenta el estado original para sumarle, restarle, etc, es buena pr谩ctica hacerlo de esta manera `setContador((prev) => prev + 1)}` De lo contrario, podr铆a dependiendo de la funci贸n y c贸mo esta sea llamada, generar errores en el resultado final y no dar el resultado esperado Por ejemplo el siguiente bloque de c贸digo, escrito como est谩 en el curso, se esperar铆a que sumara 3 veces pero solo suma 1 vez ya que en el momento en que la funci贸n es llamada el valor del estado es 0 y nunca se suma `const handleClick = () => {` ` setContador(contador + 1);` ` setContador(contador + 1);` ` setContador(contador + 1);` `};`