본문 바로가기
SPA/React

[React] MSW로 API Mocking 하기 (4) - Storybook에서 사용하기

by J4J 2023. 10. 16.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 MSW API Mocking 하기 네 번째인 Storybook에서 사용하는 방법에 대해 적어보는 시간을 가져보려고 합니다.

 

 

 

이전 글

 

[React] MSW로 API Mocking 하기 (1) - MSW란?

[React] MSW로 API Mocking 하기 (2) - Browser 환경에서 사용하기

[React] MSW로 API Mocking 하기 (3) - Node 환경에서 사용하기

 

 

반응형

 

 

설정 방법

 

Storybook에 MSW를 적용하기 위해서는 Storybook을 사용할 수 있는 환경과 MSW Browser 환경 설정이 되어 있어야 합니다.

 

만약 각 환경 구축이 필요하신 경우 다음 글들을 참고해 주시면 됩니다.

 

 

 

 

설정 들이 모두 되어 있다면 다음 순서대로 Storybook에 MSW를 적용해 볼 수 있습니다.

 

 

 

[ 1. 패키지 설치 ]

 

$ npm install -D msw-storybook-addon

 

 

 

[ 2. preview 설정 추가 ]

 

Storybook을 사용중이면 프로젝트 최상단에 .storybook 폴더가 존재할 것이고 폴더 안에는 preview 파일이 있어야 합니다.

 

preview 파일이 있으시다면 다음과 같이 MSW 관련 설정을 추가해 주시면 됩니다.

 

import { initialize, mswLoader } from "msw-storybook-addon";

// msw 초기화
initialize();

const preview: Preview = {
  parameters: {
    ...
  },
  // msw addon loader 등록
  loaders: [mswLoader],
};

export default preview;

 

 

 

[ 3. msw handler 등록 ]

 

[React] MSW로 API Mocking 하기 (2) - Browser 환경에서 사용하기를 확인해보면 다음과 같이 MSW handler를 정의해 둔 것을 확인할 수 있습니다.

 

// src/mocks/handlers/person-handler.ts
import { rest } from 'msw';

export const personHandlers = [
    // GET method인 /get-names를 호출하면 다음과 같이 response가 되도록 mocking 정의
    rest.get('/get-names', (req, res, ctx) => {
        const names = ['jimi', 'john', 'scott', 'queen']

        return res(
            ctx.status(200),
            ctx.json(names),
        )
    })
]


// src/mocks/handlers/index.ts
import { personHandlers } from "./person-handler";

// 여러 handler를 한 곳에 묶어서 return
export const handlers = [
    ...personHandlers
]

 

 

 

해당 handler를 그대로 활용한다고 가정한다면 preview 파일에 다음과 같이 handler를 등록해줄 수 있습니다.

 

import { handlers } from '../src/mocks/handlers';

const preview: Preview = {
  parameters: {
    msw: {
      handlers: {
        ...handlers // msw handler 등록
      }
    }
  },
};

export default preview;

 

 

 

 

테스트

 

위와 같이 설정을 모두 마쳤다면 테스트를 진행해보겠습니다.

 

위에서 정의했던 handler를 그대로 활용하는 페이지와 Storybook 소스를 다음과 같이 작성해 보겠습니다.

 

// src/App.tsx
import axios from "axios";
import { useEffect, useState } from "react";

export default function App() {
  const [personNames, setPersonNames] = useState<string[]>([]);

  async function apiGetNames() {
    const res = await axios.get('/get-names');
    if(res.data) {
      setPersonNames(res.data);
    }
  }

  useEffect(() => {
    apiGetNames();
  }, [])

  return (
    <div>
      <div>
        <h2>사람들의 이름을 호출해보겠습니다 !</h2>
      </div>

      <div>
        {personNames.map((personName, index) => (
          <p key={personName}>{index+1}번째 이름은 {personName}입니다.</p>
        ))}
      </div>
    </div>
  )
}


// src/App.stories.tsx
import { Meta, StoryObj } from '@storybook/react';
import App from "./App";

const meta: Meta<typeof App> = {
    title: 'Default/App',
    component: App,
};

export default meta;
type Story = StoryObj<typeof App>;

export const Default: Story = {
    args: {},
};

 

 

 

그리고 Storybook을 실행하여 확인해 보면 다음과 같이 mocking 처리가 된 API 결과를 볼 수 있습니다.

 

Storybook msw 설정 결과

 

 

 

 

상황 별 다른 Mocking 처리 (Override)

 

이전 글들인 Browser, Node 환경을 설정할 때도 override를 하여 페이지 및 테스트 별 동일한 API에 대해 서로 다른 mocking 결과를 만든 적이 있습니다.

 

Storybook에서도 해당 설정에 대해 예외는 아닙니다.

 

만약 Storybook에서도 컴포넌트 별로 동일한 API에 대해 서로 다른 mocking 정의가 필요한 경우 다음과 같이 설정해 볼 수 있습니다.

 

 

 

[ 1. storybook 컴포넌트에 override handler 정의 ]

 

import { Meta, StoryObj } from '@storybook/react';
import { rest } from 'msw';
import App from "./App";

const meta: Meta<typeof App> = {
    title: 'Default/App',
    component: App,
    parameters: {
        msw: {
            handlers: [
                // GET method인 /get-names를 해당 default component에서만 따로 활용
                rest.get('/get-names', (req, res, ctx) => {
                    const names = ['storybook-jimi', 'storybook-john', 'storybook-scott', 'storybook-queen']

                    return res(
                        ctx.status(200),
                        ctx.json(names),
                    )
                })
            ]
        }
    }
};

export default meta;
type Story = StoryObj<typeof App>;

export const Default: Story = {
    args: {},
};

 

 

 

[ 2. 테스트 ]

 

위와 같이 설정하면 preview에 handler가 정의되어 있더라도 다음과 같이 결과가 나오는 것을 확인할 수 있습니다.

 

storybook msw override 설정 결과

 

 

 

 

번외로 다음과 같이도 설정할 수 있습니다.

 

import { Meta, StoryObj } from '@storybook/react';
import { rest } from 'msw';
import App from "./App";

const meta: Meta<typeof App> = {
    title: 'Default/App',
    component: App,
};

export default meta;
type Story = StoryObj<typeof App>;

export const Default: Story = {
    args: {},
};

export const MswOverride: Story = {
    args: {},
}
MswOverride.parameters = {
    msw: {
        handlers: [
            // GET method인 /get-names를 해당 component에서만 따로 활용
            rest.get('/get-names', (req, res, ctx) => {
                const names = ['storybook-jimi', 'storybook-john', 'storybook-scott', 'storybook-queen']

                return res(
                    ctx.status(200),
                    ctx.json(names),
                )
            })
        ]
    }
}

 

storybook msw override 설정 결과

 

 

 

 

 

 

 

 

이상으로 MSW API Mocking 하기 네 번째인 Storybook에서 사용하는 방법에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

 

 

 

728x90
반응형

댓글