0Pricing
React Native Academy · 강의

다듬기, 테스트 및 양대 스토어 출시

핵심 훅에 대한 단위 테스트를 작성하고, 핵심 경로를 위한 Maestro E2E 흐름을 추가하며, 번들을 최적화하고, 스토어용 리소스를 생성한 뒤 App Store와 Google Play 양쪽에 제출합니다.

다듬기, 테스트 및 양대 스토어 출시은(는) CoddyKit의 무료 React Native Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 React Native Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. React Native Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

The Final Stretch: Polish, Test, Ship

The last phase of any app project is the most discipline-intensive: polishing the rough edges users will actually notice, writing tests that catch regressions before they reach production, and executing the submission process for both stores. Each of these feels like it should be quick but takes as long as the feature work — budget time accordingly. A well-polished app with proper test coverage ships with confidence.

UI Polish: Consistent Spacing and Typography

Polish starts with design tokens — a single source of truth for spacing, font sizes, font weights, border radii, and colors. Define these in a theme.ts file and import them everywhere instead of hard-coding padding: 16 scattered across screens. Consistency is what makes an app feel premium — when all buttons have the same height, all headings use the same font, and all cards have the same shadow, the UI feels intentional.

// src/theme.ts
export const theme = {
  colors: {
    primary: '#007AFF',
    background: '#F2F2F7',
    surface: '#FFFFFF',
    text: '#000000',
    textSecondary: '#8E8E93',
    error: '#FF3B30',
    success: '#34C759',
  },
  spacing: {
    xs: 4, sm: 8, md: 16, lg: 24, xl: 32
  },
  typography: {
    largeTitle: { fontSize: 34, fontWeight: '700' },
    title: { fontSize: 22, fontWeight: '600' },
    body: { fontSize: 17, fontWeight: '400' },
    caption: { fontSize: 12, fontWeight: '400' },
  },
  borderRadius: { sm: 8, md: 12, lg: 16, full: 999 },
};

Accessibility Audit

Accessibility is both a legal requirement and a quality marker. Audit your app for: accessible labels on all icon buttons (accessibilityLabel), minimum touch target sizes of 44×44pt on iOS and 48×48dp on Android, correct accessibility roles (accessibilityRole='button' for tappable items), and color contrast (at least 4.5:1 for body text). Use the iOS Accessibility Inspector or Android TalkBack to test screen reader behavior.

// Accessible icon button
<TouchableOpacity
  onPress={handleDelete}
  accessibilityLabel='Delete habit'
  accessibilityRole='button'
  accessibilityHint='Permanently removes this habit and its history'
  style={{ padding: 12 }}  // Ensures 44pt touch target with 20pt icon
>
  <Ionicons name='trash-outline' size={20} color='#FF3B30' />
</TouchableOpacity>

// Screen reader text for images
<Image
  source={{ uri: habit.icon }}
  accessibilityLabel={`${habit.name} habit icon`}
  accessible={true}
/>

Writing Unit Tests for Core Hooks

Unit-test the business logic that is independent of the UI — calculations, hooks with mocked queries, and utility functions. The streak calculation is a perfect candidate: test edge cases like an empty array, a single day, a gap in the middle, and today not completed. Use @testing-library/react-native with renderHook to test custom hooks that use React state and effects.

// src/utils/__tests__/streaks.test.ts
import { calculateStreak } from '../streaks';

describe('calculateStreak', () => {
  it('returns 0 for empty completions', () => {
    expect(calculateStreak([])).toBe(0);
  });

  it('returns 1 when only today is completed', () => {
    const today = new Date().toISOString().split('T')[0];
    expect(calculateStreak([today])).toBe(1);
  });

  it('returns correct streak for consecutive days', () => {
    const dates = ['2026-06-21', '2026-06-20', '2026-06-19'];
    // Mock today as 2026-06-21 in tests
    expect(calculateStreak(dates)).toBe(3);
  });

  it('stops at a gap', () => {
    // Today=21, gap at 20, then 19
    const dates = ['2026-06-21', '2026-06-19'];
    expect(calculateStreak(dates)).toBe(1);
  });
});

