Skip to content

Commit a4e211f

Browse files
committed
test: add tests for sendBinary WebSocketClient feature
- TypeScript: WebSocketClient.test.ts verifies sendBinary() delegates to NativeWebSocketClient.sendBinaryDataFor() with the correct url and data. Adds transformIgnorePatterns to jest config for validator ESM package. - Kotlin: WebSocketClientModuleImplTest covers the invalid-URL error path (URISyntaxException → promise.reject). Happy-path binary send requires android.util.Base64 and a live WebSocket, which are only available in instrumented (on-device) tests.
1 parent 6f651fb commit a4e211f

3 files changed

Lines changed: 107 additions & 0 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.mattermost.networkclient
2+
3+
import com.facebook.react.bridge.Promise
4+
import com.facebook.react.bridge.ReactApplicationContext
5+
import org.junit.Before
6+
import org.junit.Test
7+
import org.mockito.ArgumentCaptor
8+
import org.mockito.Mockito.mock
9+
import org.mockito.Mockito.verify
10+
import java.net.URISyntaxException
11+
12+
class WebSocketClientModuleImplTest {
13+
private lateinit var impl: WebSocketClientModuleImpl
14+
private lateinit var promise: Promise
15+
16+
@Before
17+
fun setUp() {
18+
val mockContext = mock(ReactApplicationContext::class.java)
19+
impl = WebSocketClientModuleImpl(mockContext)
20+
promise = mock(Promise::class.java)
21+
}
22+
23+
// Happy-path binary sends require a live WebSocket connection and android.util.Base64,
24+
// which are only available in instrumented (on-device) tests. The base64 encoding and
25+
// binary frame delivery are covered end-to-end by the mattermost-mobile test suite.
26+
27+
@Test
28+
fun `sendBinaryDataFor rejects promise for malformed URL`() {
29+
impl.sendBinaryDataFor("not a valid uri", "dGVzdA==", promise)
30+
31+
val captor = ArgumentCaptor.forClass(Throwable::class.java)
32+
verify(promise).reject(captor.capture())
33+
assert(captor.value is URISyntaxException)
34+
}
35+
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@
9494
"modulePathIgnorePatterns": [
9595
"<rootDir>/example/node_modules",
9696
"<rootDir>/lib/"
97+
],
98+
"transformIgnorePatterns": [
99+
"node_modules/(?!(@react-native|react-native|validator)/)"
97100
]
98101
},
99102
"commitlint": {
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2+
// See LICENSE.txt for license information.
3+
4+
import {getOrCreateWebSocketClient} from '../index';
5+
import NativeWebSocketClient from '../NativeWebSocketClient';
6+
7+
const mockNativeClient = NativeWebSocketClient as jest.Mocked<typeof NativeWebSocketClient>;
8+
9+
jest.mock('../NativeWebSocketClient', () => ({
10+
__esModule: true,
11+
default: {
12+
addListener: jest.fn(),
13+
removeListeners: jest.fn(),
14+
ensureClientFor: jest.fn().mockResolvedValue(undefined),
15+
connectFor: jest.fn().mockResolvedValue(undefined),
16+
disconnectFor: jest.fn().mockResolvedValue(undefined),
17+
sendDataFor: jest.fn().mockResolvedValue(undefined),
18+
sendBinaryDataFor: jest.fn().mockResolvedValue(undefined),
19+
invalidateClientFor: jest.fn().mockResolvedValue(undefined),
20+
},
21+
WebSocketReadyState: {CONNECTING: 0, OPEN: 1, CLOSING: 2, CLOSED: 3},
22+
WebSocketEvents: {
23+
OPEN_EVENT: 'WebSocketClient-Open',
24+
CLOSE_EVENT: 'WebSocketClient-Close',
25+
ERROR_EVENT: 'WebSocketClient-Error',
26+
MESSAGE_EVENT: 'WebSocketClient-Message',
27+
READY_STATE_EVENT: 'WebSocketClient-ReadyState',
28+
},
29+
}));
30+
31+
// Each test uses a unique URL to avoid the module-level CLIENTS singleton state.
32+
let urlCounter = 0;
33+
const nextUrl = () => `ws://mattermost.example.com/api/v4/websocket?t=${++urlCounter}`;
34+
35+
describe('WebSocketClient', () => {
36+
beforeEach(() => {
37+
jest.clearAllMocks();
38+
});
39+
40+
it('should call sendDataFor when send() is invoked', async () => {
41+
const url = nextUrl();
42+
const {client} = await getOrCreateWebSocketClient(url);
43+
44+
client.send('hello');
45+
46+
expect(mockNativeClient.sendDataFor).toHaveBeenCalledWith(url, 'hello');
47+
});
48+
49+
it('should call sendBinaryDataFor when sendBinary() is invoked', async () => {
50+
const url = nextUrl();
51+
const {client} = await getOrCreateWebSocketClient(url);
52+
const base64Data = 'SGVsbG8gV29ybGQ=';
53+
54+
client.sendBinary(base64Data);
55+
56+
expect(mockNativeClient.sendBinaryDataFor).toHaveBeenCalledWith(url, base64Data);
57+
});
58+
59+
it('should pass the exact url and data to sendBinaryDataFor', async () => {
60+
const url = nextUrl();
61+
const {client} = await getOrCreateWebSocketClient(url);
62+
const encoded = 'dGVzdA==';
63+
64+
client.sendBinary(encoded);
65+
66+
expect(mockNativeClient.sendBinaryDataFor).toHaveBeenCalledTimes(1);
67+
expect(mockNativeClient.sendBinaryDataFor).toHaveBeenCalledWith(url, encoded);
68+
});
69+
});

0 commit comments

Comments
 (0)