@signalwire/realtime-api
Advanced tools
Comparing version 3.3.1-dev.202207191222.6b4ad46.0 to 3.3.1-dev.202207270912.06d1678.0
@@ -35,2 +35,3 @@ import { BaseComponentOptions, BaseConsumer, JSONRPCSubscribeMethod, SessionEvents, EventEmitter, EventTransform } from '..'; | ||
}; | ||
private _checkMissingSubscriptions; | ||
subscribe(channels?: PubSubChannel): Promise<unknown>; | ||
@@ -37,0 +38,0 @@ unsubscribe(channels: PubSubChannel): Promise<void>; |
@@ -0,4 +1,6 @@ | ||
/// <reference types="jest" /> | ||
import { ConfigureStoreOptions } from './redux'; | ||
import { PubSubChannel, SwEventChannel } from './redux/interfaces'; | ||
import { RPCConnectResult, InternalSDKLogger } from './utils/interfaces'; | ||
import { EventEmitter } from './utils/EventEmitter'; | ||
export declare const createMockedLogger: () => InternalSDKLogger; | ||
@@ -22,2 +24,36 @@ /** | ||
}; | ||
/** | ||
* Helper method to configure a Store with a rootSaga | ||
* and a mocked Session object. | ||
* This allow to write integration tests. | ||
* | ||
* @returns { store, session, emitter, destroy } | ||
*/ | ||
export declare const configureFullStack: () => { | ||
store: { | ||
runSaga: <T>(saga: import("@redux-saga/types").Saga<any[]>, args: { | ||
instance: T; | ||
runSaga: any; | ||
}) => import("@redux-saga/types").Task; | ||
dispatch: import("redux").Dispatch<import("redux").AnyAction>; | ||
getState(): any; | ||
subscribe(listener: () => void): import("redux").Unsubscribe; | ||
replaceReducer(nextReducer: import("redux").Reducer<any, import("redux").AnyAction>): void; | ||
[Symbol.observable](): import("redux").Observable<any>; | ||
}; | ||
session: { | ||
dispatch: { | ||
(...data: any[]): void; | ||
(message?: any, ...optionalParams: any[]): void; | ||
}; | ||
connect: jest.Mock<any, any>; | ||
disconnect: jest.Mock<any, any>; | ||
execute: jest.Mock<any, any>; | ||
}; | ||
emitter: EventEmitter<string | symbol, any>; | ||
destroy: () => { | ||
payload: undefined; | ||
type: "swSdk/destroy"; | ||
}; | ||
}; | ||
export declare const wait: (ms: number) => Promise<unknown>; | ||
@@ -24,0 +60,0 @@ export declare const rpcConnectResultVRT: RPCConnectResult; |
@@ -9,3 +9,4 @@ import { BaseComponentOptions, ClientContextContract } from '@signalwire/core'; | ||
export { Call } from './Call'; | ||
export type { DeviceBuilder, RealTimeCallApiEvents }; | ||
export type { RealTimeCallApiEvents }; | ||
export { DeviceBuilder }; | ||
export { Playlist } from './Playlist'; | ||
@@ -12,0 +13,0 @@ export type { CallPlayback } from './CallPlayback'; |
@@ -6,3 +6,3 @@ { | ||
"license": "MIT", | ||
"version": "3.3.1-dev.202207191222.6b4ad46.0", | ||
"version": "3.3.1-dev.202207270912.06d1678.0", | ||
"main": "dist/index.node.js", | ||
@@ -45,3 +45,3 @@ "exports": { | ||
"dependencies": { | ||
"@signalwire/core": "3.10.1-dev.202207191222.6b4ad46.0", | ||
"@signalwire/core": "3.10.1-dev.202207270912.06d1678.0", | ||
"ws": "^8.5.0" | ||
@@ -48,0 +48,0 @@ }, |
import WS from 'jest-websocket-mock' | ||
import { Client } from './ChatClient' | ||
jest.mock('uuid', () => { | ||
return { | ||
v4: jest.fn(() => 'mocked-uuid'), | ||
} | ||
}) | ||
describe('ChatClient', () => { | ||
@@ -16,3 +22,3 @@ describe('Client', () => { | ||
beforeEach(async () => { | ||
server = new WS(host) | ||
server = new WS(host, { jsonProtocol: true }) | ||
server.on('connection', (socket: any) => { | ||
@@ -62,2 +68,14 @@ socket.on('message', (data: any) => { | ||
chat._session.on('session.connected', () => { | ||
expect(server).toHaveReceivedMessages([ | ||
{ | ||
jsonrpc: '2.0', | ||
id: 'mocked-uuid', | ||
method: 'signalwire.connect', | ||
params: { | ||
version: { major: 3, minor: 0, revision: 0 }, | ||
authentication: { project: 'some-project', token: '<jwt>' }, | ||
}, | ||
}, | ||
]) | ||
chat._session.disconnect() | ||
@@ -73,2 +91,3 @@ | ||
error: jest.fn(), | ||
info: jest.fn(), | ||
trace: jest.fn(), | ||
@@ -86,13 +105,16 @@ debug: jest.fn(), | ||
await chat.subscribe('some-channel') | ||
expect(logger.error).toHaveBeenNthCalledWith(1, 'Auth Error', { | ||
code: -32002, | ||
message: | ||
'Authentication service failed with status ProtocolError, 401 Unauthorized: {}', | ||
}) | ||
chat._session.disconnect() | ||
try { | ||
await chat.subscribe('some-channel') | ||
} catch (error) { | ||
expect(error).toStrictEqual(new Error('Unauthorized')) | ||
expect(logger.error).toHaveBeenNthCalledWith(1, 'Auth Error', { | ||
code: -32002, | ||
message: | ||
'Authentication service failed with status ProtocolError, 401 Unauthorized: {}', | ||
}) | ||
} finally { | ||
chat._session.disconnect() | ||
} | ||
}) | ||
}) | ||
}) |
import { | ||
BaseComponentOptions, | ||
BaseConsumer, | ||
connect, | ||
@@ -14,2 +13,3 @@ EventTransform, | ||
} from '@signalwire/core' | ||
import { AutoSubscribeConsumer } from '../AutoSubscribeConsumer' | ||
import type { RealtimeClient } from '../client/Client' | ||
@@ -110,3 +110,3 @@ | ||
/** @internal */ | ||
class VideoAPI extends BaseConsumer<RealTimeVideoApiEvents> { | ||
class VideoAPI extends AutoSubscribeConsumer<RealTimeVideoApiEvents> { | ||
/** @internal */ | ||
@@ -113,0 +113,0 @@ protected _eventsPrefix = 'video' as const |
import WS from 'jest-websocket-mock' | ||
import { Client } from './VideoClient' | ||
import * as Video from './Video' | ||
jest.mock('uuid', () => { | ||
return { | ||
v4: jest.fn(() => 'mocked-uuid'), | ||
} | ||
}) | ||
describe('VideoClient', () => { | ||
@@ -17,3 +22,3 @@ describe('Client', () => { | ||
beforeEach(async () => { | ||
server = new WS(host) | ||
server = new WS(host, { jsonProtocol: true }) | ||
server.on('connection', (socket: any) => { | ||
@@ -68,27 +73,4 @@ socket.on('message', (data: any) => { | ||
}) | ||
}) | ||
describe('Automatic subscribe', () => { | ||
let createVideoObjectMock: jest.SpyInstance | ||
const mockedVideo: any = { | ||
subscribe: jest.fn(() => Promise.resolve()), | ||
on: jest.fn(), | ||
} | ||
beforeEach(async () => { | ||
createVideoObjectMock = jest | ||
.spyOn(Video, 'createVideoObject') | ||
.mockImplementationOnce(() => { | ||
return mockedVideo | ||
}) | ||
}) | ||
afterEach(() => { | ||
createVideoObjectMock.mockRestore() | ||
Object.values(mockedVideo).forEach((mock: any) => { | ||
if (typeof mock.mockRestore === 'function') { | ||
mock.mockRestore() | ||
} | ||
}) | ||
}) | ||
it('should automatically call subscribe the moment the client is connected', async () => { | ||
it('should automatically connect the underlying client and send subscribe', async () => { | ||
const video = new Client({ | ||
@@ -101,60 +83,28 @@ // @ts-expect-error | ||
video.on('room.started', () => {}) | ||
video.once('room.started', () => {}) | ||
// Artificial timer to wait for the connect() to happen | ||
await new Promise((r) => setTimeout(r, 1000)) | ||
await server.connected | ||
expect(mockedVideo.subscribe).toHaveBeenCalledTimes(1) | ||
video._session.disconnect() | ||
}) | ||
}) | ||
describe('Subscribe error', () => { | ||
let createVideoObjectMock: jest.SpyInstance | ||
const mockedVideo: any = { | ||
subscribe: jest.fn(() => Promise.reject()), | ||
on: jest.fn(), | ||
} | ||
beforeEach(async () => { | ||
createVideoObjectMock = jest | ||
.spyOn(Video, 'createVideoObject') | ||
.mockImplementationOnce(() => { | ||
return mockedVideo | ||
}) | ||
}) | ||
afterEach(() => { | ||
createVideoObjectMock.mockRestore() | ||
Object.values(mockedVideo).forEach((mock: any) => { | ||
if (typeof mock.mockRestore === 'function') { | ||
mock.mockRestore() | ||
} | ||
await expect(server).toReceiveMessage({ | ||
jsonrpc: '2.0', | ||
id: 'mocked-uuid', | ||
method: 'signalwire.connect', | ||
params: { | ||
version: { major: 3, minor: 0, revision: 0 }, | ||
authentication: { project: 'some-project-x', token: '<jwt>' }, | ||
}, | ||
}) | ||
}) | ||
it('should show an error message if the call to subscribe fails', async () => { | ||
const logger = { | ||
error: jest.fn(), | ||
trace: jest.fn(), | ||
debug: jest.fn(), | ||
warn: jest.fn(), | ||
} | ||
const video = new Client({ | ||
// @ts-expect-error | ||
host, | ||
project: 'some-project-t', | ||
token, | ||
logger: logger as any, | ||
await expect(server).toReceiveMessage({ | ||
id: 'mocked-uuid', | ||
jsonrpc: '2.0', | ||
method: 'signalwire.subscribe', | ||
params: { | ||
event_channel: 'video.rooms', | ||
events: ['video.room.started'], | ||
get_initial_state: true, | ||
}, | ||
}) | ||
try { | ||
// It's not neccessary to call `subcribe()` | ||
// manually. We're doing it here to avoid creating | ||
// a timer for the `connect()` | ||
await video.subscribe() | ||
} catch (e) { | ||
expect(logger.error).toHaveBeenCalledWith( | ||
'Client subscription failed.' | ||
) | ||
} | ||
// FIXME: video.once start something async in background so we need to wait before disconnecting | ||
await new Promise((r) => setTimeout(r, 100)) | ||
@@ -180,13 +130,16 @@ video._session.disconnect() | ||
await video.subscribe() | ||
expect(logger.error).toHaveBeenNthCalledWith(1, 'Auth Error', { | ||
code: -32002, | ||
message: | ||
'Authentication service failed with status ProtocolError, 401 Unauthorized: {}', | ||
}) | ||
video._session.disconnect() | ||
try { | ||
await video.subscribe() | ||
} catch (error) { | ||
expect(error).toStrictEqual(new Error('Unauthorized')) | ||
expect(logger.error).toHaveBeenNthCalledWith(1, 'Auth Error', { | ||
code: -32002, | ||
message: | ||
'Authentication service failed with status ProtocolError, 401 Unauthorized: {}', | ||
}) | ||
} finally { | ||
video._session.disconnect() | ||
} | ||
}) | ||
}) | ||
}) |
import type { UserOptions } from '@signalwire/core' | ||
import type { RealTimeVideoApiEvents } from '../types' | ||
import { getLogger } from '@signalwire/core' | ||
import { setupClient, clientConnect } from '../client/index' | ||
@@ -72,14 +71,2 @@ import { createVideoObject, Video } from './Video' | ||
client.on('session.connected', async () => { | ||
try { | ||
await video.subscribe() | ||
} catch (e) { | ||
// TODO: In the future we'll provide a | ||
// `onSubscribedError` (or similar) to allow the user | ||
// customize this behavior. | ||
getLogger().error('Client subscription failed.') | ||
client.disconnect() | ||
} | ||
}) | ||
const interceptors = { | ||
@@ -86,0 +73,0 @@ on: videoOn, |
@@ -24,3 +24,4 @@ import { | ||
export { Call } from './Call' | ||
export type { DeviceBuilder, RealTimeCallApiEvents } | ||
export type { RealTimeCallApiEvents } | ||
export { DeviceBuilder } | ||
export { Playlist } from './Playlist' | ||
@@ -27,0 +28,0 @@ export type { CallPlayback } from './CallPlayback' |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
1631281
25440
+ Added@signalwire/core@3.10.1-dev.202207270912.06d1678.0(transitive)
- Removed@signalwire/core@3.10.1-dev.202207191222.6b4ad46.0(transitive)