Component Tests with React Native Testing Library

Write component tests for the most-used UI elements: the HabitCard rendering habit name and streak, the CheckInButton toggling state on press, and the OfflineBanner appearing only when offline. Mock dependencies (Supabase, React Query) at the test boundary so components are tested in isolation without real network calls.

// src/components/__tests__/HabitCard.test.tsx
import { render, fireEvent } from '@testing-library/react-native';
import { HabitCard } from '../HabitCard';

const mockHabit = {
  id: '1', name: 'Morning Run', icon: 'run',
  color: '#007AFF', streak: 5
};

it('renders habit name and streak', () => {
  const { getByText } = render(<HabitCard habit={mockHabit} onPress={() => {}} />);
  expect(getByText('Morning Run')).toBeTruthy();
  expect(getByText('5 days')).toBeTruthy();
});

it('calls onPress when tapped', () => {
  const onPress = jest.fn();
  const { getByTestId } = render(
    <HabitCard habit={mockHabit} onPress={onPress} testID='habit-card' />
  );
  fireEvent.press(getByTestId('habit-card'));
  expect(onPress).toHaveBeenCalledTimes(1);
});

Maestro E2E: Critical Path Test

Write a Maestro flow for the critical user path: sign in, create a habit, check it in, verify the streak updates, and sign out. This catches integration bugs that unit tests miss — navigation state, network calls, and UI state all working together. Run it against a real simulator or device on every CI build before promoting to the next test track.

# maestro/critical-path.yaml
---
appId: com.yourcompany.habittracker
---
- launchApp:
    clearState: true
- tapOn: 'Sign In'
- inputText: 'test@example.com'
- tapOn: 'Password'
- inputText: 'TestPass123!'
- tapOn: 'Sign In'
- waitForAnimationToEnd
- assertVisible: 'My Habits'
- tapOn: 'Add Habit'
- inputText: 'Morning Run'
- tapOn: 'Save'
- waitForAnimationToEnd
- assertVisible: 'Morning Run'
- tapOn:
    id: 'check-in-btn-1'
- waitForAnimationToEnd
- assertVisible: '1 day'  # Streak shows 1 day
- tapOn: 'Settings'
- tapOn: 'Sign Out'
- assertVisible: 'Sign In'

Bundle Size Optimization

Before submitting, analyze and minimize the JS bundle. Use react-native-bundle-visualizer to identify large dependencies. Common savings: replace moment.js (280KB) with date-fns (tree-shakeable, ~5KB per import), remove unused icon packs (only import icons you use), and apply lazy loading (React.lazy + Suspense) for heavy screens like settings or onboarding that users rarely visit after the first launch.

# Analyze bundle
npx react-native-bundle-visualizer

# Opens a visual treemap in browser showing:
# - node_modules breakdown by size
# - Your source code size
# - Duplicate modules

# Common large packages to replace:
# moment (280KB) -> date-fns tree-shaking
# lodash (full, 70KB) -> lodash-es specific imports
# FontAwesome all icons -> import only used icons

# Result: each 100KB reduction = ~50KB gzip reduction
# = faster first install + lower Play/App Store size

Generating Store Assets

