본문 바로가기
프론트엔드/단위 테스트

movie 스토어 테스트

by step 1 2022. 2. 2.
반응형

store -> movie.js 파일 테스트

 

관련 공식문서

https://jestjs.io/docs/mock-function-api

 

Mock Functions · Jest

Mock functions are also known as "spies", because they let you spy on the behavior of a function that is called indirectly by some other code, rather than only testing the output. You can create a mock function with jest.fn(). If no implementation is given

jestjs.io

 

테스트를 진행할 코드

import axios from 'axios'
//  중복제거을 위해서 uniqBy를 사용
import _uniqBy from 'lodash/uniqBy'

const _defaultMessage = 'Search for the movie title!'

export default {
  // module!
  namespaced: true,
  //data!
  state: () => ({
    movies: [],
    message: _defaultMessage,
    loading: false,
    theMovie: {}
  }),
  // computed!
  getters: {
    // 실제 데이터를 계산해서 새로운 데이터 형식으로 반영할때 사용
    
  },
  // methods!
  // 변이: 관리하는 데이터를 변경시켜줄수 있다. 다른 메소드에서 변경할 수 없다.
  mutations: {
    // ['movies', 'message', 'loading']
    updateState(state, payload) {
      Object.keys(payload).forEach(key => {
        state[key] = payload[key]
        
      })
    },
    // assignMovies (state, Search){
    //   state.movies = Search
    // },
    // 화면 이동시 초기화 설정
    resetMovies(state) {
      state.movies = []
      state.message = _defaultMessage
      state.loading = false
    }
  },
  // 비동기로 동작한다.
  actions: {
    async searchMovies({state, commit}, payload) {

      // 영화검색을 동시에 동작하는 것을 방지
      if(state.loading) {
        return
      }

      commit('updateState', {
        message: '',
        loading: true
        // 검색된 imdbID 데이터의 중복을 제거
        // movies: _uniqBy(Search,'imdbID')
        // message: 'Hello world',
        // loading: true
      })
      try {
                // const { title, type, number, year } = payload
        // const OMDB_API_KEY = '7035c60c'
        // http -> https 로 변경
        //const res = await axios.get(`https://www.omdbapi.com/?apikey=${OMDB_API_KEY}&s=${title}&type=${type}&y=${year}&page=1`);
        const res = await _fetchMovie({
          // 전개연산자 사용
          ...payload,
          page: 1
        })
         console.log(res);
        const { Search, totalResults } = res.data
        commit('updateState', {
          // 검색된 imdbID 데이터의 중복을 제거
          movies: _uniqBy(Search,'imdbID')
          // message: 'Hello world',
          // loading: true
        })
        
        console.log(totalResults) // 261
        console.log(typeof totalResults) // string

        const total = parseInt(totalResults, 10)
        const pageLength = Math.ceil(total / 10)

        // 추가 요청!
        if (pageLength > 1) {
          for (let page = 2; page <= pageLength; page += 1) {
            if (page > payload.number / 10) {
              // 반복문 종료
              // 사용자가 지정한 갯수만큼 보여주도록 설정
              break;
            }
            //const res = await axios.get(`https://www.omdbapi.com/?apikey=${OMDB_API_KEY}&s=${title}&type=${type}&y=${year}&page=${page}`);
            const res = await _fetchMovie({
              ...payload,
              page: page
            })
            const {Search} = res.data
            commit('updateState', {
              // _uniqBy 를 이용해서 중복 제거
              movies: [
                ...state.movies,
                ..._uniqBy(Search, 'imdbID')
              ]
            })
          }
        }
      } catch ({message}) {
        commit('updateState', {
          // 초기화
          movies: [],
          // 메세지 출력
          message: message
        })
      } finally {
        commit('updateState', {
          loading: false
        })
      }
    },
    async searchMovieWithId({state, commit}, payload) {
      if(state.loading) return 

      commit('updateState', {
        theMovie: {},
        loading: true
      })
      //const {id} = payload
      try {
        const res = await _fetchMovie(payload)
        commit('updateState',{
          theMovie: res.data
          // id: id
        })
        console.log(res)
      } catch(error) {
        commit('updateState', {
          theMovie: {}
        })
      } finally {
        commit('updateState', {
          loading: false
        })
      }
    }
  }
}

