🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Mobile First 테스트 전략 완벽 가이드 - 슬라이드 1/13
A

AI Generated

2025. 11. 3. · 22 Views

Mobile First 테스트 전략 완벽 가이드

모바일 우선 개발 환경에서 효과적인 테스트 전략을 구축하는 방법을 다룹니다. 단위 테스트부터 E2E 테스트까지, 실전에서 바로 적용 가능한 고급 테스트 패턴과 최적화 기법을 제공합니다.


카테고리:JavaScript
언어:JavaScript
메인 태그:#JavaScript
서브 태그:
#Jest#Testing#MobileTesting#E2E

들어가며

이 글에서는 Mobile First 테스트 전략 완벽 가이드에 대해 상세히 알아보겠습니다. 총 12가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.

목차

  1. 반응형_뷰포트_테스트
  2. 터치_이벤트_시뮬레이션
  3. 네트워크_지연_시뮬레이션
  4. 메모리_누수_감지
  5. 오프라인_모드_테스트
  6. 배터리_절약_모드_시뮬레이션
  7. 접근성_터치_타겟_검증
  8. 디바이스_방향_변경_테스트
  9. 스크롤_성능_테스트
  10. 폼_자동완성_테스트
  11. 제스처_충돌_방지_테스트
  12. PWA_설치_프롬프트_테스트

1. 반응형 뷰포트 테스트

개요

다양한 모바일 디바이스의 뷰포트 크기에서 컴포넌트가 올바르게 렌더링되는지 검증합니다.

코드 예제

describe('Responsive Component', () => {
  const viewports = [320, 375, 414, 768];

  viewports.forEach(width => {
    it(`renders correctly at ${width}px`, () => {
      window.innerWidth = width;
      window.dispatchEvent(new Event('resize'));
      expect(screen.getByTestId('container')).toBeInTheDocument();
    });
  });
});

설명

주요 모바일 디바이스의 뷰포트 크기를 배열로 정의하고, 각 크기에서 컴포넌트 렌더링을 테스트하여 반응형 동작을 검증합니다.


2. 터치 이벤트 시뮬레이션

개요

모바일 특유의 터치 제스처(탭, 스와이프, 핀치)를 테스트 환경에서 시뮬레이션합니다.

코드 예제

import { fireEvent } from '@testing-library/react';

test('handles swipe gesture', () => {
  const onSwipe = jest.fn();
  render(<SwipeableCard onSwipe={onSwipe} />);

  fireEvent.touchStart(screen.getByRole('article'), {
    touches: [{ clientX: 100, clientY: 0 }]
  });
  fireEvent.touchEnd(screen.getByRole('article'), {
    changedTouches: [{ clientX: 0, clientY: 0 }]
  });

  expect(onSwipe).toHaveBeenCalledWith('left');
});

설명

touchStart와 touchEnd 이벤트를 시뮬레이션하여 스와이프 제스처를 재현하고, 좌표 차이를 통해 방향을 감지하는 로직을 검증합니다.


3. 네트워크 지연 시뮬레이션

개요

모바일 네트워크의 불안정한 연결 상태를 테스트하기 위해 의도적인 지연을 추가합니다.

코드 예제

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

const server = setupServer(
  rest.get('/api/data', async (req, res, ctx) => {
    await new Promise(resolve => setTimeout(resolve, 3000));
    return res(ctx.json({ data: 'slow response' }));
  })
);

test('shows loading state on slow network', async () => {
  render(<DataComponent />);
  expect(screen.getByText('Loading...')).toBeInTheDocument();
});

설명

MSW(Mock Service Worker)를 사용하여 API 응답에 3초 지연을 추가하고, 로딩 상태가 올바르게 표시되는지 확인합니다.


4. 메모리 누수 감지

개요

모바일 디바이스의 제한된 메모리 환경에서 메모리 누수를 조기에 발견합니다.

코드 예제

test('cleans up event listeners', () => {
  const { unmount } = render(<ScrollTracker />);
  const initialListeners = getEventListeners(window).scroll?.length || 0;

  unmount();

  const finalListeners = getEventListeners(window).scroll?.length || 0;
  expect(finalListeners).toBeLessThanOrEqual(initialListeners);
});

설명

컴포넌트 마운트/언마운트 전후로 이벤트 리스너 수를 비교하여 정리되지 않은 리스너가 없는지 확인합니다.


5. 오프라인 모드 테스트

개요

네트워크 연결이 끊긴 상태에서 앱의 동작을 검증합니다.

코드 예제

test('works offline with cached data', async () => {
  await caches.open('app-cache').then(cache =>
    cache.put('/api/data', new Response(JSON.stringify({ cached: true })))
  );

  Object.defineProperty(navigator, 'onLine', { value: false, writable: true });

  render(<App />);
  await waitFor(() => {
    expect(screen.getByText(/cached/i)).toBeInTheDocument();
  });
});

설명

Cache API에 데이터를 미리 저장하고 navigator.onLine을 false로 설정하여, 오프라인 상태에서 캐시된 데이터가 표시되는지 확인합니다.


6. 배터리 절약 모드 시뮬레이션

개요

배터리 절약 모드에서 애니메이션과 리소스 집약적 작업이 적절히 제어되는지 테스트합니다.

