Skip to content

Commit f85c0a4

Browse files
committed
Add unit tests
1 parent dbcd952 commit f85c0a4

File tree

3 files changed

+191
-0
lines changed

3 files changed

+191
-0
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"@svgr/rollup": "^8.1.0",
103103
"@testing-library/jest-dom": "^5.16.5",
104104
"@testing-library/react": "^13.4.0",
105+
"@testing-library/react-hooks": "^8.0.1",
105106
"@testing-library/user-event": "^14.4.3",
106107
"@types/node": "^22.7.2",
107108
"@typescript-eslint/eslint-plugin": "^6.17.0",
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import { renderHook } from '@testing-library/react-hooks';
2+
import { useMessageActions } from '../hooks/useMessageActions';
3+
import { UserMessageCreateParams, FileMessageCreateParams } from '@sendbird/chat/message';
4+
5+
const mockEventHandlers = {
6+
message: {
7+
onSendMessageFailed: jest.fn(),
8+
onUpdateMessageFailed: jest.fn(),
9+
onFileUploadFailed: jest.fn(),
10+
},
11+
};
12+
13+
jest.mock('../../../../hooks/useSendbirdStateContext', () => ({
14+
__esModule: true,
15+
default: () => ({
16+
eventHandlers: mockEventHandlers,
17+
}),
18+
}));
19+
20+
describe('useMessageActions', () => {
21+
const mockParams = {
22+
sendUserMessage: jest.fn(),
23+
sendFileMessage: jest.fn(),
24+
sendMultipleFilesMessage: jest.fn(),
25+
updateUserMessage: jest.fn(),
26+
scrollToBottom: jest.fn(),
27+
replyType: 'NONE',
28+
};
29+
30+
beforeEach(() => {
31+
jest.clearAllMocks();
32+
});
33+
34+
describe('processParams', () => {
35+
it('should handle successful user message', async () => {
36+
const { result } = renderHook(() => useMessageActions(mockParams));
37+
const params: UserMessageCreateParams = { message: 'test' };
38+
39+
await result.current.sendUserMessage(params);
40+
41+
expect(mockParams.sendUserMessage).toHaveBeenCalledWith(
42+
expect.objectContaining({ message: 'test' }),
43+
expect.any(Function),
44+
);
45+
});
46+
47+
it('should handle void return from onBeforeSendFileMessage', async () => {
48+
const onBeforeSendFileMessage = jest.fn();
49+
const { result } = renderHook(() => useMessageActions({
50+
...mockParams,
51+
onBeforeSendFileMessage,
52+
}),
53+
);
54+
55+
const fileParams: FileMessageCreateParams = {
56+
file: new File([], 'test.txt'),
57+
};
58+
59+
await result.current.sendFileMessage(fileParams);
60+
61+
expect(onBeforeSendFileMessage).toHaveBeenCalled();
62+
expect(mockParams.sendFileMessage).toHaveBeenCalledWith(
63+
expect.objectContaining(fileParams),
64+
expect.any(Function),
65+
);
66+
});
67+
68+
it('should handle file upload error', async () => {
69+
// Arrange
70+
const error = new Error('Upload failed');
71+
const onBeforeSendFileMessage = jest.fn().mockRejectedValue(error);
72+
const fileParams: FileMessageCreateParams = {
73+
file: new File([], 'test.txt'),
74+
fileName: 'test.txt',
75+
};
76+
77+
const { result } = renderHook(() => useMessageActions({
78+
...mockParams,
79+
onBeforeSendFileMessage,
80+
}),
81+
);
82+
83+
// Act & Assert
84+
await expect(async () => {
85+
await result.current.sendFileMessage(fileParams);
86+
}).rejects.toThrow('Upload failed');
87+
88+
// Wait for next tick to ensure all promises are resolved
89+
await new Promise(process.nextTick);
90+
91+
expect(onBeforeSendFileMessage).toHaveBeenCalled();
92+
expect(mockEventHandlers.message.onFileUploadFailed).toHaveBeenCalledWith(error);
93+
expect(mockEventHandlers.message.onSendMessageFailed).toHaveBeenCalledWith(
94+
expect.objectContaining({
95+
file: fileParams.file,
96+
fileName: fileParams.fileName,
97+
}),
98+
error,
99+
);
100+
});
101+
102+
it('should handle message update error', async () => {
103+
// Arrange
104+
const error = new Error('Update failed');
105+
const onBeforeUpdateUserMessage = jest.fn().mockRejectedValue(error);
106+
const messageParams = {
107+
messageId: 1,
108+
message: 'update message',
109+
};
110+
111+
const { result } = renderHook(() => useMessageActions({
112+
...mockParams,
113+
onBeforeUpdateUserMessage,
114+
}),
115+
);
116+
117+
// Act & Assert
118+
await expect(async () => {
119+
await result.current.updateUserMessage(messageParams.messageId, {
120+
message: messageParams.message,
121+
});
122+
}).rejects.toThrow('Update failed');
123+
124+
// Wait for next tick to ensure all promises are resolved
125+
await new Promise(process.nextTick);
126+
127+
expect(onBeforeUpdateUserMessage).toHaveBeenCalled();
128+
expect(mockEventHandlers.message.onUpdateMessageFailed).toHaveBeenCalledWith(
129+
expect.objectContaining({
130+
message: messageParams.message,
131+
}),
132+
error,
133+
);
134+
});
135+
136+
it('should preserve modified params from onBefore handlers', async () => {
137+
const onBeforeSendUserMessage = jest.fn().mockImplementation((params) => ({
138+
...params,
139+
message: 'modified',
140+
}));
141+
142+
const { result } = renderHook(() => useMessageActions({
143+
...mockParams,
144+
onBeforeSendUserMessage,
145+
}),
146+
);
147+
148+
await result.current.sendUserMessage({ message: 'original' });
149+
150+
expect(mockParams.sendUserMessage).toHaveBeenCalledWith(
151+
expect.objectContaining({ message: 'modified' }),
152+
expect.any(Function),
153+
);
154+
});
155+
});
156+
});

