Ground truth:
@cometchat/chat-uikit-react@7. Component/method names come fromcometchat-react-v7-core+ its catalog; signatures are FETCHED viacometchat-react-v7-core/references/docs-map.md. The UI Kit docs have no dedicated testing page — this is the pack's own guidance (tracked DOCS GAP). Never assert against kit-internal DOM classes; they are not a public contract.
Companion skills (read first)
cometchat-react-v7-core— the init→login→render lifecycle these tests exercise.
Use this skill when
Adding tests around a CometChat integration, or a "how do I test this" question. NOT part of a normal build — only when tests are explicitly asked for (RULES.md → Verification scope).
Decide what you are testing
You are testing your code, not CometChat's kit. Three layers:
- Your logic (token fetch, UID mapping, routing, state) → unit-test in isolation, mock the SDK.
- Your wiring (does the surface mount after init+login, are the right props passed) → render under a test provider with the SDK mocked.
- The real round-trip (send → receive) → a thin E2E against a test app, not a unit test.
Do not unit-test that CometChatMessageList renders messages — that is the kit's own test surface.
Mock the SDK in unit tests
Mock the two entry modules so nothing hits the network and no real login is attempted:
vi.mock("@cometchat/chat-sdk-javascript", () => ({ CometChat: { getLoggedinUser: vi.fn().mockResolvedValue(null) } }));
vi.mock("@cometchat/chat-uikit-react", async (orig) => ({
...(await orig()),
CometChatUIKit: { initFromSettings: vi.fn().mockResolvedValue(null), getLoggedInUser: vi.fn().mockReturnValue(null), login: vi.fn().mockResolvedValue({ getUid: () => "u1" }), loginWithAuthToken: vi.fn().mockResolvedValue({ getUid: () => "u1" }), logout: vi.fn().mockResolvedValue(undefined) },
}));
(Jest: swap vi for jest.) Now assert your own token-fetch and error handling without a backend.
Render the surface under test
The kit surface mounts only after init+login resolve. Tests must await that gate, not assert synchronously:
render(<App />);
expect(await screen.findByText(/sign in|loading|chats/i)).toBeInTheDocument();
Prefer findBy* (async) over getBy*; a synchronous query runs before the init promise settles and fails intermittently. Wrap the surface in CometChatErrorBoundary in the app so a thrown error surfaces as a testable fallback, not an unhandled rejection.
E2E smoke (Playwright)
One high-value path against a real test app (seeded users, dev Auth Key in a test-only env): load the app, sign in, assert the conversation list renders with real height and a message can be sent. Assert on your visible text/roles and the presence of the mounted surface — not on kit BEM classes. Keep it to the happy path plus one auth-failure path; the kit's internals are already tested upstream.
Not worth automating
Kit component internals, exhaustive prop matrices, live calls/push (device-dependent), and pixel snapshots of kit UI (they churn across minor kit versions). Spend the budget on your token flow, UID mapping, and the init-gate wiring.
Common pitfalls
- Synchronous assertions before init resolves — flaky; use
findBy*/waitFor. - Asserting on kit DOM classes — they change across versions; assert your own markup + roles.
- A real login in unit tests — mock
CometChatUIKit; never ship a test Auth Key to prod env files. - StrictMode double-invoke — mocks must be idempotent (return the same resolved user), mirroring the app's in-flight guard.
Verify it works
Unit tests pass with the SDK mocked (no network) · the surface test awaits the init gate and finds the mounted UI · the E2E smoke signs in and renders conversations against a test app · no test asserts a kit-internal class.