JAVASCRIPT

vitest에서 msw를 사용해 api mocking 시작하기

Neda 2024. 2. 8. 22:19

vitest에서 msw를 사용해 api mocking 시작하기

vitest는 vite기반의 테스팅 프레임워크로, jest와 거의 같은 사용법을 가지고 있으며, 차세대 테스팅 프레임워크를 지향하고 있습니다. msw는 클라이언트에 구애받지 않고 테스트를 수행하기 위해 API를 모킹하는 라이브러리입니다. vitest에서는 api 모킹을 위해 msw와 같은 라이브러리의 사용을 권장하고 있습니다.

 

새로운 프로젝트 생성

npm init을 사용하여 프로젝트를 초기화하거나 vite와 같은 빌드 도구를 사용해 빠르게 프로젝트를 시작할 수 있습니다

npm init
npm create vite@latest

 

Vitest, MSW 설치

vitest와 msw를 사용하기 위해 개발 의존성으로 설치합니다

npm install -D vitest msw

 

package.json 스크립트 추가

npm test로 테스트를 시작하기 위한 명령어 추가

{
  ...
  "scripts": {
  ...
    "test": "vitest"
  },
  ...
}

 

vite config 설정

프로젝트 루프 경로에 vite.config.ts 생성 후 작성

// vite.config.ts
/// <reference types="vitest" />
import { defineConfig } from 'vite'

export default defineConfig({
  test: {
    globals: true,
    setupFiles: ['./test/setup.ts'],
  },
})

 

setup 파일 작성

// /test/setup.ts
import { afterAll, afterEach, beforeAll } from 'vitest'
import { setupServer } from 'msw/node'
import { HttpResponse, graphql, http } from 'msw'

const posts = [
  {
    userId: 1,
    id: 1,
    title: 'first post title',
    body: 'first post body',
  },
  // ...
]

export const restHandlers = [
  http.get('https://rest-endpoint.example/path/to/posts', () => {
    return HttpResponse.json(posts)
  }),
]

const graphqlHandlers = [
  graphql.query('ListPosts', () => {
    return HttpResponse.json({
      data: { posts },
    })
  }),
]

const server = setupServer(...restHandlers, ...graphqlHandlers)

// Start server before all tests
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))

//  Close server after all tests
afterAll(() => server.close())

// Reset handlers after each test `important for test isolation`
afterEach(() => server.resetHandlers())

 

테스트 작성

테스트파일은 ~.test.ts, ~.spec.ts와 같이  **/*.{test,spec}.?(c|m)[jt]s?(x) 정규식을 만족하도록 작성

// /test/api.test.ts
import { describe, expect, it } from 'vitest'

describe('API test', () => {
  it('should fetch posts', async () => {
    // Arrange
    const response = await fetch('https://rest-endpoint.example/path/to/posts')
    // Act
    const data = await response.json()
    // Assert
    const expected = [
      {
        userId: 1,
        id: 1,
        title: 'first post title',
        body: 'first post body',
      },
    ]
    //Test
    expect(data).toEqual(expected)
  })
})

MSW Header Authorization 사용하기

http.post('https://rest-endpoint.example/auth/login', ({ request }) => {
    const authorization = request.headers.get('Authorization')
    const token = authorization?.split(' ')[1]
    const id = token === 'valid-token' ? 1 : null
    if (id) {
      return HttpResponse.json({ id })
    }
  })

 

MSW Request Body 사용하기

http.post(
    'https://rest-endpoint.example/path/to/posts',
    async ({ request }) => {
      const json = await request.json()
      return HttpResponse.json(json)
    }
  )

 

MSW SearchParams 사용하기

http.delete('https://rest-endpoint.example/path/to/posts', ({ request }) => {
    const url = new URL(request.url)

    const id = url.searchParams.get('id')

    if (!id) {
      return new HttpResponse(null, { status: 404 })
    }

    return HttpResponse.json({
      id: Number(id),
      deleted: true,
    })
  })