Merged
Conversation
This PR was created automatically by CI. Co-authored-by: Ivan Sekovanikj <31964049+isekovanic@users.noreply.github.com> Co-authored-by: Stream Bot <runner@runnervmeorf1.mdwwigey15hubdk4xsiuhudezb.dx.internal.cloudapp.net>
…3562) ## Summary Migrates the remaining JS test infrastructure to TypeScript, then type-tightens the whole test suite with full `noImplicitAny: true` strictness and wires `yarn test:typecheck` into CI as a required check. ### Migration (baseline) - 44 mock-builders (`package/src/mock-builders/`): API response builders, event dispatchers, data generators, and the core `mock.ts` client helper - 36 `.test.js` files → `.test.ts` / `.test.tsx` across components and utils - 2 offline-support helpers → `.tsx` - `test-utils/BetterSqlite.js` → `.ts` - `jest-setup.js` → `.tsx` (contains JSX for the `BottomSheetModal` mock) - New `package/tsconfig.test.json` so tests and mock-builders are type-checked (base `tsconfig.json` still excludes them from the published build) - New `yarn test:typecheck` script, wired into `.github/workflows/check-pr.yml` ### Type-tightening - **fix(store,messagelist):** type-annotate empty arrays in 8 source files where `const queries = []` was inferring `never[]` under the broader include scope. Real latent issues; no behavior change. - **refactor(mock-builders):** tighten types in generators and event dispatchers using SDK types from `stream-chat`; drop fields not on `Attachment`; add missing `reminders` on default channel config; narrow `client.channel(...)` args. - **refactor(mock-builders): `generateMessage` now returns `LocalMessage`.** Previously typed as `MessageResponse` but at runtime produced `Date` objects for `created_at`/`updated_at`/`pinned_at` — the `LocalMessage` shape. Making the type honest eliminated 33 `as unknown as LocalMessage` casts and 57 `toLocalMessage(…)` wrapper calls across the suite. API mocks and event dispatchers that legitimately need the wire shape accept `MessageResponse | LocalMessage` at their boundary. - **refactor(tests):** annotate all test bodies. Uses the established `{...} as unknown as XContextValue` pattern for partial context mocks. Replaces every bogus `as unknown as FileUpload` (leftover silent bug — `FileUpload` was never imported) with the correct SDK type (`LocalAudioAttachment` / `LocalVoiceRecordingAttachment`). Uses `LocalAttachment` (not `Partial<Attachment>`) for attachment mocks that set `localMetadata`. Uses `ComponentProps<typeof X>` for `renderComponent({ props })` typings. - **refactor(tests): flip `noImplicitAny: true`** and annotate the ~630 resulting errors across ~20 test files. `let chatClient: StreamChat`, typed destructured params, typed `jest.fn()` callbacks, `ComponentProps<typeof X>` for helper prop shapes. Zero `any` / `as any` added. ### Dead-prop cleanup Removing spread+cast and `@ts-ignore` escape hatches made TypeScript surface a slew of props tests were passing that target components don't actually accept. 15+ dead props removed across 16 test files. Notable: - `MessageAuthor`: `alignment`, `groupStyles` (live on `MessageContextValue`; `MessageAuthor` doesn't pick them). - `MessageReplies`: `groupStyles`, `MessageRepliesAvatars`, `openThread` (typo — real prop is `onOpenThread`; silently dropped). - `Message`: `reactionsEnabled`, `MessageFooter` override. - `ScrollToBottomButton`: `t` (supplied via `TranslationProvider`). - `ChannelPreviewView`: `client`, `latestMessagePreview`, `watchers`, `latestMessage`, `latestMessageLength`. - `MessageList`: `channelUnreadState` (internal state, never a prop). - `Channel`: `client` (comes from `ChatContext`, caught on `Thread.test.tsx`). - `Giphy` test helper: widened `Record<string, unknown>` → `ComponentProps<typeof Giphy>`. Also: zero `@ts-ignore` / `@ts-expect-error` directives remain in any `*.test.*` file. ### Dependency changes - `@types/jest`: `^29.5.14` → `^30.0.0` (matches installed `jest@30`) - `jest`: `^30.0.0` → `^30.3.0` - `@total-typescript/shoehorn`: new devDependency — `fromPartial<T>()` for type-safe partial mocks, replacing `as any` / `Record<string, any>` patterns ### Source-file changes All zero-behavior-change type annotations: - `src/store/apis/{addPendingTask,deleteMessage,upsertDraft}.ts` - `src/store/sqlite-utils/{appendOrderByClause,appendWhereCluase,createCreateTableQuery}.ts` - `src/components/MessageList/hooks/useMessageList.ts` - `src/components/Message/MessageItemView/utils/renderText.tsx` — `@ts-expect-error` on the untyped `react-native-markdown-package` import switched to `@ts-ignore` so both base and test tsconfigs agree. ### Follow-ups (out of scope) - `package/src/store/apis/upsertDraft.ts:55` — `queries.concat(query)` is a no-op (returns a new array that's never used). Kept out of scope since fixing it is a behavior change on production code. - `MessageStatus.test.tsx` had `it.each('string', fn)` (malformed — string iterated as characters). Converted to `it.skip` to preserve pre-migration runtime behavior. Un-skipping and rewriting is a follow-up. ## Test plan - [x] `yarn build` passes - [x] `yarn lint` passes - [x] `yarn test:typecheck` — **0 errors with `noImplicitAny: true` and full strict mode** - [x] `yarn test:unit` — 751 passed, 14 skipped. Only the pre-existing SQLite-isolation flake in `offline-support/index.test.ts` fails intermittently (baseline on develop was 5 failures; this branch is 1 — no regressions) - [x] Zero `@ts-ignore` / `@ts-expect-error` directives remain in any `*.test.*` file - [x] `yarn test:typecheck` is wired as a required check in `.github/workflows/check-pr.yml` - [x] CI green on push
## 🎯 Goal
<!-- Describe why we are making this change -->
## 🛠 Implementation details
<!-- Provide a description of the implementation -->
## 🎨 UI Changes
<!-- Add relevant screenshots -->
<details>
<summary>iOS</summary>
<table>
<thead>
<tr>
<td>Before</td>
<td>After</td>
</tr>
</thead>
<tbody>
<tr>
<td>
<!--<img src="" /> -->
</td>
<td>
<!--<img src="" /> -->
</td>
</tr>
</tbody>
</table>
</details>
<details>
<summary>Android</summary>
<table>
<thead>
<tr>
<td>Before</td>
<td>After</td>
</tr>
</thead>
<tbody>
<tr>
<td>
<!--<img src="" /> -->
</td>
<td>
<!--<img src="" /> -->
</td>
</tr>
</tbody>
</table>
</details>
## 🧪 Testing
<!-- Explain how this change can be tested (or why it can't be tested)
-->
## ☑️ Checklist
- [ ] I have signed the [Stream
CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform)
(required)
- [ ] PR targets the `develop` branch
- [ ] Documentation is updated
- [ ] New code is tested in main example apps, including all possible
scenarios
- [ ] SampleApp iOS and Android
- [ ] Expo iOS and Android
## 🎯 Goal Depends on: GetStream/stream-chat-js#1715 ## 🛠 Implementation details <!-- Provide a description of the implementation --> ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android --------- Co-authored-by: Ivan Sekovanikj <ivan.sekovanikj@getstream.io>
## 🎯 Goal
This PR adds optional native multipart upload support for React Native
and Expo packages, with native iOS/Android uploaders, a JS axios
adapter, upload progress propagation and new attachment progress UI.
Additionally, it also moves pending attachment uploads onto
`client.uploadManager`, adds local attachment id tracking, improves
video/document attachment handling, and updates SampleApp to exercise
the new native upload path.
The reason why we decided to add an opt-in native upload is related to
the fact that `axios` does not always report upload progress correctly
on React Native, especially Android. It will sometimes either not update
the progress at all or report it badly, causing UI glitches.
Additionally, native uploads are much, much faster as we take advantage
of streaming directly without any intermediate ephemeral files in order
to do that. Finally, `axios` can easily break if an override to the
underlying RN's `fetch` implementation has been made, especially on
`Android`.
## What Changed
- Added a shared native multipart upload module for iOS and Android,
including request parsing, file/text multipart parts, progress events,
cancellation, timeouts, response handling, and bounded response body
reads.
- Added native package and Expo package bindings for
`StreamMultipartUploader`, plus native handler registration through
`stream-chat-react-native` and `stream-chat-expo`
- Added core JS helpers and public types for native multipart upload
requests, responses, progress events, abort handling, and uploader
creation
- Added `installNativeMultipartAdapter` /
`wrapAxiosAdapterWithNativeMultipart` to route multipart `FormData`
axios requests through the native uploader when available, while leaving
non-multipart requests on the existing adapter
- Added `Chat` support for enabling native multipart uploads via
`useNativeMultipartUpload`; SampleApp enables this path
- Reworked pending message attachment uploads to use
`client.uploadManager.upload` by local attachment id instead of directly
calling `channel.sendImage` / `channel.sendFile`
- Added `localId` propagation from local attachments into message
attachments so pending uploads can be correlated with
`client.uploadManager`
- Updated message sendability and upload indicator behavior to depend on
`allowSendBeforeAttachmentsUpload` rather than offline support
- Added upload progress UI for image, video, file, and audio
attachments, including circular determinate progress, media overlays,
file/audio byte progress labels, and a short completion hold to avoid UI
flicker
- Added new overrideable/default components for attachment upload
progress: `AttachmentUploadIndicator`, `CircularProgressIndicator`, and
`MediaUploadProgressOverlay`
- Updated gallery/video thumbnail rendering so pending media attachments
can show upload progress overlays
- Updated document picking in both native and Expo packages to generate
thumbnails for picked video files (this was missing from V9 initially)
- Updated iOS video thumbnail URL handling to strip query and fragment
data from local file URLs
- Refined native iOS shimmer behavior to reduce animation restarts,
handle foreground/background transitions, visibility, alpha, trait
changes, and resolved color updates more reliably (this should improve
shimmer performance for iOS significantly)
- Updated `Android` shared native source syncing to resolve shared
native sources from the canonical project path
- Replaced SampleApp’s `react-native-fast-image` dependency with
`@d11/react-native-fast-image`
## 🛠 Implementation details
<!-- Provide a description of the implementation -->
## 🎨 UI Changes
<!-- Add relevant screenshots -->
<details>
<summary>iOS</summary>
<table>
<thead>
<tr>
<td>Before</td>
<td>After</td>
</tr>
</thead>
<tbody>
<tr>
<td>
<!--<img src="" /> -->
</td>
<td>
<!--<img src="" /> -->
</td>
</tr>
</tbody>
</table>
</details>
<details>
<summary>Android</summary>
<table>
<thead>
<tr>
<td>Before</td>
<td>After</td>
</tr>
</thead>
<tbody>
<tr>
<td>
<!--<img src="" /> -->
</td>
<td>
<!--<img src="" /> -->
</td>
</tr>
</tbody>
</table>
</details>
## 🧪 Testing
<!-- Explain how this change can be tested (or why it can't be tested)
-->
## ☑️ Checklist
- [ ] I have signed the [Stream
CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform)
(required)
- [ ] PR targets the `develop` branch
- [ ] Documentation is updated
- [ ] New code is tested in main example apps, including all possible
scenarios
- [ ] SampleApp iOS and Android
- [ ] Expo iOS and Android
---------
Co-authored-by: Zita Szupera <szuperaz@gmail.com>
Contributor
SDK Size
|
Next releasesv9.1.09.1.0 (2026-04-24)
sampleapp@v4.11.04.11.0 (2026-04-24)
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🎯 Goal
🛠 Implementation details
🎨 UI Changes
iOS
Android
🧪 Testing
☑️ Checklist
developbranch