Skip to content

Commit 066d08a

Browse files
authored
Merge pull request #1099 from GetStream/khushal87-crns-430
Fix: Error handling of the context consumer hooks [CRNS - 430]
2 parents 56c7875 + ca1b8b0 commit 066d08a

File tree

33 files changed

+466
-82
lines changed

33 files changed

+466
-82
lines changed

package/src/components/Attachment/__tests__/Attachment.test.js

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
88
import {
99
generateAttachmentAction,
1010
generateAudioAttachment,
11-
generateCardAttachment,
1211
generateFileAttachment,
1312
generateImageAttachment,
1413
} from '../../../mock-builders/generator/attachment';
@@ -107,17 +106,4 @@ describe('Attachment', () => {
107106
expect(handleAction).toHaveBeenCalledTimes(2);
108107
});
109108
});
110-
111-
it('should render "Card" if attachment type is not recognized', async () => {
112-
const { getByTestId } = render(
113-
getAttachmentComponent({
114-
attachment: generateCardAttachment({
115-
type: Date.now().toString(),
116-
}),
117-
}),
118-
);
119-
await waitFor(() => {
120-
expect(getByTestId('card-attachment')).toBeTruthy();
121-
});
122-
});
123109
});

package/src/components/Attachment/__tests__/Giphy.test.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,12 @@ describe('Giphy', () => {
251251
</OverlayProvider>,
252252
);
253253

254-
expect(queryByTestId('giphy-action-attachment')).toBeTruthy();
255-
expect(getByTestId('cancel-action-button')).toBeTruthy();
256-
expect(getByTestId('shuffle-action-button')).toBeTruthy();
257-
expect(getByTestId('send-action-button')).toBeTruthy();
254+
await waitFor(() => {
255+
expect(queryByTestId('giphy-action-attachment')).toBeTruthy();
256+
expect(getByTestId('cancel-action-button')).toBeTruthy();
257+
expect(getByTestId('shuffle-action-button')).toBeTruthy();
258+
expect(getByTestId('send-action-button')).toBeTruthy();
259+
});
258260
});
259261

260262
it('giphy attachment UI should render within the message list', async () => {
@@ -285,6 +287,8 @@ describe('Giphy', () => {
285287
</OverlayProvider>,
286288
);
287289

288-
expect(queryByTestId('giphy-attachment')).toBeTruthy();
290+
await waitFor(() => {
291+
expect(queryByTestId('giphy-attachment')).toBeTruthy();
292+
});
289293
});
290294
});

