This commit is contained in:
9
react/features/base/testing/actionTypes.ts
Normal file
9
react/features/base/testing/actionTypes.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* The type of redux action which sets the configuration of the feature
|
||||
* base/logging.
|
||||
*
|
||||
* {
|
||||
* type: SET_CONNECTION_STATE
|
||||
* }
|
||||
*/
|
||||
export const SET_CONNECTION_STATE = 'SET_CONNECTION_STATE';
|
||||
28
react/features/base/testing/actions.ts
Normal file
28
react/features/base/testing/actions.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { SET_CONNECTION_STATE } from './actionTypes';
|
||||
|
||||
// eslint-disable-next-line jsdoc/require-description-complete-sentence
|
||||
/**
|
||||
* Sets the conference connection state of the testing feature.
|
||||
*
|
||||
* @param {string} connectionState - This is the lib-jitsi-meet event name. Can
|
||||
* be one of (with the string values at the time of this writing):
|
||||
* <li>{@link JitsiConferenceEvents.CONNECTION_ESTABLISHED}
|
||||
* - ("conference.connectionEstablished"</li>
|
||||
* <li>{@link JitsiConferenceEvents.CONNECTION_INTERRUPTED}
|
||||
* - ("conference.connectionInterrupted")</li>
|
||||
* <li>{@link JitsiConferenceEvents.CONNECTION_RESTORED}
|
||||
* - ("conference.connectionRestored")</li>
|
||||
* In the reducer the value will be an empty string until first event is
|
||||
* received.
|
||||
*
|
||||
* @returns {{
|
||||
* type: SET_CONNECTION_STATE,
|
||||
* connectionState: string
|
||||
* }}
|
||||
*/
|
||||
export function setConnectionState(connectionState: string) {
|
||||
return {
|
||||
type: SET_CONNECTION_STATE,
|
||||
connectionState
|
||||
};
|
||||
}
|
||||
62
react/features/base/testing/components/AbstractTestHint.ts
Normal file
62
react/features/base/testing/components/AbstractTestHint.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { GestureResponderEvent } from 'react-native';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { isTestModeEnabled } from '../functions';
|
||||
|
||||
/**
|
||||
* Describes the {@link TestHint}'s properties.
|
||||
*
|
||||
* A test hint is meant to resemble the lack of the ability to execute
|
||||
* JavaScript by the mobile torture tests. They are used to expose some of
|
||||
* the app's internal state that is not always expressed in a feasible manner by
|
||||
* the UI.
|
||||
*/
|
||||
export type TestHintProps = {
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the test mode is enabled.
|
||||
* {@link TestHint} Components are rendered only if this flag is set to
|
||||
* {@code true}.
|
||||
*/
|
||||
_testModeEnabled: boolean;
|
||||
|
||||
/**
|
||||
* The test hint's identifier string. Must be unique in the app instance
|
||||
* scope.
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* The optional "on press" handler which can be used to bind a click handler
|
||||
* to a {@link TestHint}.
|
||||
*/
|
||||
onPress?: (e?: GestureResponderEvent) => void;
|
||||
|
||||
/**
|
||||
* The test hint's (text) value which is to be consumed by the tests.
|
||||
*/
|
||||
value: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to {@link TestHint}'s React {@code Component}
|
||||
* props.
|
||||
*
|
||||
* @param {Object} state - The redux store/state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _testModeEnabled: boolean
|
||||
* }}
|
||||
*/
|
||||
export function _mapStateToProps(state: IReduxState) {
|
||||
return {
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the test mode is enabled.
|
||||
*
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
_testModeEnabled: isTestModeEnabled(state)
|
||||
};
|
||||
}
|
||||
222
react/features/base/testing/components/TestConnectionInfo.tsx
Normal file
222
react/features/base/testing/components/TestConnectionInfo.tsx
Normal file
@@ -0,0 +1,222 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import statsEmitter from '../../../connection-indicator/statsEmitter';
|
||||
import { getLocalParticipant } from '../../participants/functions';
|
||||
import { isTestModeEnabled } from '../functions';
|
||||
|
||||
import TestHint from './TestHint';
|
||||
|
||||
/**
|
||||
* Defines the TestConnectionInfo's properties.
|
||||
*/
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* The JitsiConference's connection state. It's the lib-jitsi-meet's event
|
||||
* name converted to a string directly. At the time of this writing these
|
||||
* are the possible values:
|
||||
* 'conference.connectionEstablished'
|
||||
* 'conference.connectionInterrupted'
|
||||
* 'conference.connectionRestored'.
|
||||
*/
|
||||
_conferenceConnectionState: string;
|
||||
|
||||
/**
|
||||
* This will be a boolean converted to a string. The value will be 'true'
|
||||
* once the conference is joined (the XMPP MUC room to be specific).
|
||||
*/
|
||||
_conferenceJoinedState: string;
|
||||
|
||||
/**
|
||||
* The local participant's ID. Required to be able to observe the local RTP
|
||||
* stats.
|
||||
*/
|
||||
_localUserId: string;
|
||||
|
||||
/**
|
||||
* The local participant's role.
|
||||
*/
|
||||
_localUserRole: string;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the test mode is currently on. Otherwise the
|
||||
* TestConnectionInfo component will not render.
|
||||
*/
|
||||
_testMode: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the TestConnectionInfo's state.
|
||||
*/
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* The RTP stats section.
|
||||
*/
|
||||
stats: {
|
||||
|
||||
/**
|
||||
* The local bitrate.
|
||||
*/
|
||||
bitrate: {
|
||||
|
||||
/**
|
||||
* The local download RTP bitrate.
|
||||
*/
|
||||
download: number;
|
||||
|
||||
/**
|
||||
* The local upload RTP bitrate.
|
||||
*/
|
||||
upload: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* The component will expose some of the app state to the jitsi-meet-torture
|
||||
* through the UI accessibility layer which is visible to the tests. The Web
|
||||
* tests currently will execute JavaScript and access globals variables to learn
|
||||
* this information, but there's no such option on React Native(maybe that's
|
||||
* a good thing).
|
||||
*/
|
||||
class TestConnectionInfo extends Component<IProps, State> {
|
||||
|
||||
/**
|
||||
* Initializes new <tt>TestConnectionInfo</tt> instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this._onStatsUpdated = this._onStatsUpdated.bind(this);
|
||||
|
||||
this.state = {
|
||||
stats: {
|
||||
bitrate: {
|
||||
download: 0,
|
||||
upload: 0
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link statsEmitter} callback hoked up for the local participant.
|
||||
*
|
||||
* @param {Object} stats - These are the RTP stats. Look in
|
||||
* the lib-jitsi-meet for more details on the actual structure or add
|
||||
* a console print and figure out there.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
_onStatsUpdated(stats = { bitrate: { download: undefined,
|
||||
upload: undefined } }) {
|
||||
this.setState({
|
||||
stats: {
|
||||
bitrate: {
|
||||
download: stats.bitrate?.download || 0,
|
||||
upload: stats.bitrate?.upload || 0
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts listening for the local RTP stat updates.
|
||||
*
|
||||
* @inheritdoc
|
||||
* returns {void}
|
||||
*/
|
||||
override componentDidMount() {
|
||||
statsEmitter.subscribeToClientStats(
|
||||
this.props._localUserId, this._onStatsUpdated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates which user's stats are being listened to (the local participant's
|
||||
* id changes).
|
||||
*
|
||||
* @inheritdoc
|
||||
* returns {void}
|
||||
*/
|
||||
override componentDidUpdate(prevProps: IProps) {
|
||||
if (prevProps._localUserId !== this.props._localUserId) {
|
||||
statsEmitter.unsubscribeToClientStats(
|
||||
prevProps._localUserId, this._onStatsUpdated);
|
||||
statsEmitter.subscribeToClientStats(
|
||||
this.props._localUserId, this._onStatsUpdated);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the local stats listener.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
override componentWillUnmount() {
|
||||
statsEmitter.unsubscribeToClientStats(
|
||||
this.props._localUserId, this._onStatsUpdated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component if the app is currently running in the test mode
|
||||
* (config.testing.testMode == true).
|
||||
*
|
||||
* @returns {ReactElement|null}
|
||||
*/
|
||||
override render() {
|
||||
if (!this.props._testMode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<TestHint
|
||||
id = 'org.jitsi.meet.conference.connectionState'
|
||||
value = { this.props._conferenceConnectionState } />
|
||||
<TestHint
|
||||
id = 'org.jitsi.meet.conference.joinedState'
|
||||
value = { this.props._conferenceJoinedState } />
|
||||
<TestHint
|
||||
id = 'org.jitsi.meet.conference.grantModeratorAvailable'
|
||||
value = { 'true' } />
|
||||
<TestHint
|
||||
id = 'org.jitsi.meet.conference.localParticipantRole'
|
||||
value = { this.props._localUserRole } />
|
||||
<TestHint
|
||||
id = 'org.jitsi.meet.stats.rtp'
|
||||
value = { JSON.stringify(this.state.stats) } />
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated TestConnectionInfo's props.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
const conferenceJoined
|
||||
= Boolean(state['features/base/conference'].conference);
|
||||
const localParticipant = getLocalParticipant(state);
|
||||
|
||||
return {
|
||||
_conferenceConnectionState: state['features/testing'].connectionState,
|
||||
_conferenceJoinedState: conferenceJoined.toString(),
|
||||
_localUserId: localParticipant?.id ?? '',
|
||||
_localUserRole: localParticipant?.role ?? '',
|
||||
_testMode: isTestModeEnabled(state)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(TestConnectionInfo);
|
||||
46
react/features/base/testing/components/TestHint.android.tsx
Normal file
46
react/features/base/testing/components/TestHint.android.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Text } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { TestHintProps, _mapStateToProps } from './AbstractTestHint';
|
||||
|
||||
/**
|
||||
* The Android version of <code>TestHint</code>. It will put the identifier,
|
||||
* as the 'accessibilityLabel'.
|
||||
*
|
||||
* FIXME The 'testID' attribute (which is used on iOS) does not work with
|
||||
* the react-native as expected, because is mapped to component's tag instead of
|
||||
* any attribute visible to the UI automation. Because of that it can not be
|
||||
* used to find the element.
|
||||
* On the other hand it's not possible to use 'accessibilityLabel' on the iOS
|
||||
* for the id purpose, because it will merge the value with any text content or
|
||||
* 'accessibilityLabel' values of it's children. So as a workaround a TestHint
|
||||
* class was introduced in 'jitsi-meet-torture' which will accept generic 'id'
|
||||
* attribute and then do the search 'under the hood' either by the accessibility
|
||||
* label or the id, depending on the participant's platform. On the client side
|
||||
* the TestHint class is to be the abstraction layer which masks the problem by
|
||||
* exposing id and value properties.
|
||||
*/
|
||||
class TestHint extends Component<TestHintProps> {
|
||||
|
||||
/**
|
||||
* Renders the test hint on Android.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
override render() {
|
||||
if (!this.props._testModeEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Text
|
||||
accessibilityLabel = { this.props.id }
|
||||
onPress = { this.props.onPress } >
|
||||
{ this.props.value }
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(TestHint);
|
||||
34
react/features/base/testing/components/TestHint.ios.tsx
Normal file
34
react/features/base/testing/components/TestHint.ios.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Text } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { TestHintProps, _mapStateToProps } from './AbstractTestHint';
|
||||
|
||||
/**
|
||||
* This is the iOS version of the TestHint.
|
||||
*
|
||||
* Be sure to check the description in TestHint.android and AbstractTestHint
|
||||
* files to understand what a test hint is and why different iOS and Android
|
||||
* components are necessary.
|
||||
*/
|
||||
class TestHint extends Component<TestHintProps> {
|
||||
/**
|
||||
* Renders the test hint on Android.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
override render() {
|
||||
if (!this.props._testModeEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Text
|
||||
accessibilityLabel = { this.props.value }
|
||||
onPress = { this.props.onPress }
|
||||
testID = { this.props.id } />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps)(TestHint);
|
||||
3
react/features/base/testing/components/TestHint.web.ts
Normal file
3
react/features/base/testing/components/TestHint.web.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { Component } from 'react';
|
||||
|
||||
export default Component;
|
||||
144
react/features/base/testing/functions.ts
Normal file
144
react/features/base/testing/functions.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { IReduxState, IStore } from '../../app/types';
|
||||
import { isTrackStreamingStatusActive } from '../../connection-indicator/functions';
|
||||
import { VIDEO_CODEC } from '../../video-quality/constants';
|
||||
import { MEDIA_TYPE, VIDEO_TYPE } from '../media/constants';
|
||||
import { getParticipantById, isScreenShareParticipant } from '../participants/functions';
|
||||
import {
|
||||
getLocalVideoTrack,
|
||||
getTrackByMediaTypeAndParticipant,
|
||||
getVideoTrackByParticipant
|
||||
} from '../tracks/functions';
|
||||
|
||||
/**
|
||||
* Indicates whether the test mode is enabled. When it's enabled
|
||||
* {@link TestHint} and other components from the testing package will be
|
||||
* rendered in various places across the app to help with automatic testing.
|
||||
*
|
||||
* @param {IReduxState} state - The redux store state.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isTestModeEnabled(state: IReduxState): boolean {
|
||||
const testingConfig = state['features/base/config'].testing;
|
||||
|
||||
return Boolean(testingConfig?.testMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the video type of the remote participant's video.
|
||||
*
|
||||
* @param {IStore} store - The redux store.
|
||||
* @param {string} id - The participant ID for the remote video.
|
||||
* @returns {VIDEO_TYPE}
|
||||
*/
|
||||
export function getRemoteVideoType({ getState }: IStore, id: string) {
|
||||
const state = getState();
|
||||
const participant = getParticipantById(state, id);
|
||||
|
||||
if (isScreenShareParticipant(participant)) {
|
||||
return VIDEO_TYPE.DESKTOP;
|
||||
}
|
||||
|
||||
return getTrackByMediaTypeAndParticipant(state['features/base/tracks'], MEDIA_TYPE.VIDEO, id)?.videoType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the last media event received for large video indicates that the video is playing, if not muted.
|
||||
*
|
||||
* @param {IStore} store - The redux store.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isLargeVideoReceived({ getState }: IStore): boolean {
|
||||
const state = getState();
|
||||
const largeVideoParticipantId = state['features/large-video'].participantId ?? '';
|
||||
const largeVideoParticipant = getParticipantById(state, largeVideoParticipantId ?? '');
|
||||
const videoTrack = getVideoTrackByParticipant(state, largeVideoParticipant);
|
||||
|
||||
return Boolean(videoTrack && !videoTrack.muted && isTrackStreamingStatusActive(videoTrack));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the local video track is encoded in AV1.
|
||||
*
|
||||
* @param {IStore} store - The redux store.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isLocalCameraEncodingAv1({ getState }: IStore): boolean {
|
||||
const state = getState();
|
||||
const tracks = state['features/base/tracks'];
|
||||
const localtrack = getLocalVideoTrack(tracks);
|
||||
|
||||
if (localtrack?.codec?.toLowerCase() === VIDEO_CODEC.AV1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the local video track is encoded in H.264.
|
||||
*
|
||||
* @param {IStore} store - The redux store.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isLocalCameraEncodingH264({ getState }: IStore): boolean {
|
||||
const state = getState();
|
||||
const tracks = state['features/base/tracks'];
|
||||
const localtrack = getLocalVideoTrack(tracks);
|
||||
|
||||
if (localtrack?.codec?.toLowerCase() === VIDEO_CODEC.H264) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the local video track is encoded in VP8.
|
||||
*
|
||||
* @param {IStore} store - The redux store.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isLocalCameraEncodingVp8({ getState }: IStore): boolean {
|
||||
const state = getState();
|
||||
const tracks = state['features/base/tracks'];
|
||||
const localtrack = getLocalVideoTrack(tracks);
|
||||
|
||||
if (localtrack?.codec?.toLowerCase() === VIDEO_CODEC.VP8) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the local video track is encoded in VP9.
|
||||
*
|
||||
* @param {IStore} store - The redux store.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isLocalCameraEncodingVp9({ getState }: IStore): boolean {
|
||||
const state = getState();
|
||||
const tracks = state['features/base/tracks'];
|
||||
const localtrack = getLocalVideoTrack(tracks);
|
||||
|
||||
if (localtrack?.codec?.toLowerCase() === VIDEO_CODEC.VP9) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the last media event received for a remote video indicates that the video is playing, if not muted.
|
||||
*
|
||||
* @param {IStore} store - The redux store.
|
||||
* @param {string} id - The participant ID for the remote video.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isRemoteVideoReceived({ getState }: IStore, id: string): boolean {
|
||||
const state = getState();
|
||||
const participant = getParticipantById(state, id);
|
||||
const videoTrack = getVideoTrackByParticipant(state, participant);
|
||||
|
||||
return Boolean(videoTrack && !videoTrack.muted && isTrackStreamingStatusActive(videoTrack));
|
||||
}
|
||||
3
react/features/base/testing/logger.ts
Normal file
3
react/features/base/testing/logger.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { getLogger } from '../logging/functions';
|
||||
|
||||
export default getLogger('features/base/testing');
|
||||
123
react/features/base/testing/middleware.ts
Normal file
123
react/features/base/testing/middleware.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { IStore } from '../../app/types';
|
||||
import { CONFERENCE_JOIN_IN_PROGRESS } from '../conference/actionTypes';
|
||||
import { IJitsiConference } from '../conference/reducer';
|
||||
import { SET_CONFIG } from '../config/actionTypes';
|
||||
import { JitsiConferenceEvents } from '../lib-jitsi-meet';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
import { getJitsiMeetGlobalNS } from '../util/helpers';
|
||||
|
||||
import { setConnectionState } from './actions';
|
||||
import {
|
||||
getRemoteVideoType,
|
||||
isLargeVideoReceived,
|
||||
isLocalCameraEncodingAv1,
|
||||
isLocalCameraEncodingH264,
|
||||
isLocalCameraEncodingVp8,
|
||||
isLocalCameraEncodingVp9,
|
||||
isRemoteVideoReceived,
|
||||
isTestModeEnabled
|
||||
} from './functions';
|
||||
import logger from './logger';
|
||||
|
||||
/**
|
||||
* The Redux middleware of the feature testing.
|
||||
*
|
||||
* @param {Store} store - The Redux store.
|
||||
* @returns {Function}
|
||||
* @private
|
||||
*/
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case CONFERENCE_JOIN_IN_PROGRESS:
|
||||
_bindConferenceConnectionListener(action.conference, store);
|
||||
break;
|
||||
case SET_CONFIG: {
|
||||
const result = next(action);
|
||||
|
||||
_bindTortureHelpers(store);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
||||
|
||||
/**
|
||||
* Binds a handler which will listen for the connection related conference
|
||||
* events (in the lib-jitsi-meet internals those are associated with the ICE
|
||||
* connection state).
|
||||
*
|
||||
* @param {JitsiConference} conference - The {@link JitsiConference} for which
|
||||
* the conference will join even is dispatched.
|
||||
* @param {Store} store - The redux store in which the specified action is being
|
||||
* dispatched.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function _bindConferenceConnectionListener(conference: IJitsiConference, { dispatch }: IStore) {
|
||||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.CONNECTION_ESTABLISHED,
|
||||
_onConnectionEvent.bind(
|
||||
null, JitsiConferenceEvents.CONNECTION_ESTABLISHED, dispatch));
|
||||
conference.on(
|
||||
JitsiConferenceEvents.CONNECTION_RESTORED,
|
||||
_onConnectionEvent.bind(
|
||||
null, JitsiConferenceEvents.CONNECTION_RESTORED, dispatch));
|
||||
conference.on(
|
||||
JitsiConferenceEvents.CONNECTION_INTERRUPTED,
|
||||
_onConnectionEvent.bind(
|
||||
null, JitsiConferenceEvents.CONNECTION_INTERRUPTED, dispatch));
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds all the helper functions needed by torture.
|
||||
*
|
||||
* @param {IStore} store - The redux store.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function _bindTortureHelpers(store: IStore) {
|
||||
const { getState } = store;
|
||||
|
||||
// We bind helpers only if testing mode is enabled
|
||||
if (!isTestModeEnabled(getState())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// All torture helper methods go in here
|
||||
getJitsiMeetGlobalNS().testing = {
|
||||
getRemoteVideoType: getRemoteVideoType.bind(null, store),
|
||||
isLargeVideoReceived: isLargeVideoReceived.bind(null, store),
|
||||
isLocalCameraEncodingAv1: isLocalCameraEncodingAv1.bind(null, store),
|
||||
isLocalCameraEncodingH264: isLocalCameraEncodingH264.bind(null, store),
|
||||
isLocalCameraEncodingVp8: isLocalCameraEncodingVp8.bind(null, store),
|
||||
isLocalCameraEncodingVp9: isLocalCameraEncodingVp9.bind(null, store),
|
||||
isRemoteVideoReceived: isRemoteVideoReceived.bind(null, store)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The handler function for conference connection events which will store the
|
||||
* latest even name in the Redux store of feature testing.
|
||||
*
|
||||
* @param {string} event - One of the lib-jitsi-meet JitsiConferenceEvents.
|
||||
* @param {Function} dispatch - The dispatch function of the current Redux
|
||||
* store.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function _onConnectionEvent(event: string, dispatch: IStore['dispatch']) {
|
||||
switch (event) {
|
||||
case JitsiConferenceEvents.CONNECTION_ESTABLISHED:
|
||||
case JitsiConferenceEvents.CONNECTION_INTERRUPTED:
|
||||
case JitsiConferenceEvents.CONNECTION_RESTORED:
|
||||
dispatch(setConnectionState(event));
|
||||
break;
|
||||
default:
|
||||
logger.error(`onConnectionEvent - unsupported event type: ${event}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
47
react/features/base/testing/reducer.ts
Normal file
47
react/features/base/testing/reducer.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
import { assign } from '../redux/functions';
|
||||
|
||||
import { SET_CONNECTION_STATE } from './actionTypes';
|
||||
|
||||
/**
|
||||
* The initial state of the feature testing.
|
||||
*
|
||||
* @type {{
|
||||
* connectionState: string
|
||||
* }}
|
||||
*/
|
||||
const INITIAL_STATE = {
|
||||
connectionState: ''
|
||||
};
|
||||
|
||||
export interface ITestingState {
|
||||
connectionState: string;
|
||||
}
|
||||
|
||||
ReducerRegistry.register<ITestingState>(
|
||||
'features/testing',
|
||||
(state = INITIAL_STATE, action): ITestingState => {
|
||||
switch (action.type) {
|
||||
case SET_CONNECTION_STATE:
|
||||
return _setConnectionState(state, action);
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Reduces a specific Redux action SET_CONNECTION_STATE of the feature
|
||||
* testing.
|
||||
*
|
||||
* @param {Object} state - The Redux state of the feature base/logging.
|
||||
* @param {Action} action - The Redux action SET_CONNECTION_STATE to reduce.
|
||||
* @private
|
||||
* @returns {Object} The new state of the feature testing after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _setConnectionState(state: ITestingState, action: AnyAction) {
|
||||
return assign(state, { connectionState: action.connectionState });
|
||||
}
|
||||
Reference in New Issue
Block a user