mobile-best-practices 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -0
- package/assets/data/anti-patterns.csv +114 -0
- package/assets/data/architectures.csv +50 -0
- package/assets/data/code-snippets.csv +80 -0
- package/assets/data/gradle-deps.csv +79 -0
- package/assets/data/libraries.csv +102 -0
- package/assets/data/performance.csv +229 -0
- package/assets/data/platforms/android.csv +247 -0
- package/assets/data/platforms/flutter.csv +55 -0
- package/assets/data/platforms/ios.csv +61 -0
- package/assets/data/platforms/react-native.csv +56 -0
- package/assets/data/project-templates.csv +19 -0
- package/assets/data/reasoning-rules.csv +57 -0
- package/assets/data/security.csv +438 -0
- package/assets/data/testing.csv +74 -0
- package/assets/data/ui-patterns.csv +92 -0
- package/assets/references/CHECKLIST.md +49 -0
- package/assets/references/CODE-RULES.md +123 -0
- package/assets/scripts/__pycache__/core.cpython-314.pyc +0 -0
- package/assets/scripts/core.py +432 -0
- package/assets/scripts/search.py +104 -0
- package/assets/skills/all.md +245 -0
- package/assets/skills/android.md +168 -0
- package/assets/skills/flutter.md +153 -0
- package/assets/skills/ios.md +149 -0
- package/assets/skills/react-native.md +154 -0
- package/assets/templates/base/quick-reference.md +41 -0
- package/assets/templates/base/skill-content.md +60 -0
- package/assets/templates/platforms/agent.json +11 -0
- package/assets/templates/platforms/antigravity.json +13 -0
- package/assets/templates/platforms/claude.json +27 -0
- package/assets/templates/platforms/codebuddy.json +11 -0
- package/assets/templates/platforms/codex.json +11 -0
- package/assets/templates/platforms/continue.json +11 -0
- package/assets/templates/platforms/copilot.json +11 -0
- package/assets/templates/platforms/cursor.json +11 -0
- package/assets/templates/platforms/gemini.json +11 -0
- package/assets/templates/platforms/kiro.json +11 -0
- package/assets/templates/platforms/opencode.json +11 -0
- package/assets/templates/platforms/qoder.json +11 -0
- package/assets/templates/platforms/roocode.json +11 -0
- package/assets/templates/platforms/trae.json +11 -0
- package/assets/templates/platforms/windsurf.json +11 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +94 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +28 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/versions.d.ts +2 -0
- package/dist/commands/versions.d.ts.map +1 -0
- package/dist/commands/versions.js +30 -0
- package/dist/commands/versions.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +24 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/index.d.ts +9 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +103 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Category,Pattern,Platform,Keywords,Description,Framework,Code Example,Anti Pattern,Notes,Reference URL
|
|
2
|
+
Unit Test,ViewModel Unit Test,Android,viewmodel test coroutine flow state turbine,Test ViewModel state changes and business logic,JUnit5 + Turbine + MockK,@Test fun loadData() = runTest { viewModel.load(); viewModel.state.test { assertEquals(Loading awaitItem()) } },Testing implementation details not behavior,Use Turbine for Flow testing runTest for coroutines,https://developer.android.com/training/testing/local-tests
|
|
3
|
+
Unit Test,ViewModel Test,iOS,viewmodel test combine publisher xctest async,Test ViewModel with Combine publishers,XCTest + Combine,func testLoad() async { await vm.load(); XCTAssertEqual(vm.state .loaded(items)) },Testing private properties directly,Use async/await for async tests,https://developer.apple.com/documentation/xctest
|
|
4
|
+
Unit Test,BLoC Unit Test,Flutter,bloc test cubit state event transition,Test BLoC state transitions,bloc_test + mocktail,blocTest('emits [Loading Loaded]' build: () => MyBloc() act: (b) => b.add(Load()) expect: () => [Loading() Loaded(data)]),Testing widget instead of BLoC logic,Use blocTest helper for clean BLoC tests,https://pub.dev/packages/bloc_test
|
|
5
|
+
Unit Test,Redux Test,React Native,redux reducer action state jest slice,Test Redux reducers and actions,Jest,test('handles LOAD_SUCCESS' () => { expect(reducer(initial loadSuccess(data))).toEqual({...initial data}) }),Testing store instead of reducer in isolation,Test reducers as pure functions,https://redux-toolkit.js.org/usage/writing-tests
|
|
6
|
+
Unit Test,Repository Test,All,repository test mock api database data,Test repository data layer logic,Platform-specific,@Test fun fetchUser() = runTest { whenever(api.getUser(1)).thenReturn(mockUser); assertEquals(mockUser repo.getUser(1)) },Using real API in unit tests,Mock all external dependencies,
|
|
7
|
+
Unit Test,UseCase Test,All,usecase domain business logic test execute,Test domain layer use cases,Platform-specific,@Test fun execute() = runTest { val result = useCase(params); assertTrue(result.isSuccess) },Testing trivial pass-through logic,Only test UseCases with real business logic,
|
|
8
|
+
Unit Test,Mapper Test,All,mapper dto entity model conversion transform,Test data model mapping functions,Platform-specific,@Test fun mapToEntity() { assertEquals(expected mapper.toEntity(dto)) },No null/edge case testing,Test edge cases nulls and defaults,
|
|
9
|
+
Unit Test,Validation Test,All,validation form input rules email password,Test input validation rules,Platform-specific,@Test fun emailValid() { assertTrue(validator.isEmail('a@b.com')); assertFalse(validator.isEmail('invalid')) },Testing only happy path,Cover boundary cases and unicode,
|
|
10
|
+
UI Test,Compose UI Test,Android,compose test ui semantics rule node,Test Compose UI components and interactions,Compose Testing + JUnit4,@Test fun buttonClick() { rule.setContent { MyScreen() }; rule.onNodeWithText('Submit').performClick() },Testing exact pixel positions,Use semantics matchers not visual assertions,https://developer.android.com/develop/ui/compose/testing
|
|
11
|
+
UI Test,SwiftUI Preview Test,iOS,swiftui preview test snapshot viewinspector,Test SwiftUI views behavior,ViewInspector + XCTest,func testButton() throws { let view = MyView(); let button = try view.inspect().find(button: 'Submit'); try button.tap() },Testing view hierarchy not behavior,Use ViewInspector for SwiftUI unit tests,https://github.com/nicklama/ViewInspector
|
|
12
|
+
UI Test,Widget Test,Flutter,widget test pump finder tap tester,Test Flutter widget behavior,flutter_test,testWidgets('tap increments' (tester) async { await tester.pumpWidget(MyApp()); await tester.tap(find.byIcon(Icons.add)); await tester.pump(); expect(find.text('1') findsOneWidget); }),Not pumping after state changes,Always pump after actions that change state,https://docs.flutter.dev/testing/overview#widget-tests
|
|
13
|
+
UI Test,Component Test,React Native,component test render fireEvent screen rtl,Test React Native component rendering,@testing-library/react-native,test('renders correctly' () => { render(<MyComponent />); fireEvent.press(screen.getByText('Submit')); expect(screen.getByText('Done')).toBeTruthy(); }),Using enzyme or shallow rendering,Use @testing-library for user-centric testing,https://callstack.github.io/react-native-testing-library/
|
|
14
|
+
UI Test,Accessibility Test,All,accessibility a11y test screen reader voiceover talkback,Test accessibility labels and navigation,Platform-specific,@Test fun hasAccessibility() { rule.onNodeWithContentDescription('Submit button').assertExists() },No accessibility tests at all,Test all interactive elements have labels,https://developer.android.com/guide/topics/ui/accessibility/testing
|
|
15
|
+
UI Test,Screenshot Test,All,screenshot test visual regression golden paparazzi,Detect visual regressions via screenshots,Paparazzi/Swift Snapshot/Golden,@Test fun screenshotDefault() { paparazzi.snapshot { MyScreen(state = Default) } },Brittle tests breaking on font changes,Use tolerance and update goldens intentionally,https://github.com/cashapp/paparazzi
|
|
16
|
+
Integration Test,API Integration Test,All,api integration test endpoint contract staging,Test real API contract and response parsing,Platform-specific,@Test fun apiReturnsUser() = runTest { val user = api.getUser(1); assertNotNull(user.name) },Running against production API,Use staging/test environment with test data,
|
|
17
|
+
Integration Test,Database Integration Test,All,database room coredata migration test schema,Test database operations and migrations,Platform-specific,@Test fun insertAndRead() = runTest { db.userDao().insert(user); assertEquals(user db.userDao().getById(1)) },No migration testing,Always test schema migrations,
|
|
18
|
+
Integration Test,Navigation Test,All,navigation route screen flow test destination,Test navigation flows between screens,Platform-specific,@Test fun navigateToDetail() { navController.navigate('detail/1'); assertEquals('detail/{id}' currentRoute) },Testing only forward navigation,Test back navigation and deep links too,https://developer.android.com/guide/navigation/testing
|
|
19
|
+
Integration Test,E2E Test Android,Android,e2e end to end espresso full flow ui,Test complete user flows on Android,Espresso/UIAutomator,@Test fun loginFlow() { onView(withId(R.id.email)).perform(typeText('test@mail.com')); onView(withId(R.id.login)).perform(click()) },Flaky tests depending on network,Use mock server for deterministic E2E,https://developer.android.com/training/testing/instrumented-tests
|
|
20
|
+
Integration Test,E2E Test iOS,iOS,e2e end to end xcuitest full flow,Test complete user flows on iOS,XCUITest,func testLoginFlow() { app.textFields['email'].typeText('test@mail.com'); app.buttons['Login'].tap(); XCTAssert(app.staticTexts['Welcome'].exists) },Hard-coded sleep waits,Use XCTNSPredicateExpectation for waits,https://developer.apple.com/documentation/xctest/xcuiapplication
|
|
21
|
+
Architecture Test,Dependency Rule Test,All,dependency rule layer architecture archunit,Verify layer dependencies are correct,ArchUnit/custom,@Test fun domainNotDependOnData() { classes().resideIn('domain').should().notDependOn('data') },No architecture enforcement,Add arch tests to CI pipeline,https://www.archunit.org/
|
|
22
|
+
Architecture Test,Module Boundary Test,Android,module boundary dependency graph gradle feature,Verify module dependencies are correct,Custom Gradle task,@Test fun featureNotDependOnFeature() { assertNoDirectDependency(':feature-a' ':feature-b') },Circular module dependencies,Use dependency graph visualization,
|
|
23
|
+
Architecture Test,No Framework in Domain,All,domain clean architecture framework pure kotlin swift,Domain layer must not import framework code,ArchUnit/Lint,@Test fun domainNoFramework() { classes().resideIn('domain').should().notImport('android.') },Domain importing Android/UIKit classes,Domain should only use pure Kotlin/Swift/Dart,
|
|
24
|
+
Architecture Test,Naming Convention Test,All,naming convention test consistency style viewmodel,Enforce naming conventions in codebase,Lint/custom,@Test fun viewModelsNamed() { classes().implementing(ViewModel).should().endWith('ViewModel') },Inconsistent naming across team,Automate naming checks in CI,
|
|
25
|
+
Mocking,Mock Repository,All,mock repository fake test double stub,Create test doubles for data layer,MockK/mocktail,val mockRepo = mockk<UserRepository>(); every { mockRepo.getUser(1) } returns mockUser,Mocking everything including value objects,Only mock external boundaries,
|
|
26
|
+
Mocking,Fake API Server,All,fake server mock api wiremock mockwebserver,Use fake HTTP server for testing,MockWebServer/OHHTTPStubs,server.enqueue(MockResponse().setBody(json)); val result = api.getData(),Mocking HTTP client directly,Mock at HTTP level not client level,https://github.com/square/okhttp/tree/master/mockwebserver
|
|
27
|
+
Mocking,Fake Database,All,fake database inmemory test room coredata,Use in-memory database for testing,Room inMemory/NSInMemoryStoreType,val db = Room.inMemoryDatabaseBuilder(context AppDb::class.java).build(),Using production database in tests,Always use in-memory DB for isolation,https://developer.android.com/training/data-storage/room/testing-db
|
|
28
|
+
Mocking,Test Fixtures,All,fixture factory test data builder objectmother,Create reusable test data builders,ObjectMother pattern,object UserFixture { fun create(name: String = 'John') = User(name 'john@test.com') },Duplicating test data across files,Create shared fixture factories,
|
|
29
|
+
Performance Test,Benchmark Test,Android,benchmark macrobenchmark startup frame metrics,Measure app performance with Macrobenchmark,Macrobenchmark,@Test fun startup() = benchmarkRule.measureRepeated(packageName metrics = listOf(StartupTimingMetric())),Manual timing with System.nanoTime,Use Macrobenchmark for reproducible results,https://developer.android.com/topic/performance/benchmarking/macrobenchmark-overview
|
|
30
|
+
Performance Test,XCTest Metrics,iOS,xctest metrics performance measure signpost,Measure performance in XCTest,XCTest Performance,func testScroll() { measure(metrics: [XCTOSSignpostMetric.scrollDecelerationMetric]) { app.swipeUp() } },No performance regression tests,Add performance tests to CI with baselines,https://developer.apple.com/documentation/xctest/xctmetric
|
|
31
|
+
Performance Test,Flutter Benchmark,Flutter,benchmark integration test performance timeline,Measure Flutter app performance,integration_test,await binding.traceAction(() async { await tester.pumpAndSettle(); } reportKey: 'timeline'),No performance profiling,Use DevTools timeline for frame analysis,https://docs.flutter.dev/perf/benchmarking
|
|
32
|
+
Performance Test,Detox E2E,React Native,detox e2e performance test native,End-to-end testing framework for RN,Detox,test('scroll feed' async () => { await element(by.id('feed')).scroll(500 'down') }),Using Appium for RN testing,Detox is purpose-built for RN,https://wix.github.io/Detox/
|
|
33
|
+
Best Practice,Test Coverage,All,coverage threshold minimum percentage report jacoco,Enforce minimum test coverage,JaCoCo/lcov/Istanbul,jacocoTestReport { violationRules { rule { limit { minimum = 0.80 } } } },100% coverage causing useless tests,Target 80% meaningful coverage focus on logic,https://developer.android.com/studio/test/test-in-android-studio#view_test_coverage
|
|
34
|
+
Best Practice,Test Naming,All,test naming convention describe should when given then,Use consistent descriptive test names,Convention,fun givenLoggedOut_whenLogin_thenNavigateToHome(),test1() test2() testFunction(),Use Given-When-Then or should-when naming,
|
|
35
|
+
Best Practice,Flaky Test Prevention,All,flaky test retry deterministic idempotent stable,Prevent and handle flaky tests,All,Use deterministic data disable animations use test dispatchers,Retry flaky tests and ignore failures,Quarantine flaky tests fix root cause,
|
|
36
|
+
Best Practice,CI Test Pipeline,All,ci cd pipeline github actions test automation pr,Automated test execution in CI,GitHub Actions/Fastlane,jobs: test: steps: - run: ./gradlew testDebugUnitTest,No CI pipeline running tests manually,Run unit tests on every PR UI tests nightly,https://docs.github.com/en/actions
|
|
37
|
+
Unit Test,Compose State Test,Android,compose state test semantics assertion stateflow,Test Compose state changes and emissions in ViewModel,Turbine + JUnit5,@Test fun stateChanges() = runTest { viewModel.state.test { assertEquals(Initial awaitItem()); viewModel.load(); assertEquals(Loading awaitItem()) } },Testing composable rendering instead of state,Use Turbine to test StateFlow emissions,https://github.com/cashapp/turbine
|
|
38
|
+
Unit Test,Coroutine Test,Android,coroutine test runtest dispatcher advancetimeuntilidle,Test suspend functions and coroutine dispatchers,kotlinx-coroutines-test,@Test fun fetchData() = runTest { val result = useCase.execute(); advanceUntilIdle(); assertEquals(expected result) },Using Thread.sleep in tests,Use runTest with TestDispatcher for deterministic timing,https://developer.android.com/kotlin/coroutines/test
|
|
39
|
+
Unit Test,Hilt Test,Android,hilt test injection dependency rule uninstall bind replace,Test with Hilt dependency injection in tests,hilt-android-testing,@HiltAndroidTest class MyTest { @get:Rule val hiltRule = HiltAndroidRule(this); @Inject lateinit var repo: Repo },Manual DI setup in every test,Use @UninstallModules to replace production dependencies,https://developer.android.com/training/dependency-injection/hilt-testing
|
|
40
|
+
Unit Test,Room DAO Test,Android,room dao database test inmemory query insert migration,Test Room DAO queries with in-memory database,Room testing + JUnit4,@Test fun insertAndRead() = runTest { dao.insert(user); val result = dao.getById(1); assertEquals(user result) },Using production database in tests,Use Room.inMemoryDatabaseBuilder for isolated tests,https://developer.android.com/training/data-storage/room/testing-db
|
|
41
|
+
Unit Test,MockK Verification,Android,mockk verify slot capture every coevery,Verify interactions and capture arguments with MockK,MockK,@Test fun savesUser() { every { repo.save(any()) } returns Unit; useCase.execute(user); verify(exactly = 1) { repo.save(user) } },Using Mockito for Kotlin,MockK is Kotlin-first; supports coroutines slots captures,https://mockk.io/
|
|
42
|
+
Unit Test,Flow Test,Android,flow test turbine stateflow sharedflow emission collect,Test Kotlin Flow emissions and error handling,Turbine,@Test fun flowEmissions() = runTest { repository.getData().test { assertEquals(Loading awaitItem()); assertEquals(Success(data) awaitItem()); awaitComplete() } },Collecting flow manually with launch,Use Turbine for declarative Flow testing,https://github.com/cashapp/turbine
|
|
43
|
+
Unit Test,Swift Testing Framework,iOS,swift testing macro test expect suite tag,Test with new Swift Testing framework replacing XCTest,Swift Testing,@Test func userLoads() async throws { let user = try await service.load(); #expect(user.name == 'John') },Using only XCTest for new projects,Swift Testing uses #expect macro; supports tags parameterized tests,https://developer.apple.com/documentation/testing
|
|
44
|
+
Unit Test,Combine Publisher Test,iOS,combine test publisher expectation value failure,Test Combine publisher emissions and completions,XCTest + Combine,func testPublisher() { let expectation = XCTestExpectation(); publisher.sink { value in XCTAssertEqual(value expected); expectation.fulfill() }.store(in: &cancellables) },Not testing Combine chains,Test publishers with expectation pattern,https://developer.apple.com/documentation/combine
|
|
45
|
+
Unit Test,Riverpod Provider Test,Flutter,riverpod provider test override container,Test Riverpod providers with overrides,flutter_riverpod + flutter_test,test('notifier loads data' () async { final container = ProviderContainer(overrides: [apiProvider.overrideWithValue(mockApi)]); await container.read(dataProvider.future); expect(container.read(dataProvider).value data) }),Testing providers through widgets,Use ProviderContainer for isolated provider tests,https://riverpod.dev/docs/essentials/testing
|
|
46
|
+
Unit Test,Jest Mock Module,React Native,jest mock module native spy,Mock native modules and third-party libraries in Jest,Jest,jest.mock('react-native-keychain' () => ({ setGenericPassword: jest.fn() getGenericPassword: jest.fn(() => Promise.resolve({password: 'token'})) })),Not mocking native modules,Mock all native modules in jest.setup.js,https://jestjs.io/docs/mock-functions
|
|
47
|
+
UI Test,Compose Screenshot Test,Android,compose screenshot paparazzi test visual golden regression,Capture and compare Compose UI screenshots for regression,Paparazzi,@Test fun defaultState() { paparazzi.snapshot { MyScreen(state = MyState.Default) } },Brittle pixel-perfect comparisons,Use Paparazzi for fast JVM-based screenshot tests; set tolerance,https://github.com/cashapp/paparazzi
|
|
48
|
+
UI Test,Compose Semantics Test,Android,compose semantics test accessibility contentdescription node,Test Compose accessibility and semantics tree,Compose Testing,@Test fun semantics() { rule.setContent { Screen() }; rule.onNodeWithContentDescription('Settings').assertExists().assertIsEnabled() },Testing visual layout instead of semantics,Semantics-based testing is more stable than visual assertions,https://developer.android.com/develop/ui/compose/testing
|
|
49
|
+
UI Test,Maestro Flow Test,Android,maestro flow yaml e2e automation mobile test,Write E2E tests in YAML for rapid mobile testing,Maestro,appId: com.app; --- tapOn: 'Login'; inputText: 'test@mail.com'; tapOn: 'Submit'; assertVisible: 'Welcome',Complex Espresso setup for simple flows,Maestro uses simple YAML; faster iteration than Espresso,https://maestro.mobile.dev/
|
|
50
|
+
UI Test,Roborazzi Screenshot,Android,roborazzi robolectric screenshot test jvm fast,JVM-based screenshot testing with Robolectric,Roborazzi,@Test fun screenshot() { composeTestRule.setContent { Screen() }; composeTestRule.onRoot().captureRoboImage() },Running screenshot tests on emulator only,Roborazzi runs on JVM; 10x faster than device-based screenshots,https://github.com/takahirom/roborazzi
|
|
51
|
+
UI Test,SwiftUI Preview Test,iOS,swiftui preview snapshot test device configuration,Test SwiftUI previews as screenshot regression tests,swift-snapshot-testing,func testPreview() { assertSnapshot(of: ContentView() as: .image(layout: .device(config: .iPhone15))) },No snapshot testing for SwiftUI,Use swift-snapshot-testing with device configs for visual regression,https://github.com/pointfreeco/swift-snapshot-testing
|
|
52
|
+
UI Test,Flutter Golden Test,Flutter,golden test flutter image comparison visual regression,Compare widget rendering against golden image files,flutter_test,testWidgets('golden' (tester) async { await tester.pumpWidget(MyWidget()); await expectLater(find.byType(MyWidget) matchesGoldenFile('goldens/my_widget.png')) }),No golden tests for design system,Update goldens with --update-goldens flag,https://api.flutter.dev/flutter/flutter_test/matchesGoldenFile.html
|
|
53
|
+
UI Test,Detox iOS Test,iOS,detox ios e2e end test native react,E2E testing for React Native iOS apps,Detox,test('login flow' async () => { await element(by.id('email')).typeText('test@mail.com'); await element(by.id('login')).tap(); await expect(element(by.text('Welcome'))).toBeVisible() }),Using Appium for React Native,Detox has native RN support with synchronization,https://wix.github.io/Detox/
|
|
54
|
+
Integration Test,Contract Test,All,contract test api pact consumer provider driven,Verify API contracts between client and server,Pact/custom,@Test fun userContract() { val response = pact.executeTest { api.getUser(1) }; assertEquals(200 response.status) },Only testing from server side,Consumer-driven contract tests catch API breakage early,https://docs.pact.io/
|
|
55
|
+
Integration Test,Dependency Injection Test,Android,di injection hilt module provides binds test verify,Verify DI graph is complete and correct,Hilt testing,@HiltAndroidTest class DiTest { @get:Rule val hiltRule = HiltAndroidRule(this); @Test fun injects() { hiltRule.inject(); assertNotNull(dependency) } },No DI verification tests,Catches missing bindings before runtime crashes,https://developer.android.com/training/dependency-injection/hilt-testing
|
|
56
|
+
Integration Test,Migration Test,All,migration database schema room version upgrade downgrade,Test database schema migrations,Room MigrationTestHelper,@Test fun migrate1to2() { helper.createDatabase(1).apply { execSQL('INSERT INTO users VALUES(1)') }; val db = helper.runMigrationsAndValidate(2 MIGRATION_1_2); assertEquals(1 db.query('SELECT * FROM users').count) },No migration tests; data loss on update,Test every migration before release,https://developer.android.com/training/data-storage/room/migrating-db-versions
|
|
57
|
+
Integration Test,Deep Link Test,All,deep link test navigation url scheme verify route,Test deep link routing to correct screens,Platform-specific,@Test fun deepLink() { navController.handleDeepLink(Uri.parse('app://user/123')); assertEquals('user/{id}' currentRoute) },No deep link testing,Test all deep link patterns including edge cases,https://developer.android.com/guide/navigation/testing
|
|
58
|
+
Integration Test,Work Manager Test,Android,workmanager test worker constraint periodic background,Test WorkManager workers with test utilities,work-testing,@Test fun worker() { val request = OneTimeWorkRequestBuilder<MyWorker>().build(); val result = workManagerRule.testDriver.enqueue(request); assertEquals(Result.success() result) },No background worker testing,Use TestListenableWorkerBuilder for unit testing workers,https://developer.android.com/topic/libraries/architecture/workmanager/how-to/testing-worker-impl
|
|
59
|
+
Performance Test,Benchmark CI Integration,Android,benchmark ci baseline profile startup regression github actions,Run benchmarks in CI to catch performance regressions,Macrobenchmark + CI,jobs: benchmark: steps: - run: ./gradlew :benchmark:connectedAndroidTest; - uses: benchmark-action/github-action@v1,No CI benchmarks; regressions found by users,Run weekly benchmark suite; alert on > 10% regression,https://developer.android.com/topic/performance/benchmarking/macrobenchmark-overview
|
|
60
|
+
Performance Test,Memory Leak Test,Android,memory leak test leakcanary instrumented detection retained,Detect memory leaks in instrumented tests,LeakCanary,@Test fun noLeaks() { ActivityScenario.launch(MainActivity::class.java).use { it.moveToState(DESTROYED); LeakAssertions.assertNoLeaks() } },No memory leak testing,Integrate LeakCanary assertions into UI test suite,https://square.github.io/leakcanary/recipes/#detecting-leaks-in-tests
|
|
61
|
+
Best Practice,Test Doubles Strategy,All,test double fake mock stub spy strategy boundary,Choose correct test double type for each boundary,Convention,Use fakes for repositories; mocks for verifying interactions; stubs for query responses,Mocking everything including data classes,Only mock at boundaries; use fakes for complex dependencies,
|
|
62
|
+
Best Practice,Property Based Testing,All,property based test hypothesis quickcheck arbitrary generator,Test with generated random inputs for edge case discovery,Kotest/QuickTheories,@Test fun idempotent() { checkAll(Arb.string()) { s -> assertEquals(s parse(serialize(s))) } },Only testing known inputs,Property tests find edge cases manual tests miss,https://kotest.io/docs/proptest/property-test-functions.html
|
|
63
|
+
Best Practice,Test Parallelization,All,parallel test execution concurrent speed ci gradle fork,Speed up test execution with parallelization,Gradle/Jest config,// gradle.properties: maxParallelForks = Runtime.runtime.availableProcessors() / 2,Sequential test execution taking 30 minutes,Enable parallel test execution in CI for faster feedback,
|
|
64
|
+
Best Practice,Mutation Testing,All,mutation testing pitest quality coverage kill ratio,Verify test quality by introducing code mutations,PIT/Pitest,pitest { targetClasses = setOf('com.app.*'); mutationThreshold = 70 },Relying only on code coverage percentage,Mutation testing measures test effectiveness not just coverage,https://pitest.org/
|
|
65
|
+
Mocking,Test Coroutine Dispatcher,Android,testdispatcher coroutine test time control advance,Control coroutine execution timing in tests,kotlinx-coroutines-test,@Test fun delayed() = runTest { viewModel.loadWithDelay(); advanceTimeBy(1000); assertEquals(Loaded viewModel.state.value) },Using Dispatchers.Main in tests without TestDispatcher,Set Main dispatcher to TestDispatcher in @Before,https://developer.android.com/kotlin/coroutines/test
|
|
66
|
+
Mocking,Network Mock Server,All,mock server wiremock mockwebserver http test api fixture,Serve fixture responses for network testing,MockWebServer/WireMock,server.enqueue(MockResponse().setBody(readFixture('user.json')).setResponseCode(200)); val user = api.getUser(1),Mocking Retrofit/URLSession directly,Mock at HTTP layer for realistic testing,https://github.com/square/okhttp/tree/master/mockwebserver
|
|
67
|
+
E2E Test with Maestro,UI Test,Android,maestro e2e end to end flow user journey yaml declarative,End-to-end user flow testing without brittle selectors,Use Maestro for declarative E2E tests; YAML-based; visual assertions,Fragile Espresso tests with exact view IDs; break on every UI refactor,"appId: com.example.app\n---\n- launchApp\n- tapOn: ""Sign In""\n- inputText: ""test@example.com""\n- tapOn: ""Password""\n- inputText: ""password123""\n- tapOn: ""Submit""\n- assertVisible: ""Welcome""",Maestro tests are declarative and resilient to UI changes,https://maestro.mobile.dev/
|
|
68
|
+
XCTest UI Testing,UI Test,iOS,xctest ui test xcuiapplication launch tap swipe assert ios,iOS UI testing with XCTest framework for user flow verification,Use XCUIApplication for UI tests; test critical user flows; use accessibility IDs,Skip UI tests; only unit test; catch no layout or navigation bugs,"let app = XCUIApplication(); app.launch(); app.textFields[""email""].tap(); app.textFields[""email""].typeText(""test@email.com""); XCTAssert(app.buttons[""Submit""].exists)",Use accessibilityIdentifier for reliable element lookup,https://developer.apple.com/documentation/xctest/user_interface_tests
|
|
69
|
+
Widget Golden Test,UI Test,Flutter,golden test screenshot pixel visual regression flutter pump,Flutter visual regression testing via golden file comparison,Use golden tests for UI regression; update goldens intentionally,No visual regression tests; silent UI breaks caught by users,testWidgets('matches golden' (tester) async { await tester.pumpWidget(MyWidget()); await expectLater(find.byType(MyWidget) matchesGoldenFile('goldens/my_widget.png')); });,Run: flutter test --update-goldens to update reference images,https://api.flutter.dev/flutter/flutter_test/matchesGoldenFile.html
|
|
70
|
+
Screenshot Test with Paparazzi,UI Test,Android,paparazzi screenshot jvm compose snapshot test no emulator,JVM-based screenshot tests for Compose without needing emulator,Use Paparazzi for fast JVM screenshot tests; run on CI without emulator,Only run screenshot tests on emulator; slow CI; flaky,@get:Rule val paparazzi = Paparazzi(); @Test fun homeScreen() { paparazzi.snapshot { HomeScreen(FakeHomeState()) } },No emulator needed; runs on JVM; 10x faster than instrumented screenshot tests,https://github.com/cashapp/paparazzi
|
|
71
|
+
Contract Testing,Integration Test,All,contract test api pact consumer driven schema backward compatible,API contract testing to catch breaking backend changes before deploy,Use consumer-driven contract tests; verify API schema compatibility,Only test against live API; discover breaking changes in production,// Pact: define expected request/response pairs; provider verifies; consumer gets contract guarantee,Prevents: backend removes field; mobile app crashes for 30% of users,https://docs.pact.io/
|
|
72
|
+
Accessibility Testing Automation,Integration Test,All,accessibility a11y automated test axe scanner talkback voiceover wcag,Automated accessibility validation in CI pipeline,Run accessibility checks as part of test suite; fail on violations,Manual accessibility testing only; violations shipped to production,// Android: AccessibilityChecks.enable().setRunChecksFromRootView(true); // Then normal Espresso tests auto-check a11y,Catches: missing labels; low contrast; small touch targets; incorrect roles,https://developer.android.com/guide/topics/ui/accessibility/testing
|
|
73
|
+
Fuzz Testing Inputs,Unit Test,All,fuzz test random input boundary edge case property based,Testing with randomized inputs to find edge cases and crashes,Use property-based testing for input validation; random strings; boundary values,Only happy-path tests; app crashes on special characters emoji or 10000-char input,@Test fun parsePrice_handlesAllInputs() { (1..1000).forEach { val random = randomString(); assertDoesNotThrow { parsePrice(random) } } },Find: emoji in names crash; 0-length strings; MAX_INT overflow; Unicode exploits,
|
|
74
|
+
Test Doubles: Fake vs Mock,Best Practice,All,fake mock stub spy test double strategy pattern preference,Choosing between fakes mocks stubs for maintainable tests,Prefer fakes (real implementations) over mocks for complex dependencies,class FakeUserRepository : UserRepository { private val users = mutableListOf<User>(); override suspend fun getAll() = users } // Real behavior; survives refactor,Mock everything; tests coupled to implementation; break on every refactor; every { mockRepo.getAll() } returns listOf(user) // Coupled to implementation; breaks if repo changes,Fakes over mocks for repos,https://testing.googleblog.com/2013/07/testing-on-toilet-know-your-test-doubles.html
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Pattern Name,Platform,Category,Keywords,Use Case,Components,Implementation Notes,Accessibility,Reference URL
|
|
2
|
+
Bottom Navigation,Android,Navigation,"bottom tab navbar material",Main app navigation,NavigationBar|NavController|NavHost,Use Material3 NavigationBar with 3-5 destinations,contentDescription on each tab,https://developer.android.com/develop/ui/compose/components/bottom-navigation
|
|
3
|
+
Tab Layout,Android,Navigation,"tab viewpager swipe sections",Swipeable sections,TabRow|HorizontalPager,Use HorizontalPager in Compose,Tab labels accessible,https://developer.android.com/develop/ui/compose/layouts/pager
|
|
4
|
+
Navigation Drawer,Android,Navigation,"drawer sidebar hamburger menu",Secondary navigation,ModalNavigationDrawer|DrawerState,Use ModalNavigationDrawer in Compose,Drawer toggle labeled,https://developer.android.com/develop/ui/compose/components/drawer
|
|
5
|
+
Tab Bar,iOS,Navigation,"tabbar uitabbar swiftui",Main navigation,TabView|tabItem,Max 5 tabs in TabView,VoiceOver for each tab,https://developer.apple.com/documentation/swiftui/tabview
|
|
6
|
+
Navigation Stack,iOS,Navigation,"navigationstack push pop hierarchical",Hierarchical navigation,NavigationStack|NavigationLink|NavigationPath,Use NavigationStack over deprecated NavigationView,Back button auto-labeled,https://developer.apple.com/documentation/swiftui/navigationstack
|
|
7
|
+
Bottom Navigation Bar,Flutter,Navigation,"bottomnavbar scaffold material",Main navigation,NavigationBar|Scaffold,Use NavigationBar (Material3),semanticsLabel on items,https://api.flutter.dev/flutter/material/NavigationBar-class.html
|
|
8
|
+
GoRouter Navigation,Flutter,Navigation,"gorouter deeplink routing declarative",Deep linking routing,GoRouter|ShellRoute|StatefulShellRoute,Use ShellRoute for nested navigation,Route announcements,https://pub.dev/packages/go_router
|
|
9
|
+
Bottom Tab Navigator,React Native,Navigation,"bottom tab react navigation",Main navigation,createBottomTabNavigator|Tab.Navigator,Use @react-navigation/bottom-tabs,accessibilityLabel on tabs,https://reactnavigation.org/docs/bottom-tab-navigator
|
|
10
|
+
Stack Navigator,React Native,Navigation,"stack push pop screen navigator",Screen-to-screen,createNativeStackNavigator|Stack.Navigator,Prefer native stack for performance,headerBackAccessibilityLabel,https://reactnavigation.org/docs/native-stack-navigator
|
|
11
|
+
Side Menu,All,Navigation,"side menu hamburger drawer secondary",Secondary navigation,DrawerLayout|SideMenu,Swipe gesture + button toggle,Menu toggle accessible,
|
|
12
|
+
Lazy Column,Android,List,"lazycolumn recyclerview scroll vertical",Vertical scrolling list,LazyColumn|items|key,Always provide key for stable recomposition,contentDescription on items,https://developer.android.com/develop/ui/compose/lists
|
|
13
|
+
Lazy Grid,Android,List,"lazygrid grid gallery adaptive",Grid layout,LazyVerticalGrid|GridCells.Adaptive,Use Adaptive for responsive grids,Grid item labels,https://developer.android.com/develop/ui/compose/lists#grids
|
|
14
|
+
List with SwiftUI,iOS,List,"list foreach scrollview data",Data list,List|ForEach|ScrollView,Use List for automatic cell reuse,VoiceOver navigation,https://developer.apple.com/documentation/swiftui/list
|
|
15
|
+
LazyVStack,iOS,List,"lazyvstack lazy loading scrollview",Large data set,LazyVStack|ScrollView,Use LazyVStack inside ScrollView for lazy loading,Accessible labels,https://developer.apple.com/documentation/swiftui/lazyvstack
|
|
16
|
+
ListView Builder,Flutter,List,"listview builder scroll items",Scrollable list,ListView.builder|itemBuilder,Always use builder constructor for long lists,Semantics widget,https://api.flutter.dev/flutter/widgets/ListView-class.html
|
|
17
|
+
SliverList,Flutter,List,"sliver customscrollview complex scroll",Complex scroll layouts,CustomScrollView|SliverList|SliverGrid,Use slivers for mixed scroll content,SemanticsService,https://api.flutter.dev/flutter/widgets/SliverList-class.html
|
|
18
|
+
FlatList,React Native,List,"flatlist scroll performance virtualized",Performant list,FlatList|keyExtractor|renderItem,Always provide keyExtractor avoid inline renderItem,accessibilityRole list,https://reactnative.dev/docs/flatlist
|
|
19
|
+
SectionList,React Native,List,"sectionlist grouped header sections",Grouped data,SectionList|renderSectionHeader,Use for logically grouped data,Section header accessible,https://reactnative.dev/docs/sectionlist
|
|
20
|
+
TextField,Android,Input,"textfield input form material outlined",Text input,TextField|OutlinedTextField|BasicTextField,Use OutlinedTextField for forms with validation,Label and error announced,https://developer.android.com/develop/ui/compose/text/user-input
|
|
21
|
+
Secure Field,iOS,Input,"securefield password secure entry",Password input,SecureField|TextField,Use SecureField for passwords,isSecureTextEntry announced,https://developer.apple.com/documentation/swiftui/securefield
|
|
22
|
+
Form Validation,All,Input,"form validation error inline",Form handling,Form|Validator|ErrorMessage,Show inline errors below fields,Error linked to field,
|
|
23
|
+
Search Bar,All,Input,"searchbar search filter query",Content search,SearchBar|SearchView|SearchAnchor,Debounce search input 300ms,Search role announced,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#SearchBar
|
|
24
|
+
Date Picker,All,Input,"datepicker calendar date selection",Date selection,DatePicker|DatePickerDialog,Use platform native date pickers,Date format announced,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#DatePicker
|
|
25
|
+
Dropdown Menu,All,Input,"dropdown select menu picker",Selection from options,ExposedDropdownMenuBox|Picker|DropdownButton,Avoid custom dropdowns when native exists,Selection announced,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#ExposedDropdownMenuBox
|
|
26
|
+
Slider,All,Input,"slider range seekbar value",Range selection,Slider|RangeSlider,Show current value label,Value announced on change,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#Slider
|
|
27
|
+
Bottom Sheet,Android,Modal,"bottomsheet modal sheet actions",Quick actions,ModalBottomSheet|SheetState,Use ModalBottomSheet in Compose,Sheet draggable announced,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#ModalBottomSheet
|
|
28
|
+
Alert Dialog,All,Modal,"alert dialog popup confirm",Confirmation,AlertDialog|Dialog,Use platform-native AlertDialog,Focus trapped in dialog,https://developer.android.com/develop/ui/compose/components/dialog
|
|
29
|
+
Action Sheet,iOS,Modal,"actionsheet confirmation picker ios",iOS-style actions,confirmationDialog|ActionSheet,Use confirmationDialog in SwiftUI,Actions labeled,https://developer.apple.com/documentation/swiftui/view/confirmationdialog(_:ispresented:titlevisibility:actions:)-46zbb
|
|
30
|
+
Snackbar,All,Feedback,"snackbar toast message brief",Brief feedback,Snackbar|SnackbarHost,Auto-dismiss after 4 seconds,Announced to screen reader,https://developer.android.com/develop/ui/compose/components/snackbar
|
|
31
|
+
Full Screen Dialog,All,Modal,"fullscreen dialog form multistep",Complex input,Dialog fullscreen|fullScreenCover,Use for multi-step forms,Close button accessible,
|
|
32
|
+
Popup Menu,All,Modal,"popup context menu options",Quick options,DropdownMenu|PopupMenuButton|ContextMenu,Show on long press or icon tap,Menu items labeled,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#DropdownMenu
|
|
33
|
+
Empty State,All,State,"empty placeholder illustration nodata",No data,EmptyView|placeholder,Show illustration + message + CTA,Descriptive text for reader,
|
|
34
|
+
Loading Skeleton,All,State,"loading shimmer placeholder skeleton",Data loading,Shimmer|Skeleton|redacted,Prefer skeleton over spinner for content,Loading state announced,
|
|
35
|
+
Error State,All,State,"error retry failure message",Error display,ErrorView|retry button,Show error message + retry button,Error announced,
|
|
36
|
+
Pull to Refresh,All,Interaction,"pull refresh swipe reload data",Data refresh,SwipeRefresh|refreshable|RefreshIndicator,Use platform-native pull to refresh,Refresh state announced,https://developer.android.com/reference/kotlin/androidx/compose/material3/pulltorefresh/package-summary
|
|
37
|
+
Infinite Scroll,All,List,"pagination lazy load infinite scroll endless",Long lists,Paging3|LazyColumn|FlatList onEndReached,Load more when 5 items from bottom,Loading indicator accessible,https://developer.android.com/topic/libraries/architecture/paging/v3-overview
|
|
38
|
+
Offline State,All,State,"offline no connection network",No internet,ConnectivityManager|NWPathMonitor,Cache data for offline + show banner,Connectivity change announced,https://developer.android.com/training/monitoring-device-state/connectivity-status-type
|
|
39
|
+
Card Layout,All,Layout,"card elevation surface container",Content container,Card|ElevatedCard|Surface,Use consistent elevation system,Card as button if clickable,https://developer.android.com/develop/ui/compose/components/card
|
|
40
|
+
Responsive Layout,All,Layout,"responsive adaptive screen size multiscreen",Multi-screen support,BoxWithConstraints|GeometryReader|LayoutBuilder,Use window size classes on Android,Content reflows properly,https://developer.android.com/develop/ui/compose/layouts/adaptive
|
|
41
|
+
Sticky Header,All,Layout,"sticky header pinned section",Section headers,stickyHeader|pinnedItems|SliverPersistentHeader,Use for categorized content,Header remains visible,https://developer.android.com/develop/ui/compose/lists#sticky-headers
|
|
42
|
+
Collapsing Toolbar,Android,Layout,"collapsing toolbar appbar scroll",Scrollable header,LargeTopAppBar|TopAppBarScrollBehavior,Use exitUntilCollapsed scroll behavior,Title announced,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#LargeTopAppBar
|
|
43
|
+
Floating Action Button,Android,Layout,"fab action primary button material",Primary action,FloatingActionButton|ExtendedFAB,One FAB per screen max,Action label required,https://developer.android.com/develop/ui/compose/components/fab
|
|
44
|
+
Safe Area,All,Layout,"safearea inset notch edge-to-edge",Edge-to-edge,SafeArea|safeAreaInset|SafeAreaView,Always respect safe area insets,No content behind system UI,https://developer.android.com/develop/ui/compose/layouts/insets
|
|
45
|
+
Image Loading,All,Media,"image loading cache placeholder remote",Remote images,Coil|Kingfisher|CachedNetworkImage|FastImage,Always show placeholder + error state,Alt text on images,
|
|
46
|
+
Video Player,All,Media,"video player stream media playback",Video playback,ExoPlayer|AVPlayer|video_player|react-native-video,Preload next video in list,Captions support,https://developer.android.com/media/media3/exoplayer
|
|
47
|
+
Image Carousel,All,Media,"carousel pager gallery swipe images",Image gallery,HorizontalPager|TabView|PageView|PagerView,Show page indicator,Current page announced,https://developer.android.com/develop/ui/compose/layouts/pager
|
|
48
|
+
Avatar,All,Media,"avatar profile image circle user",User profile pic,AsyncImage|CircleAvatar|Image,Show initials as fallback,User name in alt text,
|
|
49
|
+
Toast Message,All,Feedback,"toast short message notification",Brief notification,Toast|Snackbar|Fluttertoast,Max 2 lines of text,Auto-dismiss announced,
|
|
50
|
+
Progress Indicator,All,Feedback,"progress loading spinner circular linear",Loading state,CircularProgressIndicator|ProgressView,Use determinate when progress known,Progress percentage announced,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#CircularProgressIndicator
|
|
51
|
+
Badge,All,Feedback,"badge notification count dot indicator",Count indicator,Badge|BadgedBox,Use dot for boolean or count for number,Badge count announced,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#Badge
|
|
52
|
+
Rating Bar,All,Feedback,"rating stars review score",User rating,RatingBar|custom stars,Use 5-star standard,Current rating announced,
|
|
53
|
+
Swipe to Delete,All,Interaction,"swipe dismiss delete gesture remove",Item removal,SwipeToDismiss|swipeActions|Dismissible,Require confirmation for destructive,Swipe action labeled,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#SwipeToDismissBox
|
|
54
|
+
Drag and Drop,All,Interaction,"drag drop reorder sort items",Reordering,DragAndDrop|draggable|Reorderable,Show visual feedback during drag,Drag handle accessible,https://developer.android.com/develop/ui/compose/touch-input/user-interactions
|
|
55
|
+
Long Press Menu,All,Interaction,"long press context menu haptic",Context actions,combinedClickable|contextMenu|GestureDetector,Trigger haptic feedback,Alternative accessible trigger,
|
|
56
|
+
Pinch to Zoom,All,Interaction,"pinch zoom gesture scale image",Image zoom,transformable|MagnifyGesture|InteractiveViewer,Double-tap to zoom alternative,Zoom level announced,
|
|
57
|
+
Edge-to-Edge,Android,Layout,edge-to-edge inset status bar navigation bar transparent,Full-screen immersive UI,enableEdgeToEdge()|WindowInsets|Modifier.systemBarsPadding,Required in Android 15+; handle insets with Modifier.systemBarsPadding,Content not behind system UI,https://developer.android.com/develop/ui/views/layout/edge-to-edge
|
|
58
|
+
Predictive Back,Android,Navigation,predictive back gesture animation android 14 15 cross-activity,Smooth back navigation with preview,PredictiveBackHandler|enableEdgeToEdge|SharedTransition,Android 14+; shows previous screen preview during back gesture,Back gesture announced,https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture
|
|
59
|
+
Top App Bar Variants,Android,Navigation,topappbar small medium large center material3,App bar styles,TopAppBar|MediumTopAppBar|LargeTopAppBar|CenterAlignedTopAppBar,Choose based on content; LargeTopAppBar for scrollable content,Title and actions labeled,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#TopAppBar
|
|
60
|
+
Navigation Rail,Android,Navigation,navigation rail tablet desktop large screen side,Side navigation for large screens,NavigationRail|WindowSizeClass,Use NavigationRail for medium+ width; NavigationBar for compact,Rail items labeled,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#NavigationRail
|
|
61
|
+
Compose Animation,Android,Animation,compose animation animate content size visibility transition,Smooth state transitions,AnimatedVisibility|animateContentSize|Crossfade|AnimatedContent,Use AnimatedContent for state changes; animateContentSize for layout,Motion reduced respected,https://developer.android.com/develop/ui/compose/animation/introduction
|
|
62
|
+
Material 3 Dynamic Color,Android,Theme,material3 dynamic color monet wallpaper theme,Device-personalized colors,dynamicLightColorScheme|dynamicDarkColorScheme|MaterialTheme,Fallback to static scheme on API < 31; test both dynamic and static,Contrast maintained,https://developer.android.com/develop/ui/compose/designsystems/material3#dynamic-color
|
|
63
|
+
Adaptive Layout,Android,Layout,adaptive layout windowsizeclass compact medium expanded foldable,Responsive layouts for all screens,WindowSizeClass|calculateWindowSizeClass|NavigationSuiteScaffold,Compact=phone Medium=foldable/tablet Expanded=desktop,Content readable at all sizes,https://developer.android.com/develop/ui/compose/layouts/adaptive
|
|
64
|
+
Compose Shared Element,Android,Animation,shared element transition compose navigation hero,Shared element transitions between screens,SharedTransitionLayout|sharedElement|AnimatedVisibility,Use with Navigation Compose for hero animations between routes,Motion reduced respected,https://developer.android.com/develop/ui/compose/animation/shared-elements
|
|
65
|
+
Search Anchor,Android,Input,search anchor compose expandable suggestion material3,Expandable search bar with suggestions,SearchBar|DockedSearchBar|SearchBarDefaults,Material 3 search pattern; show recent and suggestion chips,Search announced,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#SearchBar
|
|
66
|
+
SwiftUI NavigationSplitView,iOS,Navigation,navigationsplitview sidebar detail ipad mac catalyst,Multi-column navigation for iPad,NavigationSplitView|sidebar|content|detail,Use for iPad and Mac Catalyst; adapts to compact on iPhone,Column navigation announced,https://developer.apple.com/documentation/swiftui/navigationsplitview
|
|
67
|
+
SwiftUI ScrollView Enhancements,iOS,List,scrollview scroll position content margins ios17,Enhanced scrolling with content margins and scroll position,ScrollView|scrollPosition|contentMargins|scrollTargetBehavior,iOS 17+; programmatic scroll position; paging behavior,Scroll position announced,https://developer.apple.com/documentation/swiftui/scrollview
|
|
68
|
+
SwiftUI Animation,iOS,Animation,swiftui animation withanimation spring phase keyframe,Declarative animations,withAnimation|PhaseAnimator|KeyframeAnimator|SpringAnimation,Use PhaseAnimator for multi-step; KeyframeAnimator for complex,Reduce motion respected,https://developer.apple.com/documentation/swiftui/animation
|
|
69
|
+
Flutter Sliver AppBar,Flutter,Navigation,sliver appbar collapsing flexible scroll custom,Flexible collapsing header,SliverAppBar|flexibleSpace|CustomScrollView|SliverList,Use with CustomScrollView; pinned=true for sticky,Header title announced,https://api.flutter.dev/flutter/material/SliverAppBar-class.html
|
|
70
|
+
Flutter Adaptive Scaffold,Flutter,Layout,adaptive scaffold responsive breakpoint material,Responsive scaffold for all screen sizes,AdaptiveScaffold|Breakpoints|NavigationRail|BottomNavigationBar,material3 adaptive scaffold; auto-switches navigation style,Content adapts properly,https://pub.dev/packages/flutter_adaptive_scaffold
|
|
71
|
+
Flutter Hero Animation,Flutter,Animation,hero animation transition shared element tag,Shared element animation between routes,Hero|tag|createRectTween|flightShuttleBuilder,Wrap both source and destination with same Hero tag,Transition announced,https://docs.flutter.dev/ui/animations/hero-animations
|
|
72
|
+
Flutter Material 3,Flutter,Theme,material3 usematerial3 color scheme seed dynamic,Material 3 theming,useMaterial3|ColorScheme.fromSeed|ThemeData,Use ColorScheme.fromSeed for consistent M3 theme,Contrast ratios met,https://docs.flutter.dev/ui/design/material
|
|
73
|
+
RN Bottom Sheet,React Native,Modal,bottom sheet modal gesture snap points react native,Gesture-enabled bottom sheet,@gorhom/bottom-sheet|BottomSheetModal|snapPoints,Use @gorhom/bottom-sheet for gesture handling and snap points,Sheet draggable announced,https://gorhom.github.io/react-native-bottom-sheet/
|
|
74
|
+
RN Animated Header,React Native,Navigation,animated header scroll collapse reanimated parallax,Collapsing header on scroll,Animated.ScrollView|useAnimatedScrollHandler|interpolate,Use Reanimated for smooth header collapse/expand on scroll,Header title accessible,https://docs.swmansion.com/react-native-reanimated/
|
|
75
|
+
RN Skeleton Loader,React Native,State,skeleton loader placeholder shimmer content loading rn,Content placeholder during loading,rn-placeholder|MotiSkeleton|Animated.View,Show skeleton matching content layout; animate shimmer,Loading state announced,
|
|
76
|
+
Chip Group,All,Input,chip filter choice action material selection tag,Selection chips for filtering,FilterChip|AssistChip|SuggestionChip|ChipGroup,Use FilterChip for multi-select; AssistChip for actions,Chip selection announced,https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#FilterChip
|
|
77
|
+
Permission Request Dialog,All,Permission,permission request dialog rationale camera location context explain why,Contextual dialog explaining why permission is needed before system prompt,Before requesting sensitive permissions show custom UI explaining the benefit,Custom Dialog|Icon showing feature|Clear benefit text|Skip/Allow buttons,Show rationale before system dialog; explain benefit not technical name; handle denial gracefully,https://developer.android.com/training/permissions/requesting
|
|
78
|
+
Onboarding Carousel,All,Onboarding,onboarding carousel walkthrough introduction first launch feature tour,Multi-step intro showing key features on first launch,First app launch; major feature introduction after update; premium feature showcase,HorizontalPager|Page indicators|Skip button|Get Started CTA|Illustrations,Max 3-4 pages; allow skipping; show progress dots; animate transitions; only show once,
|
|
79
|
+
Empty State,All,State,empty state zero data placeholder illustration call to action onboarding,Informative placeholder when list or screen has no content,Empty lists; no search results; first-time experience; error recovery,Illustration|Title|Description|Primary CTA button|Optional secondary action,Show actionable CTA; use friendly illustrations; explain how to add content; different for first-time vs filtered-empty,https://material.io/design/communication/empty-states
|
|
80
|
+
Settings Screen,All,Navigation,settings preferences configuration account profile theme language notification,Organized app settings with categories and toggles,App settings; account management; preference configuration,Section headers|Toggle switches|Navigation rows|Destructive actions at bottom|Version info footer,Group logically; destructive actions (delete account log out) at bottom with confirmation; show current values,https://developer.android.com/develop/ui/compose/components/preferences
|
|
81
|
+
Error State with Retry,All,Feedback,error state retry network failure offline placeholder recoverable,User-friendly error display with action to retry,Network failures; server errors; timeout; parse errors; offline detection,Error illustration|Title|Description|Retry button|Optional offline indicator,Show friendly message not error code; offer retry; detect offline vs server error; suggest alternatives,
|
|
82
|
+
Skeleton Loading,All,Feedback,skeleton loading shimmer placeholder content shape pulse animation,Placeholder UI mimicking content layout while loading,List loading; profile loading; feed refresh; initial data fetch,Shimmer rectangles|Content-shaped placeholders|Pulse animation|Match actual layout structure,Match real content shape; use subtle shimmer animation; avoid spinner for content areas; show 3-5 placeholder items,https://developer.android.com/develop/ui/compose/animation/quick-guide
|
|
83
|
+
Floating Action Button Menu,Android,Interaction,fab floating action button expanded menu speed dial compose material3,Expandable FAB with multiple related actions,Create/add actions; quick actions that share context; 2-4 related actions,ExtendedFAB|SmallFAB items|Labels|Scrim overlay|Smooth expand animation,Max 4-6 actions; most common action as main FAB; collapse on selection; animate expansion,https://developer.android.com/develop/ui/compose/components/fab
|
|
84
|
+
Adaptive Navigation,All,Navigation,adaptive navigation rail drawer bottom bar responsive tablet phone foldable,Navigation that adapts between bottom bar rail and drawer based on screen size,Phone shows bottom bar; tablet shows nav rail; desktop shows full nav drawer,NavigationSuiteScaffold|BottomNavigation|NavigationRail|NavigationDrawer|Window size class,Use NavigationSuiteScaffold (Compose); test all breakpoints; maintain state across configuration changes,https://developer.android.com/develop/ui/compose/layouts/adaptive
|
|
85
|
+
Chip Filter Bar,All,Input,chip filter tag category select deselect material3 horizontal,Horizontal scrollable chip row for filtering content,Category filtering; multi-select tags; quick filter toggles; search refinement,LazyRow of FilterChip|Selected state|Clear all button|Scroll indicators,Max 2 rows visible; show selected count; 'Clear all' option; scroll to show overflow; haptic on select,https://developer.android.com/develop/ui/compose/components/chip
|
|
86
|
+
Segmented Button,All,Input,segmented button toggle group selector material3 radio alternative,Multi-option toggle replacing radio buttons; Material3 component,View selector (List/Grid/Map); time range (Day/Week/Month); filter mode,SingleChoiceSegmentedButtonRow|Segments|Icons+Labels|Selected state,Max 5 segments; use icons+labels; animate selection; clear selected styling,https://developer.android.com/develop/ui/compose/components/button#segmented
|
|
87
|
+
Expandable Card,All,Layout,expandable collapsible card accordion faq section animated,Card that expands to reveal additional content with animation,FAQ section; settings with details; order summary; expandable list items,AnimatedVisibility|Icon rotation|Content reveal|Smooth height animation,Animate expand/collapse; rotate chevron icon; keep expanded state on scroll,
|
|
88
|
+
Stepper / Wizard,All,Navigation,stepper wizard multi step form progress indicator sequential,Multi-step form with progress tracking and step validation,Checkout flow; onboarding; registration; setup wizard; booking process,Step indicators|Back/Next buttons|Validation per step|Progress bar|Step content,Validate before next; allow back without losing data; show total steps; persist draft,
|
|
89
|
+
Bottom App Bar with FAB,Android,Layout,bottom app bar fab compose material3 cutout actions,Bottom app bar with embedded FAB and navigation actions; Material3,Primary screens with main action (compose/add) plus secondary navigation actions,BottomAppBar|FAB cutout|NavigationBarItem icons|Overflow menu,FAB for primary action; max 4 icons in bar; use outline icons for unselected,https://developer.android.com/develop/ui/compose/components/app-bars#bottom
|
|
90
|
+
Swipe Card / Tinder Style,All,Interaction,swipe card tinder style gesture dismiss left right action,Cards that user swipes left/right to take action; dating/decision UI,Dating apps; decision making; card review; flashcards; product discovery,DraggableCard|Swipe gesture|Action indicators|Stack of cards|Spring animation,Show action hint on partial swipe; spring back on incomplete swipe; animate card behind,
|
|
91
|
+
Contextual Action Bar,All,Interaction,contextual action bar selection mode multi select bulk action toolbar,Toolbar that appears when items are selected for bulk actions,Multi-select in lists; bulk delete/move/share; email-style selection,SelectionToolbar|Select all|Count badge|Action icons|Close selection,Show count of selected; 'Select all' option; replace normal toolbar; animate entrance,
|
|
92
|
+
In-App Review Prompt,Android,Feedback,in app review rating play store prompt timing strategy,Google Play In-App Review API for requesting ratings at the right moment,After positive experience; after achievement; after N sessions; not too early,ReviewManager|ReviewInfo|LaunchReviewFlow|Timing logic,Don't ask before value; after positive moment; respect quota; don't interrupt flow,https://developer.android.com/guide/playcore/in-app-review
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Pre-Delivery Checklist
|
|
2
|
+
|
|
3
|
+
Before delivering mobile code, verify all applicable items.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
- [ ] Proper separation of concerns (UI / ViewModel / Repository / DataSource)
|
|
7
|
+
- [ ] Dependency injection configured (Hilt for Android)
|
|
8
|
+
- [ ] Repository pattern for data access
|
|
9
|
+
- [ ] Sealed interface for UI state (Loading, Success, Error, Empty)
|
|
10
|
+
- [ ] One-shot events via Channel (not SharedFlow replay=0)
|
|
11
|
+
|
|
12
|
+
## Compose (Android)
|
|
13
|
+
- [ ] collectAsStateWithLifecycle (NOT collectAsState)
|
|
14
|
+
- [ ] LazyColumn with stable keys and contentType
|
|
15
|
+
- [ ] rememberSaveable for user input state
|
|
16
|
+
- [ ] Proper Modifier ordering (clickable before padding)
|
|
17
|
+
- [ ] Material3 components (Scaffold, TopAppBar, NavigationBar)
|
|
18
|
+
- [ ] @Preview for all screens with sample data
|
|
19
|
+
|
|
20
|
+
## Gradle (Android)
|
|
21
|
+
- [ ] Version Catalog (libs.versions.toml) for all dependencies
|
|
22
|
+
- [ ] Compose BOM managing Compose versions
|
|
23
|
+
- [ ] KSP for annotation processing (not KAPT)
|
|
24
|
+
- [ ] Correct configurations (implementation vs api vs testImplementation)
|
|
25
|
+
|
|
26
|
+
## Performance
|
|
27
|
+
- [ ] Lists use lazy/virtualized components with keys
|
|
28
|
+
- [ ] Images cached and sized appropriately (Coil with size())
|
|
29
|
+
- [ ] No work on main thread (network, DB, heavy computation)
|
|
30
|
+
- [ ] derivedStateOf for computed values
|
|
31
|
+
|
|
32
|
+
## Security
|
|
33
|
+
- [ ] No hardcoded secrets/API keys
|
|
34
|
+
- [ ] Sensitive data in secure storage (EncryptedSharedPreferences/Keychain)
|
|
35
|
+
- [ ] HTTPS for all network calls
|
|
36
|
+
- [ ] Input validation on user inputs
|
|
37
|
+
- [ ] R8/ProGuard enabled for release builds
|
|
38
|
+
|
|
39
|
+
## Testing
|
|
40
|
+
- [ ] Unit tests for ViewModels (runTest + Turbine + MockK)
|
|
41
|
+
- [ ] Mocked dependencies in tests
|
|
42
|
+
- [ ] Error states tested
|
|
43
|
+
- [ ] Compose UI tests for critical screens
|
|
44
|
+
|
|
45
|
+
## Accessibility
|
|
46
|
+
- [ ] contentDescription on Images and IconButtons
|
|
47
|
+
- [ ] Sufficient color contrast
|
|
48
|
+
- [ ] Touch targets minimum 48dp
|
|
49
|
+
- [ ] Screen reader navigation works
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Code Generation Rules
|
|
2
|
+
|
|
3
|
+
When generating mobile code, ALWAYS follow these rules.
|
|
4
|
+
|
|
5
|
+
## Android Default Stack (Jetpack Compose)
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Architecture: MVVM + Clean Architecture + Repository Pattern
|
|
9
|
+
DI: Hilt (@HiltViewModel, @Inject, @Module)
|
|
10
|
+
UI: Jetpack Compose + Material3
|
|
11
|
+
State: StateFlow + sealed interface UiState
|
|
12
|
+
Events: Channel<Event> for one-shot (navigation, snackbar)
|
|
13
|
+
Navigation: Navigation Compose with @Serializable type-safe routes
|
|
14
|
+
Network: Retrofit + Moshi + OkHttp
|
|
15
|
+
Database: Room + KSP
|
|
16
|
+
Image: Coil (AsyncImage)
|
|
17
|
+
Async: Coroutines + Flow (viewModelScope, Dispatchers.IO)
|
|
18
|
+
Testing: JUnit5 + MockK + Turbine + Compose Test
|
|
19
|
+
Build: Version Catalog (libs.versions.toml) + KSP
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Always Use Sealed Interface for UiState
|
|
23
|
+
|
|
24
|
+
```kotlin
|
|
25
|
+
sealed interface HomeUiState {
|
|
26
|
+
data object Loading : HomeUiState
|
|
27
|
+
data class Success(val items: List<Item>) : HomeUiState
|
|
28
|
+
data class Error(val message: String) : HomeUiState
|
|
29
|
+
data object Empty : HomeUiState
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Always Use @HiltViewModel Pattern
|
|
34
|
+
|
|
35
|
+
```kotlin
|
|
36
|
+
@HiltViewModel
|
|
37
|
+
class HomeViewModel @Inject constructor(
|
|
38
|
+
private val repository: HomeRepository
|
|
39
|
+
) : ViewModel() {
|
|
40
|
+
private val _uiState = MutableStateFlow<HomeUiState>(HomeUiState.Loading)
|
|
41
|
+
val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow()
|
|
42
|
+
|
|
43
|
+
fun loadData() {
|
|
44
|
+
viewModelScope.launch {
|
|
45
|
+
_uiState.value = HomeUiState.Loading
|
|
46
|
+
try {
|
|
47
|
+
val data = repository.getData()
|
|
48
|
+
_uiState.value = if (data.isEmpty()) HomeUiState.Empty
|
|
49
|
+
else HomeUiState.Success(data)
|
|
50
|
+
} catch (e: Exception) {
|
|
51
|
+
_uiState.value = HomeUiState.Error(e.message ?: "Unknown error")
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Always Use collectAsStateWithLifecycle
|
|
59
|
+
|
|
60
|
+
```kotlin
|
|
61
|
+
@Composable
|
|
62
|
+
fun HomeScreen(viewModel: HomeViewModel = hiltViewModel()) {
|
|
63
|
+
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
|
64
|
+
|
|
65
|
+
when (val state = uiState) {
|
|
66
|
+
is HomeUiState.Loading -> LoadingIndicator()
|
|
67
|
+
is HomeUiState.Success -> ItemList(state.items)
|
|
68
|
+
is HomeUiState.Error -> ErrorMessage(state.message, onRetry = viewModel::loadData)
|
|
69
|
+
is HomeUiState.Empty -> EmptyState()
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Follow Platform Conventions
|
|
75
|
+
|
|
76
|
+
| Platform | Stack |
|
|
77
|
+
|----------|-------|
|
|
78
|
+
| **Android** | Jetpack Compose + Hilt + Room + Retrofit + Coil + Navigation Compose |
|
|
79
|
+
| **iOS** | SwiftUI + Combine/async-await + SwiftData/CoreData + URLSession + Kingfisher |
|
|
80
|
+
| **Flutter** | BLoC/Riverpod + Dio + Drift/Hive + GoRouter + CachedNetworkImage |
|
|
81
|
+
| **React Native** | Redux Toolkit/Zustand + Axios/React Query + MMKV + React Navigation + FastImage |
|
|
82
|
+
|
|
83
|
+
## Anti-Patterns to ALWAYS Avoid
|
|
84
|
+
|
|
85
|
+
**All Platforms:**
|
|
86
|
+
- God classes (500+ lines)
|
|
87
|
+
- Hardcoded strings/colors
|
|
88
|
+
- No error handling
|
|
89
|
+
- Memory leaks
|
|
90
|
+
- Blocking main thread
|
|
91
|
+
- Hardcoded API keys
|
|
92
|
+
- Storing secrets in plain preferences/UserDefaults
|
|
93
|
+
- No tests
|
|
94
|
+
|
|
95
|
+
**Android Specific:**
|
|
96
|
+
- Business logic in Activities/Fragments
|
|
97
|
+
- Direct database access in UI layer
|
|
98
|
+
- GlobalScope for coroutines (use viewModelScope)
|
|
99
|
+
- collectAsState without lifecycle (use collectAsStateWithLifecycle)
|
|
100
|
+
- Not handling process death (use SavedStateHandle)
|
|
101
|
+
- KAPT instead of KSP (KSP is 2x faster)
|
|
102
|
+
- Hardcoded versions in build.gradle (use Version Catalog)
|
|
103
|
+
- Toast for user feedback (use Snackbar with SnackbarHostState)
|
|
104
|
+
|
|
105
|
+
**iOS Specific:**
|
|
106
|
+
- Force unwrapping optionals (!!)
|
|
107
|
+
- Retain cycles in closures (missing [weak self])
|
|
108
|
+
- @ObservedObject for ViewModel creation (use @StateObject)
|
|
109
|
+
- NavigationView instead of NavigationStack
|
|
110
|
+
|
|
111
|
+
**Flutter Specific:**
|
|
112
|
+
- setState for complex state management
|
|
113
|
+
- Business logic in build methods
|
|
114
|
+
- Not disposing controllers
|
|
115
|
+
- Non-const constructors for static widgets
|
|
116
|
+
- Column/Row instead of LazyColumn for long lists
|
|
117
|
+
|
|
118
|
+
**React Native Specific:**
|
|
119
|
+
- Prop drilling through many layers
|
|
120
|
+
- Missing useEffect cleanup
|
|
121
|
+
- Missing useEffect dependencies
|
|
122
|
+
- ScrollView for long lists (use FlatList/FlashList)
|
|
123
|
+
- Inline styles in render (use StyleSheet.create)
|
|
Binary file
|