Create the required store assets before submission: app icon (1024×1024 for iOS, adaptive icon for Android), splash screen (all size variants via Expo's splash config), screenshots (at least 3–6 per required device size), and a feature graphic (1024×500 for Android). Use a design tool like Figma with device frame plugins to create professional-looking screenshots without needing a marketing designer.

// app.json — icon and splash configuration
{
  'expo': {
    'icon': './assets/icon.png',        // 1024x1024 PNG
    'splash': {
      'image': './assets/splash.png',
      'resizeMode': 'contain',
      'backgroundColor': '#007AFF'
    },
    'ios': {
      'icon': './assets/icon.png'
    },
    'android': {
      'icon': './assets/icon.png',
      'adaptiveIcon': {
        'foregroundImage': './assets/adaptive-icon.png',
        'backgroundColor': '#007AFF'
      }
    }
  }
}

Final Build for Production

Trigger the production EAS builds for both platforms. Verify the version number and version code are correct before building — changing them after requires a new build. Run both builds in parallel to save time. Once both are complete, upload to TestFlight and Play Console internal testing for one final smoke test on the exact production binary before submitting for review.

# Verify versions before building
cat app.json | grep '"version"'
# -> "version": "1.0.0"
# -> "versionCode": 1
# -> "buildNumber": "1"

# Build both platforms in parallel
eas build --platform ios --profile production &
eas build --platform android --profile production &
wait

# Or use the combined command:
eas build --platform all --profile production

# After builds complete, check status:
eas build:list --status finished --limit 2

Smoke Test the Production Build

Install the exact production binary on a real device before submitting for review. Download the iOS .ipa to TestFlight and the Android .aab to Play Console internal testing. Test the sign-up flow, core feature, push notifications, and purchase flow (if applicable) from scratch — never assume the development version behavior matches the production build. Production builds have different signing, minification, and ProGuard settings that can expose bugs not seen in development.

// Pre-submission smoke test checklist:

// Install production build on physical device
// (not simulator — push notifications require real device)

// Test:
// [ ] Fresh install and sign up flow
// [ ] Sign out and sign in with existing account
// [ ] Core feature: create, complete, view streak
// [ ] Push notification: schedule and receive
// [ ] Background behavior: close and reopen app
// [ ] Deep links from browser/email
// [ ] Offline: airplane mode then restore network
// [ ] Landscape orientation (if not locked)
// [ ] All tabs and major screens load without crash
// [ ] Performance: no jank on FlatList scroll

Submitting to Both Stores

Submit to both stores simultaneously so review timelines align and you can launch on both platforms on the same day. Use eas submit for both. App Store review typically takes 1–3 days; Google Play takes 1–7 days for a first app (faster for updates). Have marketing assets ready (app website, social posts, press kit) so you can announce launch the moment both stores approve. Monitor both stores' review dashboards daily during the review period.

# Submit to App Store (TestFlight first, then App Review)
eas submit --platform ios --latest

# Submit to Play Console (internal -> production)
eas submit --platform android --latest

# Or submit both at once:
eas submit --platform all --latest

# After submission:
# iOS: App Store Connect > App > 1.0 Prepare for Submission
#      > Add for Review > Submit to App Review
# Android: Play Console > Production > Create release
#           > Promote internal build > Review > Start rollout

Quick Check

Test your understanding of React Native Mobile Development concepts from this lesson.

Lesson Recap

In this lesson you learned: how to audit and polish your app with design tokens, accessibility labels, and minimum touch targets, how to write unit tests for streak logic and component tests with RNTL, and how to write a Maestro E2E flow for the critical user path and submit to both the App Store and Play Store. Congratulations — you have completed the React Native Mobile Development track! You now have the skills to build, test, and ship production-quality React Native apps to both platforms.

자주 묻는 질문

“다듬기, 테스트 및 양대 스토어 출시” 강의는 무료인가요?

네 — “다듬기, 테스트 및 양대 스토어 출시” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 React Native Academy 강의 전체를 잠금 해제할 수 있습니다. React Native Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“다듬기, 테스트 및 양대 스토어 출시”에서 뭘 배우나요?

핵심 훅에 대한 단위 테스트를 작성하고, 핵심 경로를 위한 Maestro E2E 흐름을 추가하며, 번들을 최적화하고, 스토어용 리소스를 생성한 뒤 App Store와 Google Play 양쪽에 제출합니다. 브라우저에서 직접 실행하는 실습 코드로 React Native Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

React Native Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 React Native Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“다듬기, 테스트 및 양대 스토어 출시” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 React Native Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 React Native Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 아키텍처 및 기술 스택 계획하기
  2. 인증 흐름과 보호된 경로
  3. 핵심 기능: 오프라인을 지원하는 데이터 피드
  4. 다듬기, 테스트 및 양대 스토어 출시
← React Native Academy(으)로 돌아가기