stream-chat-react-native-core 4.11.1-beta.3 → 4.12.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/lib/commonjs/components/Attachment/Gallery.js +2 -2
  2. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  3. package/lib/commonjs/components/Attachment/{GallaryImage.js → GalleryImage.js} +3 -3
  4. package/lib/{module/components/Attachment/GallaryImage.js.map → commonjs/components/Attachment/GalleryImage.js.map} +1 -1
  5. package/lib/commonjs/components/Attachment/Giphy.js +1 -1
  6. package/lib/commonjs/components/Attachment/Giphy.js.map +1 -1
  7. package/lib/commonjs/components/Attachment/VideoThumbnail.js +4 -5
  8. package/lib/commonjs/components/Attachment/VideoThumbnail.js.map +1 -1
  9. package/lib/commonjs/components/Avatar/Avatar.js +1 -1
  10. package/lib/commonjs/components/Avatar/Avatar.js.map +1 -1
  11. package/lib/commonjs/components/Avatar/GroupAvatar.js +1 -1
  12. package/lib/commonjs/components/Avatar/GroupAvatar.js.map +1 -1
  13. package/lib/commonjs/components/Channel/Channel.js +18 -13
  14. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  15. package/lib/commonjs/components/Channel/hooks/useCreateInputMessageInputContext.js +2 -0
  16. package/lib/commonjs/components/Channel/hooks/useCreateInputMessageInputContext.js.map +1 -1
  17. package/lib/commonjs/components/ChannelPreview/ChannelPreview.js +17 -12
  18. package/lib/commonjs/components/ChannelPreview/ChannelPreview.js.map +1 -1
  19. package/lib/commonjs/components/ImageGallery/ImageGallery.js +37 -30
  20. package/lib/commonjs/components/ImageGallery/ImageGallery.js.map +1 -1
  21. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryImage.js +5 -3
  22. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryImage.js.map +1 -1
  23. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryVideo.js +10 -6
  24. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryVideo.js.map +1 -1
  25. package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js +17 -14
  26. package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
  27. package/lib/commonjs/components/ImageGallery/components/ImageGalleryHeader.js +1 -0
  28. package/lib/commonjs/components/ImageGallery/components/ImageGalleryHeader.js.map +1 -1
  29. package/lib/commonjs/components/ImageGallery/components/ImageGalleryOverlay.js +2 -1
  30. package/lib/commonjs/components/ImageGallery/components/ImageGalleryOverlay.js.map +1 -1
  31. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js +36 -18
  32. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  33. package/lib/commonjs/components/ImageGallery/components/ImageGrid.js +3 -1
  34. package/lib/commonjs/components/ImageGallery/components/ImageGrid.js.map +1 -1
  35. package/lib/commonjs/components/ImageGallery/components/ImageGridHandle.js +5 -4
  36. package/lib/commonjs/components/ImageGallery/components/ImageGridHandle.js.map +1 -1
  37. package/lib/commonjs/components/Message/Message.js +8 -6
  38. package/lib/commonjs/components/Message/Message.js.map +1 -1
  39. package/lib/commonjs/components/Message/MessageSimple/utils/parseLinks.js +1 -1
  40. package/lib/commonjs/components/Message/MessageSimple/utils/parseLinks.js.map +1 -1
  41. package/lib/commonjs/components/Message/MessageSimple/utils/parseLinks.test.js +1 -1
  42. package/lib/commonjs/components/Message/MessageSimple/utils/parseLinks.test.js.map +1 -1
  43. package/lib/commonjs/components/MessageInput/AudioAttachmentUploadPreview.js +538 -0
  44. package/lib/commonjs/components/MessageInput/AudioAttachmentUploadPreview.js.map +1 -0
  45. package/lib/commonjs/components/MessageInput/FileUploadPreview.js +143 -32
  46. package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
  47. package/lib/{module/components/ImageGallery/components → commonjs/components/ProgressControl}/ProgressControl.js +37 -24
  48. package/lib/commonjs/components/ProgressControl/ProgressControl.js.map +1 -0
  49. package/lib/commonjs/components/index.js +26 -0
  50. package/lib/commonjs/components/index.js.map +1 -1
  51. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +5 -2
  52. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  53. package/lib/commonjs/contexts/messageInputContext/hooks/useCreateMessageInputContext.js +7 -2
  54. package/lib/commonjs/contexts/messageInputContext/hooks/useCreateMessageInputContext.js.map +1 -1
  55. package/lib/commonjs/contexts/themeContext/utils/theme.js +9 -0
  56. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  57. package/lib/commonjs/icons/Pause.js +2 -2
  58. package/lib/commonjs/icons/Pause.js.map +1 -1
  59. package/lib/commonjs/mock-builders/api/channelMocks.js +1 -0
  60. package/lib/commonjs/mock-builders/api/channelMocks.js.map +1 -1
  61. package/lib/commonjs/native.js +13 -5
  62. package/lib/commonjs/native.js.map +1 -1
  63. package/lib/commonjs/version.json +1 -1
  64. package/lib/module/components/Attachment/Gallery.js +2 -2
  65. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  66. package/lib/module/components/Attachment/{GallaryImage.js → GalleryImage.js} +3 -3
  67. package/lib/{commonjs/components/Attachment/GallaryImage.js.map → module/components/Attachment/GalleryImage.js.map} +1 -1
  68. package/lib/module/components/Attachment/Giphy.js +1 -1
  69. package/lib/module/components/Attachment/Giphy.js.map +1 -1
  70. package/lib/module/components/Attachment/VideoThumbnail.js +4 -5
  71. package/lib/module/components/Attachment/VideoThumbnail.js.map +1 -1
  72. package/lib/module/components/Avatar/Avatar.js +1 -1
  73. package/lib/module/components/Avatar/Avatar.js.map +1 -1
  74. package/lib/module/components/Avatar/GroupAvatar.js +1 -1
  75. package/lib/module/components/Avatar/GroupAvatar.js.map +1 -1
  76. package/lib/module/components/Channel/Channel.js +18 -13
  77. package/lib/module/components/Channel/Channel.js.map +1 -1
  78. package/lib/module/components/Channel/hooks/useCreateInputMessageInputContext.js +2 -0
  79. package/lib/module/components/Channel/hooks/useCreateInputMessageInputContext.js.map +1 -1
  80. package/lib/module/components/ChannelPreview/ChannelPreview.js +17 -12
  81. package/lib/module/components/ChannelPreview/ChannelPreview.js.map +1 -1
  82. package/lib/module/components/ImageGallery/ImageGallery.js +37 -30
  83. package/lib/module/components/ImageGallery/ImageGallery.js.map +1 -1
  84. package/lib/module/components/ImageGallery/components/AnimatedGalleryImage.js +5 -3
  85. package/lib/module/components/ImageGallery/components/AnimatedGalleryImage.js.map +1 -1
  86. package/lib/module/components/ImageGallery/components/AnimatedGalleryVideo.js +10 -6
  87. package/lib/module/components/ImageGallery/components/AnimatedGalleryVideo.js.map +1 -1
  88. package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js +17 -14
  89. package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
  90. package/lib/module/components/ImageGallery/components/ImageGalleryHeader.js +1 -0
  91. package/lib/module/components/ImageGallery/components/ImageGalleryHeader.js.map +1 -1
  92. package/lib/module/components/ImageGallery/components/ImageGalleryOverlay.js +2 -1
  93. package/lib/module/components/ImageGallery/components/ImageGalleryOverlay.js.map +1 -1
  94. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js +36 -18
  95. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  96. package/lib/module/components/ImageGallery/components/ImageGrid.js +3 -1
  97. package/lib/module/components/ImageGallery/components/ImageGrid.js.map +1 -1
  98. package/lib/module/components/ImageGallery/components/ImageGridHandle.js +5 -4
  99. package/lib/module/components/ImageGallery/components/ImageGridHandle.js.map +1 -1
  100. package/lib/module/components/Message/Message.js +8 -6
  101. package/lib/module/components/Message/Message.js.map +1 -1
  102. package/lib/module/components/Message/MessageSimple/utils/parseLinks.js +1 -1
  103. package/lib/module/components/Message/MessageSimple/utils/parseLinks.js.map +1 -1
  104. package/lib/module/components/Message/MessageSimple/utils/parseLinks.test.js +1 -1
  105. package/lib/module/components/Message/MessageSimple/utils/parseLinks.test.js.map +1 -1
  106. package/lib/module/components/MessageInput/AudioAttachmentUploadPreview.js +538 -0
  107. package/lib/module/components/MessageInput/AudioAttachmentUploadPreview.js.map +1 -0
  108. package/lib/module/components/MessageInput/FileUploadPreview.js +143 -32
  109. package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
  110. package/lib/{commonjs/components/ImageGallery/components → module/components/ProgressControl}/ProgressControl.js +37 -24
  111. package/lib/module/components/ProgressControl/ProgressControl.js.map +1 -0
  112. package/lib/module/components/index.js +26 -0
  113. package/lib/module/components/index.js.map +1 -1
  114. package/lib/module/contexts/messageInputContext/MessageInputContext.js +5 -2
  115. package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  116. package/lib/module/contexts/messageInputContext/hooks/useCreateMessageInputContext.js +7 -2
  117. package/lib/module/contexts/messageInputContext/hooks/useCreateMessageInputContext.js.map +1 -1
  118. package/lib/module/contexts/themeContext/utils/theme.js +9 -0
  119. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  120. package/lib/module/icons/Pause.js +2 -2
  121. package/lib/module/icons/Pause.js.map +1 -1
  122. package/lib/module/mock-builders/api/channelMocks.js +1 -0
  123. package/lib/module/mock-builders/api/channelMocks.js.map +1 -1
  124. package/lib/module/native.js +13 -5
  125. package/lib/module/native.js.map +1 -1
  126. package/lib/module/version.json +1 -1
  127. package/lib/typescript/components/Attachment/{GallaryImage.d.ts → GalleryImage.d.ts} +0 -0
  128. package/lib/typescript/components/Channel/hooks/useCreateInputMessageInputContext.d.ts +1 -1
  129. package/lib/typescript/components/ImageGallery/__tests__/AnimatedVideoGallery.test.d.ts +1 -0
  130. package/lib/typescript/components/ImageGallery/__tests__/ImageGallery.test.d.ts +1 -0
  131. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryFooter.test.d.ts +1 -0
  132. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryGrid.test.d.ts +1 -0
  133. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryGridHandle.test.d.ts +1 -0
  134. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryHeader.test.d.ts +1 -0
  135. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryOverlay.test.d.ts +1 -0
  136. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryVideoControl.test.d.ts +1 -0
  137. package/lib/typescript/components/ImageGallery/components/AnimatedGalleryImage.d.ts +1 -0
  138. package/lib/typescript/components/ImageGallery/components/AnimatedGalleryVideo.d.ts +2 -3
  139. package/lib/typescript/components/ImageGallery/components/ImageGalleryFooter.d.ts +2 -1
  140. package/lib/typescript/components/ImageGallery/components/ImageGrid.d.ts +2 -3
  141. package/lib/typescript/components/Message/hooks/useMessageActionHandlers.d.ts +1 -1
  142. package/lib/typescript/components/Message/hooks/useMessageActions.d.ts +1 -1
  143. package/lib/typescript/components/MessageInput/AudioAttachmentUploadPreview.d.ts +26 -0
  144. package/lib/typescript/components/MessageInput/FileUploadPreview.d.ts +1 -1
  145. package/lib/typescript/components/MessageInput/__tests__/AudioAttachmentUploadPreviewExpo.test.d.ts +1 -0
  146. package/lib/typescript/components/MessageInput/__tests__/AudioAttachmentUploadPreviewNative.test.d.ts +1 -0
  147. package/lib/typescript/components/ProgressControl/ProgressControl.d.ts +11 -0
  148. package/lib/typescript/components/index.d.ts +2 -0
  149. package/lib/typescript/contexts/messageContext/MessageContext.d.ts +1 -1
  150. package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts +7 -1
  151. package/lib/typescript/contexts/messageInputContext/hooks/useCreateMessageInputContext.d.ts +1 -1
  152. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +9 -0
  153. package/lib/typescript/native.d.ts +59 -2
  154. package/package.json +1 -1
  155. package/src/components/Attachment/Gallery.tsx +1 -1
  156. package/src/components/Attachment/{GallaryImage.tsx → GalleryImage.tsx} +1 -1
  157. package/src/components/Attachment/Giphy.tsx +1 -1
  158. package/src/components/Attachment/VideoThumbnail.tsx +1 -2
  159. package/src/components/Attachment/__tests__/Gallery.test.js +6 -6
  160. package/src/components/Attachment/__tests__/Giphy.test.js +4 -4
  161. package/src/components/Avatar/Avatar.tsx +1 -1
  162. package/src/components/Avatar/GroupAvatar.tsx +1 -1
  163. package/src/components/Channel/Channel.tsx +3 -0
  164. package/src/components/Channel/hooks/useCreateInputMessageInputContext.ts +2 -0
  165. package/src/components/ChannelPreview/ChannelPreview.tsx +14 -12
  166. package/src/components/ImageGallery/ImageGallery.tsx +21 -11
  167. package/src/components/ImageGallery/__tests__/AnimatedVideoGallery.test.tsx +241 -0
  168. package/src/components/ImageGallery/__tests__/ImageGallery.test.tsx +192 -0
  169. package/src/components/ImageGallery/__tests__/ImageGalleryFooter.test.tsx +190 -0
  170. package/src/components/ImageGallery/__tests__/ImageGalleryGrid.test.tsx +98 -0
  171. package/src/components/ImageGallery/__tests__/ImageGalleryGridHandle.test.tsx +79 -0
  172. package/src/components/ImageGallery/__tests__/ImageGalleryHeader.test.tsx +172 -0
  173. package/src/components/ImageGallery/__tests__/ImageGalleryOverlay.test.tsx +94 -0
  174. package/src/components/ImageGallery/__tests__/ImageGalleryVideoControl.test.tsx +84 -0
  175. package/src/components/ImageGallery/components/AnimatedGalleryImage.tsx +3 -0
  176. package/src/components/ImageGallery/components/AnimatedGalleryVideo.tsx +11 -3
  177. package/src/components/ImageGallery/components/ImageGalleryFooter.tsx +9 -2
  178. package/src/components/ImageGallery/components/ImageGalleryHeader.tsx +1 -1
  179. package/src/components/ImageGallery/components/ImageGalleryOverlay.tsx +6 -1
  180. package/src/components/ImageGallery/components/ImageGalleryVideoControl.tsx +22 -9
  181. package/src/components/ImageGallery/components/ImageGrid.tsx +19 -17
  182. package/src/components/ImageGallery/components/ImageGridHandle.tsx +4 -1
  183. package/src/components/Message/Message.tsx +2 -1
  184. package/src/components/Message/MessageSimple/__tests__/MessageContent.test.js +9 -3
  185. package/src/components/Message/MessageSimple/__tests__/__snapshots__/MessageAvatar.test.js.snap +1 -1
  186. package/src/components/Message/MessageSimple/utils/parseLinks.test.ts +4 -0
  187. package/src/components/Message/MessageSimple/utils/parseLinks.ts +1 -1
  188. package/src/components/MessageInput/AudioAttachmentUploadPreview.tsx +362 -0
  189. package/src/components/MessageInput/FileUploadPreview.tsx +162 -57
  190. package/src/components/MessageInput/__tests__/AudioAttachmentUploadPreviewExpo.test.tsx +199 -0
  191. package/src/components/MessageInput/__tests__/AudioAttachmentUploadPreviewNative.test.tsx +215 -0
  192. package/src/components/MessageInput/__tests__/FileUploadPreview.test.js +64 -0
  193. package/src/components/{ImageGallery/components → ProgressControl}/ProgressControl.tsx +37 -19
  194. package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +4 -4
  195. package/src/components/index.ts +3 -0
  196. package/src/contexts/messageInputContext/MessageInputContext.tsx +13 -0
  197. package/src/contexts/messageInputContext/hooks/useCreateMessageInputContext.ts +5 -1
  198. package/src/contexts/themeContext/utils/theme.ts +15 -0
  199. package/src/icons/Pause.tsx +2 -2
  200. package/src/mock-builders/api/channelMocks.tsx +1 -0
  201. package/src/native.ts +67 -7
  202. package/src/version.json +1 -1
  203. package/lib/commonjs/components/ImageGallery/components/ProgressControl.js.map +0 -1
  204. package/lib/module/components/ImageGallery/components/ProgressControl.js.map +0 -1
  205. package/lib/typescript/components/ImageGallery/components/ProgressControl.d.ts +0 -5
