[TDD] testing-library (integration test)



Integrating Test


unit test VS integration test


unit test


1つのコンポーネントのみをテストします.すなわち,他のコンポーネントとのインタラクションをテストするのではなく,propsをランダム値としてテストする.

integration test


integration testは、接続素子間の動作をテストします.

React Component


Todo.js, AddInput.js, TodoList.jsはこのように3つの素子を集積試験する.

Todo.js


TodoListとAddInputボタンがあります.
import React, { useState } from 'react'
import AddInput from '../AddInput/AddInput'
import Header from '../Header/Header'
import TodoList from '../TodoList/TodoList'
import "./Todo.css"

function Todo() {

    const [todos, setTodos] = useState([])

    return (
        <div className="todo">
            <Header title="Todo" />
            <AddInput 
                setTodos={setTodos}
                todos={todos}
            />
            <TodoList 
                todos={todos}
                setTodos={setTodos}
            />
        </div>
    )
}

export default Todo

AddInput.js


InputフォームとAdd Buttonがあります.
import React, { useState } from 'react'
import "./AddInput.css"
import { v4 } from "uuid"

function AddInput({
    setTodos, todos
}) {

    const [todo, setTodo] = useState("")

    const addTodo = () => {
        let updatedTodos = [
            ...todos,
            {
                id: v4(),
                task: todo,
                completed: false
            }
        ]
        setTodos(updatedTodos);
        setTodo("")
    }

    return (
        <div className="input-container">
            <input 
                className="input" 
                value={todo} 
                onChange={(e) => setTodo(e.target.value)}
                placeholder="Add a new task here..."
            />
            <button 
                className="add-btn"
                onClick={addTodo}
            >
                Add
            </button>
        </div>
    )
}

export default AddInput

TodoList.js


Todoに追加されたアイテムが表示されます.
import React from 'react'
import TodoFooter from '../TodoFooter/TodoFooter'
import "./TodoList.css"

function TodoList({
    todos, setTodos
}) {

    const updateTask = (id) => {
        let updatedTasks = todos.map((todo) => {
            if (todo.id === id) {
                todo.completed = !todo.completed;
                return todo
            } else {
                return todo
            }
        });
        setTodos(updatedTasks)
    }

    const calcNumberOfIncompletedTasks = () => {
        let count = 0;
        todos.forEach(todo => {
            if (!todo.completed) count++
        })
        return count
    }

    return (
        <div className="todolist-container">
            <div className="todos-container">
                <div>
                    {
                        todos.map((todo, index) => (
                            <div
                                className={`todo-item ${todo.completed && "todo-item-active"}`}
                                onClick={() => updateTask(todo.id)}
                                data-testid="todo-item"
                                key={index}
                            >
                                {todo.task}
                            </div>
                        ))
                    }
                </div>
            </div>
            <div>
                <TodoFooter
                    numberOfIncompleteTasks={calcNumberOfIncompletedTasks()}
                />
            </div>
        </div>
    )
}

export default TodoList

Test Code


AddInput.jsに入力を入力し、Addボタンを使用してアイテムを追加します.追加したアイテムがTodoListに表示されます.2つの項目を追加し,判定長さ2のテストコードを作成する.
import { render, screen, fireEvent } from '@testing-library/react';
import Todo from '../Todo';
import { BrowserRouter } from 'react-router-dom';

const MockedTodo = () => {
  return (
    <BrowserRouter>
      <Todo />
    </BrowserRouter>
  )
}

const addInput = (values) => {
  values.forEach(value => {
    const inputEl = screen.getByPlaceholderText(/Add a new task here.../i)
    const btnEl = screen.getByRole('button', { name: /Add/i })
    fireEvent.change(inputEl, { target: { value } });
    fireEvent.click(btnEl);
  })
}

describe("Todo Test", () => {
  test("add new item", async () => {
    render(<MockedTodo />)
    addInput([
      "Learn Test Code",
      "Learn React LifeCycle"
    ])
    const todoItems = screen.getAllByTestId('todo-item');
    expect(todoItems.length).toBe(2)
  })
})