{"id":"d8c052bf-2ddd-4061-bda4-42dc5c6b4267","shortId":"HB383r","kind":"skill","title":"cometchat-android-v5-testing","tagline":"Testing patterns for CometChat Android — JUnit + Mockito setup, mocking the SDK, Espresso UI tests, E2E with Maestro, and CI integration.","description":"> **Companion skills:** `cometchat-android-v5-core` covers init/login patterns you're testing;\n> `cometchat-android-v5-components` covers component APIs to assert against.\n\n## Purpose\n\nThis skill teaches how to write and run tests against a CometChat Android integration. Covers unit tests with JUnit + Mockito/MockK, UI tests with Espresso, E2E with Maestro, and CI integration.\n\n---\n\n## Use this skill when\n\n- \"Add tests for my CometChat integration\"\n- \"How do I mock CometChat in tests?\"\n- \"Set up E2E testing\"\n- \"CI pipeline for chat tests\"\n\n## Do not use this skill when\n\n- Setting up the integration → use `cometchat-android-v5-core`\n- Diagnosing runtime issues → use `cometchat-android-v5-troubleshooting`\n\n---\n\n## 1. What to test vs what to skip\n\n**Worth testing:**\n- Custom components you wrote (custom bubbles, headers, empty states)\n- Navigation logic triggered by CometChat events (push tap → deep-link)\n- Init/login lifecycle (init before login, already-logged-in skip)\n- Production auth token refresh logic\n- User-ID mapping (your auth system → CometChat UID)\n\n**Skip:**\n- UIKit internals — that's CometChat's responsibility\n- Realtime delivery (A sends, B receives) — requires real servers, flaky\n- Presence/typing indicators — race-prone\n- Snapshot tests of CometChat components — theme changes churn them\n\n**Golden rule:** if the test fails because YOUR code changed, it's valuable. If it fails because the UIKit updated, it's churn.\n\n---\n\n## 2. Toolchain\n\n| Layer | Tool | Why |\n|---|---|---|\n| Unit tests | JUnit 4 + Mockito / MockK | Standard Android unit testing |\n| Component tests | Robolectric | Run Android component tests without emulator |\n| UI tests | Espresso | Android's native UI testing framework |\n| E2E | Maestro | Declarative YAML flows, fast, stable |\n| CI | GitHub Actions / Bitrise | Automated test runs |\n\n---\n\n## 3. Mocking the CometChat SDK\n\n**Java (Mockito):**\n```java\n@RunWith(MockitoJUnitRunner.class)\npublic class ChatViewModelTest {\n    @Test\n    public void testLoginCallsInit() {\n        try (MockedStatic<CometChatUIKit> mocked = mockStatic(CometChatUIKit.class)) {\n            mocked.when(CometChatUIKit::getLoggedInUser).thenReturn(null);\n            mocked.when(CometChatUIKit::isSDKInitialized).thenReturn(true);\n\n            // Test your ViewModel or helper that calls login\n            // Verify init was called before login\n        }\n    }\n}\n```\n\n**Kotlin (MockK):**\n```kotlin\n@Test\nfun `already logged in skips login`() {\n    mockkStatic(CometChatUIKit::class)\n    every { CometChatUIKit.getLoggedInUser() } returns mockk<User>()\n\n    // Your code should skip login\n    verify(exactly = 0) { CometChatUIKit.login(any(), any()) }\n\n    unmockkAll()\n}\n```\n\n---\n\n## 4. Espresso UI tests\n\n```java\n@RunWith(AndroidJUnit4.class)\npublic class MessagesActivityTest {\n    @Rule\n    public ActivityScenarioRule<MessagesActivity> rule =\n        new ActivityScenarioRule<>(MessagesActivity.class);\n\n    @Test\n    public void messageListIsDisplayed() {\n        onView(withId(R.id.messageList)).check(matches(isDisplayed()));\n    }\n\n    @Test\n    public void composerIsDisplayed() {\n        onView(withId(R.id.composer)).check(matches(isDisplayed()));\n    }\n}\n```\n\n---\n\n## 5. E2E with Maestro\n\n`.maestro/chat-happy-path.yaml`:\n```yaml\nappId: com.yourapp.android\n---\n- launchApp\n- tapOn: \"Login\"\n- inputText: \"cometchat-uid-1\"\n- tapOn: \"Continue\"\n- assertVisible: \"Chats\"\n- tapOn:\n    id: \"conversations\"\n    index: 0\n- assertVisible: \"Type a message\"\n- inputText: \"Hello from Maestro\"\n- tapOn:\n    id: \"send_button\"\n- assertVisible: \"Hello from Maestro\"\n```\n\nRun: `maestro test .maestro/chat-happy-path.yaml`\n\n---\n\n## 6. CI integration\n\n```yaml\n# .github/workflows/test.yml\nname: test\non: [push, pull_request]\njobs:\n  unit-tests:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-java@v4\n        with:\n          java-version: 17\n          distribution: temurin\n      - run: ./gradlew test\n```\n\n---\n\n## 7. Common failure modes\n\n| Symptom | Cause | Fix |\n|---|---|---|\n| `NoClassDefFoundError: CometChat` | SDK not mocked | Add Mockito/MockK mock for static methods |\n| Espresso test hangs | Async CometChat operation | Register `IdlingResource` |\n| Tests pass locally, fail on CI | Emulator not booted | Pin emulator API level in CI |\n| `IllegalStateException: not initialized` | `init()` not called in test setup | Mock `isSDKInitialized()` to return `true` |\n\n---\n\n## Hard rules\n\n- **Mock the SDK in every unit test.** Running real CometChat requires network + servers.\n- **Don't test UIKit internals.** You're responsible for YOUR code.\n- **Skip realtime tests.** They require real servers and produce flaky suites.\n- **Assert on view IDs and state, not pixels.** Theme changes churn pixel assertions.\n- **E2E runs on emulator/device, not JUnit.** Don't test real CometChat flow in unit tests.","tags":["cometchat","android","testing","skills","agent-skills","ai-agent","chat","claude-code","cursor","messaging","nextjs","react"],"capabilities":["skill","source-cometchat","skill-cometchat-android-v5-testing","topic-agent-skills","topic-ai-agent","topic-chat","topic-claude-code","topic-cometchat","topic-cursor","topic-messaging","topic-nextjs","topic-react","topic-react-native","topic-ui-kit"],"categories":["cometchat-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cometchat/cometchat-skills/cometchat-android-v5-testing","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cometchat/cometchat-skills","source_repo":"https://github.com/cometchat/cometchat-skills","install_from":"skills.sh"}},"qualityScore":"0.463","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 27 github stars · SKILL.md body (4,887 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:04:45.379Z","embedding":null,"createdAt":"2026-05-07T13:05:04.396Z","updatedAt":"2026-05-18T19:04:45.379Z","lastSeenAt":"2026-05-18T19:04:45.379Z","tsv":"'/gradlew':481 '0':358,424 '1':132,415 '17':477 '2':241 '3':288 '4':249,363 '5':400 '6':445 '7':483 'action':283 'actions/checkout':468 'actions/setup-java':471 'activityscenariorul':375,378 'add':85,495 'alreadi':168,339 'already-logged-in':167 'android':3,10,30,41,63,120,129,253,260,268 'androidjunit4.class':369 'api':46,520 'appid':406 'assert':48,575,587 'assertvis':418,425,437 'async':504 'auth':173,182 'autom':285 'b':198 'bitris':284 'boot':517 'bubbl':147 'button':436 'call':326,331,529 'caus':488 'chang':215,227,584 'chat':105,419 'chatviewmodeltest':300 'check':387,397 'churn':216,240,585 'ci':24,79,102,281,446,514,523 'class':299,346,371 'code':226,352,563 'com.yourapp.android':407 'cometchat':2,9,29,40,62,89,95,119,128,155,184,191,212,291,413,491,505,549,598 'cometchat-android-v5-components':39 'cometchat-android-v5-core':28,118 'cometchat-android-v5-testing':1 'cometchat-android-v5-troubleshooting':127 'cometchat-uid':412 'cometchatuikit':311,316,345 'cometchatuikit.class':309 'cometchatuikit.getloggedinuser':348 'cometchatuikit.login':359 'common':484 'companion':26 'compon':43,45,143,213,256,261 'composerisdisplay':393 'continu':417 'convers':422 'core':32,122 'cover':33,44,65 'custom':142,146 'declar':276 'deep':160 'deep-link':159 'deliveri':195 'diagnos':123 'distribut':478 'e2e':20,75,100,274,401,588 'empti':149 'emul':264,515,519 'emulator/device':591 'espresso':17,74,267,364,501 'event':156 'everi':347,544 'exact':357 'fail':223,233,512 'failur':485 'fast':279 'fix':489 'flaki':203,573 'flow':278,599 'framework':273 'fun':338 'getloggedinus':312 'github':282 'github/workflows/test.yml':449 'golden':218 'hang':503 'hard':538 'header':148 'hello':430,438 'helper':324 'id':179,421,434,578 'idlingresourc':508 'illegalstateexcept':524 'index':423 'indic':205 'init':164,329,527 'init/login':34,162 'initi':526 'inputtext':411,429 'integr':25,64,80,90,116,447 'intern':188,557 'isdisplay':389,399 'issdkiniti':317,534 'issu':125 'java':293,295,367,475 'java-vers':474 'job':456 'junit':11,69,248,593 'kotlin':334,336 'latest':465 'launchapp':408 'layer':243 'level':521 'lifecycl':163 'link':161 'local':511 'log':169,340 'logic':152,176 'login':166,327,333,343,355,410 'maestro':22,77,275,403,432,440,442 'maestro/chat-happy-path.yaml':404,444 'map':180 'match':388,398 'messag':428 'messagelistisdisplay':383 'messagesactivity.class':379 'messagesactivitytest':372 'method':500 'mock':14,94,289,307,494,497,533,540 'mocked.when':310,315 'mockedstat':306 'mockito':12,250,294 'mockito/mockk':70,496 'mockitojunitrunner.class':297 'mockk':251,335,350 'mockkstat':344 'mockstat':308 'mode':486 'name':450 'nativ':270 'navig':151 'network':551 'new':377 'noclassdeffounderror':490 'null':314 'onview':384,394 'oper':506 'pass':510 'pattern':7,35 'pin':518 'pipelin':103 'pixel':582,586 'presence/typing':204 'produc':572 'product':172 'prone':208 'public':298,302,370,374,381,391 'pull':454 'purpos':50 'push':157,453 'r.id.composer':396 'r.id.messagelist':386 'race':207 'race-pron':206 're':37,559 'real':201,548,569,597 'realtim':194,565 'receiv':199 'refresh':175 'regist':507 'request':455 'requir':200,550,568 'respons':193,560 'return':349,536 'robolectr':258 'rule':219,373,376,539 'run':58,259,287,441,461,480,547,589 'runs-on':460 'runtim':124 'runwith':296,368 'sdk':16,292,492,542 'send':197,435 'server':202,552,570 'set':98,113 'setup':13,532 'skill':27,52,83,111 'skill-cometchat-android-v5-testing' 'skip':139,171,186,342,354,564 'snapshot':209 'source-cometchat' 'stabl':280 'standard':252 'state':150,580 'static':499 'step':466 'suit':574 'symptom':487 'system':183 'tap':158 'tapon':409,416,420,433 'teach':53 'temurin':479 'test':5,6,19,38,59,67,72,86,97,101,106,135,141,210,222,247,255,257,262,266,272,286,301,320,337,366,380,390,443,451,459,482,502,509,531,546,555,566,596,602 'testlogincallsinit':304 'theme':214,583 'thenreturn':313,318 'token':174 'tool':244 'toolchain':242 'topic-agent-skills' 'topic-ai-agent' 'topic-chat' 'topic-claude-code' 'topic-cometchat' 'topic-cursor' 'topic-messaging' 'topic-nextjs' 'topic-react' 'topic-react-native' 'topic-ui-kit' 'tri':305 'trigger':153 'troubleshoot':131 'true':319,537 'type':426 'ubuntu':464 'ubuntu-latest':463 'ui':18,71,265,271,365 'uid':185,414 'uikit':187,236,556 'unit':66,246,254,458,545,601 'unit-test':457 'unmockkal':362 'updat':237 'use':81,109,117,126,467,470 'user':178 'user-id':177 'v4':469,472 'v5':4,31,42,121,130 'valuabl':230 'verifi':328,356 'version':476 'view':577 'viewmodel':322 'void':303,382,392 'vs':136 'withid':385,395 'without':263 'worth':140 'write':56 'wrote':145 'yaml':277,405,448","prices":[{"id":"ea7a37fb-290f-4b5b-9056-265ea2328f77","listingId":"d8c052bf-2ddd-4061-bda4-42dc5c6b4267","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cometchat","category":"cometchat-skills","install_from":"skills.sh"},"createdAt":"2026-05-07T13:05:04.396Z"}],"sources":[{"listingId":"d8c052bf-2ddd-4061-bda4-42dc5c6b4267","source":"github","sourceId":"cometchat/cometchat-skills/cometchat-android-v5-testing","sourceUrl":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-android-v5-testing","isPrimary":false,"firstSeenAt":"2026-05-07T13:05:04.396Z","lastSeenAt":"2026-05-18T19:04:45.379Z"}],"details":{"listingId":"d8c052bf-2ddd-4061-bda4-42dc5c6b4267","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cometchat","slug":"cometchat-android-v5-testing","github":{"repo":"cometchat/cometchat-skills","stars":27,"topics":["agent-skills","ai-agent","chat","claude-code","cometchat","cursor","messaging","nextjs","react","react-native","ui-kit"],"license":null,"html_url":"https://github.com/cometchat/cometchat-skills","pushed_at":"2026-05-18T05:04:24Z","description":"Add CometChat chat to any React, Next.js, React Native, Angular, Android, iOS, or Flutter project through your AI coding agent. Works with Claude Code, Cursor, Codex, VS Code Copilot, Windsurf, Cline, Kiro, and 50+ more agents.","skill_md_sha":"8738fef08aa4b6bf42fee0a8fc6b798ae517559c","skill_md_path":"skills/cometchat-android-v5-testing/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-android-v5-testing"},"layout":"multi","source":"github","category":"cometchat-skills","frontmatter":{"name":"cometchat-android-v5-testing","license":"MIT","description":"Testing patterns for CometChat Android — JUnit + Mockito setup, mocking the SDK, Espresso UI tests, E2E with Maestro, and CI integration.","compatibility":"Android 7.0+; Java 8+; Kotlin 1.8+; com.cometchat:chat-uikit-android:5.x; JUnit 4 (kit sample apps); Mockito/MockK"},"skills_sh_url":"https://skills.sh/cometchat/cometchat-skills/cometchat-android-v5-testing"},"updatedAt":"2026-05-18T19:04:45.379Z"}}