@@ -471,17 +471,21 @@ export const ImageGallery = <
471
471
  }
472
472
  };
473
473
 
474
- const handlePlayPause = () => {
475
- // React Native Video for RN CLI has seek as an API to move to a particular location in the video
476
- if (progress === 1 && videoRef.current && videoRef.current.seek) {
477
- videoRef.current.seek(0);
478
- }
479
- // Expo AV for Expo has replayAsync as an API to move to a starting of the video
480
- if (progress === 1 && videoRef.current && videoRef.current.replayAsync) {
481
- videoRef.current.replayAsync();
482
- }
474
+ const handlePlayPause = (status?: boolean) => {
475
+ if (status === undefined) {
476
+ // React Native Video for RN CLI has seek as an API to move to a particular location in the video
477
+ if (progress === 1 && videoRef.current && videoRef.current.seek) {
478
+ videoRef.current.seek(0);
479
+ }
480
+ // Expo AV for Expo has replayAsync as an API to move to a starting of the video
481
+ if (progress === 1 && videoRef.current && videoRef.current.replayAsync) {
482
+ videoRef.current.replayAsync();
483
+ }
483
484
 
484
- setPaused((state) => !state);
485
+ setPaused((state) => !state);
486
+ } else {
487
+ setPaused(status);
488
+ }
485
489
  };
486
490
 
487
491
  const onProgressDrag = (progress: number) => {
@@ -497,7 +501,11 @@ export const ImageGallery = <
497
501
  };
498
502
 
499
503
  return (
500
- <Animated.View pointerEvents={'auto'} style={[StyleSheet.absoluteFillObject, showScreenStyle]}>
504
+ <Animated.View
505
+ accessibilityLabel='Image Gallery'
506
+ pointerEvents={'auto'}
507
+ style={[StyleSheet.absoluteFillObject, showScreenStyle]}
508
+ >
501
509
  <Animated.View style={[StyleSheet.absoluteFillObject, containerBackground]} />
502
510
  <TapGestureHandler
503
511
  minPointers={1}
@@ -577,6 +585,7 @@ export const ImageGallery = <
577
585
  />
578
586
  ) : (
579
587
  <AnimatedGalleryImage
588
+ accessibilityLabel={'Image Item'}
580
589
  index={i}
581
590
  key={`${photo.uri}-${i}`}
582
591
  offsetScale={offsetScale}
@@ -615,6 +624,7 @@ export const ImageGallery = <
615
624
  {...imageGalleryCustomComponents?.header}
616
625
  />
617
626
  <ImageGalleryFooter<StreamChatGenerics>
627
+ accessibilityLabel={'Image Gallery Footer'}
618
628
  duration={duration}
619
629
  onPlayPause={handlePlayPause}
620
630
  onProgressDrag={onProgressDrag}
@@ -0,0 +1,241 @@
1
+ import React from 'react';
2
+
3
+ import type { SharedValue } from 'react-native-reanimated';
4
+
5
+ import { act } from 'react-test-renderer';
6
+
7
+ import { fireEvent, render } from '@testing-library/react-native';
8
+
9
+ import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
10
+ import { defaultTheme } from '../../../contexts/themeContext/utils/theme';
11
+ import { AnimatedGalleryVideo, AnimatedGalleryVideoType } from '../components/AnimatedGalleryVideo';
12
+
13
+ jest.mock('../../../native.ts', () => {
14
+ const View = require('react-native/Libraries/Components/View/View');
15
+ return {
16
+ isVideoPackageAvailable: jest.fn(() => true),
17
+ NetInfo: {
18
+ addEventListener: jest.fn(),
19
+ },
20
+ Video: View,
21
+ };
22
+ });
23
+
24
+ const getComponent = (props: Partial<AnimatedGalleryVideoType>) => (
25
+ <ThemeProvider theme={defaultTheme}>
26
+ <AnimatedGalleryVideo {...(props as unknown as AnimatedGalleryVideoType)} />
27
+ </ThemeProvider>
28
+ );
29
+
30
+ describe('ImageGallery', () => {
31
+ it('render image gallery component with video rendered', () => {
32
+ const { queryAllByA11yLabel } = render(
33
+ getComponent({
34
+ offsetScale: { value: 1 } as SharedValue<number>,
35
+ scale: { value: 1 } as SharedValue<number>,
36
+ shouldRender: true,
37
+ source: {
38
+ uri: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
39
+ },
40
+ translateX: { value: 1 } as SharedValue<number>,
41
+ }),
42
+ );
43
+ expect(queryAllByA11yLabel('Image Gallery Video')).toHaveLength(1);
44
+ });
45
+
46
+ it('render empty view when shouldRender is false', () => {
47
+ const { getByA11yLabel } = render(
48
+ getComponent({
49
+ offsetScale: { value: 1 } as SharedValue<number>,
50
+ scale: { value: 1 } as SharedValue<number>,
51
+ shouldRender: false,
52
+ translateX: { value: 1 } as SharedValue<number>,
53
+ }),
54
+ );
55
+
56
+ expect(getByA11yLabel('Empty View Image Gallery')).not.toBeUndefined();
57
+ });
58
+
59
+ it('trigger onEnd and onProgress events handlers of Video component', () => {
60
+ const handleEndMock = jest.fn();
61
+ const handleProgressMock = jest.fn();
62
+
63
+ const { getByTestId } = render(
64
+ getComponent({
65
+ handleEnd: handleEndMock,
66
+ handleProgress: handleProgressMock,
67
+ offsetScale: { value: 1 } as SharedValue<number>,
68
+ scale: { value: 1 } as SharedValue<number>,
69
+ shouldRender: true,
70
+ source: {
71
+ uri: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
72
+ },
73
+ translateX: { value: 1 } as SharedValue<number>,
74
+ }),
75
+ );
76
+
77
+ const videoComponent = getByTestId('video-player');
78
+
79
+ act(() => {
80
+ fireEvent(videoComponent, 'onEnd');
81
+ fireEvent(videoComponent, 'onProgress');
82
+ });
83
+
84
+ expect(handleEndMock).toHaveBeenCalled();
85
+ expect(handleProgressMock).toHaveBeenCalled();
86
+ });
87
+
88
+ it('trigger onLoadStart event handler of Video component', () => {
89
+ const { getByTestId, queryByA11yLabel } = render(
90
+ getComponent({
91
+ offsetScale: { value: 1 } as SharedValue<number>,
92
+ scale: { value: 1 } as SharedValue<number>,
93
+ shouldRender: true,
94
+ source: {
95
+ uri: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
96
+ },
97
+ translateX: { value: 1 } as SharedValue<number>,
98
+ }),
99
+ );
100
+
101
+ const videoComponent = getByTestId('video-player');
102
+ const spinnerComponent = queryByA11yLabel('Spinner');
103
+
104
+ act(() => {
105
+ fireEvent(videoComponent, 'onLoadStart');
106
+ });
107
+ expect(spinnerComponent?.props.style[1].opacity).toBe(1);
108
+ });
109
+
110
+ it('trigger onLoad event handler of Video component', () => {
111
+ const handleLoadMock = jest.fn();
112
+
113
+ const { getByTestId, queryByA11yLabel } = render(
114
+ getComponent({
115
+ handleLoad: handleLoadMock,
116
+ offsetScale: { value: 1 } as SharedValue<number>,
117
+ scale: { value: 1 } as SharedValue<number>,
118
+ shouldRender: true,
119
+ source: {
120
+ uri: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
121
+ },
122
+ translateX: { value: 1 } as SharedValue<number>,
123
+ }),
124
+ );
125
+
126
+ const videoComponent = getByTestId('video-player');
127
+ const spinnerComponent = queryByA11yLabel('Spinner');
128
+
129
+ act(() => {
130
+ fireEvent(videoComponent, 'onLoad');
131
+ });
132
+
133
+ expect(handleLoadMock).toHaveBeenCalled();
134
+ expect(spinnerComponent?.props.style[1].opacity).toBe(0);
135
+ });
136
+
137
+ it('trigger onBuffer event handler of Video component', () => {
138
+ const { getByTestId, queryByA11yLabel } = render(
139
+ getComponent({
140
+ offsetScale: { value: 1 } as SharedValue<number>,
141
+ scale: { value: 1 } as SharedValue<number>,
142
+ shouldRender: true,
143
+ source: {
144
+ uri: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
145
+ },
146
+ translateX: { value: 1 } as SharedValue<number>,
147
+ }),
148
+ );
149
+
150
+ const videoComponent = getByTestId('video-player');
151
+ const spinnerComponent = queryByA11yLabel('Spinner');
152
+
153
+ act(() => {
154
+ fireEvent(videoComponent, 'onBuffer', {
155
+ isBuffering: false,
156
+ });
157
+ });
158
+
159
+ expect(spinnerComponent?.props.style[1].opacity).toBe(0);
160
+
161
+ act(() => {
162
+ fireEvent(videoComponent, 'onBuffer', {
163
+ isBuffering: true,
164
+ });
165
+ });
166
+
167
+ expect(spinnerComponent?.props.style[1].opacity).toBe(1);
168
+ });
169
+
170
+ it('trigger onPlaybackStatusUpdate event handler of Video component', () => {
171
+ jest.spyOn(console, 'error');
172
+ const handleLoadMock = jest.fn();
173
+ const handleProgressMock = jest.fn();
174
+ const handleEndMock = jest.fn();
175
+
176
+ const { getByTestId, queryByA11yLabel } = render(
177
+ getComponent({
178
+ handleEnd: handleEndMock,
179
+ handleLoad: handleLoadMock,
180
+ handleProgress: handleProgressMock,
181
+ offsetScale: { value: 1 } as SharedValue<number>,
182
+ scale: { value: 1 } as SharedValue<number>,
183
+ shouldRender: true,
184
+ source: {
185
+ uri: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
186
+ },
187
+ translateX: { value: 1 } as SharedValue<number>,
188
+ }),
189
+ );
190
+
191
+ const videoComponent = getByTestId('video-player');
192
+ const spinnerComponent = queryByA11yLabel('Spinner');
193
+
194
+ act(() => {
195
+ fireEvent(videoComponent, 'onPlaybackStatusUpdate', {
196
+ error: true,
197
+ isLoaded: false,
198
+ });
199
+ });
200
+
201
+ expect(spinnerComponent?.props.style[1].opacity).toBe(1);
202
+ expect(console.error).toHaveBeenCalled();
203
+
204
+ act(() => {
205
+ fireEvent(videoComponent, 'onPlaybackStatusUpdate', {
206
+ isLoaded: true,
207
+ });
208
+ });
209
+
210
+ expect(spinnerComponent?.props.style[1].opacity).toBe(0);
211
+ expect(handleLoadMock).toHaveBeenCalled();
212
+
213
+ act(() => {
214
+ fireEvent(videoComponent, 'onPlaybackStatusUpdate', {
215
+ isLoaded: true,
216
+ isPlaying: true,
217
+ });
218
+ });
219
+
220
+ expect(handleProgressMock).toHaveBeenCalled();
221
+
222
+ act(() => {
223
+ fireEvent(videoComponent, 'onPlaybackStatusUpdate', {
224
+ isBuffering: true,
225
+ isLoaded: true,
226
+ });
227
+ });
228
+
229
+ expect(spinnerComponent?.props.style[1].opacity).toBe(1);
230
+
231
+ act(() => {
232
+ fireEvent(videoComponent, 'onPlaybackStatusUpdate', {
233
+ didJustFinish: true,
234
+ isLoaded: true,
235
+ isLooping: false,
236
+ });
237
+ });
238
+
239
+ expect(handleEndMock).toHaveBeenCalled();
240
+ });
241
+ });
@@ -0,0 +1,192 @@
1
+ import React from 'react';
2
+
3
+ import type { SharedValue } from 'react-native-reanimated';
4
+
5
+ import { act } from 'react-test-renderer';
6
+
7
+ import { fireEvent, render } from '@testing-library/react-native';
8
+
9
+ import {
10
+ ImageGalleryContext,
11
+ ImageGalleryContextValue,
12
+ } from '../../../contexts/imageGalleryContext/ImageGalleryContext';
13
+ import { OverlayProvider } from '../../../contexts/overlayContext/OverlayProvider';
14
+ import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
15
+ import { defaultTheme } from '../../../contexts/themeContext/utils/theme';
16
+ import {
17
+ generateGiphyAttachment,
18
+ generateImageAttachment,
19
+ generateVideoAttachment,
20
+ } from '../../../mock-builders/generator/attachment';
21
+ import { generateMessage } from '../../../mock-builders/generator/message';
22
+ import type { DefaultStreamChatGenerics } from '../../../types/types';
23
+ import type { MessageType } from '../../MessageList/hooks/useMessageList';
24
+ import { ImageGallery } from '../ImageGallery';
25
+
26
+ jest.mock('../../../native.ts', () => {
27
+ const View = require('react-native/Libraries/Components/View/View');
28
+ return {
29
+ isVideoPackageAvailable: jest.fn(() => true),
30
+ NetInfo: {
31
+ addEventListener: jest.fn(),
32
+ },
33
+ Video: View,
34
+ };
35
+ });
36
+
37
+ const getComponent = (props: Partial<ImageGalleryContextValue>) => (
38
+ <OverlayProvider>
39
+ <ImageGalleryContext.Provider value={{ ...(props as unknown as ImageGalleryContextValue) }}>
40
+ <ThemeProvider theme={defaultTheme}>
41
+ <ImageGallery overlayOpacity={{ value: 1 } as SharedValue<number>} />
42
+ </ThemeProvider>
43
+ </ImageGalleryContext.Provider>
44
+ </OverlayProvider>
45
+ );
46
+
47
+ describe('ImageGallery', () => {
48
+ it('render image gallery component', () => {
49
+ const { queryAllByA11yLabel } = render(
50
+ getComponent({
51
+ images: [
52
+ generateMessage({
53
+ attachments: [
54
+ generateImageAttachment(),
55
+ generateGiphyAttachment(),
56
+ generateVideoAttachment({ type: 'video' }),
57
+ ],
58
+ }),
59
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
60
+ }),
61
+ );
62
+ expect(queryAllByA11yLabel('Image Item')).toHaveLength(2);
63
+ expect(queryAllByA11yLabel('Image Gallery Video')).toHaveLength(1);
64
+ });
65
+
66
+ it('handle handleLoad function when video item present and payload duration is available', () => {
67
+ const { getByA11yLabel } = render(
68
+ getComponent({
69
+ images: [
70
+ generateMessage({
71
+ attachments: [generateVideoAttachment({ type: 'video' })],
72
+ }),
73
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
74
+ }),
75
+ );
76
+
77
+ const videoItemComponent = getByA11yLabel('Image Gallery Video');
78
+
79
+ act(() => {
80
+ fireEvent(videoItemComponent, 'handleLoad', {
81
+ duration: 10,
82
+ });
83
+ });
84
+
85
+ const videoDurationComponent = getByA11yLabel('Video Duration');
86
+ expect(videoDurationComponent.children[0]).toBe('00:10');
87
+ });
88
+
89
+ it('handle handleLoad function when video item present and payload duration is undefined', () => {
90
+ const { getByA11yLabel } = render(
91
+ getComponent({
92
+ images: [
93
+ generateMessage({
94
+ attachments: [generateVideoAttachment({ type: 'video' })],
95
+ }),
96
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
97
+ }),
98
+ );
99
+
100
+ const videoItemComponent = getByA11yLabel('Image Gallery Video');
101
+
102
+ act(() => {
103
+ fireEvent(videoItemComponent, 'handleLoad', {
104
+ duration: undefined,
105
+ });
106
+ });
107
+
108
+ const videoDurationComponent = getByA11yLabel('Video Duration');
109
+ expect(videoDurationComponent.children[0]).toBe('00:00');
110
+ });
111
+
112
+ it('handle handleProgress function when video item present and payload is well defined', () => {
113
+ const { getByA11yLabel } = render(
114
+ getComponent({
115
+ images: [
116
+ generateMessage({
117
+ attachments: [generateVideoAttachment({ type: 'video' })],
118
+ }),
119
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
120
+ }),
121
+ );
122
+
123
+ const videoItemComponent = getByA11yLabel('Image Gallery Video');
124
+
125
+ act(() => {
126
+ fireEvent(videoItemComponent, 'handleLoad', {
127
+ duration: 10,
128
+ });
129
+ fireEvent(videoItemComponent, 'handleProgress', {
130
+ currentTime: 3,
131
+ seekableDuration: 10,
132
+ });
133
+ });
134
+
135
+ const progressDurationComponent = getByA11yLabel('Progress Duration');
136
+
137
+ expect(progressDurationComponent.children[0]).toBe('00:03');
138
+ });
139
+
140
+ it('handle handleProgress function when video item present and payload is not defined', () => {
141
+ const { getByA11yLabel } = render(
142
+ getComponent({
143
+ images: [
144
+ generateMessage({
145
+ attachments: [generateVideoAttachment({ type: 'video' })],
146
+ }),
147
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
148
+ }),
149
+ );
150
+
151
+ const videoItemComponent = getByA11yLabel('Image Gallery Video');
152
+
153
+ act(() => {
154
+ fireEvent(videoItemComponent, 'handleLoad', {
155
+ duration: 10,
156
+ });
157
+ fireEvent(videoItemComponent, 'handleProgress', {
158
+ currentTime: undefined,
159
+ seekableDuration: undefined,
160
+ });
161
+ });
162
+
163
+ const progressDurationComponent = getByA11yLabel('Progress Duration');
164
+
165
+ expect(progressDurationComponent.children[0]).toBe('00:00');
166
+ });
167
+
168
+ it('handle handleEnd function when video item present', () => {
169
+ const { getByA11yLabel } = render(
170
+ getComponent({
171
+ images: [
172
+ generateMessage({
173
+ attachments: [generateVideoAttachment({ type: 'video' })],
174
+ }),
175
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
176
+ }),
177
+ );
178
+
179
+ const videoItemComponent = getByA11yLabel('Image Gallery Video');
180
+
181
+ act(() => {
182
+ fireEvent(videoItemComponent, 'handleLoad', {
183
+ duration: 10,
184
+ });
185
+ fireEvent(videoItemComponent, 'handleEnd');
186
+ });
187
+
188
+ const progressDurationComponent = getByA11yLabel('Progress Duration');
189
+ expect(getByA11yLabel('Play Icon')).not.toBeUndefined();
190
+ expect(progressDurationComponent.children[0]).toBe('00:10');
191
+ });
192
+ });
@@ -0,0 +1,190 @@
1
+ import React from 'react';
2
+
3
+ import { Text, View } from 'react-native';
4
+ import type { SharedValue } from 'react-native-reanimated';
5
+
6
+ import { act, ReactTestInstance } from 'react-test-renderer';
7
+
8
+ import { fireEvent, render, waitFor } from '@testing-library/react-native';
9
+
10
+ import { Chat } from '../../../components/Chat/Chat';
11
+ import {
12
+ ImageGalleryContext,
13
+ ImageGalleryContextValue,
14
+ } from '../../../contexts/imageGalleryContext/ImageGalleryContext';
15
+ import { OverlayProvider } from '../../../contexts/overlayContext/OverlayProvider';
16
+ import {
17
+ generateImageAttachment,
18
+ generateVideoAttachment,
19
+ } from '../../../mock-builders/generator/attachment';
20
+ import { generateMessage } from '../../../mock-builders/generator/message';
21
+ import { getTestClientWithUser } from '../../../mock-builders/mock';
22
+ import * as NativeUtils from '../../../native';
23
+ import type { DefaultStreamChatGenerics } from '../../../types/types';
24
+ import type { MessageType } from '../../MessageList/hooks/useMessageList';
25
+ import { ImageGallery, ImageGalleryCustomComponents } from '../ImageGallery';
26
+
27
+ jest.mock('../../../native.ts', () => {
28
+ const View = require('react-native/Libraries/Components/View/View');
29
+ return {
30
+ deleteFile: jest.fn(),
31
+ isVideoPackageAvailable: jest.fn(() => true),
32
+ NetInfo: {
33
+ addEventListener: jest.fn(),
34
+ },
35
+ saveFile: jest.fn(),
36
+ shareImage: jest.fn(),
37
+ Video: View,
38
+ };
39
+ });
40
+
41
+ describe('ImageGalleryFooter', () => {
42
+ it('render image gallery footer component with custom component footer props', async () => {
43
+ const chatClient = await getTestClientWithUser({ id: 'testID' });
44
+
45
+ const CustomFooterLeftElement = () => (
46
+ <View>
47
+ <Text>Left element</Text>
48
+ </View>
49
+ );
50
+
51
+ const CustomFooterRightElement = () => (
52
+ <View>
53
+ <Text>Right element</Text>
54
+ </View>
55
+ );
56
+
57
+ const CustomFooterCenterElement = () => (
58
+ <View>
59
+ <Text>Center element</Text>
60
+ </View>
61
+ );
62
+
63
+ const CustomFooterVideoControlElement = () => (
64
+ <View>
65
+ <Text>Video Control element</Text>
66
+ </View>
67
+ );
68
+
69
+ const { queryAllByText } = render(
70
+ <OverlayProvider>
71
+ <ImageGalleryContext.Provider
72
+ value={
73
+ {
74
+ images: [
75
+ generateMessage({
76
+ attachments: [generateVideoAttachment({ type: 'video' })],
77
+ }),
78
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
79
+ } as unknown as ImageGalleryContextValue
80
+ }
81
+ >
82
+ <Chat client={chatClient}>
83
+ <ImageGallery
84
+ imageGalleryCustomComponents={
85
+ {
86
+ footer: {
87
+ centerElement: CustomFooterCenterElement,
88
+ leftElement: CustomFooterLeftElement,
89
+ rightElement: CustomFooterRightElement,
90
+ videoControlElement: CustomFooterVideoControlElement,
91
+ },
92
+ } as ImageGalleryCustomComponents['imageGalleryCustomComponents']
93
+ }
94
+ overlayOpacity={{ value: 1 } as SharedValue<number>}
95
+ />
96
+ </Chat>
97
+ </ImageGalleryContext.Provider>
98
+ </OverlayProvider>,
99
+ );
100
+ expect(queryAllByText('Left element')).toHaveLength(1);
101
+ expect(queryAllByText('Right element')).toHaveLength(1);
102
+ expect(queryAllByText('Center element')).toHaveLength(1);
103
+ expect(queryAllByText('Video Control element')).toHaveLength(1);
104
+ });
105
+
106
+ it('render image gallery footer component with custom component footer Grid Icon and Share Icon component', async () => {
107
+ const chatClient = await getTestClientWithUser({ id: 'testID' });
108
+
109
+ const CustomShareIconElement = () => (
110
+ <View>
111
+ <Text>Share Icon element</Text>
112
+ </View>
113
+ );
114
+
115
+ const CustomGridIconElement = () => (
116
+ <View>
117
+ <Text>Grid Icon element</Text>
118
+ </View>
119
+ );
120
+
121
+ const { queryAllByText } = render(
122
+ <OverlayProvider>
123
+ <ImageGalleryContext.Provider
124
+ value={
125
+ {
126
+ images: [
127
+ generateMessage({
128
+ attachments: [generateVideoAttachment({ type: 'video' })],
129
+ }),
130
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
131
+ } as unknown as ImageGalleryContextValue
132
+ }
133
+ >
134
+ <Chat client={chatClient}>
135
+ <ImageGallery
136
+ imageGalleryCustomComponents={
137
+ {
138
+ footer: {
139
+ GridIcon: <CustomGridIconElement />,
140
+ ShareIcon: <CustomShareIconElement />,
141
+ },
142
+ } as ImageGalleryCustomComponents['imageGalleryCustomComponents']
143
+ }
144
+ overlayOpacity={{ value: 1 } as SharedValue<number>}
145
+ />
146
+ </Chat>
147
+ </ImageGalleryContext.Provider>
148
+ </OverlayProvider>,
149
+ );
150
+ expect(queryAllByText('Share Icon element')).toHaveLength(1);
151
+ expect(queryAllByText('Grid Icon element')).toHaveLength(1);
152
+ });
153
+
154
+ it('should trigger the share button onPress Handler', async () => {
155
+ const chatClient = await getTestClientWithUser({ id: 'testID' });
156
+ const saveFileMock = jest.spyOn(NativeUtils, 'saveFile');
157
+ const shareImageMock = jest.spyOn(NativeUtils, 'shareImage');
158
+ const deleteFileMock = jest.spyOn(NativeUtils, 'deleteFile');
159
+
160
+ const { queryByA11yLabel } = render(
161
+ <OverlayProvider>
162
+ <ImageGalleryContext.Provider
163
+ value={
164
+ {
165
+ images: [
166
+ generateMessage({
167
+ attachments: [generateImageAttachment()],
168
+ }),
169
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
170
+ } as unknown as ImageGalleryContextValue
171
+ }
172
+ >
173
+ <Chat client={chatClient}>
174
+ <ImageGallery overlayOpacity={{ value: 1 } as SharedValue<number>} />
175
+ </Chat>
176
+ </ImageGalleryContext.Provider>
177
+ </OverlayProvider>,
178
+ );
179
+
180
+ act(() => {
181
+ fireEvent(queryByA11yLabel('Share Button') as ReactTestInstance, 'onPress');
182
+ });
183
+
184
+ await waitFor(() => {
185
+ expect(saveFileMock).toHaveBeenCalled();
186
+ expect(shareImageMock).toHaveBeenCalled();
187
+ expect(deleteFileMock).toHaveBeenCalled();
188
+ });
189
+ });
190
+ });