async function _fetchMovie(payload) {
  // 서버리스 함수로 처리
  return await axios.post('/.netlify/functions/movie', payload)

  // const { title, type, year, page, id } = payload;
  // const OMDB_API_KEY = '7035c60c';
  // const url = id 
  //   ? `https://www.omdbapi.com/?apikey=${OMDB_API_KEY}&i=${id}` 
  //   : `https://www.omdbapi.com/?apikey=${OMDB_API_KEY}&s=${title}&type=${type}&y=${year}&page=${page}`;
  // // const url = `https://www.omdbapi.com/?apikey=${OMDB_API_KEY}`;

  // return new Promise((resolve, reject) => {
  //   axios.get(url)
  //     .then((res) => {
  //       // console.log(res)
  //       if (res.data.Error) {
  //         reject(res.data.Error)
  //       }
  //       resolve(res)
  //     })
  //     .catch((err) => {
  //       reject(err.message)
  //     })
  // })
}

 

테스트 코드

import movieStore from '~/store/movie.js'
import _cloneDeep from 'lodash/cloneDeep'
import axios from 'axios'

describe('store/movie.js', () => {
  let store

  beforeEach(() => {
    // 원본 훼손을 방지하기 위해 복사 기능 이용
    store = _cloneDeep(movieStore)
    store.state = store.state()
    // this.$store.state.movies
    store.commit = (name, payload) => {
      store.mutations[name](store.state, payload)
      
    }
    
     store.dispatch = (name, payload) => {
       const context = {
         state: store.state,
         commit: store.commit,
         dispatch: store.dispatch
       }
       return store.actions[name](context, payload)
     }
    
  })

  test('영화 데이터를 초기화합니다.', () => {
    store.commit('updateState', {
      movies: [{imdbId: '1'}],
      message: 'Hello world',
      loading: true
    })
    store.commit('resetMovies')    
    expect(store.state.movies).toEqual([])
    expect(store.state.message).toBe('Search for the movie title!')
    expect(store.state.loading).toBe(false)
    //store.mutations.updateState(store.state, {})
    //store.dispatch('searchMovies', {})
  })

  test('영화 목록을 잘 가져온 경우 데이터를 확인합니다.', async () => {
    const res = {
      data: {
        totalResults: '1',
        Search: [
          {
            imdbID: '1',
            Title: 'Hello',
            Poster: 'hello.jpg',
            Year: '2021'
          }
        ]
      }
    }
    // 모의함수 및 가짜 데이터 설정
    axios.post = jest.fn().mockResolvedValue(res)
    await store.dispatch('searchMovies')
    expect(store.state.movies).toEqual(res.data.Search)
  })

  test('영화 목록을 가져오지 못한 경우 에러 메시지를 확인합니다.', async () => {
    const errorMessage = 'Network Error'
    axios.post = jest.fn().mockRejectedValue(new Error(errorMessage))
    await store.dispatch('searchMovies')
    expect(store.state.message).toBe(errorMessage)
  })

  test('영화 아이템이 중복된 경우 고유하게 처리합니다.', async () => {
    const res = {
      data: {
        totalResults: '1',
        Search: [
          {
            imdbID: '1',
            Title: 'Hello',
            Poster: 'hello.jpg',
            Year: '2021'
          },
          {
            imdbID: '1',
            Title: 'Hello',
            Poster: 'hello.jpg',
            Year: '2021'
          },
          {
            imdbID: '1',
            Title: 'Hello',
            Poster: 'hello.jpg',
            Year: '2021'
          }
        ]
      }
    }
    axios.post = jest.fn().mockResolvedValue(res)
    await store.dispatch('searchMovies')
    expect(store.state.movies.length).toBe(1)
  })

  test('단일 영화의 상세 정보를 잘 가져온 경우 데이터를 확인합니다.', async () => {
    const res = {
      data: {
        imdbID: '1',
        Title: 'Frozen',
        Poster: 'frozen.jpg',
        Year: '2021'
      }
    }
    axios.post = jest.fn().mockResolvedValue(res)
    await store.dispatch('searchMovieWithId')
    expect(store.state.theMovie).toEqual(res.data)
  })
})

 

반응형