package/src/components/AutoCompleteInput/AutoCompleteSuggestionList.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ export const AutoCompleteSuggestionList = <
197197
) => {
198198
const { AutoCompleteSuggestionHeader, AutoCompleteSuggestionItem } =
199199
useSuggestionsContext<StreamChatGenerics>();
200+
200201
return (
201202
<MemoizedAutoCompleteSuggestionList
202203
{...{ AutoCompleteSuggestionHeader, AutoCompleteSuggestionItem }}

package/src/components/ImageGallery/components/__tests__/ImageGalleryHeader.test.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import { useSharedValue } from 'react-native-reanimated';
44

55
import { renderHook } from '@testing-library/react-hooks';
66

7-
import { render } from '@testing-library/react-native';
7+
import { render, waitFor } from '@testing-library/react-native';
88

99
import { ThemeProvider } from '../../../../contexts/themeContext/ThemeContext';
1010

1111
import { ImageGalleryHeader } from '../ImageGalleryHeader';
1212

13-
it('doesnt fail if fromNow is not available on first render', () => {
13+
it('doesnt fail if fromNow is not available on first render', async () => {
1414
try {
1515
let sharedValueOpacity: Animated.SharedValue<number>;
1616
let sharedValueVisible: Animated.SharedValue<number>;
@@ -32,7 +32,9 @@ it('doesnt fail if fromNow is not available on first render', () => {
3232
/>
3333
</ThemeProvider>,
3434
);
35-
expect(getAllByText('Unknown User')).toBeTruthy();
35+
await waitFor(() => {
36+
expect(getAllByText('Unknown User')).toBeTruthy();
37+
});
3638
} catch (error: unknown) {
3739
if (error instanceof Error) {
3840
throw new Error(`Error encountered on first render of ImageGalleryHeader: ${error.message}`);

package/src/components/MessageInput/SendMessageDisallowedIndicator.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const SendMessageDisallowedIndicator = () => {
2727
},
2828
},
2929
} = useTheme();
30+
3031
return (
3132
<View
3233
style={[

package/src/components/MessageInput/__tests__/FileUploadPreview.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ describe('FileUploadPreview', () => {
256256
generateFileUploadPreview({ id: 'file-upload-id-1', state: FileState.UPLOADING }),
257257
generateFileUploadPreview({ id: 'file-upload-id-2', state: FileState.UPLOADED }),
258258
generateFileUploadPreview({ id: 'file-upload-id-3', state: FileState.UPLOAD_FAILED }),
259-
generateFileUploadPreview({ id: 'file-upload-id-3', state: FileState.NOT_SUPPORTED }),
259+
generateFileUploadPreview({ id: 'file-upload-id-4', state: FileState.NOT_SUPPORTED }),
260260
];
261261
const removeFile = jest.fn();
262262
const uploadFile = jest.fn();
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import React from 'react';
2+
import { View } from 'react-native';
3+
4+
import { render } from '@testing-library/react-native';
5+
6+
import {
7+
useAttachmentPickerContext,
8+
useChannelContext,
9+
useChannelsContext,
10+
useChatContext,
11+
useImageGalleryContext,
12+
useMessageContext,
13+
useMessageOverlayContext,
14+
useMessagesContext,
15+
useOverlayContext,
16+
useOwnCapabilitiesContext,
17+
usePaginatedMessageListContext,
18+
useSuggestionsContext,
19+
useTheme,
20+
useThreadContext,
21+
useTypingContext,
22+
} from '../';
23+
import { useChannelsStateContext } from '../channelsStateContext/ChannelsStateContext';
24+
25+
jest.mock('../utils/isTestEnvironment', () => ({ isTestEnvironment: jest.fn(() => false) }));
26+
console.error = jest.fn();
27+
describe('contexts hooks in a component throws an error with message when not wrapped in a provider', () => {
28+
const TestComponent = ({ useContextHook }: { useContextHook(): void }) => {
29+
useContextHook();
30+
return <View />;
31+
};
32+
33+
it.each([
34+
[
35+
useOverlayContext,
36+
'The useOverlayContext hook was called outside the OverlayContext Provider. Make sure you have configured OverlayProvider component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#overlay-provider',
37+
],
38+
[
39+
usePaginatedMessageListContext,
40+
'The usePaginatedMessageListContext hook was called outside of the PaginatedMessageList provider. Make sure you have configured Channel component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#channel',
41+
],
42+
[
43+
useChannelsStateContext,
44+
`The useChannelStateContext hook was called outside the ChannelStateContext Provider. Make sure you have configured OverlayProvider component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#overlay-provider`,
45+
],
46+
[
47+
useOwnCapabilitiesContext,
48+
`The useOwnCapabilitiesContext hook was called outside the Channel Component. Make sure you have configured Channel component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#channel`,
49+
],
50+
[
51+
useSuggestionsContext,
52+
'The useSuggestionsContext hook was called outside of the SuggestionsContext provider. Make sure you have configured Channel component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#channel',
53+
],
54+
[
55+
useTypingContext,
56+
`The useTypingContext hook was called outside of the TypingContext provider. Make sure you have configured Channel component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#channel`,
57+
],
58+
[
59+
useTheme,
60+
`The useThemeContext hook was called outside the ThemeContext Provider. Make sure you have configured OverlayProvider component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#overlay-provider`,
61+
],
62+
[
63+
useChannelContext,
64+
`The useChannelContext hook was called outside of the ChannelContext provider. Make sure you have configured Channel component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#channel`,
65+
],
66+
[
67+
useChannelsContext,
68+
`The useChannelsContext hook was called outside of the ChannelsContext provider. Make sure you have configured ChannelList component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#channel-list`,
69+
],
70+
[
71+
useChatContext,
72+
`The useChatContext hook was called outside the ChatContext Provider. Make sure you have configured Chat component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#chat`,
73+
],
74+
[
75+
useImageGalleryContext,
76+
`The useImageGalleryContext hook was called outside the ImageGalleryContext Provider. Make sure you have configured OverlayProvider component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#overlay-provider`,
77+
],
78+
[
79+
useMessageContext,
80+
`The useMessageContext hook was called outside of the MessageContext provider. Make sure you have configured MessageList component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#message-list`,
81+
],
82+
[
83+
useMessageOverlayContext,
84+
`The useMessageOverlayContext hook was called outside the MessageOverlayContext Provider. Make sure you have configured OverlayProvider component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#overlay-provider`,
85+
],
86+
[
87+
useMessagesContext,
88+
`The useMessagesContext hook was called outside of the MessagesContext provider. Make sure you have configured MessageList component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#message-list`,
89+
],
90+
[
91+
useThreadContext,
92+
`The useThreadContext hook was called outside of the ThreadContext provider. Make sure you have configured Channel component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#channel`,
93+
],
94+
[
95+
useAttachmentPickerContext,
96+
`The useAttachmentPickerContext hook was called outside the AttachmentPickerContext provider. Make sure you have configured OverlayProvider component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#overlay-provider`,
97+
],
98+
])('calls %p results in error %p', (useContextHook, expectedErrorMessage) => {
99+
expect(() => render(<TestComponent useContextHook={useContextHook} />)).toThrowError(
100+
expectedErrorMessage,
101+
);
102+
});
103+
});

package/src/contexts/activeChannelsRefContext/ActiveChannelsRefContext.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { PropsWithChildren, useContext } from 'react';
22

33
import type { UnknownType } from '../../types/types';
4+
45
import { getDisplayName } from '../utils/getDisplayName';
56

67
type ActiveChannels = React.MutableRefObject<string[]>;

package/src/contexts/attachmentPickerContext/AttachmentPickerContext.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import React, { PropsWithChildren, useContext, useEffect, useState } from 'react';
22

33
import type { Asset, DefaultStreamChatGenerics, File } from '../../types/types';
4+
import { DEFAULT_BASE_CONTEXT_VALUE } from '../utils/defaultBaseContextValue';
5+
46
import { getDisplayName } from '../utils/getDisplayName';
7+
import { isTestEnvironment } from '../utils/isTestEnvironment';
58

69
export type AttachmentPickerIconProps = {
710
numberOfImageUploads: number;
@@ -55,8 +58,8 @@ export type AttachmentPickerContextValue = {
5558
selectedPicker?: 'images';
5659
};
5760

58-
export const AttachmentPickerContext = React.createContext<AttachmentPickerContextValue>(
59-
{} as AttachmentPickerContextValue,
61+
export const AttachmentPickerContext = React.createContext(
62+
DEFAULT_BASE_CONTEXT_VALUE as AttachmentPickerContextValue,
6063
);
6164

6265
export const AttachmentPickerProvider = ({
@@ -118,8 +121,19 @@ export const AttachmentPickerProvider = ({
118121
);
119122
};
120123

121-
export const useAttachmentPickerContext = () =>
122-
useContext(AttachmentPickerContext) as unknown as AttachmentPickerContextValue;
124+
export const useAttachmentPickerContext = () => {
125+
const contextValue = useContext(
126+
AttachmentPickerContext,
127+
) as unknown as AttachmentPickerContextValue;
128+
129+
if (contextValue === DEFAULT_BASE_CONTEXT_VALUE && !isTestEnvironment()) {
130+
throw new Error(
131+
`The useAttachmentPickerContext hook was called outside the AttachmentPickerContext provider. Make sure you have configured OverlayProvider component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#overlay-provider`,
132+
);
133+
}
134+
135+
return contextValue;
136+
};
123137

124138
export const withAttachmentPickerContext = <
125139
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,

package/src/contexts/channelContext/ChannelContext.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import type { Channel, ChannelState } from 'stream-chat';
55
import type { EmptyStateProps } from '../../components/Indicators/EmptyStateIndicator';
66
import type { LoadingProps } from '../../components/Indicators/LoadingIndicator';
77
import type { DefaultStreamChatGenerics, UnknownType } from '../../types/types';
8+
import { DEFAULT_BASE_CONTEXT_VALUE } from '../utils/defaultBaseContextValue';
9+
810
import { getDisplayName } from '../utils/getDisplayName';
11+
import { isTestEnvironment } from '../utils/isTestEnvironment';
912

1013
export type ChannelContextValue<
1114
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
@@ -167,7 +170,9 @@ export type ChannelContextValue<
167170
watcherCount?: ChannelState<StreamChatGenerics>['watcher_count'];
168171
};
169172

170-
export const ChannelContext = React.createContext({} as ChannelContextValue);
173+
export const ChannelContext = React.createContext(
174+
DEFAULT_BASE_CONTEXT_VALUE as ChannelContextValue,
175+
);
171176

172177
export const ChannelProvider = <
173178
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
@@ -184,8 +189,19 @@ export const ChannelProvider = <
184189

185190
export const useChannelContext = <
186191
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
187-
>() => useContext(ChannelContext) as unknown as ChannelContextValue<StreamChatGenerics>;
192+
>() => {
193+
const contextValue = useContext(
194+
ChannelContext,
195+
) as unknown as ChannelContextValue<StreamChatGenerics>;
188196

197+
if (contextValue === DEFAULT_BASE_CONTEXT_VALUE && !isTestEnvironment()) {
198+
throw new Error(
199+
`The useChannelContext hook was called outside of the ChannelContext provider. Make sure you have configured Channel component correctly - https://getstream.io/chat/docs/sdk/reactnative/basics/hello_stream_chat/#channel`,
200+
);
201+
}
202+
203+
return contextValue;
204+
};
189205
/**
190206
* Typescript currently does not support partial inference so if ChatContext
191207
* typing is desired while using the HOC withChannelContext the Props for the

0 commit comments

Comments
 (0)