0Pricing
React Native Academy · Pelajaran

Penyempurnaan, Pengujian, dan Rilis ke Kedua Toko

Tulis pengujian unit untuk kait inti, tambahkan alur E2E Maestro untuk jalur kritis, optimalkan bundel, buat aset toko, dan kirimkan ke App Store serta Google Play.

Penyempurnaan, Pengujian, dan Rilis ke Kedua Toko adalah pelajaran React Native Academy gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar React Native Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus React Native Academy mencakup 4 pelajaran total.

Bagian dari pelajaran ini belum diterjemahkan dan ditampilkan dalam bahasa Inggris.

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.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Penyempurnaan, Pengujian, dan Rilis ke Kedua Toko” gratis?

Ya — teks lengkap “Penyempurnaan, Pengujian, dan Rilis ke Kedua Toko” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus React Native Academy, upgrade ke CoddyKit PRO. Kursus React Native Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Penyempurnaan, Pengujian, dan Rilis ke Kedua Toko”?

Tulis pengujian unit untuk kait inti, tambahkan alur E2E Maestro untuk jalur kritis, optimalkan bundel, buat aset toko, dan kirimkan ke App Store serta Google Play. Kamu berlatih React Native Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai React Native Academy?

Tidak diperlukan pengalaman sebelumnya. React Native Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.

Berapa lama pelajaran “Penyempurnaan, Pengujian, dan Rilis ke Kedua Toko” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran React Native Academy ini?

Ya. Setiap pelajaran React Native Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Merencanakan Arsitektur dan Tumpukan Teknologi
  2. Alur Autentikasi dan Rute Terlindungi
  3. Fitur Inti: Umpan Data dengan Dukungan Luring
  4. Penyempurnaan, Pengujian, dan Rilis ke Kedua Toko
← Kembali ke React Native Academy