yarn.lock

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2778,6 +2778,7 @@ __metadata:
27782778
"@svgr/rollup": ^8.1.0
27792779
"@testing-library/jest-dom": ^5.16.5
27802780
"@testing-library/react": ^13.4.0
2781+
"@testing-library/react-hooks": ^8.0.1
27812782
"@testing-library/user-event": ^14.4.3
27822783
"@types/node": ^22.7.2
27832784
"@typescript-eslint/eslint-plugin": ^6.17.0
@@ -3468,6 +3469,28 @@ __metadata:
34683469
languageName: node
34693470
linkType: hard
34703471

3472+
"@testing-library/react-hooks@npm:^8.0.1":
3473+
version: 8.0.1
3474+
resolution: "@testing-library/react-hooks@npm:8.0.1"
3475+
dependencies:
3476+
"@babel/runtime": ^7.12.5
3477+
react-error-boundary: ^3.1.0
3478+
peerDependencies:
3479+
"@types/react": ^16.9.0 || ^17.0.0
3480+
react: ^16.9.0 || ^17.0.0
3481+
react-dom: ^16.9.0 || ^17.0.0
3482+
react-test-renderer: ^16.9.0 || ^17.0.0
3483+
peerDependenciesMeta:
3484+
"@types/react":
3485+
optional: true
3486+
react-dom:
3487+
optional: true
3488+
react-test-renderer:
3489+
optional: true
3490+
checksum: 7fe44352e920deb5cb1876f80d64e48615232072c9d5382f1e0284b3aab46bb1c659a040b774c45cdf084a5257b8fe463f7e08695ad8480d8a15635d4d3d1f6d
3491+
languageName: node
3492+
linkType: hard
3493+
34713494
"@testing-library/react@npm:^13.4.0":
34723495
version: 13.4.0
34733496
resolution: "@testing-library/react@npm:13.4.0"
@@ -12532,6 +12555,17 @@ __metadata:
1253212555
languageName: node
1253312556
linkType: hard
1253412557

12558+
"react-error-boundary@npm:^3.1.0":
12559+
version: 3.1.4
12560+
resolution: "react-error-boundary@npm:3.1.4"
12561+
dependencies:
12562+
"@babel/runtime": ^7.12.5
12563+
peerDependencies:
12564+
react: ">=16.13.1"
12565+
checksum: f36270a5d775a25c8920f854c0d91649ceea417b15b5bc51e270a959b0476647bb79abb4da3be7dd9a4597b029214e8fe43ea914a7f16fa7543c91f784977f1b
12566+
languageName: node
12567+
linkType: hard
12568+
1253512569
"react-is@npm:18.1.0":
1253612570
version: 18.1.0
1253712571
resolution: "react-is@npm:18.1.0"

0 commit comments

Comments
 (0)