Jest | Api 테스트 쉽게하기 feat. msw 라이브러리

쪼개발자·2023년 8월 29일

구현 코드 (HomeRoute)

import Hero from '../components/Hero';
import RepositoriesTable from '../components/repositories/RepositoriesTable';
import useRepositories from '../hooks/useRepositories';

function HomeRoute() {
  const { data: jsRepos } = useRepositories('stars:>10000 language:javascript');
  const { data: tsRepos } = useRepositories('stars:>10000 language:typescript');
  const { data: rustRepos } = useRepositories('stars:>10000 language:rust');
  const { data: goRepos } = useRepositories('stars:>10000 language:go');
  const { data: pythonRepos } = useRepositories('stars:>10000 language:python');
  const { data: javaRepos } = useRepositories('stars:>10000 language:java');

  return (
    <div>
      <Hero />
      <div className="container mx-auto py-8 grid grid-cols-1 gap-4 md:grid-cols-2">
        <RepositoriesTable
          label="Most Popular Javascript"
          repositories={jsRepos}
        />
        <RepositoriesTable
          label="Most Popular Typescript"
          repositories={tsRepos}
        />
        <RepositoriesTable label="Most Popular Rust" repositories={rustRepos} />
        <RepositoriesTable label="Most Popular Go" repositories={goRepos} />
        <RepositoriesTable
          label="Most Popular Python"
          repositories={pythonRepos}
        />
        <RepositoriesTable label="Most Popular Java" repositories={javaRepos} />
      </div>
    </div>
  );
}

export default HomeRoute;

구현 코드 (RepositoriesTable)

import { Link } from 'react-router-dom';
function RepositoriesTable({ label, repositories, id }) {
  const rendered =
    repositories &&
    repositories.map((repo, i) => {
      return (
        <div key={repo.id} className="p-0.5">
          <Link
            className="text-blue-500"
            to={`/repositories/${repo.full_name}`}
          >
            {repo.full_name}
          </Link>
        </div>
      );
    });
  return (
    <div className="border p-4 rounded">
      <h1 id={id || ''} className="text-lg font-bold border-b mb-1">
        {label}
      </h1>
      {rendered}
    </div>
  );
}
export default RepositoriesTable;

테스트 코드

import { setupServer } from 'msw/node';
import { rest } from 'msw';

export function createServer(handlerConfig) {
  const handlers = handlerConfig.map((config) => {
    return rest[config.method || 'get'](config.path, (req, res, ctx) => {
      return res(
        ctx.json(config.res(req, res, ctx)
        )
      );
    })
  });
  const server = setupServer(...handlers);

  beforeAll(() => {
    server.listen();
  });

  afterEach(() => {
    server.resetHandlers();  
  });

  afterAll(() => {
    server.close();
  });

}


import { render, screen } from '@testing-library/react';
import { setupServer } from 'msw/node';
import { rest} from 'msw';
import { MemoryRouter} from 'react-router-dom';
import HomeRoute from './HomeRoute'
import { createServer } from '../test/server';

// to make the handler test for multiple compenents ???  using createServer
createServer([
  {
    path: '/api/repositories',
    method: 'get', 
    res: (req) => { 
      const lauguage = req.url.searchParams.get('q').split("language:")[1];
      return {
        items: [
          { id:1, full_name: `${lauguage}_one`},
          { id:2, full_name: `${lauguage}_two` }
        ]
      }
    }
  }
]);

test('Renders two links for each language', async () => {

  render(
    <MemoryRouter> // homeroute에 link가 있어서 memoryrouter로 감싸준다
      <HomeRoute />
    </MemoryRouter>
  );

  // loop over each language
  const languages = ['javascript', 'typescript', 'rust', 'go', 'python', 'java'];
  
  for(let language of languages) {
    const links = await screen.findAllByRole('link', {
      name: new RegExp(`${language}_`)
    })
    expect(links).toHaveLength(2);
    expect(links[0]).toHaveTextContent(`${language}_one`)
    expect(links[1]).toHaveTextContent(`${language}_two`)
    expect(links[0]).toHaveAttribute('href', `/repositories/${language}_one`)
    expect(links[1]).toHaveAttribute('href', `/repositories/${language}_two`)
  }

});

0개의 댓글