{"id":"778b2c74-a381-4ae5-9b0b-ee1226d21a6d","shortId":"ymPeEy","kind":"skill","title":"cometchat-native-testing","tagline":"Testing patterns for CometChat React Native — Jest + React Native Testing Library setup, mocking the UI Kit + SDK, testing custom bubbles / headers / composer actions, snapshot pitfalls, E2E with Detox vs Maestro, and CI integration. Covers what to test vs what to skip.","description":"## Purpose\n\nTeaches Claude how to write and run tests against a CometChat React Native integration. Covers:\n\n- Unit / component tests with Jest + React Native Testing Library (RNTL)\n- How to mock `@cometchat/chat-uikit-react-native` and `@cometchat/chat-sdk-react-native` (both pull in native modules that fail in Node's jest-expo / jest-react-native environments)\n- Testing custom bubbles, headers, composer actions, empty states\n- Snapshot testing pitfalls specific to theme-driven components\n- E2E with Detox (iOS + Android native drivers) vs Maestro (declarative YAML)\n- Which tests catch real regressions vs which are flaky churn\n\nGround truth: `@cometchat/chat-uikit-react-native@5.3.3`'s example jest config (`examples/SampleAppWithPushNotifications/jest.config.js`) and the standard RN testing toolkit docs (callstack.github.io/react-native-testing-library, wix.github.io/Detox, maestro.mobile.dev).\n\n---\n\n## 1. What to test, what to skip\n\nNot every test is worth the maintenance cost. A few rules of thumb:\n\n**Worth testing:**\n- Custom components you wrote (custom bubble, custom header, empty-state view)\n- Navigation logic triggered by CometChat events (push tap → deep-link)\n- Message render logic with text formatters\n- Your provider chain wires correctly (four-wrapper order, init called, login called)\n- Production auth token refresh + retry logic\n- User-ID mapping (Firebase UID → CometChat UID)\n\n**Skip:**\n- UI Kit internals — that's the UI Kit's responsibility. Testing `<CometChatConversations>` renders a list is testing CometChat's code.\n- Realtime delivery (A sends, B receives) — requires real servers; flaky and slow; use manual QA or E2E with real accounts.\n- Presence / typing indicators — race-prone, depend on socket state.\n- Snapshot tests of CometChat components — theme changes, UI Kit updates, and `cometchat-native-theming` edits all churn the snapshots with no real signal.\n- Native module calls (camera, picker) — Jest's mocks already return stubs; testing them verifies the mock, not the integration.\n\nThe golden rule: if the test fails because **your code** changed, it's valuable. If it fails because **the UI Kit updated** or **a network blip happened**, it's churn.\n\n---\n\n## 2. Toolchain\n\n| Layer | Tool | Why |\n|---|---|---|\n| Unit + component tests | Jest + `@testing-library/react-native` | The RN default. Preset handles metro module resolution. |\n| Mocking | Jest `moduleNameMapper` + manual mocks | UI Kit imports native modules — can't run real components in a Node env. |\n| Snapshot | Jest's built-in | Use sparingly — see §7 |\n| E2E | Maestro OR Detox | See §10 for tradeoff |\n| CI | GitHub Actions / EAS / Bitrise | §11 |\n\nInstall:\n```bash\n# Bare RN\nnpm install --save-dev jest @testing-library/react-native @testing-library/jest-native \\\n  react-test-renderer @types/jest\n\n# Expo\nnpx expo install --dev jest-expo @testing-library/react-native @testing-library/jest-native \\\n  react-test-renderer\n```\n\n`jest-expo` wraps `react-native` preset with Expo-specific module resolution (handles `expo-modules-core`, `expo-router`, etc.).\n\n---\n\n## 3. Jest config\n\n**Bare RN** — `jest.config.js`:\n```js\nmodule.exports = {\n  preset: \"react-native\",\n  setupFilesAfterEach: [\"<rootDir>/jest.setup.ts\"],\n  transformIgnorePatterns: [\n    \"node_modules/(?!(?:react-native|@react-native|@react-navigation|\" +\n      \"@cometchat/chat-uikit-react-native|@cometchat/chat-sdk-react-native|\" +\n      \"react-native-.+|@notifee/react-native)/)\",\n  ],\n  moduleNameMapper: {\n    \"^@cometchat/chat-uikit-react-native$\": \"<rootDir>/__mocks__/cometchat-uikit.ts\",\n    \"^@cometchat/chat-sdk-react-native$\": \"<rootDir>/__mocks__/cometchat-sdk.ts\",\n  },\n};\n```\n\n**Expo** — `jest.config.js`:\n```js\nmodule.exports = {\n  preset: \"jest-expo\",\n  setupFilesAfterEach: [\"<rootDir>/jest.setup.ts\"],\n  transformIgnorePatterns: [\n    \"node_modules/(?!(?:(jest-)?react-native|@react-native|expo(nent)?|@expo(nent)?/.*|\" +\n      \"@expo-google-fonts/.*|react-navigation|@react-navigation/.*|\" +\n      \"@cometchat/chat-uikit-react-native|@cometchat/chat-sdk-react-native|\" +\n      \"@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg)/)\",\n  ],\n  moduleNameMapper: {\n    \"^@cometchat/chat-uikit-react-native$\": \"<rootDir>/__mocks__/cometchat-uikit.ts\",\n    \"^@cometchat/chat-sdk-react-native$\": \"<rootDir>/__mocks__/cometchat-sdk.ts\",\n  },\n};\n```\n\n**`transformIgnorePatterns` matters.** By default Jest doesn't transform anything under `node_modules`, but CometChat ships ES module source. Without the pattern, Jest errors with `SyntaxError: Unexpected token 'export'`. The UI Kit + SDK names must be in the allow list.\n\n---\n\n## 4. Global setup — `jest.setup.ts`\n\n```ts\nimport \"@testing-library/jest-native/extend-expect\";\n\n// Silence RN's \"AnimatedValue\" warning noise in tests\njest.mock(\"react-native/Libraries/Animated/NativeAnimatedHelper\");\n\n// Mock native modules that the UI Kit pulls in\njest.mock(\"react-native-gesture-handler\", () => {\n  const View = require(\"react-native/Libraries/Components/View/View\");\n  return {\n    GestureHandlerRootView: View,\n    PanGestureHandler: View,\n    TapGestureHandler: View,\n    State: {},\n    Directions: {},\n  };\n});\n\n// react-native-reanimated is NOT a peer dep of the kit. Only add this\n// mock if your app installs reanimated for its own animation needs.\n// jest.mock(\"react-native-reanimated\", () =>\n//   require(\"react-native-reanimated/mock\"),\n// );\n\njest.mock(\"react-native-safe-area-context\", () => ({\n  SafeAreaProvider: ({ children }: { children: React.ReactNode }) => children,\n  SafeAreaView: ({ children }: { children: React.ReactNode }) => children,\n  useSafeAreaInsets: () => ({ top: 0, right: 0, bottom: 0, left: 0 }),\n}));\n\n// Silence console.warn from legacy components in tests — re-enable locally if debugging\nconst originalWarn = console.warn;\nconsole.warn = (...args: unknown[]) => {\n  if (\n    typeof args[0] === \"string\" &&\n    /componentWill|Unable to find|act\\(\\)/i.test(args[0])\n  ) {\n    return;\n  }\n  originalWarn(...args);\n};\n```\n\n---\n\n## 5. Mocking the UI Kit\n\nThe UI Kit's top-level components (`CometChatConversations`, `CometChatMessageList`, etc.) wire socket listeners, call native modules, and render FlatLists with async data. Rendering them in Jest is more effort than value.\n\n**Strategy: mock them as transparent Views that forward children.** This lets your tests verify your integration (are the right props being passed? does the right component mount in the right screen?) without pulling in the real implementation.\n\n`__mocks__/cometchat-uikit.ts`:\n```ts\nimport React from \"react\";\nimport { View } from \"react-native\";\n\nconst passThrough = (name: string) =>\n  React.forwardRef<unknown, Record<string, unknown>>((props, ref) => {\n    const { children, ...rest } = props as { children?: React.ReactNode };\n    return (\n      <View ref={ref as never} testID={name} {...rest}>\n        {children}\n      </View>\n    );\n  });\n\nexport const CometChatUIKit = {\n  init: jest.fn(async () => undefined),\n  login: jest.fn(async () => ({ getUid: () => \"cometchat-uid-1\" })),\n  logout: jest.fn(async () => undefined),\n  getLoggedInUser: jest.fn(async () => ({ getUid: () => \"cometchat-uid-1\" })),\n};\n\n// NOTE: the v5 RN UI Kit does NOT export `UIKitSettingsBuilder` — `init()` takes\n// a flat `UIKitSettings` object. No mock needed for a builder that doesn't exist.\n\nexport const CometChatThemeProvider = passThrough(\"CometChatThemeProvider\");\nexport const CometChatI18nProvider = passThrough(\"CometChatI18nProvider\");\nexport const CometChatConversations = passThrough(\"CometChatConversations\");\nexport const CometChatMessageList = passThrough(\"CometChatMessageList\");\nexport const CometChatMessageComposer = passThrough(\"CometChatMessageComposer\");\nexport const CometChatMessageHeader = passThrough(\"CometChatMessageHeader\");\nexport const CometChatUsers = passThrough(\"CometChatUsers\");\nexport const CometChatGroups = passThrough(\"CometChatGroups\");\nexport const CometChatIncomingCall = passThrough(\"CometChatIncomingCall\");\nexport const CometChatOutgoingCall = passThrough(\"CometChatOutgoingCall\");\n\nexport const CometChatUIEventHandler = {\n  addUIListener: jest.fn(),\n  removeListener: jest.fn(),\n};\nexport const CometChatUIEvents = {};\n\nexport const useTheme = () => ({\n  color: {\n    primary: \"#6852D6\",\n    background1: \"#FFFFFF\",\n    textPrimary: \"#141414\",\n  },\n  typography: {\n    heading1: { fontFamily: \"System\", fontSize: 28 },\n    body1: { fontFamily: \"System\", fontSize: 16 },\n  },\n});\n```\n\n`__mocks__/cometchat-sdk.ts`:\n```ts\nexport const CometChat = {\n  getUser: jest.fn(async (uid: string) => ({ getUid: () => uid, getName: () => \"Test User\" })),\n  getGroup: jest.fn(async (guid: string) => ({ getGuid: () => guid, getName: () => \"Test Group\" })),\n  addMessageListener: jest.fn(),\n  removeMessageListener: jest.fn(),\n};\n\nexport const CometChatNotifications = {\n  PushPlatforms: {\n    FCM_REACT_NATIVE_ANDROID: \"fcm-android\",\n    FCM_REACT_NATIVE_IOS: \"fcm-ios\",\n    APNS_REACT_NATIVE_DEVICE: \"apns-device\",\n    APNS_REACT_NATIVE_VOIP: \"apns-voip\",\n  },\n  registerPushToken: jest.fn(async () => ({ success: true })),\n  unregisterPushToken: jest.fn(async () => ({ success: true })),\n};\n```\n\nEvery real `<CometChatMessageList>` in your code renders as `<View testID=\"CometChatMessageList\">` in tests. You can assert on `testID` + the props you passed.\n\n---\n\n## 6. Testing a custom component\n\nExample — a custom chat screen that renders `<CometChatMessageList>` for a specific user:\n\n```tsx\n// src/screens/MessagesScreen.tsx\nimport { CometChat } from \"@cometchat/chat-sdk-react-native\";\nimport { CometChatMessageList } from \"@cometchat/chat-uikit-react-native\";\nimport { useEffect, useState } from \"react\";\n\nexport function MessagesScreen({ uid }: { uid: string }) {\n  const [user, setUser] = useState<CometChat.User | null>(null);\n\n  useEffect(() => {\n    CometChat.getUser(uid).then(setUser);\n  }, [uid]);\n\n  if (!user) return null;\n\n  return <CometChatMessageList user={user} hideReplyInThreadOption />;\n}\n```\n\nTest:\n```tsx\n// src/screens/__tests__/MessagesScreen.test.tsx\nimport { render, waitFor } from \"@testing-library/react-native\";\nimport { CometChat } from \"@cometchat/chat-sdk-react-native\";\nimport { MessagesScreen } from \"../MessagesScreen\";\n\ntest(\"fetches user then renders MessageList\", async () => {\n  const { getByTestId, queryByTestId } = render(<MessagesScreen uid=\"alice\" />);\n\n  // Before fetch resolves — nothing rendered\n  expect(queryByTestId(\"CometChatMessageList\")).toBeNull();\n\n  // After fetch resolves — list renders with user prop\n  await waitFor(() => expect(getByTestId(\"CometChatMessageList\")).toBeTruthy());\n\n  expect(CometChat.getUser).toHaveBeenCalledWith(\"alice\");\n});\n\ntest(\"passes hideReplyInThreadOption to MessageList\", async () => {\n  const { findByTestId } = render(<MessagesScreen uid=\"alice\" />);\n  const list = await findByTestId(\"CometChatMessageList\");\n\n  // The mocked component stored props on the View — check them\n  expect(list.props.hideReplyInThreadOption).toBe(true);\n});\n```\n\nThe second test is the valuable one — it guards the mandatory `hideReplyInThreadOption` flag (hard rule §4 in `cometchat-native-core`) against a future refactor dropping it.\n\n---\n\n## 7. Snapshot testing — use sparingly\n\n**Do snapshot:**\n- Pure presentational components with no UI Kit dependency\n- Custom bubble renderers with fixed inputs\n- Data transforms (message → display string)\n\n**Don't snapshot:**\n- Anything wrapped in `CometChatThemeProvider` — a token change churns snapshots with no regression meaning.\n- Components rendering UI Kit internals — even with mocks, prop churn from UI Kit updates churns your snapshots.\n- Navigators / full screens — too many variables.\n\n```tsx\n// Good — isolated, theme-free\ntest(\"formatTimestamp(1700000000000) matches snapshot\", () => {\n  expect(formatTimestamp(1_700_000_000_000)).toMatchInlineSnapshot(`\"Tue, 14 Nov 2023\"`);\n});\n```\n\nIf a snapshot test churns on every UI Kit update, delete it — it's net-negative.\n\n---\n\n## 8. Testing the provider chain\n\nThe four-wrapper chain (hard rule §3 in `cometchat-native-core`) is one of the most common regressions AI edits introduce. Test that all four wrappers render:\n\n```tsx\n// src/App.test.tsx\nimport { render } from \"@testing-library/react-native\";\nimport App from \"./App\";\n\ntest(\"App mounts all four CometChat wrappers\", () => {\n  const { getByTestId } = render(<App />);\n\n  // The mocked wrappers each render a View with testID matching their name\n  expect(getByTestId(\"CometChatThemeProvider\")).toBeTruthy();\n  // Note: GestureHandlerRootView and SafeAreaProvider are pass-through Views\n  // without distinct testIDs in our setup, so assert via presence of children\n  // OR extend the mock in jest.setup.ts to add testIDs.\n});\n```\n\nFor the `GestureHandlerRootView` + `SafeAreaProvider` assertion, extend their mocks in `jest.setup.ts` to add `testID`:\n\n```ts\njest.mock(\"react-native-gesture-handler\", () => {\n  const { View } = require(\"react-native\");\n  return {\n    GestureHandlerRootView: (props: any) =>\n      require(\"react\").createElement(View, { ...props, testID: \"GestureHandlerRootView\" }),\n    // ...\n  };\n});\n```\n\n---\n\n## 9. Testing login lifecycle\n\nThe `ensureLoggedIn` helper (hard rule §2 in `cometchat-native-core`) must handle concurrent calls safely:\n\n```tsx\n// src/providers/__tests__/CometChatProvider.test.tsx\nimport { CometChatUIKit } from \"@cometchat/chat-uikit-react-native\";\nimport { ensureLoggedIn } from \"../CometChatProvider\";\n\nbeforeEach(() => {\n  jest.clearAllMocks();\n});\n\ntest(\"concurrent ensureLoggedIn calls only invoke login once\", async () => {\n  (CometChatUIKit.getLoggedInUser as jest.Mock).mockResolvedValue(null);\n\n  const results = await Promise.all([\n    ensureLoggedIn(\"alice\"),\n    ensureLoggedIn(\"alice\"),\n    ensureLoggedIn(\"alice\"),\n  ]);\n\n  expect(CometChatUIKit.login).toHaveBeenCalledTimes(1);\n});\n\ntest(\"already-logged-in skips login entirely\", async () => {\n  (CometChatUIKit.getLoggedInUser as jest.Mock).mockResolvedValue({\n    getUid: () => \"alice\",\n  });\n\n  await ensureLoggedIn(\"alice\");\n\n  expect(CometChatUIKit.login).not.toHaveBeenCalled();\n});\n```\n\nThese two tests catch the most common `ensureLoggedIn` breakages — dropping the module-level promise guard, or forgetting the `getLoggedInUser` short-circuit.\n\n---\n\n## 10. E2E — Detox vs Maestro\n\nTwo choices for end-to-end. Different philosophies.\n\n| | Detox | Maestro |\n|---|---|---|\n| Config | Native drivers (iOS + Android). `.detoxrc.js`. | YAML flows. Single binary. |\n| Language | JavaScript / TypeScript | YAML |\n| Setup | Heavy — Xcode build, Detox CLI, Jest runner | Light — brew install, run CLI |\n| CI | Slow (full native build each run) | Fast (reuses install) |\n| Speed | Flaky in CI, reliable locally | Fast, stable |\n| iOS + Android parity | Yes | Yes |\n| Cloud runs | No native cloud support | Maestro Cloud (paid) |\n| Learning curve | Steep if you don't know RN internals | Low |\n\n**Recommendation: Maestro for most teams.** Flows are readable, runs in seconds, CI-friendly. Detox makes sense if you have existing Jest infrastructure and want E2E to live in the same runner.\n\n### Maestro flow (recommended)\n\n`.maestro/chat-happy-path.yaml`:\n```yaml\nappId: com.yourapp.mobile\n---\n- launchApp\n- tapOn: \"Login\"\n- inputText: \"cometchat-uid-1\"\n- tapOn: \"Continue\"\n- assertVisible: \"Messages\"\n- tapOn: \"Messages\"\n- assertVisible: \"Conversations\"\n- tapOn: id: \"conversation-cometchat-uid-2\"\n- inputText: \"Hello from Maestro\"\n- tapOn: id: \"send-button\"\n- assertVisible: \"Hello from Maestro\"\n```\n\nRun:\n```bash\nmaestro test .maestro/chat-happy-path.yaml\n```\n\nNeeds your RN `<CometChatMessageComposer>` to expose `testID=\"send-button\"` — the UI Kit supports this via the `sendButtonStyle` slot or via a Custom view template.\n\n### Detox\n\n`.detoxrc.js` (abbreviated):\n```js\nmodule.exports = {\n  testRunner: { args: { $0: \"jest\", config: \"e2e/jest.config.js\" } },\n  apps: {\n    \"ios.debug\": {\n      type: \"ios.app\",\n      binaryPath: \"ios/build/Build/Products/Debug-iphonesimulator/YourApp.app\",\n    },\n  },\n  devices: { simulator: { type: \"ios.simulator\", device: { type: \"iPhone 15\" } } },\n  configurations: {\n    \"ios.sim.debug\": { device: \"simulator\", app: \"ios.debug\" },\n  },\n};\n```\n\nTest:\n```ts\n// e2e/chat.test.ts\ndescribe(\"chat flow\", () => {\n  beforeAll(async () => {\n    await device.launchApp();\n  });\n\n  it(\"sends a message\", async () => {\n    await element(by.text(\"Login\")).tap();\n    await element(by.id(\"uid-input\")).typeText(\"cometchat-uid-1\");\n    await element(by.text(\"Continue\")).tap();\n    await element(by.text(\"Messages\")).tap();\n    await element(by.id(\"conversation-cometchat-uid-2\")).tap();\n    await element(by.id(\"message-input\")).typeText(\"Hello from Detox\");\n    await element(by.id(\"send-button\")).tap();\n    await expect(element(by.text(\"Hello from Detox\"))).toBeVisible();\n  });\n});\n```\n\nDetox needs a native dev build first (`detox build --configuration ios.sim.debug`) — slow in CI.\n\n### What NOT to E2E\n\n- Login with a real auth provider (Firebase / Clerk). Mock the auth callback or use a test account with a fixed password.\n- Real push delivery. Fire via a CI-only fake push tool, or skip entirely.\n- Group calls with real peers. Use two simulators only if Detox/Maestro supports it (both do, but flaky).\n\n---\n\n## 11. CI integration\n\n### GitHub Actions — Jest on every push\n\n`.github/workflows/test.yml`:\n```yaml\nname: test\non: [push, pull_request]\njobs:\n  jest:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 20\n          cache: npm\n      - run: npm ci\n      - run: npx tsc --noEmit\n      - run: npm test -- --ci --coverage\n```\n\n### Maestro in CI\n\nMaestro runs on macOS runners (iOS) or Linux runners with Android emulators. The `mobile-dev-inc/action-maestro-cloud` action simplifies it:\n\n```yaml\n  e2e:\n    runs-on: macos-14\n    steps:\n      - uses: actions/checkout@v4\n      - name: Build iOS\n        run: |\n          cd ios\n          pod install\n          xcodebuild -workspace YourApp.xcworkspace -scheme YourApp \\\n            -sdk iphonesimulator -configuration Debug \\\n            -derivedDataPath build\n      - name: Run Maestro flows\n        uses: mobile-dev-inc/action-maestro-cloud@v1\n        with:\n          api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }}\n          app-file: ios/build/Build/Products/Debug-iphonesimulator/YourApp.app\n          workspace: .maestro\n```\n\n### EAS + Expo\n\nIf you're on EAS, `eas build --profile preview` followed by `maestro test` against the preview build works for CI smoke tests. EAS Test (paid) orchestrates Maestro runs across multiple devices.\n\n---\n\n## 12. Common failure modes\n\n| Symptom | Cause | Fix |\n|---|---|---|\n| `SyntaxError: Unexpected token 'export'` | Jest not transforming a UI Kit or SDK file | Add package name to `transformIgnorePatterns` allow list |\n| `TypeError: Cannot read properties of undefined (reading 'Directions')` | Gesture handler native module missing | Mock in `jest.setup.ts` (see §4) |\n| Tests hang for 30s+ | Real WebSocket or fetch not mocked | Add `jest.useFakeTimers()` + mock `fetch` |\n| Snapshot fails after no code change | Theme token update churned output | Either delete the snapshot (§7) or run `--updateSnapshot` |\n| `useInsertionEffect must not schedule updates` warning | React Navigation dev warning, harmless in tests | Silence in `jest.setup.ts` (see §4) |\n| `Could not find React Testing Library matchers` | `@testing-library/jest-native` not extended | `import \"@testing-library/jest-native/extend-expect\"` in setup |\n| Maestro \"app not installed\" | Bundle ID mismatch or simulator not booted | `xcrun simctl boot \"iPhone 15\"`, verify `appId` in YAML |\n| Detox \"Cannot find element\" | `testID` not set on UI Kit component | Add via slot view template or custom view; don't rely on text matching |\n\n---\n\n## 13. Hard rules\n\n- **Mock the UI Kit and SDK in every test file.** Running real components in Node fails on native modules and wastes CI time even when it works.\n- **Don't test what the UI Kit already tests.** You're responsible for YOUR code — bubbles, headers, navigation, auth mapping. UI Kit internals are CometChat's job.\n- **Skip realtime and presence.** They require real servers and produce flaky suites. Use manual QA or E2E with real test accounts.\n- **Assert on `testID` and prop values, not on pixel output.** Theme changes, font metrics, and platform differences all churn pixel-level assertions.\n- **Keep snapshot tests scoped.** Use for pure data transforms and isolated presentational code. Never snapshot a full screen.\n- **E2E tests run against a dev build, not Jest.** Don't try to test real CometChat flow in Jest — it belongs in Detox/Maestro.\n\n---\n\n## 14. Skill routing\n\n| This skill | Covers |\n|---|---|\n| `cometchat-native-testing` (this) | Jest + RNTL setup, mocking UI Kit + SDK, component / provider / login tests, Detox vs Maestro for E2E, CI |\n| `cometchat-native-core` | The provider chain + login concurrency patterns you're testing |\n| `cometchat-native-components` | Component catalog — what props to assert in tests |\n| `cometchat-native-customization` | DataSource decorators + custom views — test per §6 |\n| `cometchat-native-push` | Push tests (mock `CometChatNotifications`); E2E tap-to-deep-link needs a real device |\n| `cometchat-native-troubleshooting` | Metro cache / pod install / native module errors (often surface first in a CI run) |","tags":["cometchat","native","testing","skills","agent-skills","ai-agent","chat","claude-code","cursor","messaging","nextjs","react"],"capabilities":["skill","source-cometchat","skill-cometchat-native-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-native-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 (21,471 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:54.957Z","embedding":null,"createdAt":"2026-05-07T13:05:15.310Z","updatedAt":"2026-05-18T19:04:54.957Z","lastSeenAt":"2026-05-18T19:04:54.957Z","tsv":"'-14':2076 '/__mocks__/cometchat-sdk.ts':524,577 '/__mocks__/cometchat-uikit.ts':522,575 '/action-maestro-cloud':2066,2109 '/app':1430 '/cometchat-sdk.ts':1019 '/cometchat-uikit.ts':844 '/cometchatprovider':1553 '/componentwill':758 '/detox,':155 '/i.test':763 '/jest-native':439,460,2264 '/jest-native/extend-expect':626,2271 '/jest.setup.ts':501,534 '/libraries/animated/nativeanimatedhelper':639 '/libraries/components/view/view':661 '/messagesscreen':1185 '/mock':707 '/react-native':370,435,456,1177,1426 '/react-native-testing-library,':152 '0':727,729,731,733,756,765,1825 '000':1359,1360,1361 '1':157,898,910,1357,1583,1760,1879 '10':413,1628 '11':421,1995 '12':2158 '13':2319 '14':1364,2461 '141414':1006 '15':1842,2289 '16':1017 '1700000000000':1352 '2':358,1533,1775,1897 '20':2031 '2023':1366 '28':1012 '3':488,1396 '30s':2206 '4':617,1267,2202,2253 '5':769 '5.3.3':137 '6':1108,2524 '6852d6':1002 '7':407,1279,2232 '700':1358 '8':1384 '9':1524 'abbrevi':1820 'account':274,1958,2396 'across':2155 'act':762 'action':27,101,418,1999,2067 'actions/checkout':2022,2079 'actions/setup-node':2025 'add':684,1485,1498,2178,2213,2305 'addmessagelisten':1044 'adduilisten':990 'ai':1409 'alic':1223,1575,1577,1579,1598,1601 'allow':615,2183 'alreadi':317,1586,2356 'already-logged-in':1585 'android':117,1055,1058,1648,1690,2059 'anim':695 'animatedvalu':630 'anyth':586,1308 'api':2113,2117 'api-key':2112 'apn':1066,1071,1073,1078 'apns-devic':1070 'apns-voip':1077 'app':689,1428,1432,1829,1847,2120,2275 'app-fil':2119 'appid':1751,2291 'area':713 'arg':751,755,764,768,1824 'assert':1101,1473,1491,2397,2419,2511 'assertvis':1763,1767,1785 'async':795,889,893,901,905,1026,1036,1082,1087,1192,1229,1564,1592,1856,1863 'auth':222,1946,1952,2367 'await':1214,1235,1572,1599,1857,1864,1869,1880,1885,1890,1899,1909,1916 'b':259 'background1':1003 'bare':424,491 'base':568 'bash':423,1790 'beforeal':1855 'beforeeach':1554 'belong':2458 'binari':1653 'binarypath':1833 'bitris':420 'blip':353 'body1':1013 'boot':2284,2287 'bottom':730 'breakag':1613 'brew':1667 'bubbl':24,98,184,1295,2364 'build':1661,1675,1929,1932,2082,2099,2133,2143,2444 'builder':932 'built':402 'built-in':401 'bundl':2278 'button':1784,1802,1914 'by.id':1871,1892,1901,1911 'by.text':1866,1882,1887,1919 'cach':2032,2548 'call':218,220,311,788,1542,1559,1979 'callback':1953 'callstack.github.io':151 'callstack.github.io/react-native-testing-library,':150 'camera':312 'cannot':2186,2295 'catalog':2507 'catch':126,1608 'caus':2163 'cd':2085 'chain':210,1388,1393,2495 'chang':291,338,1314,2222,2408 'chat':1116,1853 'check':1246 'children':716,717,719,721,722,724,814,868,872,883,1477 'choic':1634 'churn':133,302,357,1315,1330,1335,1371,2226,2415 'ci':36,416,1671,1684,1726,1937,1970,1996,2036,2044,2048,2146,2343,2488,2559 'ci-friend':1725 'ci-on':1969 'circuit':1627 'claud':48 'clerk':1949 'cli':1663,1670 'cloud':1694,1698,1701,2116 'code':254,337,1094,2221,2363,2432 'color':1000 'com.yourapp.mobile':1752 'cometchat':2,8,57,195,233,252,288,297,591,896,908,1023,1127,1179,1270,1399,1436,1536,1758,1773,1877,1895,2373,2453,2468,2490,2503,2515,2526,2544 'cometchat-native-compon':2502 'cometchat-native-cor':1269,1398,1535,2489 'cometchat-native-custom':2514 'cometchat-native-push':2525 'cometchat-native-test':1,2467 'cometchat-native-them':296 'cometchat-native-troubleshoot':2543 'cometchat-uid':895,907,1757,1876 'cometchat.getuser':1153,1221 'cometchat.user':1149 'cometchat/chat-sdk-react-native':77,515,523,560,576,1129,1181 'cometchat/chat-uikit-react-native':75,136,514,521,559,574,1133,1549 'cometchatconvers':782,949,951 'cometchatgroup':974,976 'cometchati18nprovider':944,946 'cometchatincomingcal':979,981 'cometchatmessagecompos':959,961 'cometchatmessagehead':964,966 'cometchatmessagelist':783,954,956,1131,1163,1204,1218,1237 'cometchatnotif':1050,2532 'cometchatoutgoingcal':984,986 'cometchatthemeprovid':939,941,1311,1455 'cometchatuiev':996 'cometchatuieventhandl':989 'cometchatuikit':886,1547 'cometchatuikit.getloggedinuser':1565,1593 'cometchatuikit.login':1581,1603 'cometchatus':969,971 'common':1407,1611,2159 'compon':63,112,180,289,364,393,738,781,831,1112,1240,1288,1321,2304,2334,2479,2505,2506 'compos':26,100 'concurr':1541,1557,2497 'config':141,490,1644,1827 'configur':1843,1933,2096 'console.warn':735,749,750 'const':655,747,856,867,885,938,943,948,953,958,963,968,973,978,983,988,995,998,1022,1049,1145,1193,1230,1233,1438,1507,1570 'context':714 'continu':1762,1883 'convers':1768,1772,1894 'conversation-cometchat-uid':1771,1893 'core':483,1272,1401,1538,2492 'correct':212 'cost':171 'could':2254 'cover':38,61,2466 'coverag':2045 'createel':1519 'curv':1704 'custom':23,97,179,183,185,1111,1115,1294,1815,2311,2517,2520 'data':796,1300,2427 'datasourc':2518 'debug':746,2097 'declar':122 'decor':2519 'deep':200,2537 'deep-link':199 'default':373,581 'delet':1377,2229 'deliveri':256,1965 'dep':679 'depend':281,1293 'deriveddatapath':2098 'describ':1852 'detox':32,115,411,1630,1642,1662,1728,1818,1908,1922,1924,1931,2294,2483 'detox/maestro':1988,2460 'detoxrc.js':1649,1819 'dev':430,449,1928,2064,2107,2244,2443 'devic':1069,1072,1835,1839,1845,2157,2542 'device.launchapp':1858 'differ':1640,2413 'direct':670,2192 'display':1303 'distinct':1467 'doc':149 'doesn':583,934 'driven':111 'driver':119,1646 'drop':1277,1614 'e2e':30,113,271,408,1629,1739,1941,2071,2392,2438,2487,2533 'e2e/chat.test.ts':1851 'e2e/jest.config.js':1828 'ea':419,2125,2131,2132,2149 'edit':300,1410 'effort':803 'either':2228 'element':1865,1870,1881,1886,1891,1900,1910,1918,2297 'empti':102,188 'empty-st':187 'emul':2060 'enabl':743 'end':1637,1639 'end-to-end':1636 'ensureloggedin':1529,1551,1558,1574,1576,1578,1600,1612 'entir':1591,1977 'env':397 'environ':95 'error':600,2553 'es':593 'etc':487,784 'even':1326,2345 'event':196 'everi':165,1090,1373,2002,2329 'exampl':139,1113 'examples/sampleappwithpushnotifications/jest.config.js':142 'exist':936,1734 'expect':1202,1216,1220,1248,1355,1453,1580,1602,1917 'expo':90,445,447,452,467,475,481,485,525,532,545,547,550,565,2126 'expo-google-font':549 'expo-modules-cor':480 'expo-rout':484 'expo-specif':474 'export':605,884,919,937,942,947,952,957,962,967,972,977,982,987,994,997,1021,1048,1139,2168 'expos':1798 'extend':1479,1492,2266 'fail':84,334,344,2218,2337 'failur':2160 'fake':1972 'fast':1678,1687 'fcm':1052,1057,1059,1064 'fcm-android':1056 'fcm-io':1063 'fetch':1187,1198,1207,2210,2216 'ffffff':1004 'file':2121,2177,2331 'find':761,2256,2296 'findbytestid':1231,1236 'fire':1966 'firebas':231,1948 'first':1930,2556 'fix':1298,1961,2164 'flag':1264 'flaki':132,264,1682,1994,2386 'flat':924 'flatlist':793 'flow':1651,1719,1747,1854,2103,2454 'follow':2136 'font':552,2409 'fontfamili':1009,1014 'fontsiz':1011,1016 'forget':1622 'formatt':207 'formattimestamp':1351,1356 'forward':813 'four':214,1391,1415,1435 'four-wrapp':213,1390 'free':1349 'friend':1727 'full':1339,1673,2436 'function':1140 'futur':1275 'gestur':653,1505,2193 'gesturehandlerrootview':663,1458,1489,1514,1523 'getbytestid':1194,1217,1439,1454 'getgroup':1034 'getguid':1039 'getloggedinus':903,1624 'getnam':1031,1041 'getuid':894,906,1029,1597 'getus':1024 'github':417,1998 'github/workflows/test.yml':2004 'global':618 'golden':329 'good':1345 'googl':551 'ground':134 'group':1043,1978 'guard':1260,1620 'guid':1037,1040 'handl':375,479,1540 'handler':654,1506,2194 'hang':2204 'happen':354 'hard':1265,1394,1531,2320 'harmless':2246 'header':25,99,186,2365 'heading1':1008 'heavi':1659 'hello':1777,1786,1906,1920 'helper':1530 'hidereplyinthreadopt':1166,1226,1263 'id':229,1770,1781,2279 'implement':842 'import':386,622,846,850,1126,1130,1134,1170,1178,1182,1420,1427,1546,1550,2267 'inc':2065,2108 'indic':277 'infrastructur':1736 'init':217,887,921 'input':1299,1874,1904 'inputtext':1756,1776 'instal':422,427,448,690,1668,1680,2088,2277,2550 'integr':37,60,327,821,1997 'intern':238,1325,1712,2371 'introduc':1411 'invok':1561 'io':116,1062,1065,1647,1689,2054,2083,2086 'ios.app':1832 'ios.debug':1830,1848 'ios.sim.debug':1844,1934 'ios.simulator':1838 'ios/build/build/products/debug-iphonesimulator/yourapp.app':1834,2122 'iphon':1841,2288 'iphonesimul':2095 'isol':1346,2430 'javascript':1655 'jest':11,66,89,92,140,314,366,380,399,431,451,466,489,531,538,582,599,800,1664,1735,1826,2000,2013,2169,2446,2456,2472 'jest-expo':88,450,465,530 'jest-react-n':91 'jest.clearallmocks':1555 'jest.config.js':493,526 'jest.fn':888,892,900,904,991,993,1025,1035,1045,1047,1081,1086 'jest.mock':635,649,697,708,1501,1567,1595 'jest.setup.ts':620,1483,1496,2200,2251 'jest.usefaketimers':2214 'job':2012,2375 'js':494,527,1821 'keep':2420 'key':2114,2118 'kit':20,237,243,293,348,385,608,646,682,773,776,916,1292,1324,1333,1375,1805,2174,2303,2325,2355,2370,2477 'know':1710 'languag':1654 'latest':2019 'launchapp':1753 'layer':360 'learn':1703 'left':732 'legaci':737 'let':816 'level':780,1618,2418 'librari':15,70,369,434,438,455,459,625,1176,1425,2259,2263,2270 'lifecycl':1527 'light':1666 'link':201,2538 'linux':2056 'list':249,616,1209,1234,2184 'list.props.hidereplyinthreadoption':1249 'listen':787 'live':1741 'local':744,1686 'log':1587 'logic':192,204,226 'login':219,891,1526,1562,1590,1755,1867,1942,2481,2496 'logout':899 'low':1713 'maco':2052,2075 'maestro':34,121,409,1632,1643,1700,1715,1746,1779,1788,1791,2046,2049,2102,2124,2138,2153,2274,2485 'maestro.mobile.dev':156 'maestro/chat-happy-path.yaml':1749,1793 'mainten':170 'make':1729 'mandatori':1262 'mani':1342 'manual':268,382,2389 'map':230,2368 'match':1353,1450,2318 'matcher':2260 'matter':579 'mean':1320 'messag':202,1302,1764,1766,1862,1888,1903 'message-input':1902 'messagelist':1191,1228 'messagesscreen':1141,1183 'metric':2410 'metro':376,2547 'mismatch':2280 'miss':2197 'mobil':2063,2106 'mobile-dev-inc':2062,2105 'mock':17,74,316,324,379,383,640,686,770,807,843,928,1018,1239,1328,1442,1481,1494,1950,2198,2212,2215,2322,2475,2531 'mockresolvedvalu':1568,1596 'mode':2161 'modul':82,310,377,388,477,482,504,537,589,594,642,790,1617,2196,2340,2552 'module-level':1616 'module.exports':495,528,1822 'modulenamemapp':381,520,573 'mount':832,1433 'multipl':2156 'must':611,1539,2237 'name':610,858,881,1452,2006,2081,2100,2180 'nativ':3,10,13,59,68,81,94,118,298,309,387,471,499,507,510,518,541,544,567,571,638,641,652,660,673,700,705,711,789,855,1054,1061,1068,1075,1271,1400,1504,1512,1537,1645,1674,1697,1927,2195,2339,2469,2491,2504,2516,2527,2545,2551 'native-bas':566 'navig':191,513,555,558,1338,2243,2366 'need':696,929,1794,1925,2539 'negat':1383 'nent':546,548 'net':1382 'net-neg':1381 'network':352 'never':879,2433 'node':86,396,503,536,588,2029,2336 'node-vers':2028 'noemit':2040 'nois':632 'not.tohavebeencalled':1604 'note':911,1457 'noth':1200 'notifee/react-native':519 'nov':1365 'npm':426,2033,2035,2042 'npx':446,2038 'null':1150,1151,1161,1569 'object':926 'often':2554 'one':1258,1403 'orchestr':2152 'order':216 'originalwarn':748,767 'output':2227,2406 'packag':2179 'paid':1702,2151 'pangesturehandl':665 'pariti':1691 'pass':827,1107,1225,1463 'pass-through':1462 'passthrough':857,940,945,950,955,960,965,970,975,980,985 'password':1962 'pattern':6,598,2498 'peer':678,1982 'per':2523 'philosophi':1641 'picker':313 'pitfal':29,106 'pixel':2405,2417 'pixel-level':2416 'platform':2412 'pod':2087,2549 'presenc':275,1475,2379 'present':1287,2431 'preset':374,472,496,529 'preview':2135,2142 'primari':1001 'produc':2385 'product':221 'profil':2134 'promis':1619 'promise.all':1573 'prone':280 'prop':825,865,870,1105,1213,1242,1329,1515,1521,2401,2509 'properti':2188 'provid':209,1387,1947,2480,2494 'pull':79,647,838,2010 'pure':1286,2426 'purpos':46 'push':197,1964,1973,2003,2009,2528,2529 'pushplatform':1051 'qa':269,2390 'querybytestid':1195,1203 'race':279 'race-pron':278 're':742,2129,2359,2500 're-en':741 'react':9,12,58,67,93,441,462,470,498,506,509,512,517,540,543,554,557,570,637,651,659,672,699,704,710,847,849,854,1053,1060,1067,1074,1138,1503,1511,1518,2242,2257 'react-nat':469,497,505,508,516,539,542,636,658,853,1510 'react-native-gesture-handl':650,1502 'react-native-reanim':671,698,703 'react-native-safe-area-context':709 'react-native-svg':569 'react-navig':511,553,556 'react-test-render':440,461 'react.forwardref':860 'react.reactnode':718,723,873 'read':2187,2191 'readabl':1721 'real':127,262,273,307,392,841,1091,1945,1963,1981,2207,2333,2382,2394,2452,2541 'realtim':255,2377 'reanim':674,691,701,706 'receiv':260 'recommend':1714,1748 'record':862 'ref':866,876,877 'refactor':1276 'refresh':224 'registerpushtoken':1080 'regress':128,1319,1408 'reli':2315 'reliabl':1685 'removelisten':992 'removemessagelisten':1046 'render':203,247,443,464,792,797,1095,1119,1171,1190,1196,1201,1210,1232,1296,1322,1417,1421,1440,1445 'request':2011 'requir':261,657,702,1509,1517,2381 'resolut':378,478 'resolv':1199,1208 'respons':245,2360 'rest':869,882 'result':1571 'retri':225 'return':318,662,766,874,1160,1162,1513 'reus':1679 'right':728,824,830,835 'rn':146,372,425,492,628,914,1711,1796 'rntl':71,2473 'rout':2463 'router':486 'rule':174,330,1266,1395,1532,2321 'run':53,391,1669,1677,1695,1722,1789,2015,2034,2037,2041,2050,2073,2084,2101,2154,2234,2332,2440,2560 'runner':1665,1745,2053,2057 'runs-on':2014,2072 'safe':712,1543 'safeareaprovid':715,1460,1490 'safeareaview':720 'save':429 'save-dev':428 'schedul':2239 'scheme':2092 'scope':2423 'screen':836,1117,1340,2437 'sdk':21,609,2094,2176,2327,2478 'second':1253,1724 'secrets.maestro':2115 'see':406,412,2201,2252 'send':258,1783,1801,1860,1913 'send-button':1782,1800,1912 'sendbuttonstyl':1810 'sens':1730 'sentri':564 'sentry-expo':563 'server':263,2383 'set':2300 'setup':16,619,1471,1658,2273,2474 'setupfilesaftereach':500,533 'setus':1147,1156 'ship':592 'short':1626 'short-circuit':1625 'signal':308 'silenc':627,734,2249 'simctl':2286 'simplifi':2068 'simul':1836,1846,1985,2282 'singl':1652 'skill':2462,2465 'skill-cometchat-native-testing' 'skip':45,163,235,1589,1976,2376 'slot':1811,2307 'slow':266,1672,1935 'smoke':2147 'snapshot':28,104,285,304,398,1280,1285,1307,1316,1337,1354,1369,2217,2231,2421,2434 'socket':283,786 'sourc':595 'source-cometchat' 'spare':405,1283 'specif':107,476,1122 'speed':1681 'src/app.test.tsx':1419 'src/providers/__tests__/cometchatprovider.test.tsx':1545 'src/screens/__tests__/messagesscreen.test.tsx':1169 'src/screens/messagesscreen.tsx':1125 'stabl':1688 'standard':145 'state':103,189,284,669 'steep':1705 'step':2020,2077 'store':1241 'strategi':806 'string':757,859,863,1028,1038,1144,1304 'stub':319 'success':1083,1088 'suit':2387 'support':1699,1806,1989 'surfac':2555 'svg':572 'symptom':2162 'syntaxerror':602,2165 'system':1010,1015 'take':922 'tap':198,1868,1884,1889,1898,1915,2535 'tap-to-deep-link':2534 'tapgesturehandl':667 'tapon':1754,1761,1765,1769,1780 'teach':47 'team':1718 'templat':1817,2309 'test':4,5,14,22,41,54,64,69,96,105,125,147,160,166,178,246,251,286,320,333,365,368,433,437,442,454,458,463,624,634,740,818,1032,1042,1098,1109,1167,1175,1186,1224,1254,1281,1350,1370,1385,1412,1424,1431,1525,1556,1584,1607,1792,1849,1957,2007,2043,2139,2148,2150,2203,2248,2258,2262,2269,2330,2351,2357,2395,2422,2439,2451,2470,2482,2501,2513,2522,2530 'testid':880,1103,1449,1468,1486,1499,1522,1799,2298,2399 'testing-librari':367,432,436,453,457,623,1174,1423,2261,2268 'testrunn':1823 'text':206,2317 'textprimari':1005 'theme':110,290,299,1348,2223,2407 'theme-driven':109 'theme-fre':1347 'thumb':176 'time':2344 'tobe':1250 'tobenul':1205 'tobetruthi':1219,1456 'tobevis':1923 'tohavebeencalledtim':1582 'tohavebeencalledwith':1222 'token':223,604,1313,2167,2224 'tomatchinlinesnapshot':1362 'tool':361,1974 'toolchain':359 'toolkit':148 'top':726,779 'top-level':778 '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' 'tradeoff':415 'transform':585,1301,2171,2428 'transformignorepattern':502,535,578,2182 'transpar':810 'tri':2449 'trigger':193 'troubleshoot':2546 'true':1084,1089,1251 'truth':135 'ts':621,845,1020,1500,1850 'tsc':2039 'tsx':1124,1168,1344,1418,1544 'tue':1363 'two':1606,1633,1984 'type':276,1831,1837,1840 'typeerror':2185 'typeof':754 'types/jest':444 'typescript':1656 'typetext':1875,1905 'typographi':1007 'ubuntu':2018 'ubuntu-latest':2017 'ui':19,236,242,292,347,384,607,645,772,775,915,1291,1323,1332,1374,1804,2173,2302,2324,2354,2369,2476 'uid':232,234,897,909,1027,1030,1142,1143,1154,1157,1759,1774,1873,1878,1896 'uid-input':1872 'uikitset':925 'uikitsettingsbuild':920 'unabl':759 'undefin':890,902,2190 'unexpect':603,2166 'unimodul':561,562 'unit':62,363 'unknown':752,861,864 'unregisterpushtoken':1085 'updat':294,349,1334,1376,2225,2240 'updatesnapshot':2235 'use':267,404,1282,1955,1983,2021,2024,2078,2104,2388,2424 'useeffect':1135,1152 'useinsertioneffect':2236 'user':228,1033,1123,1146,1159,1164,1165,1188,1212 'user-id':227 'usesafeareainset':725 'usest':1136,1148 'usethem':999 'v1':2110 'v4':2023,2026,2080 'v5':913 'valu':805,2402 'valuabl':341,1257 'variabl':1343 'verifi':322,819,2290 'version':2030 'via':1474,1808,1813,1967,2306 'view':190,656,664,666,668,811,851,875,1245,1447,1465,1508,1520,1816,2308,2312,2521 'voip':1076,1079 'vs':33,42,120,129,1631,2484 'waitfor':1172,1215 'want':1738 'warn':631,2241,2245 'wast':2342 'websocket':2208 'wire':211,785 'without':596,837,1466 'wix.github.io':154 'wix.github.io/detox,':153 'work':2144,2348 'workspac':2090,2123 'worth':168,177 'wrap':468,1309 'wrapper':215,1392,1416,1437,1443 'write':51 'wrote':182 'xcode':1660 'xcodebuild':2089 'xcrun':2285 'yaml':123,1650,1657,1750,2005,2070,2293 'yes':1692,1693 'yourapp':2093 'yourapp.xcworkspace':2091","prices":[{"id":"a8b2e82e-86cb-4bfd-b638-e36c04162094","listingId":"778b2c74-a381-4ae5-9b0b-ee1226d21a6d","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:15.310Z"}],"sources":[{"listingId":"778b2c74-a381-4ae5-9b0b-ee1226d21a6d","source":"github","sourceId":"cometchat/cometchat-skills/cometchat-native-testing","sourceUrl":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-native-testing","isPrimary":false,"firstSeenAt":"2026-05-07T13:05:15.310Z","lastSeenAt":"2026-05-18T19:04:54.957Z"}],"details":{"listingId":"778b2c74-a381-4ae5-9b0b-ee1226d21a6d","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cometchat","slug":"cometchat-native-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":"aae7a5cf9e099bd37cd160eaaf0de69d20ee80d5","skill_md_path":"skills/cometchat-native-testing/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-native-testing"},"layout":"multi","source":"github","category":"cometchat-skills","frontmatter":{"name":"cometchat-native-testing","license":"MIT","description":"Testing patterns for CometChat React Native — Jest + React Native Testing Library setup, mocking the UI Kit + SDK, testing custom bubbles / headers / composer actions, snapshot pitfalls, E2E with Detox vs Maestro, and CI integration. Covers what to test vs what to skip.","compatibility":"Node.js >=18; React Native >=0.70; @cometchat/chat-uikit-react-native ^5; Jest ^29; @testing-library/react-native ^12"},"skills_sh_url":"https://skills.sh/cometchat/cometchat-skills/cometchat-native-testing"},"updatedAt":"2026-05-18T19:04:54.957Z"}}