-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
567 additions
and
16 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { renderHook } from '@testing-library/react-hooks' | ||
import WS from 'jest-websocket-mock' | ||
import { SocketProvider } from 'test/testMocks' | ||
|
||
import { SocketContainer } from './SocketContainer' | ||
|
||
let consoleSpy: jest.SpyInstance | ||
|
||
describe('Socket Container', () => { | ||
beforeEach(() => { | ||
consoleSpy = jest.spyOn(console, 'log') | ||
}) | ||
|
||
afterEach(() => { | ||
consoleSpy.mockClear() | ||
}) | ||
|
||
afterAll(() => { | ||
consoleSpy.mockRestore() | ||
}) | ||
|
||
test('adds function to listener list', () => { | ||
const mockFn = jest.fn() | ||
const { result } = renderHook(() => SocketContainer.useContainer(), { | ||
wrapper: SocketProvider, | ||
}) | ||
result.current.addCallback('testCB', mockFn) | ||
expect(consoleSpy).toHaveBeenCalledWith('Adding testCB socket listener') | ||
}) | ||
|
||
test('does not error adding existing function to listener list', () => { | ||
const mockFn = jest.fn() | ||
const { result } = renderHook(() => SocketContainer.useContainer(), { | ||
wrapper: SocketProvider, | ||
}) | ||
result.current.addCallback('testCB', mockFn) | ||
result.current.addCallback('testCB', mockFn) | ||
expect(consoleSpy).toHaveBeenCalledWith('Adding testCB socket listener') | ||
expect(consoleSpy).toHaveBeenCalledTimes(2) | ||
}) | ||
|
||
test('does not remove non-existent function from listener list if', () => { | ||
const { result } = renderHook(() => SocketContainer.useContainer(), { | ||
wrapper: SocketProvider, | ||
}) | ||
result.current.removeCallback('testCB') | ||
expect(consoleSpy).not.toHaveBeenCalledWith( | ||
'Removing testCB socket listener', | ||
) | ||
}) | ||
|
||
test('removes function from listener list', () => { | ||
const mockFn = jest.fn() | ||
const { result } = renderHook(() => SocketContainer.useContainer(), { | ||
wrapper: SocketProvider, | ||
}) | ||
result.current.addCallback('testCB', mockFn) | ||
consoleSpy.mockClear() | ||
result.current.removeCallback('testCB') | ||
expect(consoleSpy).toHaveBeenCalledWith('Removing testCB socket listener') | ||
}) | ||
|
||
describe('Websocket Tests', () => { | ||
let server: WS | ||
|
||
beforeEach(() => { | ||
server = new WS('ws://localhost:2337/api/v1/socket/events') | ||
}) | ||
|
||
afterEach(() => { | ||
WS.clean() | ||
}) | ||
|
||
test('calls listeners on message', async () => { | ||
const testMsg = JSON.stringify({ test: 'This is a test' }) | ||
const mockFn = jest.fn() | ||
const { result } = renderHook(() => SocketContainer.useContainer(), { | ||
wrapper: SocketProvider, | ||
}) | ||
result.current.addCallback('testAdd', mockFn) | ||
await server.connected | ||
server.send(testMsg) | ||
expect(consoleSpy).toHaveBeenCalledWith( | ||
'Socket message', | ||
JSON.parse(testMsg), | ||
) | ||
expect(mockFn).toHaveBeenCalledWith(JSON.parse(testMsg)) | ||
}, 8000) | ||
|
||
test('sends token to authenticate', async () => { | ||
const msg = { name: 'UPDATE_TOKEN', payload: 'valid_token' } | ||
const msgStr = JSON.stringify(msg) | ||
const { result } = renderHook(() => SocketContainer.useContainer(), { | ||
wrapper: SocketProvider, | ||
}) | ||
await server.connected | ||
result.current.updateSocketToken(msg.payload) | ||
await expect(server).toReceiveMessage(msgStr) | ||
expect(server).toHaveReceivedMessages([msgStr]) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { DebugContainer } from 'containers/DebugContainer' | ||
import { useEffect, useMemo, useRef } from 'react' | ||
import { createContainer } from 'unstated-next' | ||
|
||
type WsCallback = (arg0: MessageEvent['data']) => void | ||
interface CallbackList { | ||
[key: string]: WsCallback | ||
} | ||
|
||
const useSocket = () => { | ||
const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://' | ||
const eventUrl = | ||
protocol + window.location.hostname + ':2337/api/v1/socket/events' | ||
const ws = useMemo(() => new WebSocket(eventUrl), [eventUrl]) | ||
|
||
const cbList = useRef<CallbackList>({}) | ||
const { DEBUG_SOCKET } = DebugContainer.useContainer() | ||
|
||
useEffect(() => { | ||
/** | ||
* Emit event to each callback in list upon getting WS message | ||
* @param message WS event | ||
*/ | ||
ws.onmessage = (message) => { | ||
const event = JSON.parse(message.data) | ||
if (DEBUG_SOCKET) console.log('Socket message', event) | ||
Object.values(cbList.current).forEach((callback: WsCallback) => { | ||
callback(event) | ||
}) | ||
} | ||
}, [DEBUG_SOCKET, ws]) | ||
|
||
/** | ||
* Adds function to list of callbacks, WILL OVERWRITE EXISTING FUNCTION | ||
* if key already exists in list | ||
* @param key string Name of cb | ||
* @param cb function Callback function | ||
*/ | ||
const addCallback = (key: string, cb: WsCallback) => { | ||
if (DEBUG_SOCKET) console.log(`Adding ${key} socket listener`) | ||
cbList.current[key] = cb | ||
} | ||
|
||
const removeCallback = (key: string) => { | ||
if (cbList.current[key]) { | ||
if (DEBUG_SOCKET) console.log(`Removing ${key} socket listener`) | ||
delete cbList.current[key] | ||
} | ||
} | ||
|
||
const updateSocketToken = (token: string) => { | ||
if (token && ws.readyState === WebSocket.OPEN) { | ||
ws.send(JSON.stringify({ name: 'UPDATE_TOKEN', payload: token })) | ||
} | ||
} | ||
|
||
return { | ||
addCallback, | ||
removeCallback, | ||
updateSocketToken, | ||
} | ||
} | ||
|
||
export const SocketContainer = createContainer(useSocket) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters