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
@@ -0,0 +1,98 @@
1
+ import React from 'react';
2
+
3
+ import { Text, View } from 'react-native';
4
+ import { act } from 'react-test-renderer';
5
+
6
+ import { fireEvent, render } from '@testing-library/react-native';
7
+
8
+ import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
9
+ import { defaultTheme } from '../../../contexts/themeContext/utils/theme';
10
+ import {
11
+ TranslationContextValue,
12
+ TranslationProvider,
13
+ } from '../../../contexts/translationContext/TranslationContext';
14
+ import {
15
+ generateImageAttachment,
16
+ generateVideoAttachment,
17
+ } from '../../../mock-builders/generator/attachment';
18
+ import { ImageGrid, ImageGridType } from '../components/ImageGrid';
19
+
20
+ jest.mock('@gorhom/bottom-sheet', () => {
21
+ const View = require('react-native/Libraries/Components/View/View');
22
+ const FlatList = require('react-native/Libraries/Lists/FlatList');
23
+ return {
24
+ BottomSheetFlatList: FlatList,
25
+ TouchableOpacity: View,
26
+ };
27
+ });
28
+
29
+ const getComponent = (props: Partial<ImageGridType> = {}) => {
30
+ const t = jest.fn((key) => key);
31
+
32
+ return (
33
+ <TranslationProvider value={{ t } as unknown as TranslationContextValue}>
34
+ <ThemeProvider style={defaultTheme}>
35
+ <ImageGrid {...(props as unknown as ImageGridType)} />
36
+ </ThemeProvider>
37
+ </TranslationProvider>
38
+ );
39
+ };
40
+
41
+ describe('ImageGalleryOverlay', () => {
42
+ it('should render ImageGalleryGrid', () => {
43
+ const { queryAllByA11yLabel } = render(
44
+ getComponent({ photos: [generateImageAttachment(), generateImageAttachment()] }),
45
+ );
46
+
47
+ expect(queryAllByA11yLabel('Image Grid')).toHaveLength(1);
48
+ });
49
+
50
+ it('should render ImageGalleryGrid individual images', () => {
51
+ const { queryAllByA11yLabel } = render(
52
+ getComponent({
53
+ photos: [generateImageAttachment(), generateVideoAttachment({ type: 'video' })],
54
+ }),
55
+ );
56
+
57
+ expect(queryAllByA11yLabel('Grid Image')).toHaveLength(2);
58
+ });
59
+
60
+ it('should render ImageGalleryGrid with custom image component', () => {
61
+ const CustomImageComponent = () => (
62
+ <View>
63
+ <Text>Image Attachment</Text>
64
+ </View>
65
+ );
66
+
67
+ const { queryAllByText } = render(
68
+ getComponent({
69
+ imageComponent: CustomImageComponent,
70
+ photos: [generateImageAttachment(), generateVideoAttachment({ type: 'video' })],
71
+ }),
72
+ );
73
+
74
+ expect(queryAllByText('Image Attachment')).toHaveLength(2);
75
+ });
76
+
77
+ it('should trigger the selectAndClose when the Image item is pressed', () => {
78
+ const closeGridViewMock = jest.fn();
79
+ const setImageMock = jest.fn();
80
+
81
+ const { getAllByA11yLabel } = render(
82
+ getComponent({
83
+ closeGridView: closeGridViewMock,
84
+ photos: [generateImageAttachment(), generateVideoAttachment({ type: 'video' })],
85
+ setImage: setImageMock,
86
+ }),
87
+ );
88
+
89
+ const component = getAllByA11yLabel('Grid Image');
90
+
91
+ act(() => {
92
+ fireEvent(component[0], 'onPress');
93
+ });
94
+
95
+ expect(closeGridViewMock).toHaveBeenCalledTimes(1);
96
+ expect(setImageMock).toHaveBeenCalledTimes(1);
97
+ });
98
+ });
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+
3
+ import { Text, View } from 'react-native';
4
+
5
+ import { render } from '@testing-library/react-native';
6
+
7
+ import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
8
+ import { defaultTheme } from '../../../contexts/themeContext/utils/theme';
9
+ import {
10
+ TranslationContextValue,
11
+ TranslationProvider,
12
+ } from '../../../contexts/translationContext/TranslationContext';
13
+ import {
14
+ ImageGalleryGridHandleCustomComponentProps,
15
+ ImageGridHandle,
16
+ } from '../components/ImageGridHandle';
17
+
18
+ type ImageGridHandleProps = ImageGalleryGridHandleCustomComponentProps & {
19
+ closeGridView: () => void;
20
+ };
21
+
22
+ jest.mock('@gorhom/bottom-sheet', () => {
23
+ const View = require('react-native/Libraries/Components/View/View');
24
+ return {
25
+ TouchableOpacity: View,
26
+ };
27
+ });
28
+
29
+ const getComponent = (props: Partial<ImageGridHandleProps> = {}) => {
30
+ const t = jest.fn((key) => key);
31
+
32
+ return (
33
+ <TranslationProvider value={{ t } as unknown as TranslationContextValue}>
34
+ <ThemeProvider style={defaultTheme}>
35
+ <ImageGridHandle {...(props as unknown as ImageGridHandleProps)} />
36
+ </ThemeProvider>
37
+ </TranslationProvider>
38
+ );
39
+ };
40
+
41
+ describe('ImageGalleryOverlay', () => {
42
+ it('should render ImageGalleryGridHandle', () => {
43
+ const { queryAllByA11yLabel } = render(getComponent());
44
+
45
+ expect(queryAllByA11yLabel('Image Grid Handle')).toHaveLength(1);
46
+ });
47
+
48
+ it('should render the custom components', () => {
49
+ const CustomLeftComponent = () => (
50
+ <View>
51
+ <Text>Left Element</Text>
52
+ </View>
53
+ );
54
+
55
+ const CustomRightComponent = () => (
56
+ <View>
57
+ <Text>Right Element</Text>
58
+ </View>
59
+ );
60
+
61
+ const CustomCenterComponent = () => (
62
+ <View>
63
+ <Text>Center Element</Text>
64
+ </View>
65
+ );
66
+
67
+ const { queryAllByText } = render(
68
+ getComponent({
69
+ centerComponent: CustomCenterComponent,
70
+ leftComponent: CustomLeftComponent,
71
+ rightComponent: CustomRightComponent,
72
+ }),
73
+ );
74
+
75
+ expect(queryAllByText('Left Element')).toHaveLength(1);
76
+ expect(queryAllByText('Right Element')).toHaveLength(1);
77
+ expect(queryAllByText('Center Element')).toHaveLength(1);
78
+ });
79
+ });
@@ -0,0 +1,172 @@
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 {
16
+ OverlayContext,
17
+ OverlayContextValue,
18
+ } from '../../../contexts/overlayContext/OverlayContext';
19
+ import { OverlayProvider } from '../../../contexts/overlayContext/OverlayProvider';
20
+ import {
21
+ generateImageAttachment,
22
+ generateVideoAttachment,
23
+ } from '../../../mock-builders/generator/attachment';
24
+ import { generateMessage } from '../../../mock-builders/generator/message';
25
+ import { getTestClientWithUser } from '../../../mock-builders/mock';
26
+ import type { DefaultStreamChatGenerics } from '../../../types/types';
27
+ import type { MessageType } from '../../MessageList/hooks/useMessageList';
28
+ import { ImageGallery, ImageGalleryCustomComponents } from '../ImageGallery';
29
+
30
+ jest.mock('../../../native.ts', () => {
31
+ const View = require('react-native/Libraries/Components/View/View');
32
+ return {
33
+ isVideoPackageAvailable: jest.fn(() => true),
34
+ NetInfo: {
35
+ addEventListener: jest.fn(),
36
+ },
37
+ Video: View,
38
+ };
39
+ });
40
+
41
+ describe('ImageGalleryHeader', () => {
42
+ it('render image gallery header component with custom component header props', async () => {
43
+ const chatClient = await getTestClientWithUser({ id: 'testID' });
44
+
45
+ const CustomHeaderLeftElement = () => (
46
+ <View>
47
+ <Text>Left element</Text>
48
+ </View>
49
+ );
50
+
51
+ const CustomHeaderRightElement = () => (
52
+ <View>
53
+ <Text>Right element</Text>
54
+ </View>
55
+ );
56
+
57
+ const CustomHeaderCenterElement = () => (
58
+ <View>
59
+ <Text>Center element</Text>
60
+ </View>
61
+ );
62
+
63
+ const { queryAllByText } = render(
64
+ <OverlayProvider>
65
+ <ImageGalleryContext.Provider
66
+ value={
67
+ {
68
+ images: [
69
+ generateMessage({
70
+ attachments: [generateImageAttachment()],
71
+ }),
72
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
73
+ } as unknown as ImageGalleryContextValue
74
+ }
75
+ >
76
+ <Chat client={chatClient}>
77
+ <ImageGallery
78
+ imageGalleryCustomComponents={
79
+ {
80
+ header: {
81
+ centerElement: CustomHeaderCenterElement,
82
+ leftElement: CustomHeaderLeftElement,
83
+ rightElement: CustomHeaderRightElement,
84
+ },
85
+ } as ImageGalleryCustomComponents['imageGalleryCustomComponents']
86
+ }
87
+ overlayOpacity={{ value: 1 } as SharedValue<number>}
88
+ />
89
+ </Chat>
90
+ </ImageGalleryContext.Provider>
91
+ </OverlayProvider>,
92
+ );
93
+ expect(queryAllByText('Left element')).toHaveLength(1);
94
+ expect(queryAllByText('Right element')).toHaveLength(1);
95
+ expect(queryAllByText('Center element')).toHaveLength(1);
96
+ });
97
+
98
+ it('render image gallery header component with custom Close Icon component', async () => {
99
+ const chatClient = await getTestClientWithUser({ id: 'testID' });
100
+
101
+ const CustomCloseIconElement = () => (
102
+ <View>
103
+ <Text>Close Icon element</Text>
104
+ </View>
105
+ );
106
+
107
+ const { queryAllByText } = render(
108
+ <OverlayProvider>
109
+ <ImageGalleryContext.Provider
110
+ value={
111
+ {
112
+ images: [
113
+ generateMessage({
114
+ attachments: [generateVideoAttachment({ type: 'video' })],
115
+ }),
116
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
117
+ } as unknown as ImageGalleryContextValue
118
+ }
119
+ >
120
+ <Chat client={chatClient}>
121
+ <ImageGallery
122
+ imageGalleryCustomComponents={
123
+ {
124
+ header: {
125
+ CloseIcon: <CustomCloseIconElement />,
126
+ },
127
+ } as ImageGalleryCustomComponents['imageGalleryCustomComponents']
128
+ }
129
+ overlayOpacity={{ value: 1 } as SharedValue<number>}
130
+ />
131
+ </Chat>
132
+ </ImageGalleryContext.Provider>
133
+ </OverlayProvider>,
134
+ );
135
+ expect(queryAllByText('Close Icon element')).toHaveLength(1);
136
+ });
137
+
138
+ it('should trigger the hideOverlay function on button onPress', async () => {
139
+ const chatClient = await getTestClientWithUser({ id: 'testID' });
140
+ const setOverlayMock = jest.fn();
141
+
142
+ const { queryByA11yLabel } = render(
143
+ <OverlayContext.Provider
144
+ value={{ setOverlay: setOverlayMock } as unknown as OverlayContextValue}
145
+ >
146
+ <ImageGalleryContext.Provider
147
+ value={
148
+ {
149
+ images: [
150
+ generateMessage({
151
+ attachments: [generateImageAttachment()],
152
+ }),
153
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
154
+ } as unknown as ImageGalleryContextValue
155
+ }
156
+ >
157
+ <Chat client={chatClient}>
158
+ <ImageGallery overlayOpacity={{ value: 1 } as SharedValue<number>} />
159
+ </Chat>
160
+ </ImageGalleryContext.Provider>
161
+ </OverlayContext.Provider>,
162
+ );
163
+
164
+ act(() => {
165
+ fireEvent(queryByA11yLabel('Hide Overlay') as ReactTestInstance, 'onPress');
166
+ });
167
+
168
+ await waitFor(() => {
169
+ expect(setOverlayMock).toHaveBeenCalledWith('none');
170
+ });
171
+ });
172
+ });
@@ -0,0 +1,94 @@
1
+ import React from 'react';
2
+
3
+ import { State } from 'react-native-gesture-handler';
4
+ import type { SharedValue } from 'react-native-reanimated';
5
+
6
+ import { act } 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 {
16
+ OverlayContext,
17
+ OverlayContextValue,
18
+ } from '../../../contexts/overlayContext/OverlayContext';
19
+ import { generateImageAttachment } 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 { ImageGalleryOverlay } from '../components/ImageGalleryOverlay';
26
+
27
+ describe('ImageGalleryOverlay', () => {
28
+ jest.spyOn(NativeUtils, 'isVideoPackageAvailable').mockImplementation(() => true);
29
+
30
+ it('should have currentBottomSheetIndex as a prop', async () => {
31
+ const chatClient = await getTestClientWithUser({ id: 'testID' });
32
+ const setOverlayMock = jest.fn();
33
+
34
+ const { queryByTestId } = render(
35
+ <OverlayContext.Provider
36
+ value={{ setOverlay: setOverlayMock } as unknown as OverlayContextValue}
37
+ >
38
+ <ImageGalleryContext.Provider
39
+ value={
40
+ {
41
+ images: [
42
+ generateMessage({
43
+ attachments: [generateImageAttachment()],
44
+ }),
45
+ ] as unknown as MessageType<DefaultStreamChatGenerics>[],
46
+ } as unknown as ImageGalleryContextValue
47
+ }
48
+ >
49
+ <Chat client={chatClient}>
50
+ <ImageGalleryOverlay
51
+ animatedBottomSheetIndex={{ value: 1 } as SharedValue<number>}
52
+ closeGridView={jest.fn()}
53
+ currentBottomSheetIndex={1}
54
+ />
55
+ </Chat>
56
+ </ImageGalleryContext.Provider>
57
+ </OverlayContext.Provider>,
58
+ );
59
+
60
+ await waitFor(() => {
61
+ const view = queryByTestId('image-gallery-overlay');
62
+ expect(view).not.toBeUndefined();
63
+ });
64
+ });
65
+
66
+ it('should trigger tapEvent on handler state change', async () => {
67
+ const closeGridViewMock = jest.fn();
68
+ const chatClient = await getTestClientWithUser({ id: 'testID' });
69
+
70
+ const { getByTestId } = render(
71
+ <Chat client={chatClient}>
72
+ <ImageGalleryOverlay
73
+ animatedBottomSheetIndex={{ value: 1 } as SharedValue<number>}
74
+ closeGridView={closeGridViewMock}
75
+ currentBottomSheetIndex={1}
76
+ />
77
+ </Chat>,
78
+ );
79
+
80
+ const view = getByTestId('image-gallery-overlay');
81
+
82
+ act(() => {
83
+ fireEvent(view, 'onHandlerStateChange', {
84
+ nativeEvent: {
85
+ state: State.END,
86
+ },
87
+ });
88
+ });
89
+
90
+ await waitFor(() => {
91
+ expect(closeGridViewMock).toHaveBeenCalled();
92
+ });
93
+ });
94
+ });
@@ -0,0 +1,84 @@
1
+ import React from 'react';
2
+
3
+ import { act, ReactTestInstance } from 'react-test-renderer';
4
+
5
+ import { fireEvent, render, waitFor } from '@testing-library/react-native';
6
+
7
+ import dayjs from 'dayjs';
8
+ import duration from 'dayjs/plugin/duration';
9
+
10
+ import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
11
+ import { defaultTheme } from '../../../contexts/themeContext/utils/theme';
12
+ import type { ImageGalleryFooterVideoControlProps } from '../components/ImageGalleryFooter';
13
+ import { ImageGalleryVideoControl } from '../components/ImageGalleryVideoControl';
14
+
15
+ dayjs.extend(duration);
16
+
17
+ const getComponent = (props: Partial<ImageGalleryFooterVideoControlProps>) => (
18
+ <ThemeProvider theme={defaultTheme}>
19
+ <ImageGalleryVideoControl {...(props as unknown as ImageGalleryFooterVideoControlProps)} />
20
+ </ThemeProvider>
21
+ );
22
+
23
+ describe('ImageGalleryOverlay', () => {
24
+ it('should trigger the onPlayPause when play/pause button is pressed', async () => {
25
+ const onPlayPauseMock = jest.fn();
26
+
27
+ const { queryByA11yLabel } = render(getComponent({ onPlayPause: onPlayPauseMock }));
28
+
29
+ const component = queryByA11yLabel('Play Pause Button') as ReactTestInstance;
30
+
31
+ act(() => {
32
+ fireEvent(component, 'onPress');
33
+ });
34
+
35
+ await waitFor(() => {
36
+ expect(component).not.toBeUndefined();
37
+ expect(onPlayPauseMock).toHaveBeenCalled();
38
+ });
39
+ });
40
+
41
+ it('should render the play icon when paused prop is true', async () => {
42
+ const { queryByA11yLabel } = render(getComponent({ paused: true }));
43
+
44
+ const component = queryByA11yLabel('Play Icon') as ReactTestInstance;
45
+
46
+ await waitFor(() => {
47
+ expect(component).not.toBeUndefined();
48
+ });
49
+ });
50
+
51
+ it('should calculate the videoDuration and progressDuration when they are greater than or equal to 3600', () => {
52
+ jest.spyOn(dayjs, 'duration');
53
+
54
+ const { queryByA11yLabel } = render(
55
+ getComponent({
56
+ duration: 3600,
57
+ progress: 1,
58
+ }),
59
+ );
60
+
61
+ const videoDurationComponent = queryByA11yLabel('Video Duration') as ReactTestInstance;
62
+ const progressDurationComponent = queryByA11yLabel('Progress Duration') as ReactTestInstance;
63
+
64
+ expect(videoDurationComponent.children[0]).toBe('01:00:00');
65
+ expect(progressDurationComponent.children[0]).toBe('01:00:00');
66
+ });
67
+
68
+ it('should calculate the videoDuration and progressDuration when they are less than 3600', () => {
69
+ jest.spyOn(dayjs, 'duration');
70
+
71
+ const { queryByA11yLabel } = render(
72
+ getComponent({
73
+ duration: 60,
74
+ progress: 0.5,
75
+ }),
76
+ );
77
+
78
+ const videoDurationComponent = queryByA11yLabel('Video Duration') as ReactTestInstance;
79
+ const progressDurationComponent = queryByA11yLabel('Progress Duration') as ReactTestInstance;
80
+
81
+ expect(videoDurationComponent.children[0]).toBe('01:00');
82
+ expect(progressDurationComponent.children[0]).toBe('00:30');
83
+ });
84
+ });
@@ -10,6 +10,7 @@ const halfScreenWidth = vw(50);
10
10
  const oneEighth = 1 / 8;
11
11
 
12
12
  type Props = {
13
+ accessibilityLabel: string;
13
14
  index: number;
14
15
  offsetScale: Animated.SharedValue<number>;
15
16
  photo: { uri: string };
@@ -26,6 +27,7 @@ type Props = {
26
27
  export const AnimatedGalleryImage: React.FC<Props> = React.memo(
27
28
  (props) => {
28
29
  const {
30
+ accessibilityLabel,
29
31
  index,
30
32
  offsetScale,
31
33
  photo,
@@ -83,6 +85,7 @@ export const AnimatedGalleryImage: React.FC<Props> = React.memo(
83
85
 
84
86
  return (
85
87
  <Animated.Image
88
+ accessibilityLabel={accessibilityLabel}
86
89
  resizeMode={'contain'}
87
90
  source={{ uri: photo.uri }}
88
91
  style={[
@@ -19,7 +19,7 @@ const screenWidth = vw(100);
19
19
  const halfScreenWidth = vw(50);
20
20
  const oneEighth = 1 / 8;
21
21
 
22
- type Props = {
22
+ export type AnimatedGalleryVideoType = {
23
23
  handleEnd: () => void;
24
24
  handleLoad: (payload: VideoPayloadData) => void;
25
25
  handleProgress: (data: VideoProgressData) => void;
@@ -48,7 +48,7 @@ const styles = StyleSheet.create({
48
48
  },
49
49
  });
50
50
 
51
- export const AnimatedGalleryVideo: React.FC<Props> = React.memo(
51
+ export const AnimatedGalleryVideo: React.FC<AnimatedGalleryVideoType> = React.memo(
52
52
  (props) => {
53
53
  const [opacity, setOpacity] = useState<number>(1);
54
54
  const {
@@ -154,11 +154,17 @@ export const AnimatedGalleryVideo: React.FC<Props> = React.memo(
154
154
  * load on memory.
155
155
  */
156
156
  if (!shouldRender) {
157
- return <View style={[style, { transform: [{ scale: oneEighth }] }]} />;
157
+ return (
158
+ <View
159
+ accessibilityLabel='Empty View Image Gallery'
160
+ style={[style, { transform: [{ scale: oneEighth }] }]}
161
+ />
162
+ );
158
163
  }
159
164
 
160
165
  return (
161
166
  <Animated.View
167
+ accessibilityLabel='Image Gallery Video'
162
168
  style={[
163
169
  style,
164
170
  animatedViewStyles,
@@ -185,11 +191,13 @@ export const AnimatedGalleryVideo: React.FC<Props> = React.memo(
185
191
  paused={paused}
186
192
  resizeMode='contain'
187
193
  style={style}
194
+ testID='video-player'
188
195
  uri={source.uri}
189
196
  videoRef={videoRef}
190
197
  />
191
198
  )}
192
199
  <Animated.View
200
+ accessibilityLabel='Spinner'
193
201
  style={[
194
202
  styles.activityIndicator,
195
203
  {
@@ -64,7 +64,7 @@ export type ImageGalleryFooterCustomComponent<
64
64
 
65
65
  export type ImageGalleryFooterVideoControlProps = {
66
66
  duration: number;
67
- onPlayPause: () => void;
67
+ onPlayPause: (status?: boolean) => void;
68
68
  onProgressDrag: (progress: number) => void;
69
69
  paused: boolean;
70
70
  progress: number;
@@ -92,6 +92,7 @@ export type ImageGalleryFooterCustomComponentProps<
92
92
  type ImageGalleryFooterPropsWithContext<
93
93
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
94
94
  > = ImageGalleryFooterCustomComponentProps<StreamChatGenerics> & {
95
+ accessibilityLabel: string;
95
96
  duration: number;
96
97
  onPlayPause: () => void;
97
98
  onProgressDrag: (progress: number) => void;
@@ -111,6 +112,7 @@ export const ImageGalleryFooterWithContext = <
111
112
  props: ImageGalleryFooterPropsWithContext<StreamChatGenerics>,
112
113
  ) => {
113
114
  const {
115
+ accessibilityLabel,
114
116
  centerElement,
115
117
  duration,
116
118
  GridIcon,
@@ -182,6 +184,7 @@ export const ImageGalleryFooterWithContext = <
182
184
 
183
185
  return (
184
186
  <Animated.View
187
+ accessibilityLabel={accessibilityLabel}
185
188
  onLayout={(event) => setHeight(event.nativeEvent.layout.height)}
186
189
  pointerEvents={'box-none'}
187
190
  style={styles.wrapper}
@@ -204,7 +207,11 @@ export const ImageGalleryFooterWithContext = <
204
207
  {leftElement ? (
205
208
  leftElement({ openGridView, photo, share, shareMenuOpen })
206
209
  ) : (
207
- <TouchableOpacity disabled={shareMenuOpen} onPress={share}>
210
+ <TouchableOpacity
211
+ accessibilityLabel='Share Button'
212
+ disabled={shareMenuOpen}
213
+ onPress={share}
214
+ >
208
215
  <View style={[styles.leftContainer, leftContainer]}>
209
216
  {ShareIcon ? ShareIcon : <ShareIconDefault pathFill={black} />}
210
217
  </View>
@@ -167,7 +167,7 @@ export const ImageGalleryHeader = <
167
167
  {leftElement ? (
168
168
  leftElement({ hideOverlay, photo })
169
169
  ) : (
170
- <TouchableOpacity onPress={hideOverlay}>
170
+ <TouchableOpacity accessibilityLabel='Hide Overlay' onPress={hideOverlay}>
171
171
  <View style={[styles.leftContainer, leftContainer]}>
172
172
  {CloseIcon ? CloseIcon : <Close />}
173
173
  </View>
@@ -74,7 +74,12 @@ export const ImageGalleryOverlay: React.FC<Props> = (props) => {
74
74
  }
75
75
 
76
76
  return (
77
- <TapGestureHandler maxDeltaX={16} maxDeltaY={16} onHandlerStateChange={tapEvent}>
77
+ <TapGestureHandler
78
+ maxDeltaX={16}
79
+ maxDeltaY={16}
80
+ onHandlerStateChange={tapEvent}
81
+ testID='image-gallery-overlay'
82
+ >
78
83
  <Animated.View
79
84
  style={[
80
85
  StyleSheet.absoluteFillObject,