0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

React-Redux, Reduxの基本的なテスト

Last updated at Posted at 2021-08-06

Reactはともかく、最近はReduxはReact contextもあるからか、記事が少なくてテストについてもどうやれば良いのか悩みました。

テストについてはまだ学び始めたばかりなので、基本的なテストの内容についてまとめました。

今回は簡単なTodoリストを使ってテストについてまとめます。

コードはこちらに上げています。

Reduxのreducer周りのテスト

今回作成したReducerはこちらです。

todoSlice.js
import { combineReducers, createSlice } from '@reduxjs/toolkit'

const initialState = {
    count: 0,
    todo: []
}

const todoSlice = createSlice({
    name: "todo",
    initialState,
    reducers: {
        addTodo: (state, action) => {
            state.todo.push({id: state.count++, text: action.payload, completed: false})
        },
        deleteTodo: (state, action) => {
            const index = state.todo.findIndex(i => i.id === action.payload);
            if(index !== -1) {
                    state.todo.splice(index,1);
            }
        },
        completeTodo: (state, action) => {
            const todo = state.todo.find(i => i.id === action.payload);
            if(todo !== undefined) {
                todo.completed = !todo.completed;
            }
        }
    }
})

export const selectTodo = state => state.todo;

export const rootReducer = combineReducers({todo: todoSlice.reducer})
export const {addTodo, deleteTodo, completeTodo} = todoSlice.actions;
export default todoSlice.reducer;

こちらをテストします。

src直下のディレクトリに___test__という名前のフォルダを作成して、テストファイルを格納します。it()内に書いたテストごとにテストケースとして認識されます。今回割と名前は適当にしてしまいましたが、it("should add todo text to the state",()=>{})とかshould...としてどういう内容のテストをするのか書いたほうが分かりやすくなりますね。

このTodoリストは、画面上のinputからtodoを「追加」、「削除」、「完了」とすることが出来るreducerを作成したので、この3つのreducerが想定通り機能しているかどうかをテストしています。

Reducer.test.js
import reducer, {addTodo, deleteTodo, completeTodo} from '../features/todoSlice'

describe("Reducer test", ()=> {
    it("addTodo", ()=> {
        let initialState = {
        count: 0,
        todo: []
        }

    const action = {type: addTodo.type, payload: 'walk the dog'}
    const state = reducer(initialState, action);
    expect(state.todo).toEqual([{id: 0, text: 'walk the dog', completed: false}])
    })

    it("deleteTodo", ()=> {
        let initialState = {
            count: 0,
            todo: [{id: 0, text: 'walk the dog', completed: false}]
            }
    
        const action = {type: deleteTodo.type, payload: 0}
        const state = reducer(initialState, action);
        expect(state.todo).toEqual([])
    })

    it("completeTodo", ()=> {
        let initialState = {
            count: 0,
            todo: [{id: 0, text: 'walk the dog', completed: false}]
            }
    
        const action = {type: completeTodo.type, payload: 0}
        const state = reducer(initialState, action);
        expect(state.todo).toEqual([{id: 0, text: 'walk the dog', completed: true}])
    })
})

次に、react-redux周りのテストをします。

主な内容は、inputから入力したtodoがちゃんとReactのコンポーネント内にレンダリングされているか、deleteしたらちゃんと画面上から消えるかなどをチェックします。
今回はReduxのstoreに保存したtodoがReact内でレンダリングされているかテストしているので、テストするコンポーネントの<Todo>をテストファイル内で<Provider store={store}></Provider>で囲んでいます。
このstoreはredux-mock-storeを使ってモックする方法もあるのですが、とりあえずスタンダード?なやり方でテストしてみました。

Render.test.js
import { render, cleanup, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import {Provider} from 'react-redux'
import { configureStore } from "@reduxjs/toolkit";
import rootReducer from '../features/todoSlice'
import Todo from '../features/Todo'

afterEach(()=> cleanup());

describe("Render test", ()=> {
    let store;
    beforeEach(()=> {
        store = configureStore({ reducer: rootReducer })
    })

    it("should render todo text into the list",()=> {
        render(<Provider store={store}><Todo/></Provider>)
        userEvent.type(screen.getByPlaceholderText("Enter"),"walk the dog")
        userEvent.click(screen.getByText("Add Todo"))
        expect(screen.getByTestId("test-todo")).toHaveTextContent("walk the dog")
    })

    it("should line-through todo if the todo been completed", ()=> {
        render(<Provider store={store}><Todo/></Provider>)
        userEvent.type(screen.getByPlaceholderText("Enter"),"walk the dog")
        userEvent.click(screen.getByText("Add Todo"))
        userEvent.click(screen.getByRole("checkbox"))
        expect(screen.getByTestId("test-todo2")).not.toBeNull()
    })

    it("should be removed from the screen if been deleted", ()=> {
        render(<Provider store={store}><Todo/></Provider>)
        userEvent.type(screen.getByPlaceholderText("Enter"),"walk the dog")
        userEvent.click(screen.getByText("Add Todo"))
        userEvent.click(screen.getByText("×"))
        expect(screen.getByRole("todoul")).not.toHaveTextContent("walk the dog")
    })
})

メモがてら書いてみてみたのですが、テストのやり方はもうちょっと色々なやり方を知っておきたいなと思っているので、また追記するかもしれません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?