diff --git a/package.json b/package.json index 888050b04c..8121dbc444 100644 --- a/package.json +++ b/package.json @@ -234,7 +234,7 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "semantic-release": "^25.0.2", - "stream-chat": "^9.38.0", + "stream-chat": "^9.41.1", "ts-jest": "^29.2.5", "typescript": "^5.4.5", "typescript-eslint": "^8.17.0" diff --git a/src/components/Message/utils.tsx b/src/components/Message/utils.tsx index 5a1974d6be..8b998b79ab 100644 --- a/src/components/Message/utils.tsx +++ b/src/components/Message/utils.tsx @@ -497,11 +497,12 @@ export const isMessageBounced = ( message.moderation?.action === 'bounce'); export const isMessageBlocked = ( - message: Pick, + message: Pick, ) => - message.type === 'error' && - (message.moderation_details?.action === 'MESSAGE_RESPONSE_ACTION_REMOVE' || - message.moderation?.action === 'remove'); + message.shadowed || + (message.type === 'error' && + (message.moderation_details?.action === 'MESSAGE_RESPONSE_ACTION_REMOVE' || + message.moderation?.action === 'remove')); export const isMessageEdited = (message: Pick) => !!message.message_text_updated_at; diff --git a/src/components/MessageInput/__tests__/EditMessageForm.test.js b/src/components/MessageInput/__tests__/EditMessageForm.test.js index e2c2daeb84..7626b7185b 100644 --- a/src/components/MessageInput/__tests__/EditMessageForm.test.js +++ b/src/components/MessageInput/__tests__/EditMessageForm.test.js @@ -91,6 +91,27 @@ const fileUploadUrl = 'http://www.getstream.io'; // real url, because ImageAttac const getImage = () => new File(['content'], filename, { type: 'image/png' }); const getFile = (name = filename) => new File(['content'], name, { type: 'text/plain' }); +/** Matches Channel.sendFile / sendImage (uri, name?, contentType?, user?, axiosRequestConfig?). */ +const expectChannelUploadSendFile = (spy, file) => { + expect(spy).toHaveBeenCalledWith( + file, + undefined, + undefined, + undefined, + expect.objectContaining({ onUploadProgress: expect.any(Function) }), + ); +}; + +const expectChannelUploadSendImage = (spy, image) => { + expect(spy).toHaveBeenCalledWith( + image, + undefined, + undefined, + undefined, + expect.objectContaining({ onUploadProgress: expect.any(Function) }), + ); +}; + const sendMessageMock = jest.fn(); const editMock = jest.fn(); const mockAddNotification = jest.fn(); @@ -440,8 +461,8 @@ describe(`EditMessageForm`, () => { }); const filenameTexts = await screen.findAllByTitle(filename); await waitFor(() => { - expect(sendFileSpy).toHaveBeenCalledWith(file); - expect(sendImageSpy).toHaveBeenCalledWith(image); + expectChannelUploadSendFile(sendFileSpy, file); + expectChannelUploadSendImage(sendImageSpy, image); expect(screen.getByTestId(IMAGE_PREVIEW_TEST_ID)).toBeInTheDocument(); expect(screen.getByTestId(FILE_PREVIEW_TEST_ID)).toBeInTheDocument(); filenameTexts.forEach((filenameText) => expect(filenameText).toBeInTheDocument()); @@ -512,7 +533,7 @@ describe(`EditMessageForm`, () => { dropFile(file, formElement); }); await waitFor(() => { - expect(sendImageSpy).toHaveBeenCalledWith(file); + expectChannelUploadSendImage(sendImageSpy, file); }); const results = await axe(container); expect(results).toHaveNoViolations(); @@ -579,7 +600,7 @@ describe(`EditMessageForm`, () => { act(() => dropFile(file, formElement)); await waitFor(() => { - expect(sendFileSpy).toHaveBeenCalledWith(file); + expectChannelUploadSendFile(sendFileSpy, file); }); sendFileSpy.mockImplementationOnce(() => Promise.resolve({ file })); @@ -590,7 +611,7 @@ describe(`EditMessageForm`, () => { await waitFor(() => { expect(sendFileSpy).toHaveBeenCalledTimes(2); - expect(sendFileSpy).toHaveBeenCalledWith(file); + expectChannelUploadSendFile(sendFileSpy, file); }); await axeNoViolations(container); }); diff --git a/src/components/MessageInput/__tests__/MessageInput.test.js b/src/components/MessageInput/__tests__/MessageInput.test.js index 0ce72535ec..ddd97cdad9 100644 --- a/src/components/MessageInput/__tests__/MessageInput.test.js +++ b/src/components/MessageInput/__tests__/MessageInput.test.js @@ -79,6 +79,27 @@ const fileUploadUrl = 'http://www.getstream.io'; // real url, because ImageAttac const getImage = () => new File(['content'], filename, { type: 'image/png' }); const getFile = (name = filename) => new File(['content'], name, { type: 'text/plain' }); +/** Matches Channel.sendFile / sendImage (uri, name?, contentType?, user?, axiosRequestConfig?). */ +const expectChannelUploadSendFile = (spy, file) => { + expect(spy).toHaveBeenCalledWith( + file, + undefined, + undefined, + undefined, + expect.objectContaining({ onUploadProgress: expect.any(Function) }), + ); +}; + +const expectChannelUploadSendImage = (spy, image) => { + expect(spy).toHaveBeenCalledWith( + image, + undefined, + undefined, + undefined, + expect.objectContaining({ onUploadProgress: expect.any(Function) }), + ); +}; + const sendMessageMock = jest.fn(); const mockAddNotification = jest.fn(); @@ -411,8 +432,8 @@ describe(`MessageInputFlat`, () => { }); const filenameTexts = await screen.findAllByTitle(filename); await waitFor(() => { - expect(sendFileSpy).toHaveBeenCalledWith(file); - expect(sendImageSpy).toHaveBeenCalledWith(image); + expectChannelUploadSendFile(sendFileSpy, file); + expectChannelUploadSendImage(sendImageSpy, image); expect(screen.getByTestId(IMAGE_PREVIEW_TEST_ID)).toBeInTheDocument(); expect(screen.getByTestId(FILE_PREVIEW_TEST_ID)).toBeInTheDocument(); filenameTexts.forEach((filenameText) => expect(filenameText).toBeInTheDocument()); @@ -483,7 +504,7 @@ describe(`MessageInputFlat`, () => { dropFile(file, formElement); }); await waitFor(() => { - expect(sendImageSpy).toHaveBeenCalledWith(file); + expectChannelUploadSendImage(sendImageSpy, file); }); const results = await axe(container); expect(results).toHaveNoViolations(); diff --git a/yarn.lock b/yarn.lock index 2e1732b2a2..4687ef2fd8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11936,10 +11936,10 @@ stdin-discarder@^0.2.2: resolved "https://registry.yarnpkg.com/stdin-discarder/-/stdin-discarder-0.2.2.tgz#390037f44c4ae1a1ae535c5fe38dc3aba8d997be" integrity sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ== -stream-chat@^9.38.0: - version "9.38.0" - resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-9.38.0.tgz#5c13eb8bbc2fa4adb774687b0c9c51f129d1b458" - integrity sha512-nyTFKHnhGfk1Op/xuZzPKzM9uNTy4TBma69+ApwGj/UtrK2pT6rSaU0Qy/oAqub+Bh7jR2/5vlV/8FWJ2BObFg== +stream-chat@^9.41.1: + version "9.41.1" + resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-9.41.1.tgz#a877c8aa800d78b497eec2fad636345d4422309c" + integrity sha512-W8zjfINYol2UtdRMz2t/NN2GyjDrvb4pJgKmhtuRYzCY1u0Cjezcsu5OCNgyAM0QsenlY6tRqnvAU8Qam5R49Q== dependencies: "@types/jsonwebtoken" "^9.0.8" "@types/ws" "^8.5.14" @@ -11984,16 +11984,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -12118,7 +12109,7 @@ stringify-entities@^4.0.0: character-entities-html4 "^2.0.0" character-entities-legacy "^3.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -12132,13 +12123,6 @@ strip-ansi@^3.0.0: dependencies: ansi-regex "^2.0.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -13227,7 +13211,7 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -13245,15 +13229,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"