코드 예제

test('reduces animations in power save mode', () => {
  const matchMedia = jest.fn().mockReturnValue({
    matches: true,
    addEventListener: jest.fn()
  });
  window.matchMedia = matchMedia;

  render(<AnimatedComponent />);

  const element = screen.getByTestId('animated');
  expect(element).toHaveStyle({ animation: 'none' });
});

설명

prefers-reduced-motion 미디어 쿼리를 모킹하여 배터리 절약 모드를 시뮬레이션하고, 애니메이션이 비활성화되는지 검증합니다.


7. 접근성 터치 타겟 검증

개요

모바일 접근성 가이드라인에 따라 터치 타겟의 최소 크기를 검증합니다.

코드 예제

test('touch targets meet minimum size', () => {
  render(<ButtonGroup />);

  const buttons = screen.getAllByRole('button');
  buttons.forEach(button => {
    const { width, height } = button.getBoundingClientRect();
    expect(width).toBeGreaterThanOrEqual(44);
    expect(height).toBeGreaterThanOrEqual(44);
  });
});

설명

모든 버튼 요소의 크기를 측정하여 WCAG 가이드라인(최소 44x44px)을 충족하는지 확인합니다.


8. 디바이스 방향 변경 테스트

개요

세로/가로 모드 전환 시 레이아웃과 상태가 올바르게 유지되는지 검증합니다.

코드 예제

test('adapts to orientation change', () => {
  render(<ResponsiveLayout />);

  Object.defineProperty(window.screen.orientation, 'type', {
    value: 'landscape-primary',
    writable: true
  });
  window.dispatchEvent(new Event('orientationchange'));

  expect(screen.getByTestId('layout')).toHaveClass('landscape');
});

설명

screen.orientation 속성을 변경하고 orientationchange 이벤트를 발생시켜, 레이아웃이 적절히 반응하는지 테스트합니다.


9. 스크롤 성능 테스트

개요

긴 리스트를 스크롤할 때 성능 저하 없이 부드럽게 동작하는지 측정합니다.

코드 예제

test('virtualizes long list efficiently', () => {
  const items = Array.from({ length: 10000 }, (_, i) => ({ id: i }));
  const { container } = render(<VirtualList items={items} />);

  const renderedItems = container.querySelectorAll('[data-item]');
  expect(renderedItems.length).toBeLessThan(50); // Only visible items
  expect(screen.getByText('Item 0')).toBeInTheDocument();
});

설명

10,000개 항목의 리스트를 렌더링했을 때 실제 DOM에는 화면에 보이는 일부만 렌더링되는지 확인하여 가상화가 작동하는지 검증합니다.


10. 폼 자동완성 테스트

개요

모바일 환경에서 자동완성과 입력 타입이 올바르게 설정되었는지 검증합니다.

코드 예제

test('has proper autocomplete attributes', () => {
  render(<LoginForm />);

  const emailInput = screen.getByLabelText(/email/i);
  expect(emailInput).toHaveAttribute('autocomplete', 'email');
  expect(emailInput).toHaveAttribute('type', 'email');
  expect(emailInput).toHaveAttribute('inputmode', 'email');
});

설명

이메일 입력 필드가 적절한 autocomplete, type, inputmode 속성을 가지고 있는지 확인하여 모바일 키보드와 자동완성이 최적화되었는지 검증합니다.


11. 제스처 충돌 방지 테스트

개요

커스텀 제스처가 브라우저 기본 제스처와 충돌하지 않는지 확인합니다.

코드 예제

test('prevents default browser gestures', () => {
  render(<CustomSwipeHandler />);

  const handler = screen.getByTestId('swipe-area');
  const touchEvent = new TouchEvent('touchmove', {
    cancelable: true,
    touches: [{ clientX: 50, clientY: 0 }]
  });

  handler.dispatchEvent(touchEvent);
  expect(touchEvent.defaultPrevented).toBe(true);
});

설명

touchmove 이벤트가 발생했을 때 preventDefault가 호출되어 브라우저의 기본 동작(뒤로가기, 새로고침 등)이 차단되는지 확인합니다.


12. PWA 설치 프롬프트 테스트

개요

Progressive Web App의 설치 프롬프트가 적절한 타이밍에 표시되는지 테스트합니다.

코드 예제

test('shows install prompt after engagement', async () => {
  const deferredPrompt = { prompt: jest.fn(), userChoice: Promise.resolve({ outcome: 'accepted' }) };
  window.dispatchEvent(new Event('beforeinstallprompt', { deferredPrompt }));

  render(<App />);
  fireEvent.click(screen.getByText('Install App'));

  await waitFor(() => {
    expect(deferredPrompt.prompt).toHaveBeenCalled();
  });
});

설명

beforeinstallprompt 이벤트를 시뮬레이션하고, 사용자가 설치 버튼을 클릭했을 때 프롬프트가 표시되는지 확인합니다.


마치며

이번 글에서는 Mobile First 테스트 전략 완벽 가이드에 대해 알아보았습니다. 총 12가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.

관련 태그

#JavaScript #Jest #Testing #MobileTesting #E2E

#JavaScript#Jest#Testing#MobileTesting#E2E

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.