Merge pull request #13209 from ramonlsouza/v24-develop
chore: Merge 2.4 into develop
This commit is contained in:
commit
d7df8dd048
@ -4,6 +4,7 @@ import org.bigbluebutton.common2.msgs._
|
||||
import org.bigbluebutton.core.domain.MeetingState2x
|
||||
import org.bigbluebutton.core.running.{ MeetingActor, OutMsgRouter }
|
||||
import org.bigbluebutton.core.apps.{ PermissionCheck, RightsManagementTrait }
|
||||
import org.bigbluebutton.core.models.{ Users2x, Roles }
|
||||
|
||||
trait RequestBreakoutJoinURLReqMsgHdlr extends RightsManagementTrait {
|
||||
this: MeetingActor =>
|
||||
@ -19,15 +20,22 @@ trait RequestBreakoutJoinURLReqMsgHdlr extends RightsManagementTrait {
|
||||
for {
|
||||
model <- state.breakout
|
||||
room <- model.find(msg.body.breakoutId)
|
||||
requesterUser <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
|
||||
} yield {
|
||||
BreakoutHdlrHelpers.sendJoinURL(
|
||||
liveMeeting,
|
||||
outGW,
|
||||
msg.body.userId,
|
||||
room.externalId,
|
||||
room.sequence.toString(),
|
||||
room.id
|
||||
)
|
||||
if (requesterUser.role == Roles.MODERATOR_ROLE || room.freeJoin) {
|
||||
BreakoutHdlrHelpers.sendJoinURL(
|
||||
liveMeeting,
|
||||
outGW,
|
||||
msg.body.userId,
|
||||
room.externalId,
|
||||
room.sequence.toString(),
|
||||
room.id
|
||||
)
|
||||
} else {
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
val reason = "No permission to request breakout room URL for meeting."
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,6 @@ class App extends React.Component {
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
this.setState({ activitiesJson: json });
|
||||
document.title = `Learning Dashboard - ${json.name}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -54,6 +53,8 @@ class App extends React.Component {
|
||||
const { activitiesJson, tab } = this.state;
|
||||
const { intl } = this.props;
|
||||
|
||||
document.title = `${intl.formatMessage({ id: 'app.learningDashboard.dashboardTitle', defaultMessage: 'Learning Dashboard' })} - ${activitiesJson.name}`;
|
||||
|
||||
function totalOfRaiseHand() {
|
||||
if (activitiesJson && activitiesJson.users) {
|
||||
return Object.values(activitiesJson.users)
|
||||
|
@ -1 +1 @@
|
||||
BIGBLUEBUTTON_RELEASE=2.4-beta-4
|
||||
BIGBLUEBUTTON_RELEASE=2.4-rc-1
|
||||
|
@ -74,6 +74,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
[hidden]:not([hidden="false"]) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
textarea::-webkit-input-placeholder,
|
||||
input::-webkit-input-placeholder {
|
||||
color: var(--palette-placeholder-text);
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('gesturestart', function (e) {
|
||||
|
@ -253,7 +253,6 @@ class BreakoutRoom extends PureComponent {
|
||||
roomList.removeEventListener('keydown', this.handleMoveEvent, true);
|
||||
}
|
||||
}
|
||||
this.handleDismiss();
|
||||
}
|
||||
|
||||
handleShiftUser(activeListSibling) {
|
||||
@ -373,7 +372,7 @@ class BreakoutRoom extends PureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ preventClosing: false });
|
||||
this.handleDismiss();
|
||||
|
||||
const rooms = _.range(1, numberOfRooms + 1).map((seq) => ({
|
||||
users: this.getUserByRoom(seq).map((u) => u.userId),
|
||||
@ -403,7 +402,7 @@ class BreakoutRoom extends PureComponent {
|
||||
breakoutUsers.forEach((user) => sendInvitation(breakoutId, user.userId));
|
||||
});
|
||||
|
||||
this.setState({ preventClosing: false });
|
||||
this.handleDismiss();
|
||||
}
|
||||
|
||||
onAssignRandomly() {
|
||||
|
@ -47,6 +47,7 @@ import ConnectionStatusService from '/imports/ui/components/connection-status/se
|
||||
import { NAVBAR_HEIGHT, LARGE_NAVBAR_HEIGHT } from '/imports/ui/components/layout/defaultValues';
|
||||
import Settings from '/imports/ui/services/settings';
|
||||
import LayoutService from '/imports/ui/components/layout/service';
|
||||
import { registerTitleView } from '/imports/utils/dom-utils';
|
||||
|
||||
const MOBILE_MEDIA = 'only screen and (max-width: 40em)';
|
||||
const APP_CONFIG = Meteor.settings.public.app;
|
||||
@ -99,6 +100,10 @@ const intlMessages = defineMessages({
|
||||
id: 'app.whiteboard.annotations.poll',
|
||||
description: 'message displayed when a poll is published',
|
||||
},
|
||||
defaultViewLabel: {
|
||||
id: 'app.title.defaultViewLabel',
|
||||
description: 'view name apended to document title',
|
||||
},
|
||||
});
|
||||
|
||||
const propTypes = {
|
||||
@ -153,12 +158,14 @@ class App extends Component {
|
||||
const { browserName } = browserInfo;
|
||||
const { osName } = deviceInfo;
|
||||
|
||||
registerTitleView(intl.formatMessage(intlMessages.defaultViewLabel));
|
||||
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_IS_RTL,
|
||||
value: isRTL,
|
||||
});
|
||||
|
||||
MediaService.setSwapLayout();
|
||||
MediaService.setSwapLayout(layoutContextDispatch);
|
||||
Modal.setAppElement('#app');
|
||||
|
||||
const fontSize = isMobile() ? MOBILE_FONT_SIZE : DESKTOP_FONT_SIZE;
|
||||
|
@ -60,6 +60,7 @@ const AppContainer = (props) => {
|
||||
settingsLayout,
|
||||
pushLayoutToEveryone,
|
||||
currentUserId,
|
||||
shouldShowPresentation: propsShouldShowPresentation,
|
||||
...otherProps
|
||||
} = props;
|
||||
const {
|
||||
@ -68,12 +69,14 @@ const AppContainer = (props) => {
|
||||
layoutType,
|
||||
deviceType,
|
||||
} = layoutContextState;
|
||||
const { sidebarContent, sidebarNavigation } = input;
|
||||
const { sidebarContent, sidebarNavigation, presentation } = input;
|
||||
const { actionBar: actionsBarStyle, captions: captionsStyle } = output;
|
||||
const { sidebarNavPanel } = sidebarNavigation;
|
||||
const { sidebarContentPanel } = sidebarContent;
|
||||
const sidebarNavigationIsOpen = sidebarNavigation.isOpen;
|
||||
const sidebarContentIsOpen = sidebarContent.isOpen;
|
||||
const presentationIsOpen = presentation.isOpen;
|
||||
const shouldShowPresentation = propsShouldShowPresentation && presentationIsOpen;
|
||||
|
||||
return currentUserId
|
||||
? (
|
||||
@ -93,6 +96,7 @@ const AppContainer = (props) => {
|
||||
sidebarNavigationIsOpen,
|
||||
sidebarContentPanel,
|
||||
sidebarContentIsOpen,
|
||||
shouldShowPresentation,
|
||||
}}
|
||||
{...otherProps}
|
||||
/>
|
||||
|
@ -79,6 +79,7 @@ class AudioControls extends PureComponent {
|
||||
hideLabel
|
||||
aria-label={intl.formatMessage(intlMessages.joinAudio)}
|
||||
label={intl.formatMessage(intlMessages.joinAudio)}
|
||||
data-test="joinAudio"
|
||||
color="default"
|
||||
ghost
|
||||
icon="audio_off"
|
||||
|
@ -290,6 +290,7 @@ class InputStreamLiveSelector extends Component {
|
||||
aria-label={intl.formatMessage(intlMessages.leaveAudio)}
|
||||
label={intl.formatMessage(intlMessages.leaveAudio)}
|
||||
accessKey={shortcuts.leaveaudio}
|
||||
data-test="leaveAudio"
|
||||
hideLabel
|
||||
color="primary"
|
||||
icon={isListenOnly ? 'listen' : 'audio_on'}
|
||||
|
@ -187,7 +187,7 @@ class AudioModal extends Component {
|
||||
|
||||
if (autoplayBlocked !== prevProps.autoplayBlocked) {
|
||||
if (autoplayBlocked) {
|
||||
this.setContent('autoplayBlocked');
|
||||
this.setContent({ content: 'autoplayBlocked' });
|
||||
} else {
|
||||
closeModal();
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import _ from 'lodash';
|
||||
import BBBMenu from "/imports/ui/components/menu/component";
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
|
||||
import { alertScreenReader } from '/imports/utils/dom-utils';
|
||||
|
||||
import ChatService from '../service';
|
||||
|
||||
const intlMessages = defineMessages({
|
||||
@ -20,6 +22,14 @@ const intlMessages = defineMessages({
|
||||
id: 'app.chat.dropdown.copy',
|
||||
description: 'Copy button label',
|
||||
},
|
||||
copySuccess: {
|
||||
id: 'app.chat.copySuccess',
|
||||
description: 'aria success alert',
|
||||
},
|
||||
copyErr: {
|
||||
id: 'app.chat.copyErr',
|
||||
description: 'aria error alert',
|
||||
},
|
||||
options: {
|
||||
id: 'app.chat.dropdown.options',
|
||||
description: 'Chat Options',
|
||||
@ -92,7 +102,11 @@ class ChatDropdown extends PureComponent {
|
||||
label: intl.formatMessage(intlMessages.copy),
|
||||
onClick: () => {
|
||||
let chatHistory = ChatService.exportChat(timeWindowsValues, users, intl);
|
||||
navigator.clipboard.writeText(chatHistory);
|
||||
navigator.clipboard.writeText(chatHistory).then(() => {
|
||||
alertScreenReader(intl.formatMessage(intlMessages.copySuccess));
|
||||
}).catch(() => {
|
||||
alertScreenReader(intl.formatMessage(intlMessages.copyErr));
|
||||
});
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -121,6 +135,7 @@ class ChatDropdown extends PureComponent {
|
||||
|
||||
if (!amIModerator && !ENABLE_SAVE_AND_COPY_PUBLIC_CHAT) return null;
|
||||
return (
|
||||
<>
|
||||
<BBBMenu
|
||||
trigger={
|
||||
<Button
|
||||
@ -148,6 +163,7 @@ class ChatDropdown extends PureComponent {
|
||||
}}
|
||||
actions={this.getAvailableActions()}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +125,7 @@
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
flex-basis: 3.5rem;
|
||||
color: var(--color-gray-light);
|
||||
color: var(--palette-placeholder-text);
|
||||
text-transform: uppercase;
|
||||
font-size: 75%;
|
||||
margin: 0 0 0 calc(var(--line-height-computed) / 2);
|
||||
|
@ -321,7 +321,7 @@ class ConnectionStatusComponent extends PureComponent {
|
||||
{conn.offline ? ` (${intl.formatMessage(intlMessages.offline)})` : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.status}>
|
||||
<div aria-label={`${intl.formatMessage(intlMessages.title)} ${conn.level}`} className={styles.status}>
|
||||
<div className={styles.icon}>
|
||||
<Icon level={conn.level} />
|
||||
</div>
|
||||
|
@ -147,6 +147,7 @@ class CustomLayout extends Component {
|
||||
isOpen: false,
|
||||
},
|
||||
presentation: {
|
||||
isOpen: input.presentation.isOpen,
|
||||
slidesLength: input.presentation.slidesLength,
|
||||
currentSlide: {
|
||||
...input.presentation.currentSlide,
|
||||
@ -174,6 +175,7 @@ class CustomLayout extends Component {
|
||||
isOpen: false,
|
||||
},
|
||||
presentation: {
|
||||
isOpen: input.presentation.isOpen,
|
||||
slidesLength: input.presentation.slidesLength,
|
||||
currentSlide: {
|
||||
...input.presentation.currentSlide,
|
||||
@ -426,6 +428,7 @@ class CustomLayout extends Component {
|
||||
const { isOpen } = presentation;
|
||||
const { camerasMargin } = DEFAULT_VALUES;
|
||||
const sidebarSize = sidebarNavWidth + sidebarContentWidth;
|
||||
const bannerAreaHeight = this.bannerAreaHeight();
|
||||
|
||||
const cameraDockBounds = {};
|
||||
|
||||
@ -462,7 +465,7 @@ class CustomLayout extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
cameraDockBounds.top = DEFAULT_VALUES.navBarHeight;
|
||||
cameraDockBounds.top = DEFAULT_VALUES.navBarHeight + bannerAreaHeight;
|
||||
cameraDockBounds.left = cameraDockLeft;
|
||||
cameraDockBounds.right = isRTL ? sidebarSize : null;
|
||||
cameraDockBounds.minWidth = mediaAreaBounds.width;
|
||||
@ -490,7 +493,7 @@ class CustomLayout extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
cameraDockBounds.top = DEFAULT_VALUES.navBarHeight;
|
||||
cameraDockBounds.top = DEFAULT_VALUES.navBarHeight + bannerAreaHeight;
|
||||
const sizeValue = input.presentation.isOpen
|
||||
? (mediaAreaBounds.left + mediaAreaBounds.width) - cameraDockWidth
|
||||
: mediaAreaBounds.left;
|
||||
@ -527,7 +530,7 @@ class CustomLayout extends Component {
|
||||
}
|
||||
|
||||
cameraDockBounds.top = DEFAULT_VALUES.navBarHeight
|
||||
+ mediaAreaBounds.height - cameraDockHeight;
|
||||
+ mediaAreaBounds.height - cameraDockHeight + bannerAreaHeight;
|
||||
cameraDockBounds.left = cameraDockLeft;
|
||||
cameraDockBounds.right = isRTL ? sidebarSize : null;
|
||||
cameraDockBounds.minWidth = mediaAreaBounds.width;
|
||||
@ -555,7 +558,7 @@ class CustomLayout extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
cameraDockBounds.top = DEFAULT_VALUES.navBarHeight;
|
||||
cameraDockBounds.top = DEFAULT_VALUES.navBarHeight + bannerAreaHeight;
|
||||
cameraDockBounds.left = mediaAreaBounds.left + camerasMargin;
|
||||
cameraDockBounds.right = isRTL ? sidebarSize + (camerasMargin * 2) : null;
|
||||
cameraDockBounds.minWidth = DEFAULT_VALUES.cameraDockMinWidth;
|
||||
@ -629,8 +632,9 @@ class CustomLayout extends Component {
|
||||
const { presentation } = input;
|
||||
const { isOpen } = presentation;
|
||||
const { height: actionBarHeight } = this.calculatesActionbarHeight();
|
||||
const bannerAreaHeight = this.bannerAreaHeight();
|
||||
const mediaAreaHeight = windowHeight()
|
||||
- (DEFAULT_VALUES.navBarHeight + actionBarHeight);
|
||||
- (DEFAULT_VALUES.navBarHeight + actionBarHeight + bannerAreaHeight);
|
||||
const mediaAreaWidth = windowWidth() - (sidebarNavWidth + sidebarContentWidth);
|
||||
const mediaBounds = {};
|
||||
const { element: fullscreenElement } = fullscreen;
|
||||
@ -663,7 +667,7 @@ class CustomLayout extends Component {
|
||||
case CAMERADOCK_POSITION.CONTENT_TOP: {
|
||||
mediaBounds.width = mediaAreaWidth;
|
||||
mediaBounds.height = mediaAreaHeight - cameraDockBounds.height - camerasMargin;
|
||||
mediaBounds.top = navBarHeight + cameraDockBounds.height + camerasMargin;
|
||||
mediaBounds.top = navBarHeight + cameraDockBounds.height + camerasMargin + bannerAreaHeight;
|
||||
mediaBounds.left = !isRTL ? sidebarSize : null;
|
||||
mediaBounds.right = isRTL ? sidebarSize : null;
|
||||
break;
|
||||
@ -671,7 +675,7 @@ class CustomLayout extends Component {
|
||||
case CAMERADOCK_POSITION.CONTENT_RIGHT: {
|
||||
mediaBounds.width = mediaAreaWidth - cameraDockBounds.width - camerasMargin;
|
||||
mediaBounds.height = mediaAreaHeight;
|
||||
mediaBounds.top = navBarHeight;
|
||||
mediaBounds.top = navBarHeight + bannerAreaHeight;
|
||||
mediaBounds.left = !isRTL ? sidebarSize : null;
|
||||
mediaBounds.right = isRTL ? sidebarSize - (camerasMargin * 2) : null;
|
||||
break;
|
||||
@ -679,7 +683,7 @@ class CustomLayout extends Component {
|
||||
case CAMERADOCK_POSITION.CONTENT_BOTTOM: {
|
||||
mediaBounds.width = mediaAreaWidth;
|
||||
mediaBounds.height = mediaAreaHeight - cameraDockBounds.height - camerasMargin;
|
||||
mediaBounds.top = navBarHeight - camerasMargin;
|
||||
mediaBounds.top = navBarHeight - camerasMargin + bannerAreaHeight;
|
||||
mediaBounds.left = !isRTL ? sidebarSize : null;
|
||||
mediaBounds.right = isRTL ? sidebarSize : null;
|
||||
break;
|
||||
@ -687,7 +691,7 @@ class CustomLayout extends Component {
|
||||
case CAMERADOCK_POSITION.CONTENT_LEFT: {
|
||||
mediaBounds.width = mediaAreaWidth - cameraDockBounds.width - camerasMargin;
|
||||
mediaBounds.height = mediaAreaHeight;
|
||||
mediaBounds.top = navBarHeight;
|
||||
mediaBounds.top = navBarHeight + bannerAreaHeight;
|
||||
const sizeValue = sidebarNavWidth
|
||||
+ sidebarContentWidth + mediaAreaWidth - mediaBounds.width;
|
||||
mediaBounds.left = !isRTL ? sizeValue : null;
|
||||
@ -697,7 +701,7 @@ class CustomLayout extends Component {
|
||||
case CAMERADOCK_POSITION.SIDEBAR_CONTENT_BOTTOM: {
|
||||
mediaBounds.width = mediaAreaWidth;
|
||||
mediaBounds.height = mediaAreaHeight;
|
||||
mediaBounds.top = navBarHeight;
|
||||
mediaBounds.top = navBarHeight + bannerAreaHeight;
|
||||
mediaBounds.left = !isRTL ? sidebarSize : null;
|
||||
mediaBounds.right = isRTL ? sidebarSize : null;
|
||||
break;
|
||||
@ -710,7 +714,7 @@ class CustomLayout extends Component {
|
||||
} else {
|
||||
mediaBounds.width = mediaAreaWidth;
|
||||
mediaBounds.height = mediaAreaHeight;
|
||||
mediaBounds.top = DEFAULT_VALUES.navBarHeight + this.bannerAreaHeight();
|
||||
mediaBounds.top = DEFAULT_VALUES.navBarHeight + bannerAreaHeight;
|
||||
mediaBounds.left = !isRTL ? sidebarSize : null;
|
||||
mediaBounds.right = isRTL ? sidebarSize : null;
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ class PresentationFocusLayout extends Component {
|
||||
isOpen: false,
|
||||
},
|
||||
presentation: {
|
||||
isOpen: input.presentation.isOpen,
|
||||
slidesLength: input.presentation.slidesLength,
|
||||
currentSlide: {
|
||||
...input.presentation.currentSlide,
|
||||
@ -108,6 +109,7 @@ class PresentationFocusLayout extends Component {
|
||||
isOpen: false,
|
||||
},
|
||||
presentation: {
|
||||
isOpen: input.presentation.isOpen,
|
||||
slidesLength: input.presentation.slidesLength,
|
||||
currentSlide: {
|
||||
...input.presentation.currentSlide,
|
||||
@ -276,6 +278,8 @@ class PresentationFocusLayout extends Component {
|
||||
calculatesSidebarContentHeight() {
|
||||
const { layoutContextState } = this.props;
|
||||
const { deviceType, input } = layoutContextState;
|
||||
const { presentation } = input;
|
||||
const { isOpen } = presentation;
|
||||
const {
|
||||
navBarHeight,
|
||||
sidebarContentMinHeight,
|
||||
@ -288,7 +292,7 @@ class PresentationFocusLayout extends Component {
|
||||
height = windowHeight() - navBarHeight - this.bannerAreaHeight();
|
||||
minHeight = height;
|
||||
maxHeight = height;
|
||||
} else if (input.cameraDock.numCameras > 0) {
|
||||
} else if (input.cameraDock.numCameras > 0 && isOpen) {
|
||||
if (input.sidebarContent.height === 0) {
|
||||
height = (windowHeight() * 0.75) - this.bannerAreaHeight();
|
||||
} else {
|
||||
@ -368,57 +372,70 @@ class PresentationFocusLayout extends Component {
|
||||
const {
|
||||
deviceType, input, fullscreen, isRTL,
|
||||
} = layoutContextState;
|
||||
const { presentation } = input;
|
||||
const { isOpen } = presentation;
|
||||
const cameraDockBounds = {};
|
||||
const sidebarSize = sidebarNavWidth + sidebarContentWidth;
|
||||
|
||||
if (input.cameraDock.numCameras > 0) {
|
||||
let cameraDockHeight = 0;
|
||||
|
||||
if (fullscreen.group === 'webcams') {
|
||||
cameraDockBounds.width = windowWidth();
|
||||
cameraDockBounds.minWidth = windowWidth();
|
||||
cameraDockBounds.maxWidth = windowWidth();
|
||||
cameraDockBounds.height = windowHeight();
|
||||
cameraDockBounds.minHeight = windowHeight();
|
||||
cameraDockBounds.maxHeight = windowHeight();
|
||||
cameraDockBounds.top = 0;
|
||||
cameraDockBounds.left = 0;
|
||||
cameraDockBounds.right = 0;
|
||||
cameraDockBounds.zIndex = 99;
|
||||
return cameraDockBounds;
|
||||
}
|
||||
|
||||
if (deviceType === DEVICE_TYPE.MOBILE) {
|
||||
cameraDockBounds.top = mediaAreaBounds.top + mediaBounds.height;
|
||||
cameraDockBounds.left = 0;
|
||||
cameraDockBounds.right = 0;
|
||||
cameraDockBounds.minWidth = mediaAreaBounds.width;
|
||||
if (!isOpen) {
|
||||
cameraDockBounds.width = mediaAreaBounds.width;
|
||||
cameraDockBounds.maxWidth = mediaAreaBounds.width;
|
||||
cameraDockBounds.minHeight = DEFAULT_VALUES.cameraDockMinHeight;
|
||||
cameraDockBounds.height = mediaAreaBounds.height - mediaBounds.height;
|
||||
cameraDockBounds.maxHeight = mediaAreaBounds.height - mediaBounds.height;
|
||||
cameraDockBounds.height = mediaAreaBounds.height;
|
||||
cameraDockBounds.maxHeight = mediaAreaBounds.height;
|
||||
cameraDockBounds.top = DEFAULT_VALUES.navBarHeight;
|
||||
cameraDockBounds.left = !isRTL ? mediaAreaBounds.left : 0;
|
||||
cameraDockBounds.right = isRTL ? sidebarSize : null;
|
||||
} else {
|
||||
if (input.cameraDock.height === 0) {
|
||||
cameraDockHeight = min(
|
||||
max((windowHeight() - sidebarContentHeight), DEFAULT_VALUES.cameraDockMinHeight),
|
||||
(windowHeight() - DEFAULT_VALUES.cameraDockMinHeight),
|
||||
);
|
||||
} else {
|
||||
cameraDockHeight = min(
|
||||
max(input.cameraDock.height, DEFAULT_VALUES.cameraDockMinHeight),
|
||||
(windowHeight() - DEFAULT_VALUES.cameraDockMinHeight),
|
||||
);
|
||||
let cameraDockHeight = 0;
|
||||
|
||||
if (fullscreen.group === 'webcams') {
|
||||
cameraDockBounds.width = windowWidth();
|
||||
cameraDockBounds.minWidth = windowWidth();
|
||||
cameraDockBounds.maxWidth = windowWidth();
|
||||
cameraDockBounds.height = windowHeight();
|
||||
cameraDockBounds.minHeight = windowHeight();
|
||||
cameraDockBounds.maxHeight = windowHeight();
|
||||
cameraDockBounds.top = 0;
|
||||
cameraDockBounds.left = 0;
|
||||
cameraDockBounds.right = 0;
|
||||
cameraDockBounds.zIndex = 99;
|
||||
return cameraDockBounds;
|
||||
}
|
||||
|
||||
if (deviceType === DEVICE_TYPE.MOBILE) {
|
||||
cameraDockBounds.top = mediaAreaBounds.top + mediaBounds.height;
|
||||
cameraDockBounds.left = 0;
|
||||
cameraDockBounds.right = 0;
|
||||
cameraDockBounds.minWidth = mediaAreaBounds.width;
|
||||
cameraDockBounds.width = mediaAreaBounds.width;
|
||||
cameraDockBounds.maxWidth = mediaAreaBounds.width;
|
||||
cameraDockBounds.minHeight = DEFAULT_VALUES.cameraDockMinHeight;
|
||||
cameraDockBounds.height = mediaAreaBounds.height - mediaBounds.height;
|
||||
cameraDockBounds.maxHeight = mediaAreaBounds.height - mediaBounds.height;
|
||||
} else {
|
||||
if (input.cameraDock.height === 0) {
|
||||
cameraDockHeight = min(
|
||||
max((windowHeight() - sidebarContentHeight), DEFAULT_VALUES.cameraDockMinHeight),
|
||||
(windowHeight() - DEFAULT_VALUES.cameraDockMinHeight),
|
||||
);
|
||||
} else {
|
||||
cameraDockHeight = min(
|
||||
max(input.cameraDock.height, DEFAULT_VALUES.cameraDockMinHeight),
|
||||
(windowHeight() - DEFAULT_VALUES.cameraDockMinHeight),
|
||||
);
|
||||
}
|
||||
cameraDockBounds.top = windowHeight() - cameraDockHeight;
|
||||
cameraDockBounds.left = !isRTL ? sidebarNavWidth : 0;
|
||||
cameraDockBounds.right = isRTL ? sidebarNavWidth : 0;
|
||||
cameraDockBounds.minWidth = sidebarContentWidth;
|
||||
cameraDockBounds.width = sidebarContentWidth;
|
||||
cameraDockBounds.maxWidth = sidebarContentWidth;
|
||||
cameraDockBounds.minHeight = DEFAULT_VALUES.cameraDockMinHeight;
|
||||
cameraDockBounds.height = cameraDockHeight;
|
||||
cameraDockBounds.maxHeight = windowHeight() - sidebarContentHeight;
|
||||
cameraDockBounds.zIndex = 1;
|
||||
}
|
||||
cameraDockBounds.top = windowHeight() - cameraDockHeight;
|
||||
cameraDockBounds.left = !isRTL ? sidebarNavWidth : 0;
|
||||
cameraDockBounds.right = isRTL ? sidebarNavWidth : 0;
|
||||
cameraDockBounds.minWidth = sidebarContentWidth;
|
||||
cameraDockBounds.width = sidebarContentWidth;
|
||||
cameraDockBounds.maxWidth = sidebarContentWidth;
|
||||
cameraDockBounds.minHeight = DEFAULT_VALUES.cameraDockMinHeight;
|
||||
cameraDockBounds.height = cameraDockHeight;
|
||||
cameraDockBounds.maxHeight = windowHeight() - sidebarContentHeight;
|
||||
cameraDockBounds.zIndex = 1;
|
||||
}
|
||||
} else {
|
||||
cameraDockBounds.width = 0;
|
||||
|
@ -81,6 +81,7 @@ class SmartLayout extends Component {
|
||||
isOpen: false,
|
||||
},
|
||||
presentation: {
|
||||
isOpen: input.presentation.isOpen,
|
||||
slidesLength: input.presentation.slidesLength,
|
||||
currentSlide: {
|
||||
...input.presentation.currentSlide,
|
||||
@ -108,6 +109,7 @@ class SmartLayout extends Component {
|
||||
isOpen: false,
|
||||
},
|
||||
presentation: {
|
||||
isOpen: input.presentation.isOpen,
|
||||
slidesLength: input.presentation.slidesLength,
|
||||
currentSlide: {
|
||||
...input.presentation.currentSlide,
|
||||
|
@ -83,6 +83,7 @@ class VideoFocusLayout extends Component {
|
||||
isOpen: false,
|
||||
},
|
||||
presentation: {
|
||||
isOpen: input.presentation.isOpen,
|
||||
slidesLength: input.presentation.slidesLength,
|
||||
currentSlide: {
|
||||
...input.presentation.currentSlide,
|
||||
@ -113,6 +114,7 @@ class VideoFocusLayout extends Component {
|
||||
isOpen: false,
|
||||
},
|
||||
presentation: {
|
||||
isOpen: input.presentation.isOpen,
|
||||
slidesLength: input.presentation.slidesLength,
|
||||
currentSlide: {
|
||||
...input.presentation.currentSlide,
|
||||
@ -374,42 +376,52 @@ class VideoFocusLayout extends Component {
|
||||
const {
|
||||
deviceType, input, fullscreen, isRTL,
|
||||
} = layoutContextState;
|
||||
const { cameraDock } = input;
|
||||
const { cameraDock, presentation } = input;
|
||||
const { isOpen } = presentation;
|
||||
const { numCameras } = cameraDock;
|
||||
|
||||
const cameraDockBounds = {};
|
||||
|
||||
if (numCameras > 0) {
|
||||
if (deviceType === DEVICE_TYPE.MOBILE) {
|
||||
cameraDockBounds.minHeight = mediaAreaBounds.height * 0.7;
|
||||
cameraDockBounds.height = mediaAreaBounds.height * 0.7;
|
||||
cameraDockBounds.maxHeight = mediaAreaBounds.height * 0.7;
|
||||
} else {
|
||||
cameraDockBounds.minHeight = mediaAreaBounds.height;
|
||||
if (!isOpen) {
|
||||
cameraDockBounds.width = mediaAreaBounds.width;
|
||||
cameraDockBounds.maxWidth = mediaAreaBounds.width;
|
||||
cameraDockBounds.height = mediaAreaBounds.height;
|
||||
cameraDockBounds.maxHeight = mediaAreaBounds.height;
|
||||
cameraDockBounds.top = DEFAULT_VALUES.navBarHeight;
|
||||
cameraDockBounds.left = !isRTL ? mediaAreaBounds.left : 0;
|
||||
cameraDockBounds.right = isRTL ? sidebarSize : null;
|
||||
} else {
|
||||
if (deviceType === DEVICE_TYPE.MOBILE) {
|
||||
cameraDockBounds.minHeight = mediaAreaBounds.height * 0.7;
|
||||
cameraDockBounds.height = mediaAreaBounds.height * 0.7;
|
||||
cameraDockBounds.maxHeight = mediaAreaBounds.height * 0.7;
|
||||
} else {
|
||||
cameraDockBounds.minHeight = mediaAreaBounds.height;
|
||||
cameraDockBounds.height = mediaAreaBounds.height;
|
||||
cameraDockBounds.maxHeight = mediaAreaBounds.height;
|
||||
}
|
||||
|
||||
cameraDockBounds.top = DEFAULT_VALUES.navBarHeight;
|
||||
cameraDockBounds.left = !isRTL ? mediaAreaBounds.left : null;
|
||||
cameraDockBounds.right = isRTL ? sidebarSize : null;
|
||||
cameraDockBounds.minWidth = mediaAreaBounds.width;
|
||||
cameraDockBounds.width = mediaAreaBounds.width;
|
||||
cameraDockBounds.maxWidth = mediaAreaBounds.width;
|
||||
cameraDockBounds.zIndex = 1;
|
||||
|
||||
if (fullscreen.group === 'webcams') {
|
||||
cameraDockBounds.width = windowWidth();
|
||||
cameraDockBounds.minWidth = windowWidth();
|
||||
cameraDockBounds.maxWidth = windowWidth();
|
||||
cameraDockBounds.height = windowHeight();
|
||||
cameraDockBounds.minHeight = windowHeight();
|
||||
cameraDockBounds.maxHeight = windowHeight();
|
||||
cameraDockBounds.top = 0;
|
||||
cameraDockBounds.left = 0;
|
||||
cameraDockBounds.zIndex = 99;
|
||||
}
|
||||
}
|
||||
|
||||
cameraDockBounds.top = DEFAULT_VALUES.navBarHeight;
|
||||
cameraDockBounds.left = !isRTL ? mediaAreaBounds.left : null;
|
||||
cameraDockBounds.right = isRTL ? sidebarSize : null;
|
||||
cameraDockBounds.minWidth = mediaAreaBounds.width;
|
||||
cameraDockBounds.width = mediaAreaBounds.width;
|
||||
cameraDockBounds.maxWidth = mediaAreaBounds.width;
|
||||
cameraDockBounds.zIndex = 1;
|
||||
|
||||
if (fullscreen.group === 'webcams') {
|
||||
cameraDockBounds.width = windowWidth();
|
||||
cameraDockBounds.minWidth = windowWidth();
|
||||
cameraDockBounds.maxWidth = windowWidth();
|
||||
cameraDockBounds.height = windowHeight();
|
||||
cameraDockBounds.minHeight = windowHeight();
|
||||
cameraDockBounds.maxHeight = windowHeight();
|
||||
cameraDockBounds.top = 0;
|
||||
cameraDockBounds.left = 0;
|
||||
cameraDockBounds.zIndex = 99;
|
||||
}
|
||||
|
||||
return cameraDockBounds;
|
||||
}
|
||||
|
||||
|
@ -47,9 +47,14 @@ const swapLayout = {
|
||||
tracker: new Tracker.Dependency(),
|
||||
};
|
||||
|
||||
const setSwapLayout = () => {
|
||||
const setSwapLayout = (layoutContextDispatch) => {
|
||||
swapLayout.value = getFromUserSettings('bbb_auto_swap_layout', LAYOUT_CONFIG.autoSwapLayout);
|
||||
swapLayout.tracker.changed();
|
||||
|
||||
layoutContextDispatch({
|
||||
type: ACTIONS.SET_PRESENTATION_IS_OPEN,
|
||||
value: !swapLayout.value,
|
||||
});
|
||||
};
|
||||
|
||||
const toggleSwapLayout = (layoutContextDispatch) => {
|
||||
|
@ -117,6 +117,7 @@ class BBBMenu extends React.Component {
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={this.handleClose}
|
||||
className={menuClasses.join(' ')}
|
||||
style={{ zIndex: 9999 }}
|
||||
>
|
||||
{actionsItems}
|
||||
{anchorEl && window.innerWidth < MAX_WIDTH &&
|
||||
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactModal from 'react-modal';
|
||||
import { styles } from './styles.scss';
|
||||
import { registerTitleView, unregisterTitleView } from '/imports/utils/dom-utils';
|
||||
|
||||
const propTypes = {
|
||||
overlayClassName: PropTypes.string.isRequired,
|
||||
@ -19,6 +20,15 @@ const defaultProps = {
|
||||
};
|
||||
|
||||
export default class ModalBase extends Component {
|
||||
|
||||
componentDidMount() {
|
||||
registerTitleView(this.props.contentLabel);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
unregisterTitleView();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.props.isOpen) return null;
|
||||
|
||||
@ -27,8 +37,8 @@ export default class ModalBase extends Component {
|
||||
{...this.props}
|
||||
parentSelector={() => {
|
||||
if (document.fullscreenElement &&
|
||||
document.fullscreenElement.nodeName &&
|
||||
document.fullscreenElement.nodeName.toLowerCase() === 'div')
|
||||
document.fullscreenElement.nodeName &&
|
||||
document.fullscreenElement.nodeName.toLowerCase() === 'div')
|
||||
return document.fullscreenElement;
|
||||
else return document.body;
|
||||
}}
|
||||
@ -55,12 +65,12 @@ export const withModalState = ComponentToWrap =>
|
||||
this.show = this.show.bind(this);
|
||||
}
|
||||
|
||||
hide(cb = () => {}) {
|
||||
hide(cb = () => { }) {
|
||||
Promise.resolve(cb())
|
||||
.then(() => this.setState({ isOpen: false }));
|
||||
}
|
||||
|
||||
show(cb = () => {}) {
|
||||
show(cb = () => { }) {
|
||||
Promise.resolve(cb())
|
||||
.then(() => this.setState({ isOpen: true }));
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import LiveResult from './live-result/component';
|
||||
import { styles } from './styles.scss';
|
||||
import { PANELS, ACTIONS } from '../layout/enums';
|
||||
import DragAndDrop from './dragAndDrop/component';
|
||||
import { alertScreenReader } from '/imports/utils/dom-utils';
|
||||
|
||||
const intlMessages = defineMessages({
|
||||
pollPaneTitle: {
|
||||
@ -185,6 +186,14 @@ const intlMessages = defineMessages({
|
||||
id: 'app.switch.offLabel',
|
||||
description: 'label for toggle switch off state',
|
||||
},
|
||||
removePollOpt: {
|
||||
id: 'app.poll.removePollOpt',
|
||||
description: 'screen reader alert for removed poll option',
|
||||
},
|
||||
emptyPollOpt: {
|
||||
id: 'app.poll.emptyPollOpt',
|
||||
description: 'screen reader for blank poll option',
|
||||
},
|
||||
});
|
||||
|
||||
const POLL_SETTINGS = Meteor.settings.public.poll;
|
||||
@ -295,10 +304,15 @@ class Poll extends Component {
|
||||
}
|
||||
|
||||
handleRemoveOption(index) {
|
||||
const { intl } = this.props;
|
||||
const { optList } = this.state;
|
||||
const list = [...optList];
|
||||
const removed = list[index];
|
||||
list.splice(index, 1);
|
||||
this.setState({ optList: list });
|
||||
this.setState({ optList: list }, () => {
|
||||
alertScreenReader(`${intl.formatMessage(intlMessages.removePollOpt,
|
||||
{ 0: removed.val || intl.formatMessage(intlMessages.emptyPollOpt) })}`);
|
||||
});
|
||||
}
|
||||
|
||||
handleAddOption() {
|
||||
@ -395,7 +409,10 @@ class Poll extends Component {
|
||||
this.handleRemoveOption(i);
|
||||
}}
|
||||
/>
|
||||
<span className="sr-only" id={`option-${i}`}>{intl.formatMessage(intlMessages.deleteRespDesc, { 0: o.val })}</span>
|
||||
<span className="sr-only" id={`option-${i}`}>
|
||||
{intl.formatMessage(intlMessages.deleteRespDesc,
|
||||
{ 0: (o.val || intl.formatMessage(intlMessages.emptyPollOpt)) })}
|
||||
</span>
|
||||
</>
|
||||
)
|
||||
: <div style={{ width: '40px' }} />}
|
||||
|
@ -13,6 +13,7 @@ import logger from '/imports/startup/client/logger';
|
||||
import { notify } from '/imports/ui/services/notification';
|
||||
import { toast } from 'react-toastify';
|
||||
import _ from 'lodash';
|
||||
import { registerTitleView, unregisterTitleView } from '/imports/utils/dom-utils';
|
||||
import { styles } from './styles';
|
||||
|
||||
const { isMobile } = deviceInfo;
|
||||
@ -214,6 +215,10 @@ const intlMessages = defineMessages({
|
||||
id: 'app.presentationUploder.clearErrorsDesc',
|
||||
description: 'aria description for button clearing upload error',
|
||||
},
|
||||
uploadViewTitle: {
|
||||
id: 'app.presentationUploder.uploadViewTitle',
|
||||
description: 'view name apended to document title',
|
||||
}
|
||||
});
|
||||
|
||||
class PresentationUploader extends Component {
|
||||
@ -251,10 +256,16 @@ class PresentationUploader extends Component {
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { isOpen, presentations: propPresentations } = this.props;
|
||||
const { isOpen, presentations: propPresentations, intl } = this.props;
|
||||
const { presentations } = this.state;
|
||||
|
||||
if (!isOpen && prevProps.isOpen) {
|
||||
unregisterTitleView();
|
||||
}
|
||||
|
||||
// Updates presentation list when chat modal opens to avoid missing presentations
|
||||
if (isOpen && !prevProps.isOpen) {
|
||||
registerTitleView(intl.formatMessage(intlMessages.uploadViewTitle));
|
||||
const focusableElements =
|
||||
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
||||
const modal = document.getElementById('upload-modal');
|
||||
|
@ -22,6 +22,10 @@ const intlMessages = defineMessages({
|
||||
id: 'app.guest-policy.description',
|
||||
description: 'Guest policy description',
|
||||
},
|
||||
policyBtnDesc: {
|
||||
id: 'app.guest-policy.policyBtnDesc',
|
||||
description: 'aria description for guest policy button',
|
||||
},
|
||||
askModerator: {
|
||||
id: 'app.guest-policy.button.askModerator',
|
||||
description: 'Ask moderator button label',
|
||||
@ -84,9 +88,11 @@ class GuestPolicyComponent extends PureComponent {
|
||||
<div className={styles.content}>
|
||||
<Button
|
||||
color="primary"
|
||||
className={styles.button}
|
||||
className={[styles.button, guestPolicy === ASK_MODERATOR && styles.active].join(' ')}
|
||||
disabled={guestPolicy === ASK_MODERATOR}
|
||||
label={intl.formatMessage(intlMessages.askModerator)}
|
||||
aria-describedby={guestPolicy === ASK_MODERATOR ? 'selected-btn-desc' : 'policy-btn-desc'}
|
||||
aria-pressed={guestPolicy === ASK_MODERATOR}
|
||||
data-test="askModerator"
|
||||
onClick={() => {
|
||||
changeGuestPolicy(ASK_MODERATOR);
|
||||
@ -95,9 +101,11 @@ class GuestPolicyComponent extends PureComponent {
|
||||
/>
|
||||
<Button
|
||||
color="primary"
|
||||
className={styles.button}
|
||||
className={[styles.button, guestPolicy === ALWAYS_ACCEPT && styles.active].join(' ')}
|
||||
disabled={guestPolicy === ALWAYS_ACCEPT}
|
||||
label={intl.formatMessage(intlMessages.alwaysAccept)}
|
||||
aria-describedby={guestPolicy === ALWAYS_ACCEPT ? 'selected-btn-desc' : 'policy-btn-desc'}
|
||||
aria-pressed={guestPolicy === ALWAYS_ACCEPT}
|
||||
data-test="alwaysAccept"
|
||||
onClick={() => {
|
||||
changeGuestPolicy(ALWAYS_ACCEPT);
|
||||
@ -106,9 +114,11 @@ class GuestPolicyComponent extends PureComponent {
|
||||
/>
|
||||
<Button
|
||||
color="primary"
|
||||
className={styles.button}
|
||||
className={[styles.button, guestPolicy === ALWAYS_DENY && styles.active].join(' ')}
|
||||
disabled={guestPolicy === ALWAYS_DENY}
|
||||
label={intl.formatMessage(intlMessages.alwaysDeny)}
|
||||
aria-describedby={guestPolicy === ALWAYS_DENY ? 'selected-btn-desc' : 'policy-btn-desc'}
|
||||
aria-pressed={guestPolicy === ALWAYS_DENY}
|
||||
data-test="alwaysDeny"
|
||||
onClick={() => {
|
||||
changeGuestPolicy(ALWAYS_DENY);
|
||||
@ -116,6 +126,9 @@ class GuestPolicyComponent extends PureComponent {
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div id="policy-btn-desc" aria-hidden className="sr-only">
|
||||
{intl.formatMessage(intlMessages.policyBtnDesc)}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
@ -66,3 +66,9 @@
|
||||
box-sizing: border-box;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.active {
|
||||
span {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ const WebcamComponent = ({
|
||||
);
|
||||
Storage.setItem('webcamSize', { width: newCameraMaxWidth, height: lastHeight });
|
||||
}
|
||||
}, [cameraDock.position, isPresenter, displayPresentation]);
|
||||
}, [cameraDock.position, cameraDock.maxWidth, isPresenter, displayPresentation]);
|
||||
|
||||
const onResizeHandle = (deltaWidth, deltaHeight) => {
|
||||
if (cameraDock.resizableEdge.top || cameraDock.resizableEdge.bottom) {
|
||||
|
@ -1,4 +1,6 @@
|
||||
:root {
|
||||
--palette-placeholder-text: #787675;
|
||||
|
||||
--color-white: #FFF;
|
||||
--color-off-white: #F3F6F9;
|
||||
|
||||
|
40
bigbluebutton-html5/imports/utils/dom-utils.js
Normal file
40
bigbluebutton-html5/imports/utils/dom-utils.js
Normal file
@ -0,0 +1,40 @@
|
||||
|
||||
const TITLE_WITH_VIEW = 3;
|
||||
const ARIA_ALERT_TIMEOUT = 3000;
|
||||
|
||||
const getTitleData = () => {
|
||||
const title = document.getElementsByTagName('title')[0];
|
||||
return { title, data: title?.text?.split(' - ') };
|
||||
}
|
||||
|
||||
export const registerTitleView = (v) => {
|
||||
const { title, data } = getTitleData();
|
||||
if (data.length < TITLE_WITH_VIEW) data.push(`${v}`);
|
||||
else data.splice(TITLE_WITH_VIEW - 1, TITLE_WITH_VIEW, v);
|
||||
title.text = data.join(' - ');
|
||||
};
|
||||
|
||||
export const unregisterTitleView = () => {
|
||||
const { title, data } = getTitleData();
|
||||
if (data.length === TITLE_WITH_VIEW) {
|
||||
data.splice(TITLE_WITH_VIEW - 1, TITLE_WITH_VIEW, 'Default');
|
||||
}
|
||||
title.text = data.join(' - ');
|
||||
};
|
||||
|
||||
export const alertScreenReader = (s = '') => {
|
||||
const app = document.getElementById('app');
|
||||
const ariaAlert = document.createElement("div");
|
||||
ariaAlert.setAttribute("id", "aria-alert");
|
||||
ariaAlert.setAttribute("role", "alert");
|
||||
ariaAlert.setAttribute("aria-hidden", false);
|
||||
ariaAlert.setAttribute("className", "sr-only");
|
||||
ariaAlert.textContent = s;
|
||||
app.appendChild(ariaAlert);
|
||||
|
||||
setTimeout(() => {
|
||||
document.getElementById('aria-alert').remove();
|
||||
}, ARIA_ALERT_TIMEOUT);
|
||||
};
|
||||
|
||||
export default { registerTitleView, unregisterTitleView, alertScreenReader };
|
@ -25,6 +25,8 @@
|
||||
"app.chat.multi.typing": "Multiple users are typing",
|
||||
"app.chat.one.typing": "{0} is typing",
|
||||
"app.chat.two.typing": "{0} and {1} are typing",
|
||||
"app.chat.copySuccess": "Copied chat transcript",
|
||||
"app.chat.copyErr": "Copy chat transcript failed",
|
||||
"app.captions.label": "Captions",
|
||||
"app.captions.menu.close": "Close",
|
||||
"app.captions.menu.start": "Start",
|
||||
@ -51,6 +53,7 @@
|
||||
"app.captions.pad.dictationOffDesc": "Turns speech recognition off",
|
||||
"app.captions.pad.speechRecognitionStop": "Speech recognition stopped due to the browser incompatibility or some time of silence",
|
||||
"app.textInput.sendLabel": "Send",
|
||||
"app.title.defaultViewLabel": "Default presentation view",
|
||||
"app.note.title": "Shared Notes",
|
||||
"app.note.label": "Note",
|
||||
"app.note.hideNoteLabel": "Hide note",
|
||||
@ -230,6 +233,7 @@
|
||||
"app.presentationUploder.itemPlural" : "items",
|
||||
"app.presentationUploder.clearErrors": "Clear errors",
|
||||
"app.presentationUploder.clearErrorsDesc": "Clears failed presentation uploads",
|
||||
"app.presentationUploder.uploadViewTitle": "Upload Presentation",
|
||||
"app.poll.pollPaneTitle": "Polling",
|
||||
"app.poll.quickPollTitle": "Quick Poll",
|
||||
"app.poll.hidePollDesc": "Hides the poll menu pane",
|
||||
@ -288,6 +292,8 @@
|
||||
"app.poll.liveResult.usersTitle": "Users",
|
||||
"app.poll.liveResult.responsesTitle": "Response",
|
||||
"app.poll.liveResult.secretLabel": "This is an anonymous poll. Individual responses are not shown.",
|
||||
"app.poll.removePollOpt": "Removed Poll option {0}",
|
||||
"app.poll.emptyPollOpt": "Blank",
|
||||
"app.polling.pollingTitle": "Polling options",
|
||||
"app.polling.pollQuestionTitle": "Polling Question",
|
||||
"app.polling.submitLabel": "Submit",
|
||||
@ -662,6 +668,7 @@
|
||||
"app.guest-policy.button.askModerator": "Ask moderator",
|
||||
"app.guest-policy.button.alwaysAccept": "Always accept",
|
||||
"app.guest-policy.button.alwaysDeny": "Always deny",
|
||||
"app.guest-policy.policyBtnDesc": "Sets meeting guest policy",
|
||||
"app.connection-status.ariaTitle": "Connection status modal",
|
||||
"app.connection-status.title": "Connection status",
|
||||
"app.connection-status.description": "View users' connection status",
|
||||
|
@ -7,11 +7,11 @@ class Audio extends Page {
|
||||
}
|
||||
|
||||
async test() {
|
||||
return await util.joinAudio(this);
|
||||
return util.joinAudio(this);
|
||||
}
|
||||
|
||||
async microphone() {
|
||||
return await util.joinMicrophone(this);
|
||||
return util.joinMicrophone(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,26 +1,27 @@
|
||||
const ae = require('./elements');
|
||||
const { clickElement, getElementLength } = require('../core/util');
|
||||
const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
|
||||
|
||||
async function joinAudio(test) {
|
||||
await test.waitForSelector(ae.joinAudio, ELEMENT_WAIT_TIME);
|
||||
await test.page.evaluate(clickTestElement, ae.joinAudio);
|
||||
await test.page.evaluate(clickElement, ae.joinAudio);
|
||||
await test.waitForSelector(ae.listen, ELEMENT_WAIT_TIME);
|
||||
await test.page.evaluate(clickTestElement, ae.listen);
|
||||
await test.page.evaluate(clickElement, ae.listen);
|
||||
await test.waitForSelector(ae.connectingStatus, ELEMENT_WAIT_TIME);
|
||||
await test.waitForElementHandleToBeRemoved(ae.connectingStatus, ELEMENT_WAIT_LONGER_TIME);
|
||||
const parsedSettings = await test.getSettingsYaml();
|
||||
const listenOnlyCallTimeout = parseInt(parsedSettings.public.media.listenOnlyCallTimeout);
|
||||
await test.waitForSelector(ae.leaveAudio, listenOnlyCallTimeout);
|
||||
await test.waitForSelector(ae.whiteboard, ELEMENT_WAIT_TIME);
|
||||
const resp = await test.page.evaluate(getTestElement, ae.leaveAudio);
|
||||
const resp = await test.page.evaluate(getElementLength, ae.leaveAudio) >= 1;
|
||||
return resp;
|
||||
}
|
||||
|
||||
async function joinMicrophone(test) {
|
||||
await test.waitForSelector(ae.joinAudio, ELEMENT_WAIT_TIME);
|
||||
await test.page.evaluate(clickTestElement, ae.joinAudio);
|
||||
await test.page.evaluate(clickElement, ae.joinAudio);
|
||||
await test.waitForSelector(ae.microphone, ELEMENT_WAIT_TIME);
|
||||
await test.page.evaluate(clickTestElement, ae.microphone);
|
||||
await test.page.evaluate(clickElement, ae.microphone);
|
||||
await test.waitForSelector(ae.connectingStatus, ELEMENT_WAIT_TIME);
|
||||
await test.waitForElementHandleToBeRemoved(ae.connectingStatus, ELEMENT_WAIT_LONGER_TIME);
|
||||
const parsedSettings = await test.getSettingsYaml();
|
||||
@ -28,17 +29,9 @@ async function joinMicrophone(test) {
|
||||
await test.waitForSelector(ae.audioAudible, listenOnlyCallTimeout);
|
||||
await test.click(ae.audioAudible, true);
|
||||
await test.waitForSelector(ae.whiteboard, ELEMENT_WAIT_TIME);
|
||||
const resp = await test.page.evaluate(getTestElement, ae.audioAudible);
|
||||
const resp = await test.page.evaluate(getElementLength, ae.audioAudible) >= 1;
|
||||
return resp;
|
||||
}
|
||||
|
||||
async function clickTestElement(element) {
|
||||
document.querySelectorAll(element)[0].click();
|
||||
}
|
||||
|
||||
async function getTestElement(element) {
|
||||
return document.querySelectorAll(element).length >= 1 === true;
|
||||
}
|
||||
|
||||
exports.joinAudio = joinAudio;
|
||||
exports.joinMicrophone = joinMicrophone;
|
||||
|
@ -2,14 +2,13 @@ const moment = require('moment');
|
||||
const path = require('path');
|
||||
const Page = require('../core/page');
|
||||
const params = require('../params');
|
||||
const util = require('./util');
|
||||
const be = require('./elements'); // breakout elements
|
||||
const we = require('../webcam/elements'); // webcam elements
|
||||
const ae = require('../audio/elements'); // audio elements
|
||||
const ue = require('../user/elements'); // user elements
|
||||
const ce = require('../customparameters/elements'); // customparameters elements
|
||||
const e = require('../core/elements'); // page base elements
|
||||
// core constants (Timeouts vars imported)
|
||||
const { checkElement, clickElement } = require('../core/util');
|
||||
const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
|
||||
|
||||
const today = moment().format('DD-MM-YYYY');
|
||||
@ -48,7 +47,7 @@ class Create {
|
||||
await this.page1.click(ue.askModerator, true);
|
||||
await this.page1.screenshot(`${testName}`, `05-clicked-askModerator-[${this.page1.meetingId}]`);
|
||||
await this.initViewer(testName);
|
||||
const responseLoggedIn = await this.page1.page.evaluate(util.getTestElement, ue.waitingUsersBtn);
|
||||
const responseLoggedIn = await this.page1.page.evaluate(checkElement, ue.waitingUsersBtn);
|
||||
await this.page1.screenshot(`${testName}`, `06-after-viewer-acceptance-[${this.page1.meetingId}]`);
|
||||
return responseLoggedIn;
|
||||
} catch (err) {
|
||||
@ -74,7 +73,7 @@ class Create {
|
||||
await this.page1.screenshot(`${testName}`, `05-clicked-alwaysAccept-[${this.page1.meetingId}]`);
|
||||
await this.initViewer(testName);
|
||||
await this.page3.closeAudioModal();
|
||||
const responseLoggedIn = await this.page3.page.evaluate(util.getTestElement, e.whiteboard);
|
||||
const responseLoggedIn = await this.page3.page.evaluate(checkElement, e.whiteboard);
|
||||
await this.page3.screenshot(`${testName}`, `06-after-viewer-connection-[${this.page1.meetingId}]`);
|
||||
return responseLoggedIn;
|
||||
} catch (err) {
|
||||
@ -99,7 +98,7 @@ class Create {
|
||||
await this.page1.click(ue.alwaysAccept, true);
|
||||
await this.page1.screenshot(`${testName}`, `05-clicked-alwaysAccept-[${this.page1.meetingId}]`);
|
||||
await this.initViewer(testName);
|
||||
const responseLoggedIn = await this.page3.page.evaluate(util.getTestElement, ue.joinMeetingDemoPage);
|
||||
const responseLoggedIn = await this.page3.page.evaluate(checkElement, ue.joinMeetingDemoPage);
|
||||
await this.page3.screenshot(`${testName}`, `06-after-viewer-gets-denied-[${this.page1.meetingId}]`);
|
||||
return responseLoggedIn;
|
||||
} catch (err) {
|
||||
@ -116,20 +115,20 @@ class Create {
|
||||
await this.page1.screenshot(`${testName}`, `01-page01-initialized-${testName}`);
|
||||
await this.page2.screenshot(`${testName}`, `01-page02-initialized-${testName}`);
|
||||
|
||||
await this.page1.page.evaluate(util.clickTestElement, be.manageUsers);
|
||||
await this.page1.page.evaluate(util.clickTestElement, be.createBreakoutRooms);
|
||||
await this.page1.page.evaluate(clickElement, be.manageUsers);
|
||||
await this.page1.page.evaluate(clickElement, be.createBreakoutRooms);
|
||||
await this.page1.screenshot(`${testName}`, `02-page01-creating-breakoutrooms-${testName}`);
|
||||
|
||||
await this.page1.waitForSelector(be.randomlyAssign, ELEMENT_WAIT_TIME);
|
||||
await this.page1.page.evaluate(util.clickTestElement, be.randomlyAssign);
|
||||
await this.page1.page.evaluate(clickElement, be.randomlyAssign);
|
||||
await this.page1.screenshot(`${testName}`, `03-page01-randomly-assign-user-${testName}`);
|
||||
|
||||
await this.page1.waitForSelector(be.modalConfirmButton, ELEMENT_WAIT_LONGER_TIME);
|
||||
await this.page1.page.evaluate(util.clickTestElement, be.modalConfirmButton);
|
||||
await this.page1.page.evaluate(clickElement, be.modalConfirmButton);
|
||||
await this.page1.screenshot(`${testName}`, `04-page01-confirm-breakoutrooms-creation-${testName}`);
|
||||
|
||||
await this.page2.waitForSelector(be.modalConfirmButton, ELEMENT_WAIT_LONGER_TIME);
|
||||
await this.page2.page.evaluate(util.clickTestElement, be.modalConfirmButton);
|
||||
await this.page2.page.evaluate(clickElement, be.modalConfirmButton);
|
||||
await this.page2.screenshot(`${testName}`, `02-page02-accept-invite-breakoutrooms-${testName}`);
|
||||
|
||||
await this.page2.page.bringToFront();
|
||||
@ -157,7 +156,7 @@ class Create {
|
||||
// Check if Breakoutrooms have been created
|
||||
async testCreatedBreakout(testName) {
|
||||
try {
|
||||
const resp = await this.page1.page.evaluate(() => document.querySelectorAll('div[data-test="breakoutRoomsItem"]').length !== 0);
|
||||
const resp = await this.page1.page.evaluate(checkElement, be.breakoutRoomsItem);
|
||||
if (resp === true) {
|
||||
await this.page1.screenshot(`${testName}`, `05-page01-success-${testName}`);
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
const path = require('path');
|
||||
const moment = require('moment');
|
||||
const Page = require('../core/page');
|
||||
const Create = require('./create');
|
||||
const util = require('./util');
|
||||
const utilScreenShare = require('../screenshare/util');
|
||||
const e = require('./elements');
|
||||
const pe = require('../core/elements');
|
||||
const we = require('../webcam/elements');
|
||||
const ae = require('../audio/elements');
|
||||
const { checkElement } = require('../core/util');
|
||||
const { ELEMENT_WAIT_TIME, VIDEO_LOADING_WAIT_TIME } = require('../core/constants'); // core constants (Timeouts vars imported)
|
||||
|
||||
const today = moment().format('DD-MM-YYYY');
|
||||
@ -41,7 +40,7 @@ class Join extends Create {
|
||||
}
|
||||
await this.page3.logger('before pages check');
|
||||
|
||||
const resp = await page2[2].evaluate(util.getTestElement, pe.isTalking);
|
||||
const resp = await page2[2].evaluate(checkElement, pe.isTalking);
|
||||
|
||||
if (process.env.GENERATE_EVIDENCES === 'true') {
|
||||
await page2[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/06-breakout-page02-user-joined-with-audio-after-check-${testName}.png`) });
|
||||
@ -58,7 +57,7 @@ class Join extends Create {
|
||||
}
|
||||
await this.page3.logger('before pages check');
|
||||
|
||||
const resp = await page2[2].evaluate(util.getTestElement, we.videoContainer);
|
||||
const resp = await page2[2].evaluate(checkElement, we.videoContainer);
|
||||
|
||||
if (process.env.GENERATE_EVIDENCES === 'true') {
|
||||
await page2[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/06-breakout-page02-user-joined-webcam-before-check-${testName}.png`) });
|
||||
@ -80,7 +79,7 @@ class Join extends Create {
|
||||
await page2[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/06-breakout-page02-user-joined-screenshare-after-check-${testName}.png`) });
|
||||
}
|
||||
|
||||
await this.page3.logger('after pages check');
|
||||
this.page2.logger('after pages check');
|
||||
return resp === true;
|
||||
} else {
|
||||
await this.page3.page.bringToFront();
|
||||
@ -88,7 +87,8 @@ class Join extends Create {
|
||||
await this.page3.waitForSelector(e.chatButton, ELEMENT_WAIT_TIME);
|
||||
await this.page3.click(e.chatButton, true);
|
||||
await this.page3.click(e.breakoutRoomsItem, true);
|
||||
const resp = await this.page3.page.evaluate(async () => await document.querySelectorAll('span[class^="alreadyConnected--"]') !== null);
|
||||
const resp = await this.page3.page.evaluate(checkElement, e.alreadyConnected);
|
||||
|
||||
return resp === true;
|
||||
}
|
||||
} catch (err) {
|
||||
|
@ -1,5 +1,4 @@
|
||||
const e = require('./elements');
|
||||
const pe = require('../core/elements');
|
||||
const { ELEMENT_WAIT_TIME } = require('../core/constants'); // core constants (Timeouts vars imported)
|
||||
|
||||
async function createBreakoutRooms(page1, page2) {
|
||||
@ -13,14 +12,4 @@ async function createBreakoutRooms(page1, page2) {
|
||||
await page2.click(e.modalConfirmButton, true);
|
||||
}
|
||||
|
||||
async function getTestElement(element) {
|
||||
return document.querySelectorAll(element)[0] !== null;
|
||||
}
|
||||
|
||||
async function clickTestElement(element) {
|
||||
await document.querySelectorAll(element)[0].click();
|
||||
}
|
||||
|
||||
exports.getTestElement = getTestElement;
|
||||
exports.createBreakoutRooms = createBreakoutRooms;
|
||||
exports.clickTestElement = clickTestElement;
|
||||
|
@ -3,7 +3,7 @@
|
||||
const Page = require('../core/page');
|
||||
const e = require('./elements');
|
||||
const util = require('./util');
|
||||
const { chatPushAlerts } = require('../notifications/elements');
|
||||
const { checkElementLengthEqualTo } = require('../core/util');
|
||||
const { ELEMENT_WAIT_TIME } = require('../core/constants');
|
||||
|
||||
class Clear extends Page {
|
||||
@ -23,7 +23,7 @@ class Clear extends Page {
|
||||
await this.screenshot(`${testName}`, `02-after-chat-message-send-[${this.meetingId}]`);
|
||||
|
||||
|
||||
const chat0 = await this.page.evaluate(() => document.querySelectorAll('p[data-test="chatClearMessageText"]').length === 0);
|
||||
const chat0 = await this.page.evaluate(checkElementLengthEqualTo, e.chatClearMessageText, 0);
|
||||
|
||||
// clear
|
||||
await this.click(e.chatOptions, true);
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Test: Sending a chat message
|
||||
|
||||
const Notifications = require('../notifications/notifications');
|
||||
const Page = require('../core/page');
|
||||
const e = require('./elements');
|
||||
const { checkElementLengthEqualTo } = require('../core/util');
|
||||
const { ELEMENT_WAIT_TIME } = require('../core/constants');
|
||||
|
||||
class Poll extends Notifications {
|
||||
@ -13,7 +13,7 @@ class Poll extends Notifications {
|
||||
async test(testName) {
|
||||
try {
|
||||
// 0 messages
|
||||
const chat0 = await this.page3.page.evaluate(() => document.querySelectorAll('p[data-test="chatPollMessageText"]').length === 0);
|
||||
const chat0 = await this.page3.page.evaluate(checkElementLengthEqualTo, e.chatPollMessageText, 0);
|
||||
await this.page3.screenshot(`${testName}`, `01-before-chat-message-send-[${this.page3.meetingId}]`);
|
||||
|
||||
await this.publishPollResults(testName);
|
||||
@ -23,7 +23,7 @@ class Poll extends Notifications {
|
||||
await this.page3.waitForSelector(e.chatPollMessageText, ELEMENT_WAIT_TIME);
|
||||
|
||||
// 1 message
|
||||
const chat1 = await this.page3.page.evaluate(() => document.querySelectorAll('p[data-test="chatPollMessageText"]').length === 1);
|
||||
const chat1 = await this.page3.page.evaluate(checkElementLengthEqualTo, e.chatPollMessageText, 1);
|
||||
return chat0 === chat1;
|
||||
} catch (err) {
|
||||
await this.page3.logger(err);
|
||||
|
@ -3,6 +3,7 @@
|
||||
const Page = require('../core/page');
|
||||
const e = require('./elements');
|
||||
const util = require('./util');
|
||||
const { checkElementLengthEqualTo } = require('../core/util');
|
||||
|
||||
class Send extends Page {
|
||||
constructor() {
|
||||
@ -14,7 +15,7 @@ class Send extends Page {
|
||||
await util.openChat(this);
|
||||
|
||||
// 0 messages
|
||||
const chat0 = await this.page.evaluate((chatSelector) => document.querySelectorAll(chatSelector).length === 0, e.chatUserMessageText);
|
||||
const chat0 = await this.page.evaluate(checkElementLengthEqualTo, e.chatUserMessageText, 0);
|
||||
await this.screenshot(`${testName}`, `01-before-chat-message-send-[${this.meetingId}]`);
|
||||
|
||||
// send a message
|
||||
@ -27,7 +28,7 @@ class Send extends Page {
|
||||
await this.waitForSelector(e.chatUserMessageText);
|
||||
|
||||
// 1 message
|
||||
const chat1 = await this.page.evaluate((chatSelector) => document.querySelectorAll(chatSelector).length === 1, e.chatUserMessageText);
|
||||
const chat1 = await this.page.evaluate(checkElementLengthEqualTo, e.chatUserMessageText, 1);
|
||||
return chat0 === chat1;
|
||||
} catch (err) {
|
||||
await this.logger(err);
|
||||
|
@ -1,5 +1,6 @@
|
||||
const e = require('./elements');
|
||||
const ule = require('../user/elements');
|
||||
const { clickElement } = require('../core/util');
|
||||
const { ELEMENT_WAIT_TIME } = require('../core/constants');
|
||||
|
||||
async function openChat(test) {
|
||||
@ -20,12 +21,12 @@ async function sendPublicChatMessage(page1, page2) {
|
||||
async function openPrivateChatMessage(page1, page2) {
|
||||
// Open private Chat with the other User
|
||||
Object.values(arguments).forEach(async argument => await argument.waitForSelector(ule.userListItem, ELEMENT_WAIT_TIME));
|
||||
await page1.page.evaluate(clickOnTheOtherUser, ule.userListItem);
|
||||
await page2.page.evaluate(clickOnTheOtherUser, ule.userListItem);
|
||||
await page1.page.evaluate(clickElement, ule.userListItem);
|
||||
await page2.page.evaluate(clickElement, ule.userListItem);
|
||||
await page1.page.waitForSelector(e.activeChat, ELEMENT_WAIT_TIME);
|
||||
await page1.page.evaluate(clickThePrivateChatButton, e.activeChat);
|
||||
await page1.page.evaluate(clickElement, e.activeChat);
|
||||
await page2.page.waitForSelector(e.activeChat, ELEMENT_WAIT_TIME);
|
||||
await page2.page.evaluate(clickThePrivateChatButton, e.activeChat);
|
||||
await page2.page.evaluate(clickElement, e.activeChat);
|
||||
}
|
||||
|
||||
async function sendPrivateChatMessage(page1, page2) {
|
||||
@ -41,14 +42,6 @@ async function sendPrivateChatMessage(page1, page2) {
|
||||
await page2.page.screenshot(true);
|
||||
}
|
||||
|
||||
async function clickOnTheOtherUser(element) {
|
||||
await document.querySelectorAll(element)[0].click();
|
||||
}
|
||||
|
||||
async function clickThePrivateChatButton(element) {
|
||||
await document.querySelectorAll(element)[0].click();
|
||||
}
|
||||
|
||||
async function checkForPublicMessageReception(page1, page2) {
|
||||
const publicChat1 = await page1.page.$$(`${e.chatUserMessage} ${e.chatMessageText}`);
|
||||
const publicChat2 = await page2.page.$$(`${e.chatUserMessage} ${e.chatMessageText}`);
|
||||
|
@ -6,18 +6,18 @@ exports.echoYes = 'button[aria-label="Echo is audible"]';
|
||||
exports.title = '._imports_ui_components_nav_bar__styles__presentationTitle';
|
||||
exports.alerts = '.toastify-content';
|
||||
exports.presenterClassName = 'presenter--';
|
||||
exports.zoomIn = 'button[aria-label="Zoom in"]';
|
||||
exports.pdfFileName = '100PagesFile';
|
||||
|
||||
exports.isTalking = '[data-test="isTalking"]';
|
||||
exports.wasTalking = '[data-test="wasTalking"]';
|
||||
exports.joinAudio = 'button[data-test="joinAudio"]';
|
||||
exports.leaveAudio = 'button[aria-label="Leave audio"]';
|
||||
exports.leaveAudio = 'button[data-test="leaveAudio"]';
|
||||
exports.disconnectAudio = 'li[data-test="disconnectAudio"]';
|
||||
|
||||
exports.actions = 'button[aria-label="Actions"]';
|
||||
exports.options = 'button[aria-label="Options"]';
|
||||
exports.userList = 'button[aria-label="Users and Messages Toggle"]';
|
||||
exports.joinAudio = 'button[aria-label="Join Audio"]';
|
||||
exports.connectingStatus = 'div[class^="connecting--"]';
|
||||
exports.videoMenu = 'button[aria-label="Open video menu dropdown"]';
|
||||
exports.screenShare = 'button[aria-label="Share your screen"]';
|
||||
@ -28,5 +28,5 @@ exports.logout = 'li[data-test="logout"]';
|
||||
exports.meetingEndedModal = 'div[data-test="meetingEndedModal"]';
|
||||
exports.rating = 'div[data-test="rating"]';
|
||||
exports.whiteboard = 'svg[data-test="whiteboard"]';
|
||||
exports.pollMenuButton = 'button[data-test="pollMenuButton"]';
|
||||
exports.pollMenuButton = 'div[data-test="pollMenuButton"]';
|
||||
exports.unauthorized = 'h1[data-test="unauthorized"]';
|
||||
|
@ -9,6 +9,7 @@ const PuppeteerVideoRecorder = require('puppeteer-video-recorder');
|
||||
const helper = require('./helper');
|
||||
const params = require('../params');
|
||||
const { ELEMENT_WAIT_TIME } = require('./constants');
|
||||
const { getElementLength } = require('./util');
|
||||
const e = require('./elements');
|
||||
const ue = require('../user/elements');
|
||||
const { NETWORK_PRESETS } = require('./profiles');
|
||||
@ -169,7 +170,7 @@ class Page {
|
||||
}
|
||||
|
||||
async returnElement(element) {
|
||||
return await document.querySelectorAll(element)[0];
|
||||
return document.querySelectorAll(element)[0];
|
||||
}
|
||||
|
||||
async getUserAgent(test) {
|
||||
@ -410,7 +411,7 @@ class Page {
|
||||
const users = collection.default._collection.find({}, {}, {}, {}, {}, { loggedOut: 'false' }).count();
|
||||
return users;
|
||||
});
|
||||
const totalNumberOfUsersDom = await this.page.evaluate(async () => await document.querySelectorAll('[data-test^="userListItem"]').length);
|
||||
const totalNumberOfUsersDom = await this.page.evaluate(getElementLength, '[data-test^="userListItem"]');
|
||||
await this.logger({ totalNumberOfUsersDom, totalNumberOfUsersMongo });
|
||||
const metric = await this.page.metrics();
|
||||
pageMetricsObj.totalNumberOfUsersMongoObj = totalNumberOfUsersMongo;
|
||||
|
44
bigbluebutton-tests/puppeteer/core/util.js
Normal file
44
bigbluebutton-tests/puppeteer/core/util.js
Normal file
@ -0,0 +1,44 @@
|
||||
// Common
|
||||
function checkElement(element, index = 0) {
|
||||
return document.querySelectorAll(element)[index] !== undefined;
|
||||
}
|
||||
|
||||
function clickElement(element, index = 0) {
|
||||
document.querySelectorAll(element)[index].click();
|
||||
}
|
||||
|
||||
// Text
|
||||
function checkElementText(element, param, index = 0) {
|
||||
return document.querySelectorAll(element)[index].innerText === param;
|
||||
}
|
||||
|
||||
function checkElementTextIncludes(element, param, index = 0) {
|
||||
return document.querySelectorAll(element)[index].innerText.includes(param);
|
||||
}
|
||||
|
||||
function getElementText(element, index = 0) {
|
||||
return document.querySelectorAll(element)[index].innerText;
|
||||
}
|
||||
|
||||
// Length
|
||||
function checkElementLengthEqualTo(element, param) {
|
||||
return document.querySelectorAll(element).length === param;
|
||||
}
|
||||
|
||||
function checkElementLengthDifferentTo(element, param) {
|
||||
return document.querySelectorAll(element).length !== param;
|
||||
}
|
||||
|
||||
// use this for other operations
|
||||
function getElementLength(element) {
|
||||
return document.querySelectorAll(element).length;
|
||||
}
|
||||
|
||||
exports.checkElement = checkElement;
|
||||
exports.clickElement = clickElement;
|
||||
exports.checkElementText = checkElementText;
|
||||
exports.checkElementTextIncludes = checkElementTextIncludes;
|
||||
exports.getElementText = getElementText;
|
||||
exports.checkElementLengthEqualTo = checkElementLengthEqualTo;
|
||||
exports.checkElementLengthDifferentTo = checkElementLengthDifferentTo;
|
||||
exports.getElementLength = getElementLength;
|
@ -1,4 +1,3 @@
|
||||
const path = require('path');
|
||||
const Page = require('../core/page');
|
||||
const params = require('../params');
|
||||
const ne = require('../notifications/elements');
|
||||
@ -6,9 +5,11 @@ const pe = require('../core/elements');
|
||||
const cpe = require('./elements');
|
||||
const we = require('../webcam/elements');
|
||||
const ae = require('../audio/elements');
|
||||
const ce = require('../chat/elements');
|
||||
const util = require('./util');
|
||||
const c = require('./constants');
|
||||
const { ELEMENT_WAIT_TIME, VIDEO_LOADING_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants'); // core constants (Timeouts vars imported)
|
||||
const { checkElementLengthEqualTo, checkElementLengthDifferentTo } = require('../core/util');
|
||||
|
||||
class CustomParameters {
|
||||
constructor() {
|
||||
@ -30,12 +31,13 @@ class CustomParameters {
|
||||
await this.page1.startRecording(testName);
|
||||
await this.page1.screenshot(`${testName}`, `01-${testName}`);
|
||||
await this.page1.waitForSelector('div[data-test="chatMessages"]', ELEMENT_WAIT_TIME);
|
||||
if (await this.page1.page.evaluate(util.getTestElement, cpe.audioModal) === false) {
|
||||
await this.page1.waitForSelector(ce.chatMessages, ELEMENT_WAIT_TIME);
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, cpe.audioModal, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `02-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.getTestElement, cpe.audioModal) === true;
|
||||
await this.page1.screenshot(`${testName}`, `02-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -46,26 +48,22 @@ class CustomParameters {
|
||||
await this.page1.startRecording(testName);
|
||||
await this.page1.waitForSelector(pe.audioDialog, ELEMENT_WAIT_TIME);
|
||||
await this.page1.screenshot(`${testName}`, `01-page1-${testName}`);
|
||||
const audioOptionsButton = await this.page1.page.evaluate(async () => {
|
||||
const countFoundElements = await document.querySelectorAll('[class^="audioOptions"] > button').length;
|
||||
return countFoundElements;
|
||||
});
|
||||
if (audioOptionsButton === 1) {
|
||||
await this.page1.screenshot(`${testName}`, `04-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return true;
|
||||
} if (audioOptionsButton !== 1) {
|
||||
const audioOptionsButton = await this.page1.page.evaluate(checkElementLengthEqualTo, cpe.audioOptionsButtons, 1);
|
||||
if (!audioOptionsButton) {
|
||||
await this.page1.screenshot(`${testName}`, `04-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
await this.page1.screenshot(`${testName}`, `04-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return true;
|
||||
}
|
||||
|
||||
async forceListenOnly(testName, args, meetingId, customParameter) {
|
||||
await this.page2.init(args, meetingId, { ...params, fullName: 'Attendee', moderatorPW: '' }, customParameter, testName);
|
||||
await this.page2.startRecording(testName);
|
||||
await this.page2.screenshot(`${testName}`, `01-${testName}`);
|
||||
if (await this.page2.page.$('[data-test="audioModalHeader"]')) {
|
||||
if (await this.page2.page.$(cpe.audioModalHeader)) {
|
||||
await this.page2.screenshot(`${testName}`, `02-fail-${testName}`);
|
||||
this.page2.logger(testName, ' failed');
|
||||
return false;
|
||||
@ -87,32 +85,30 @@ class CustomParameters {
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
await this.page1.waitForElementHandleToBeRemoved(ae.connectingStatus, ELEMENT_WAIT_LONGER_TIME);
|
||||
await this.page1.screenshot(`${testName}`, `03-${testName}`);
|
||||
if (await this.page1.page.evaluate(util.countTestElements, cpe.echoTestYesButton) === true) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, cpe.echoTestYesButton, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `04-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.countTestElements, cpe.echoTestYesButton) === false;
|
||||
await this.page1.screenshot(`${testName}`, `04-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
}
|
||||
|
||||
async skipCheckOnFirstJoin(testName, args, meetingId, customParameter) {
|
||||
const parsedSettings = await this.page1.getSettingsYaml();
|
||||
const listenOnlyCallTimeout = parseInt(parsedSettings.public.media.listenOnlyCallTimeout);
|
||||
await this.page1.init(args, meetingId, { ...params, fullName: 'Moderator' }, customParameter, testName);
|
||||
await this.page1.startRecording(testName);
|
||||
await this.page1.screenshot(`${testName}`, `01-${testName}`);
|
||||
await this.page1.click(ae.microphone, true);
|
||||
const firstCheck = await this.page1.page.evaluate(util.getTestElement, ae.connecting) === false;
|
||||
const firstCheck = await this.page1.page.evaluate(checkElementLengthDifferentTo, ae.connecting, 0);
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
await this.page1.leaveAudio();
|
||||
await this.page1.screenshot(`${testName}`, `03-${testName}`);
|
||||
await this.page1.waitForSelector(pe.joinAudio, ELEMENT_WAIT_TIME);
|
||||
await this.page1.click(pe.joinAudio, true);
|
||||
await this.page1.click(ae.microphone, true);
|
||||
const secondCheck = await this.page1.page.evaluate(util.getTestElement, ae.connectingToEchoTest) === false;
|
||||
const secondCheck = await this.page1.page.evaluate(checkElementLengthDifferentTo, ae.connectingToEchoTest, 0);
|
||||
|
||||
if (firstCheck !== secondCheck) {
|
||||
await this.page1.screenshot(`${testName}`, `04-fail-${testName}`);
|
||||
@ -130,12 +126,12 @@ class CustomParameters {
|
||||
await this.page1.screenshot(`${testName}`, `01-${testName}`);
|
||||
await this.page1.waitForSelector(pe.whiteboard, ELEMENT_WAIT_TIME);
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
if (await !(await this.page1.page.title()).includes(c.docTitle)) {
|
||||
const resp = await (await this.page1.page.title()).includes(c.docTitle);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await (await this.page1.page.title()).includes(c.docTitle);
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -152,12 +148,12 @@ class CustomParameters {
|
||||
await this.page1.waitForSelector(cpe.meetingEndedModal, ELEMENT_WAIT_TIME);
|
||||
await this.page1.screenshot(`${testName}`, `04-${testName}`);
|
||||
this.page1.logger('audio modal closed');
|
||||
if (await this.page1.page.evaluate(util.countTestElements, cpe.rating) === false) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthDifferentTo, cpe.rating, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `05-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.countTestElements, cpe.rating) === true;
|
||||
await this.page1.screenshot(`${testName}`, `05-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -171,12 +167,12 @@ class CustomParameters {
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
this.page1.logger('audio modal closed');
|
||||
await this.page1.waitForSelector(cpe.userListContent, ELEMENT_WAIT_TIME);
|
||||
if (await this.page1.page.evaluate(util.countTestElements, cpe.brandingAreaLogo) === false) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthDifferentTo, cpe.brandingAreaLogo, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.countTestElements, cpe.brandingAreaLogo) === true;
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -192,12 +188,12 @@ class CustomParameters {
|
||||
await this.page1.waitForSelector(pe.options, ELEMENT_WAIT_TIME);
|
||||
await this.page1.page.keyboard.down('Alt');
|
||||
await this.page1.page.keyboard.press('O');
|
||||
if (await this.page1.page.evaluate(util.getTestElement, cpe.verticalListOptions) === false) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, cpe.verticalListOptions, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.getTestElement, cpe.verticalListOptions) === true;
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -208,12 +204,12 @@ class CustomParameters {
|
||||
await this.page1.startRecording(testName);
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page1.screenshot(`${testName}`, `01-${testName}`);
|
||||
if (await this.page1.page.evaluate(util.getTestElement, cpe.screenShareButton) === false) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, cpe.screenShareButton, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `02-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.getTestElement, cpe.screenShareButton) === true;
|
||||
await this.page1.screenshot(`${testName}`, `02-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -224,12 +220,12 @@ class CustomParameters {
|
||||
await this.page1.startRecording(testName);
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page1.screenshot(`${testName}`, `01-${testName}`);
|
||||
if (await this.page1.page.evaluate(util.getTestElement, cpe.shareWebcamButton) === false) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, cpe.shareWebcamButton, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `02-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.getTestElement, cpe.shareWebcamButton) === true;
|
||||
await this.page1.screenshot(`${testName}`, `02-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -241,12 +237,12 @@ class CustomParameters {
|
||||
await this.page1.screenshot(`${testName}`, `01-${testName}`);
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
if (await this.page1.page.evaluate(util.getTestElement, cpe.webcamSettingsModal) === true) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, cpe.webcamSettingsModal, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.getTestElement, cpe.webcamSettingsModal) === false;
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -269,12 +265,14 @@ class CustomParameters {
|
||||
await this.page2.waitForSelector(cpe.tools, ELEMENT_WAIT_TIME);
|
||||
await this.page2.click(cpe.tools, true);
|
||||
await this.page2.screenshot(`${testName}`, `04-page2-${testName}`);
|
||||
if (await this.page2.page.evaluate(async () => await document.querySelectorAll('[aria-label="Tools"]')[0].parentElement.childElementCount === 2)) {
|
||||
const resp = await this.page2.page.evaluate((toolsElement) => {
|
||||
return document.querySelectorAll(toolsElement)[0].parentElement.childElementCount === 1;
|
||||
}, cpe.tools);
|
||||
if (!resp) {
|
||||
await this.page2.screenshot(`${testName}`, `05-page2-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page2.page.evaluate(async () => await document.querySelectorAll('[aria-label="Tools"]')[0].parentElement.childElementCount === 1);
|
||||
await this.page2.screenshot(`${testName}`, `05-page2-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -289,12 +287,14 @@ class CustomParameters {
|
||||
await this.page1.waitForSelector(cpe.tools, ELEMENT_WAIT_TIME);
|
||||
await this.page1.click(cpe.tools, true);
|
||||
await this.page1.screenshot(`${testName}`, `03-${testName}`);
|
||||
if (await this.page1.page.evaluate(async () => await document.querySelectorAll('[aria-label="Tools"]')[0].parentElement.querySelector('[class^="toolbarList--"]').childElementCount === 7)) {
|
||||
const resp = await this.page1.page.evaluate((toolsElement, toolbarListSelector) => {
|
||||
return document.querySelectorAll(toolsElement)[0].parentElement.querySelector(toolbarListSelector).childElementCount === 2;
|
||||
}, cpe.tools, cpe.toolbarListClass);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `04-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(async () => await document.querySelectorAll('[aria-label="Tools"]')[0].parentElement.querySelector('[class^="toolbarList--"]').childElementCount === 2);
|
||||
await this.page1.screenshot(`${testName}`, `04-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -317,12 +317,14 @@ class CustomParameters {
|
||||
await this.page2.waitForSelector(cpe.tools, ELEMENT_WAIT_TIME);
|
||||
await this.page2.click(cpe.tools, true);
|
||||
await this.page2.screenshot(`${testName}`, `04-page2-${testName}`);
|
||||
if (await this.page2.page.evaluate(async () => await document.querySelectorAll('[aria-label="Tools"]')[0].parentElement.querySelector('[class^="toolbarList--"]').childElementCount === 7)) {
|
||||
const resp = await this.page2.page.evaluate((toolsElement, toolbarListSelector) => {
|
||||
return document.querySelectorAll(toolsElement)[0].parentElement.querySelector(toolbarListSelector).childElementCount === 2;
|
||||
}, cpe.tools, cpe.toolbarListClass);
|
||||
if (!resp) {
|
||||
await this.page2.screenshot(`${testName}`, `05-page2-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page2.page.evaluate(async () => await document.querySelectorAll('[aria-label="Tools"]')[0].parentElement.querySelector('[class^="toolbarList--"]').childElementCount === 2);
|
||||
await this.page2.screenshot(`${testName}`, `05-page2-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -335,17 +337,16 @@ class CustomParameters {
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page1.waitForSelector(cpe.whiteboard, ELEMENT_WAIT_TIME);
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
const isHidden = await this.page1.page.$eval('[class="presentationTitle--1LT79g"]', elem => elem.offsetHeight == 0);
|
||||
if (isHidden === false) {
|
||||
const isHidden = await this.page1.page.$eval(cpe.presentationTitle, elem => elem.offsetHeight == 0);
|
||||
if (isHidden !== true) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
} if (isHidden === true) {
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
const resp = isHidden;
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
}
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
const resp = isHidden;
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
}
|
||||
|
||||
async customStyleUrl(testName, args, meetingId, customParameter) {
|
||||
@ -355,17 +356,16 @@ class CustomParameters {
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page1.waitForSelector(cpe.whiteboard, ELEMENT_WAIT_TIME);
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
const isHidden = await this.page1.page.$eval('[class="presentationTitle--1LT79g"]', elem => elem.offsetHeight == 0);
|
||||
if (isHidden === false) {
|
||||
const isHidden = await this.page1.page.$eval(cpe.presentationTitle, elem => elem.offsetHeight == 0);
|
||||
if (isHidden !== true) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
} if (isHidden === true) {
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
const resp = isHidden;
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
}
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
const resp = isHidden;
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
}
|
||||
|
||||
async autoSwapLayout(testName, args, meetingId, customParameter) {
|
||||
@ -373,19 +373,18 @@ class CustomParameters {
|
||||
await this.page1.startRecording(testName);
|
||||
await this.page1.screenshot(`${testName}`, `01-${testName}`);
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page1.waitForSelector(cpe.container, ELEMENT_WAIT_TIME);
|
||||
await this.page1.waitForSelector(pe.actions, ELEMENT_WAIT_TIME);
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
const isNotHidden = await this.page1.page.$eval(cpe.restorePresentation, elem => elem.offsetHeight !== 0);
|
||||
if (isNotHidden === false) {
|
||||
if (isNotHidden !== true) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
} if (isNotHidden === true) {
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
const resp = isNotHidden;
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
}
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
const resp = isNotHidden;
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
}
|
||||
|
||||
async hidePresentation(testName, args, meetingId, customParameter) {
|
||||
@ -395,12 +394,12 @@ class CustomParameters {
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page1.waitForSelector(cpe.actions, ELEMENT_WAIT_TIME);
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
if (await this.page1.page.evaluate(util.countTestElements, cpe.defaultContent) === false) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthDifferentTo, cpe.defaultContent, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.countTestElements, cpe.defaultContent) === true;
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -413,12 +412,12 @@ class CustomParameters {
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page1.waitForSelector(cpe.actions, ELEMENT_WAIT_TIME);
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
if (await this.page1.page.evaluate(util.countTestElements, cpe.notificationBar) === false) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthDifferentTo, cpe.notificationBar, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.countTestElements, cpe.notificationBar) === true;
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -436,11 +435,10 @@ class CustomParameters {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
} if (notificationBarColor === colorToRGB) {
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return true;
|
||||
}
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return true;
|
||||
}
|
||||
|
||||
async hideAndSwapPresentation(testName, args, meetingId, customParameter) {
|
||||
@ -448,13 +446,13 @@ class CustomParameters {
|
||||
await this.page1.startRecording(testName);
|
||||
await this.page1.screenshot(`${testName}`, `01-${testName}`);
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page1.waitForSelector(cpe.container, ELEMENT_WAIT_TIME);
|
||||
if (await this.page1.page.evaluate(util.countTestElements, cpe.restorePresentation) === false && await this.page1.page.evaluate(util.countTestElements, cpe.defaultContent) === false) {
|
||||
await this.page1.waitForSelector(pe.actions, ELEMENT_WAIT_TIME);
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthDifferentTo, cpe.restorePresentation, 0) && await this.page1.page.evaluate(checkElementLengthDifferentTo, cpe.defaultContent, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.countTestElements, cpe.restorePresentation) === true && await this.page1.page.evaluate(util.countTestElements, cpe.defaultContent) === true;
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -465,13 +463,13 @@ class CustomParameters {
|
||||
await this.page1.startRecording(testName);
|
||||
await this.page1.screenshot(`${testName}`, `01-${testName}`);
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page1.waitForSelector(cpe.container, ELEMENT_WAIT_TIME);
|
||||
if (await this.page1.page.evaluate(util.countTestElements, cpe.chat) === true) {
|
||||
await this.page1.waitForSelector(pe.actions, ELEMENT_WAIT_TIME);
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, cpe.chat, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.countTestElements, cpe.chat) === false;
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -488,7 +486,6 @@ class CustomParameters {
|
||||
await this.page1.screenshot(`${testName}`, `02-page1-${testName}`);
|
||||
await this.page2.closeAudioModal();
|
||||
await this.page2.screenshot(`${testName}`, `02-page2-${testName}`);
|
||||
await this.page1.waitForSelector(cpe.container, ELEMENT_WAIT_TIME);
|
||||
await this.page2.waitForSelector(cpe.hidePresentation, ELEMENT_WAIT_TIME);
|
||||
await this.page2.click(cpe.hidePresentation, true);
|
||||
await this.page2.screenshot(`${testName}`, `03-page2-${testName}`);
|
||||
@ -510,13 +507,15 @@ class CustomParameters {
|
||||
const annotationCase = await util.annotation(this.page1);
|
||||
await this.page1.screenshot(`${testName}`, `06-page1-${testName}`);
|
||||
await this.page2.screenshot(`${testName}`, `07-page2-${testName}`);
|
||||
if (zoomInCase === true && zoomOutCase === true && pollCase === true && previousSlideCase === true && nextSlideCase === true && annotationCase === true
|
||||
&& await this.page2.page.evaluate(util.countTestElements, cpe.restorePresentation) === true) {
|
||||
|
||||
const test = await this.page2.page.evaluate(checkElementLengthDifferentTo, cpe.restorePresentation, 0);
|
||||
const resp = (zoomInCase && zoomOutCase && pollCase && previousSlideCase && nextSlideCase && annotationCase && test);
|
||||
if (resp) {
|
||||
await this.page2.screenshot(`${testName}`, `08-page2-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
await this.page2.page.evaluate(util.countTestElements, cpe.restorePresentation) === false;
|
||||
await this.page2.page.evaluate(checkElementLengthEqualTo, cpe.restorePresentation, 0);
|
||||
await this.page2.screenshot(`${testName}`, `08-page2-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return true;
|
||||
@ -534,17 +533,17 @@ class CustomParameters {
|
||||
await this.page2.screenshot(`${testName}`, `02-page2-${testName}`);
|
||||
await this.page2.click(cpe.hidePresentation, true);
|
||||
await this.page2.screenshot(`${testName}`, `03-page2-${testName}`);
|
||||
const pollCase = await util.poll(this.page1, this.page2);
|
||||
const pollCase = await util.poll(this.page1, this.page2) === true;
|
||||
await this.page2.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
|
||||
await this.page1.screenshot(`${testName}`, `03-page1-${testName}`);
|
||||
await this.page2.screenshot(`${testName}`, `04-page2-${testName}`);
|
||||
if (pollCase === true
|
||||
&& await this.page2.page.evaluate(util.countTestElements, cpe.restorePresentation) === true) {
|
||||
|
||||
const test = await this.page2.page.evaluate(checkElementLengthDifferentTo, cpe.restorePresentation, 0);
|
||||
if (pollCase && test) {
|
||||
await this.page2.screenshot(`${testName}`, `05-page2-fail-${testName}`);
|
||||
await this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
await this.page2.page.evaluate(util.countTestElements, cpe.restorePresentation) === false;
|
||||
await this.page2.screenshot(`${testName}`, `05-page2-success-${testName}`);
|
||||
await this.page1.logger(testName, ' passed');
|
||||
return true;
|
||||
@ -555,12 +554,12 @@ class CustomParameters {
|
||||
await this.page1.startRecording(testName);
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page1.screenshot(`${testName}`, `01-${testName}`);
|
||||
if (await this.page1.page.evaluate(util.getTestElement, cpe.recordingIndicator) === false) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, cpe.recordingIndicator, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `02-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.getTestElement, cpe.recordingIndicator) === true;
|
||||
await this.page1.screenshot(`${testName}`, `02-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -574,12 +573,12 @@ class CustomParameters {
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
await this.page1.waitForSelector(cpe.shareWebcamButton, ELEMENT_WAIT_TIME);
|
||||
await this.page1.click(cpe.shareWebcamButton, true);
|
||||
if (await this.page1.page.evaluate(util.getTestElement, cpe.webcamSettingsModal) === false) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, cpe.webcamSettingsModal, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.getTestElement, cpe.webcamSettingsModal) === true;
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -593,7 +592,7 @@ class CustomParameters {
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
await this.page1.waitForSelector(we.joinVideo, ELEMENT_WAIT_TIME);
|
||||
await this.page1.click(we.joinVideo, true);
|
||||
const firstCheck = await this.page1.page.evaluate(util.getTestElement, cpe.webcamSettingsModal) === true;
|
||||
const firstCheck = await this.page1.page.evaluate(checkElementLengthEqualTo, cpe.webcamSettingsModal, 0);
|
||||
await this.page1.waitForSelector(we.leaveVideo, VIDEO_LOADING_WAIT_TIME);
|
||||
await this.page1.click(we.leaveVideo, true);
|
||||
await this.page1.waitForElementHandleToBeRemoved(we.webcamVideo), ELEMENT_WAIT_LONGER_TIME;
|
||||
@ -605,7 +604,7 @@ class CustomParameters {
|
||||
const videoPreviewTimeout = parseInt(parsedSettings.public.kurento.gUMTimeout);
|
||||
await this.page1.waitForSelector(cpe.webcamVideoPreview, videoPreviewTimeout);
|
||||
await this.page1.waitForSelector(cpe.startSharingWebcamButton, ELEMENT_WAIT_TIME);
|
||||
const secondCheck = await this.page1.page.evaluate(util.getTestElement, cpe.webcamSettingsModal) === false;
|
||||
const secondCheck = await this.page1.page.evaluate(checkElementLengthDifferentTo, cpe.webcamSettingsModal, 0);
|
||||
await this.page1.click(cpe.startSharingWebcamButton, true);
|
||||
await this.page1.waitForSelector(we.webcamConnecting, ELEMENT_WAIT_TIME);
|
||||
|
||||
@ -630,12 +629,12 @@ class CustomParameters {
|
||||
await this.page1.waitForSelector(cpe.webcamMirroredVideoPreview, ELEMENT_WAIT_TIME);
|
||||
await this.page1.waitForSelector(cpe.startSharingWebcamButton, ELEMENT_WAIT_TIME);
|
||||
await this.page1.click(cpe.startSharingWebcamButton, true);
|
||||
if (await this.page1.page.evaluate(util.getTestElement, cpe.webcamMirroredVideoContainer) === true) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthDifferentTo, cpe.webcamMirroredVideoContainer, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.getTestElement, cpe.webcamMirroredVideoContainer) === false;
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
@ -648,12 +647,12 @@ class CustomParameters {
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page1.screenshot(`${testName}`, `02-${testName}`);
|
||||
await this.page1.waitForSelector(cpe.whiteboard, ELEMENT_WAIT_TIME);
|
||||
if (await this.page1.page.evaluate(util.getTestElement, cpe.userslistContainer) === false) {
|
||||
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, cpe.userslistContainer, 0);
|
||||
if (!resp) {
|
||||
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
|
||||
this.page1.logger(testName, ' failed');
|
||||
return false;
|
||||
}
|
||||
const resp = await this.page1.page.evaluate(util.getTestElement, cpe.userslistContainer) === true;
|
||||
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
|
||||
this.page1.logger(testName, ' passed');
|
||||
return resp === true;
|
||||
|
@ -1,5 +1,7 @@
|
||||
exports.audioModal = 'div[aria-label="Join audio modal"]';
|
||||
exports.audioOverlay = 'div[class^="ReactModal__Overlay"]';
|
||||
exports.audioModalHeader = '[data-test="audioModalHeader"]';
|
||||
exports.audioOptionsButtons = '[class^="audioOptions"] > button';
|
||||
exports.whiteboard = 'svg[data-test="whiteboard"]';
|
||||
exports.echoTestYesButton = 'button[aria-label="Echo is audible"]';
|
||||
exports.echoTestNoButton = 'button[aria-label="Echo is inaudible"]';
|
||||
@ -17,11 +19,12 @@ exports.stopWebcamButton = 'button[data-test="leaveVideo"]';
|
||||
exports.webcamSettingsModal = 'div[aria-label="Webcam settings"]';
|
||||
exports.startWebcamSharingConfirm = 'button[aria-label="Start sharing"]';
|
||||
exports.multiUsersWhiteboard = 'button[aria-label="Turn multi-user whiteboard on"]';
|
||||
exports.toolbarListClass = '[class^="toolbarList--"]';
|
||||
exports.tools = 'button[aria-label="Tools"]';
|
||||
exports.actions = 'button[aria-label="Actions"]';
|
||||
exports.hidePresentation = 'button[data-test="hidePresentationButton"]';
|
||||
exports.restorePresentation = 'button[data-test="restorePresentationButton"]';
|
||||
exports.container = 'div[id="container"]';
|
||||
exports.presentationTitle = '[class^="presentationTitle--"]';
|
||||
exports.defaultContent = 'div[class^="defaultContent--"]';
|
||||
exports.notificationBar = 'div[class^="notificationsBar--"]';
|
||||
exports.chat = 'section[aria-label="Chat"]';
|
||||
|
@ -1,28 +1,31 @@
|
||||
const path = require('path');
|
||||
const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
|
||||
const ne = require('../notifications/elements');
|
||||
const pe = require('../presentation/elements');
|
||||
const ce = require('../customparameters/elements');
|
||||
const we = require('../whiteboard/elements');
|
||||
const poe = require('../polling/elemens');
|
||||
const e = require('../core/elements');
|
||||
const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
|
||||
const { checkElementLengthEqualTo, checkElementLengthDifferentTo, checkElementText } = require('../core/util');
|
||||
|
||||
async function autoJoinTest(test) {
|
||||
const resp = await test.page.evaluate(async () => {
|
||||
const rep = await document.querySelectorAll('div[aria-label="Join audio modal"]').length === 0;
|
||||
return rep !== false;
|
||||
});
|
||||
return resp;
|
||||
try {
|
||||
const resp = await test.page.evaluate(checkElementLengthEqualTo, e.audioDialog, 0);
|
||||
return resp === true;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function listenOnlyMode(test) {
|
||||
// maybe not used
|
||||
try {
|
||||
const resp = await test.page.evaluate(async () => {
|
||||
await document.querySelectorAll('div[class^="connecting--"]')[0];
|
||||
const audibleButton = await document.querySelectorAll('button[aria-label="Echo is audible"]').length !== 0;
|
||||
return audibleButton !== false;
|
||||
});
|
||||
return resp;
|
||||
const resp = await test.page.evaluate(async (connectionSelector, echoYes) => {
|
||||
await document.querySelectorAll(connectionSelector)[0];
|
||||
return document.querySelectorAll(echoYes).length !== 0;
|
||||
}, e.connectingStatus, e.echoYes);
|
||||
return resp === true;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
@ -30,40 +33,31 @@ async function listenOnlyMode(test) {
|
||||
|
||||
async function forceListenOnly(test) {
|
||||
try {
|
||||
const resp = await test.page.evaluate(async () => {
|
||||
await document.querySelectorAll('div[class^="connecting--"]')[0];
|
||||
if (await document.querySelectorAll('button[aria-label="Echo is audible"]').length > 0) {
|
||||
return false;
|
||||
}
|
||||
const audibleNotification = await document.querySelectorAll('div[class^="toastContainer--"]')[0].innerText === 'You have joined the audio conference';
|
||||
return audibleNotification !== false;
|
||||
});
|
||||
return resp;
|
||||
const checkEchoYes = await test.page.evaluate(checkElementLengthEqualTo, e.echoYes, 0);
|
||||
if (!checkEchoYes) return false;
|
||||
const resp = await test.page.evaluate(checkElementText, ce.toastContainer, 'You have joined the audio conference');
|
||||
|
||||
return resp === true;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function skipCheck(test) {
|
||||
// maybe not used
|
||||
try {
|
||||
await test.waitForSelector(ce.toastContainer, ELEMENT_WAIT_TIME);
|
||||
const resp1 = await test.page.evaluate(async () => await document.querySelectorAll('div[class^="toastContainer--"]').length !== 0);
|
||||
const resp1 = await test.page.evaluate(checkElementLengthDifferentTo, e.toastContainer, 0);
|
||||
await test.waitForSelector(ce.muteBtn, ELEMENT_WAIT_TIME);
|
||||
const resp2 = await test.page.evaluate(async () => await document.querySelectorAll('button[aria-label="Mute"]').length !== 0);
|
||||
const resp2 = await test.page.evaluate(checkElementLengthDifferentTo, ce.muteBtn, 0);
|
||||
return resp1 === true && resp2 === true;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function countTestElements(element) {
|
||||
return document.querySelectorAll(element).length !== 0;
|
||||
}
|
||||
|
||||
async function getTestElement(element) {
|
||||
return document.querySelectorAll(element).length === 0;
|
||||
}
|
||||
|
||||
function hexToRgb(hex) {
|
||||
const bigint = parseInt(hex, 16);
|
||||
const r = (bigint >> 16) & 255;
|
||||
@ -74,11 +68,11 @@ function hexToRgb(hex) {
|
||||
|
||||
async function zoomIn(test) {
|
||||
try {
|
||||
await test.page.evaluate(() => {
|
||||
await test.page.evaluate((zoomIn) => {
|
||||
setInterval(() => {
|
||||
document.querySelector('button[aria-label="Zoom in"]').scrollBy(0, 10);
|
||||
document.querySelector(zoomIn).scrollBy(0, 10);
|
||||
}, 100);
|
||||
});
|
||||
}, e.zoomIn);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
@ -88,11 +82,12 @@ async function zoomIn(test) {
|
||||
|
||||
async function zoomOut(test) {
|
||||
try {
|
||||
await test.page.evaluate(() => {
|
||||
await test.page.evaluate((zoomIn) => {
|
||||
setInterval(() => {
|
||||
document.querySelector('button[aria-label="Zoom in"]').scrollBy(10, 0);
|
||||
document.querySelector(zoomIn).scrollBy(10, 0);
|
||||
}, 100);
|
||||
}); return true;
|
||||
}, e.zoomIn);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return false;
|
||||
@ -102,7 +97,7 @@ async function zoomOut(test) {
|
||||
async function poll(page1, page2) {
|
||||
try {
|
||||
await page1.page.waitForSelector(ce.whiteboard, { visible: true, timeout: ELEMENT_WAIT_LONGER_TIME });
|
||||
await page1.page.evaluate(async () => await document.querySelectorAll('button[aria-label="Actions"]')[0].click());
|
||||
await page1.click(e.actions);
|
||||
await page1.waitForSelector(ne.polling, ELEMENT_WAIT_TIME);
|
||||
await page1.click(ne.polling, true);
|
||||
await page1.waitForSelector(ne.pollYesNoAbstentionBtn, ELEMENT_WAIT_TIME);
|
||||
@ -149,8 +144,10 @@ async function annotation(test) {
|
||||
await test.waitForSelector(we.pencil, ELEMENT_WAIT_TIME);
|
||||
await test.click(we.pencil, true);
|
||||
await test.click(ce.whiteboard, true);
|
||||
const annoted = await test.page.evaluate(async () => await document.querySelectorAll('[data-test="whiteboard"] > g > g')[1].innerHTML !== '');
|
||||
return annoted;
|
||||
const annoted = await test.page.evaluate((whiteboard) => {
|
||||
return document.querySelectorAll(`${whiteboard} > g > g`)[1].innerHTML !== '';
|
||||
}, e.whiteboard);
|
||||
return annoted === true;
|
||||
}
|
||||
|
||||
async function presetationUpload(test) {
|
||||
@ -159,7 +156,7 @@ async function presetationUpload(test) {
|
||||
await test.click(ce.actions, true);
|
||||
await test.waitForSelector(pe.uploadPresentation, ELEMENT_WAIT_TIME);
|
||||
await test.click(pe.uploadPresentation, true);
|
||||
const elementHandle = await test.page.$('input[type=file]');
|
||||
const elementHandle = await test.page.$(pe.fileUpload);
|
||||
await elementHandle.uploadFile(path.join(__dirname, `../media/${e.pdfFileName}.pdf`));
|
||||
await test.click(ce.confirmBtn, true);
|
||||
return true;
|
||||
@ -187,8 +184,6 @@ exports.nextSlide = nextSlide;
|
||||
exports.annotation = annotation;
|
||||
exports.presetationUpload = presetationUpload;
|
||||
exports.hexToRgb = hexToRgb;
|
||||
exports.getTestElement = getTestElement;
|
||||
exports.countTestElements = countTestElements;
|
||||
exports.autoJoinTest = autoJoinTest;
|
||||
exports.listenOnlyMode = listenOnlyMode;
|
||||
exports.forceListenOnly = forceListenOnly;
|
||||
|
@ -1,9 +1,9 @@
|
||||
const Page = require('../core/page');
|
||||
const e = require('../core/elements');
|
||||
const util = require('../customparameters/util');
|
||||
const { exec } = require("child_process");
|
||||
const { CLIENT_RECONNECTION_TIMEOUT } = require('../core/constants'); // core constants (Timeouts vars imported)
|
||||
const { sleep } = require('../core/helper');
|
||||
const e = require('../core/elements');
|
||||
const { checkElementLengthDifferentTo } = require('../core/util');
|
||||
|
||||
class Trigger extends Page {
|
||||
constructor() {
|
||||
@ -33,7 +33,7 @@ class Trigger extends Page {
|
||||
await sleep(3000);
|
||||
await this.screenshot(`${testName}`, `04-after-meteor-reconnection-[${this.meetingId}]`);
|
||||
|
||||
const findUnauthorized = await this.page.evaluate(util.countTestElements, e.unauthorized) === true;
|
||||
const findUnauthorized = await this.page.evaluate(checkElementLengthDifferentTo, e.unauthorized, 0) === true;
|
||||
await this.logger('Check if Unauthorized message appears => ', findUnauthorized);
|
||||
return meteorStatusConfirm && getAudioButton && findUnauthorized;
|
||||
} catch (err) {
|
||||
@ -85,12 +85,12 @@ class Trigger extends Page {
|
||||
|
||||
await this.page.reload();
|
||||
await this.closeAudioModal();
|
||||
const getAudioButton = await this.page.evaluate(() =>
|
||||
document.querySelectorAll('button[aria-label="Join audio"]')[0]
|
||||
.getAttribute('aria-disabled') === "true");
|
||||
const getAudioButton = await this.page.evaluate((joinAudioSelector) => {
|
||||
return document.querySelectorAll(joinAudioSelector)[0].getAttribute('aria-disabled') === "true";
|
||||
}, e.joinAudio)
|
||||
await this.logger('Check if Connections Buttons are disabled => ', getAudioButton);
|
||||
await sleep(3000);
|
||||
const findUnauthorized = await this.page.evaluate(util.countTestElements, e.unauthorized) === true;
|
||||
const findUnauthorized = await this.page.evaluate(checkElementLengthDifferentTo, e.unauthorized, 0) === true;
|
||||
await this.logger('Check if Unauthorized message appears => ', findUnauthorized);
|
||||
return meteorStatusConfirm && getAudioButton && findUnauthorized;
|
||||
} catch (err) {
|
||||
|
@ -12,8 +12,13 @@ class SharedNotes extends Create {
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this.page1.close();
|
||||
await this.page2.close();
|
||||
try {
|
||||
await this.page1.close();
|
||||
await this.page2.close();
|
||||
} catch (e) {
|
||||
await this.page1.logger(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = SharedNotes;
|
||||
|
@ -1,19 +1,19 @@
|
||||
const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
|
||||
const se = require('./elements');
|
||||
const { getElementLength } = require('../core/util');
|
||||
|
||||
async function startSharedNotes(test) {
|
||||
await test.waitForSelector(se.sharedNotes, ELEMENT_WAIT_TIME);
|
||||
await test.click(se.sharedNotes, true);
|
||||
await test.waitForSelector(se.hideNoteLabel, ELEMENT_WAIT_LONGER_TIME);
|
||||
const resp = await test.page.evaluate(getTestElement, se.etherpad);
|
||||
await test.waitForSelector(se.etherpad, ELEMENT_WAIT_TIME);
|
||||
return resp;
|
||||
try {
|
||||
await test.waitForSelector(se.sharedNotes, ELEMENT_WAIT_TIME);
|
||||
await test.click(se.sharedNotes, true);
|
||||
await test.waitForSelector(se.hideNoteLabel, ELEMENT_WAIT_LONGER_TIME);
|
||||
const resp = await test.page.evaluate(getElementLength, se.etherpad) >= 1;
|
||||
await test.waitForSelector(se.etherpad, ELEMENT_WAIT_TIME);
|
||||
return resp === true;
|
||||
} catch (e) {
|
||||
await test.logger(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function getTestElement(element) {
|
||||
const response = await document.querySelectorAll(element).length >= 1;
|
||||
return response;
|
||||
}
|
||||
|
||||
exports.getTestElement = getTestElement;
|
||||
exports.startSharedNotes = startSharedNotes;
|
||||
|
@ -9,6 +9,7 @@ const ne = require('./elements');
|
||||
const pe = require('../presentation/elements');
|
||||
const we = require('../whiteboard/elements');
|
||||
const { ELEMENT_WAIT_TIME, UPLOAD_PDF_WAIT_TIME } = require('../core/constants');
|
||||
const { checkElementTextIncludes } = require('../core/util');
|
||||
|
||||
class Notifications extends MultiUsers {
|
||||
constructor() {
|
||||
@ -127,8 +128,8 @@ class Notifications extends MultiUsers {
|
||||
await this.initUser4(testName);
|
||||
await this.page4.closeAudioModal();
|
||||
await this.page3.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
|
||||
await this.page3.page.waitForFunction(
|
||||
'document.querySelector("body").innerText.includes("User joined the session")',
|
||||
await this.page3.page.waitForFunction(checkElementTextIncludes, {},
|
||||
'body', 'User joined the session'
|
||||
);
|
||||
await this.page3.screenshot(`${testName}`, `04-page03-user-join-toast-${testName}`);
|
||||
return true;
|
||||
@ -151,20 +152,20 @@ class Notifications extends MultiUsers {
|
||||
await this.page3.waitForSelector(pe.fileUpload, ELEMENT_WAIT_TIME);
|
||||
const fileUpload = await this.page3.page.$(pe.fileUpload);
|
||||
await fileUpload.uploadFile(path.join(__dirname, `../media/${e.pdfFileName}.pdf`));
|
||||
await this.page3.page.waitForFunction(
|
||||
'document.querySelector("body").innerText.includes("To be uploaded ...")',
|
||||
await this.page3.page.waitForFunction(checkElementTextIncludes, {},
|
||||
'body', 'To be uploaded ...'
|
||||
);
|
||||
await this.page3.waitForSelector(pe.upload, ELEMENT_WAIT_TIME);
|
||||
await this.page3.click(pe.upload, true);
|
||||
await this.page3.page.waitForFunction(
|
||||
'document.querySelector("body").innerText.includes("Converting file")',
|
||||
await this.page3.page.waitForFunction(checkElementTextIncludes, {},
|
||||
'body', 'Converting file'
|
||||
);
|
||||
await this.page3.screenshot(`${testName}`, `04-page03-file-uploaded-and-ready-${testName}`);
|
||||
await this.page3.waitForSelector(ne.smallToastMsg, UPLOAD_PDF_WAIT_TIME);
|
||||
await this.page3.waitForSelector(we.whiteboard, ELEMENT_WAIT_TIME);
|
||||
await this.page3.screenshot(`${testName}`, `05-page03-presentation-changed-${testName}`);
|
||||
await this.page3.page.waitForFunction(
|
||||
'document.querySelector("body").innerText.includes("Current presentation")',
|
||||
await this.page3.page.waitForFunction(checkElementTextIncludes, {},
|
||||
'body', 'Current presentation'
|
||||
);
|
||||
await this.page3.screenshot(`${testName}`, `06-page03-presentation-change-toast-${testName}`);
|
||||
return true;
|
||||
@ -186,7 +187,7 @@ class Notifications extends MultiUsers {
|
||||
await this.page3.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
|
||||
const resp = await util.getLastToastValue(this.page3);
|
||||
await this.page3.screenshot(`${testName}`, `04-page03-poll-toast-${testName}`);
|
||||
return resp === true;
|
||||
return resp;
|
||||
} catch (err) {
|
||||
await this.page3.logger(err);
|
||||
return false;
|
||||
@ -202,7 +203,7 @@ class Notifications extends MultiUsers {
|
||||
await this.page3.screenshot(`${testName}`, `02-page03-joined-microphone-${testName}`);
|
||||
const resp = await util.getLastToastValue(this.page3) === ne.joinAudioToast;
|
||||
await this.page3.screenshot(`${testName}`, `03-page03-audio-toast-${testName}`);
|
||||
return resp === true;
|
||||
return resp;
|
||||
} catch (err) {
|
||||
await this.page3.logger(err);
|
||||
return false;
|
||||
@ -220,7 +221,7 @@ class Notifications extends MultiUsers {
|
||||
await this.page3.screenshot(`${testName}`, `03-page03-screenshare-started-${testName}`);
|
||||
const response = await util.getLastToastValue(this.page3);
|
||||
await this.page3.screenshot(`${testName}`, `04-page03-screenshare-toast-${testName}`);
|
||||
return response === true;
|
||||
return response;
|
||||
} catch (err) {
|
||||
await this.page3.logger(err);
|
||||
return false;
|
||||
|
@ -3,28 +3,25 @@ const ule = require('../user/elements');
|
||||
const ce = require('../chat/elements');
|
||||
const e = require('../core/elements');
|
||||
const { ELEMENT_WAIT_TIME } = require('../core/constants');
|
||||
|
||||
async function clickTestElement(element) {
|
||||
await document.querySelectorAll(element)[0].click();
|
||||
}
|
||||
const { clickElement, getElementText, checkElement, checkElementLengthEqualTo } = require('../core/util');
|
||||
|
||||
async function popupMenu(test) {
|
||||
await test.page.evaluate(clickTestElement, e.options);
|
||||
await test.page.evaluate(clickTestElement, ne.settings);
|
||||
await test.page.evaluate(clickElement, e.options);
|
||||
await test.page.evaluate(clickElement, ne.settings);
|
||||
}
|
||||
|
||||
async function enableChatPopup(test) {
|
||||
await test.waitForSelector(ne.notificationsTab, ELEMENT_WAIT_TIME);
|
||||
await test.page.evaluate(clickTestElement, ne.notificationsTab);
|
||||
await test.page.evaluate(clickElement, ne.notificationsTab);
|
||||
await test.waitForSelector(ne.chatPushAlerts, ELEMENT_WAIT_TIME);
|
||||
await test.page.evaluate(clickTestElement, ne.chatPushAlerts);
|
||||
await test.page.evaluate(clickElement, ne.chatPushAlerts);
|
||||
}
|
||||
|
||||
async function enableUserJoinPopup(test) {
|
||||
await test.waitForSelector(ne.notificationsTab, ELEMENT_WAIT_TIME);
|
||||
await test.page.evaluate(clickTestElement, ne.notificationsTab);
|
||||
await test.page.evaluate(clickElement, ne.notificationsTab);
|
||||
await test.waitForSelector(ne.userJoinPushAlerts, ELEMENT_WAIT_TIME);
|
||||
await test.page.evaluate(clickTestElement, ne.userJoinPushAlerts);
|
||||
await test.page.evaluate(clickElement, ne.userJoinPushAlerts);
|
||||
}
|
||||
|
||||
async function saveSettings(page) {
|
||||
@ -34,44 +31,26 @@ async function saveSettings(page) {
|
||||
|
||||
async function waitForToast(test) {
|
||||
await test.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
|
||||
const resp = await test.page.evaluate(getTestElement, ne.smallToastMsg) !== null;
|
||||
const resp = await test.page.evaluate(checkElement, ne.smallToastMsg, 1);
|
||||
return resp;
|
||||
}
|
||||
|
||||
async function getLastToastValue(test) {
|
||||
await test.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
|
||||
const toast = test.page.evaluate(async (toastMsgSelector) => {
|
||||
const lastToast = await document.querySelectorAll(toastMsgSelector)[0].innerText;
|
||||
return lastToast;
|
||||
}, ne.smallToastMsg);
|
||||
const toast = test.page.evaluate(getElementText, ne.smallToastMsg);
|
||||
return toast;
|
||||
}
|
||||
|
||||
async function getOtherToastValue(test) {
|
||||
await test.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
|
||||
const toast = test.page.evaluate(async (toastMsgSelector) => {
|
||||
const lastToast = await document.querySelectorAll(toastMsgSelector)[1].innerText;
|
||||
return lastToast;
|
||||
}, ne.smallToastMsg);
|
||||
const toast = test.page.evaluate(getElementText, ne.smallToastMsg, 1);
|
||||
return toast;
|
||||
}
|
||||
|
||||
async function getTestElement(element) {
|
||||
await document.querySelectorAll(element)[1];
|
||||
}
|
||||
|
||||
async function clickOnElement(element) {
|
||||
await document.querySelectorAll(element)[0].click();
|
||||
}
|
||||
|
||||
async function clickThePrivateChatButton(element) {
|
||||
await document.querySelectorAll(element)[0].click();
|
||||
}
|
||||
|
||||
async function publicChatMessageToast(page1, page2) {
|
||||
// Open private Chat with the other User
|
||||
await page1.page.evaluate(clickOnElement, ule.userListItem);
|
||||
await page1.page.evaluate(clickThePrivateChatButton, ce.activeChat);
|
||||
await page1.page.evaluate(clickElement, ule.userListItem);
|
||||
await page1.page.evaluate(clickElement, ce.activeChat);
|
||||
// send a public message
|
||||
await page2.page.type(ce.publicChat, ce.publicMessage1);
|
||||
await page2.click(ce.sendButton, true);
|
||||
@ -80,13 +59,13 @@ async function publicChatMessageToast(page1, page2) {
|
||||
|
||||
async function privateChatMessageToast(page2) {
|
||||
// Open private Chat with the other User
|
||||
await page2.page.evaluate(clickOnElement, ule.userListItem);
|
||||
await page2.page.evaluate(clickThePrivateChatButton, ce.activeChat);
|
||||
await page2.page.evaluate(clickElement, ule.userListItem);
|
||||
await page2.page.evaluate(clickElement, ce.activeChat);
|
||||
// wait for the private chat to be ready
|
||||
await page2.page.waitForFunction(
|
||||
(chatSelector) => document.querySelectorAll(chatSelector).length == 2,
|
||||
checkElementLengthEqualTo,
|
||||
{ timeout: ELEMENT_WAIT_TIME },
|
||||
ce.chatButton
|
||||
ce.chatButton, 2
|
||||
);
|
||||
// send a private message
|
||||
await page2.page.type(ce.privateChat, ce.message1);
|
||||
@ -100,27 +79,20 @@ async function uploadFileMenu(test) {
|
||||
await test.click(ne.uploadPresentation);
|
||||
}
|
||||
|
||||
async function getFileItemStatus(element, value) {
|
||||
document.querySelectorAll(element)[1].innerText.includes(value);
|
||||
}
|
||||
|
||||
async function startPoll(test) {
|
||||
await test.waitForSelector(e.actions);
|
||||
await test.click(e.actions);
|
||||
await test.waitForSelector(ne.polling);
|
||||
await test.click(ne.polling);
|
||||
await test.waitForSelector(ne.hidePollDesc, ELEMENT_WAIT_TIME);
|
||||
await test.waitForSelector(ne.polling, ELEMENT_WAIT_TIME);
|
||||
await test.page.evaluate(clickOnElement, ne.polling);
|
||||
await test.page.evaluate(clickElement, ne.polling);
|
||||
await test.waitForSelector(ne.pollYesNoAbstentionBtn, ELEMENT_WAIT_TIME);
|
||||
await test.click(ne.pollYesNoAbstentionBtn, true);
|
||||
await test.waitForSelector(ne.startPoll, ELEMENT_WAIT_TIME);
|
||||
await test.click(ne.startPoll, true);
|
||||
await test.waitForSelector(ne.publishLabel, ELEMENT_WAIT_TIME);
|
||||
await test.page.evaluate(clickOnElement, ne.publishLabel);
|
||||
await test.page.evaluate(clickElement, ne.publishLabel);
|
||||
}
|
||||
|
||||
exports.getFileItemStatus = getFileItemStatus;
|
||||
exports.privateChatMessageToast = privateChatMessageToast;
|
||||
exports.publicChatMessageToast = publicChatMessageToast;
|
||||
exports.enableUserJoinPopup = enableUserJoinPopup;
|
||||
@ -128,10 +100,7 @@ exports.getOtherToastValue = getOtherToastValue;
|
||||
exports.getLastToastValue = getLastToastValue;
|
||||
exports.enableChatPopup = enableChatPopup;
|
||||
exports.uploadFileMenu = uploadFileMenu;
|
||||
exports.getTestElement = getTestElement;
|
||||
exports.saveSettings = saveSettings;
|
||||
exports.waitForToast = waitForToast;
|
||||
exports.popupMenu = popupMenu;
|
||||
exports.clickTestElement = clickTestElement;
|
||||
exports.startPoll = startPoll;
|
||||
exports.clickOnElement = clickOnElement;
|
||||
|
6
bigbluebutton-tests/puppeteer/package-lock.json
generated
6
bigbluebutton-tests/puppeteer/package-lock.json
generated
@ -5289,9 +5289,9 @@
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
|
||||
"integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA=="
|
||||
"version": "7.5.4",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.4.tgz",
|
||||
"integrity": "sha512-zP9z6GXm6zC27YtspwH99T3qTG7bBFv2VIkeHstMLrLlDJuzA7tQ5ls3OJ1hOGGCzTQPniNJoHXIAOS0Jljohg=="
|
||||
},
|
||||
"xml-name-validator": {
|
||||
"version": "3.0.0",
|
||||
|
@ -1,7 +1,8 @@
|
||||
exports.pollingContainer = 'div[data-test="pollingContainer"]';
|
||||
exports.pollQuestionArea = 'textarea[data-test="pollQuestionArea"]';
|
||||
exports.pollQuestion = 'Are we good ?';
|
||||
exports.responseTypes = 'div[data-test="responseTypesLabel"]';
|
||||
exports.responseTypes = 'div[data-test="responseTypes"]';
|
||||
exports.responseTypesLabel = 'div[data-test="responseTypesLabel"]';
|
||||
exports.responseChoices = 'div[data-test="responseChoices"]';
|
||||
exports.addItem = 'button[data-test="addItem"]';
|
||||
exports.pollOptionItem = 'input[data-test="pollOptionItem"]';
|
||||
|
@ -1,6 +1,7 @@
|
||||
const Page = require('../core/page');
|
||||
const e = require('../core/elements');
|
||||
const utilNotification = require('../notifications/util');
|
||||
const { ELEMENT_WAIT_TIME, VIDEO_LOADING_WAIT_TIME } = require('../core/constants'); // core constants (Timeouts vars imported)
|
||||
const { checkElementLengthEqualTo } = require('../core/util');
|
||||
|
||||
class Polling extends Page {
|
||||
constructor() {
|
||||
@ -12,7 +13,7 @@ class Polling extends Page {
|
||||
await utilNotification.startPoll(this);
|
||||
await this.screenshot(`${testName}`, `01-before-chat-message-send-[${this.meetingId}]`);
|
||||
|
||||
const resp = this.page.evaluate(() => document.querySelectorAll('[data-test="pollMenuButton"]').length === 1);
|
||||
const resp = this.page.evaluate(checkElementLengthEqualTo, e.pollMenuButton, 1);
|
||||
return resp;
|
||||
} catch (err) {
|
||||
await this.logger(err);
|
||||
|
@ -2,6 +2,7 @@ const Page = require('../core/page');
|
||||
const e = require('./elements');
|
||||
const we = require('../whiteboard/elements');
|
||||
const { ELEMENT_WAIT_LONGER_TIME, ELEMENT_WAIT_TIME } = require('../core/constants');
|
||||
const util = require('./util');
|
||||
|
||||
class Slide extends Page {
|
||||
constructor() {
|
||||
@ -13,21 +14,21 @@ class Slide extends Page {
|
||||
await this.waitForSelector(we.whiteboard, ELEMENT_WAIT_LONGER_TIME);
|
||||
await this.waitForSelector(e.presentationToolbarWrapper, ELEMENT_WAIT_TIME);
|
||||
|
||||
const svg0 = await this.page.evaluate(async () => await document.querySelector('svg g g g').outerHTML.indexOf('/svg/1') !== -1);
|
||||
const svg0 = await this.page.evaluate(util.checkSvgIndex, '/svg/1');
|
||||
|
||||
await this.waitForSelector(e.nextSlide, ELEMENT_WAIT_TIME);
|
||||
await this.click(e.nextSlide, true);
|
||||
await this.waitForSelector(we.whiteboard, ELEMENT_WAIT_TIME);
|
||||
await this.page.waitFor(1000);
|
||||
await this.page.waitForTimeout(1000);
|
||||
|
||||
const svg1 = await this.page.evaluate(async () => await document.querySelector('svg g g g').outerHTML.indexOf('/svg/2') !== -1);
|
||||
const svg1 = await this.page.evaluate(util.checkSvgIndex, '/svg/2');
|
||||
|
||||
await this.waitForSelector(e.prevSlide, ELEMENT_WAIT_TIME);
|
||||
await this.click(e.prevSlide, true);
|
||||
await this.waitForSelector(we.whiteboard, ELEMENT_WAIT_TIME);
|
||||
await this.page.waitFor(1000);
|
||||
await this.page.waitForTimeout(1000);
|
||||
|
||||
const svg2 = await this.page.evaluate(async () => await document.querySelector('svg g g g').outerHTML.indexOf('/svg/1') !== -1);
|
||||
const svg2 = await this.page.evaluate(util.checkSvgIndex, '/svg/1');
|
||||
|
||||
return svg0 === true && svg1 === true && svg2 === true;
|
||||
} catch (err) {
|
||||
|
@ -3,6 +3,8 @@ const e = require('./elements');
|
||||
const we = require('../whiteboard/elements');
|
||||
const ce = require('../core/elements');
|
||||
const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
|
||||
const { checkElementTextIncludes } = require('../core/util');
|
||||
const util = require('./util');
|
||||
|
||||
class Upload extends Page {
|
||||
constructor() {
|
||||
@ -14,7 +16,7 @@ class Upload extends Page {
|
||||
await this.waitForSelector(we.whiteboard, ELEMENT_WAIT_LONGER_TIME);
|
||||
await this.waitForSelector(e.skipSlide, ELEMENT_WAIT_TIME);
|
||||
|
||||
const slides0 = await this.page.evaluate(async () => await document.querySelector('svg g g g').outerHTML);
|
||||
const slides0 = await this.page.evaluate(util.getSvgOuterHtml);
|
||||
|
||||
await this.click(ce.actions, true);
|
||||
await this.click(e.uploadPresentation, true);
|
||||
@ -24,19 +26,19 @@ class Upload extends Page {
|
||||
await this.waitForSelector(e.fileUpload, ELEMENT_WAIT_TIME);
|
||||
const fileUpload = await this.page.$(e.fileUpload);
|
||||
await fileUpload.uploadFile(`${__dirname}/upload-test.png`);
|
||||
await this.page.waitForFunction(
|
||||
'document.querySelector("body").innerText.includes("To be uploaded ...")',
|
||||
await this.page.waitForFunction(checkElementTextIncludes, {},
|
||||
'body', 'To be uploaded ...'
|
||||
);
|
||||
await this.page.waitForSelector(e.upload, ELEMENT_WAIT_TIME);
|
||||
|
||||
await this.page.click(e.upload, true);
|
||||
await this.logger('\nWaiting for the new presentation to upload...');
|
||||
await this.page.waitForFunction(
|
||||
'document.querySelector("body").innerText.includes("Converting file")',
|
||||
await this.page.waitForFunction(checkElementTextIncludes, {},
|
||||
'body', 'Converting file'
|
||||
);
|
||||
await this.logger('\nPresentation uploaded!');
|
||||
await this.page.waitForFunction(
|
||||
'document.querySelector("body").innerText.includes("Current presentation")',
|
||||
await this.page.waitForFunction(checkElementTextIncludes, {},
|
||||
'body', 'Current presentation'
|
||||
);
|
||||
await this.screenshot(`${testName}`, `02-after-presentation-upload-[${testName}]`);
|
||||
|
||||
@ -53,12 +55,6 @@ class Upload extends Page {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async getTestElements() {
|
||||
const svg = await this.page.evaluate(async () => await document.querySelector('svg g g g').outerHTML);
|
||||
await this.logger(svg);
|
||||
return svg;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = Upload;
|
||||
|
10
bigbluebutton-tests/puppeteer/presentation/util.js
Normal file
10
bigbluebutton-tests/puppeteer/presentation/util.js
Normal file
@ -0,0 +1,10 @@
|
||||
function checkSvgIndex (element) {
|
||||
return document.querySelector('svg g g g').outerHTML.indexOf(element) !== -1;
|
||||
}
|
||||
|
||||
function getSvgOuterHtml() {
|
||||
return document.querySelector('svg g g g').outerHTML;
|
||||
}
|
||||
|
||||
exports.checkSvgIndex = checkSvgIndex;
|
||||
exports.getSvgOuterHtml = getSvgOuterHtml;
|
@ -3,6 +3,7 @@ const util = require('./util');
|
||||
const e = require('../core/elements');
|
||||
const { ELEMENT_WAIT_TIME, VIDEO_LOADING_WAIT_TIME } = require('../core/constants');
|
||||
const { sleep } = require('../core/helper');
|
||||
const { checkElementLengthEqualTo } = require('../core/util');
|
||||
|
||||
class ShareScreen extends Page {
|
||||
constructor() {
|
||||
@ -28,7 +29,7 @@ class ShareScreen extends Page {
|
||||
await this.init(args, undefined, undefined, undefined, testName, undefined, deviceX);
|
||||
await this.startRecording(testName);
|
||||
await this.closeAudioModal();
|
||||
const screenshareBtn = await this.page.evaluate(() => document.querySelectorAll('button[aria-label="Share your screen"]').length === 0) === true;
|
||||
const screenshareBtn = await this.page.evaluate(checkElementLengthEqualTo, e.screenShare, 1);
|
||||
return screenshareBtn;
|
||||
} catch (err) {
|
||||
await this.logger(err);
|
||||
|
@ -1,15 +1,12 @@
|
||||
const { ELEMENT_WAIT_TIME, VIDEO_LOADING_WAIT_TIME } = require('../core/constants');
|
||||
const e = require('../core/elements');
|
||||
const { checkElement } = require('../core/util');
|
||||
|
||||
async function startScreenshare(test) {
|
||||
await test.waitForSelector(e.screenShare, ELEMENT_WAIT_TIME);
|
||||
await test.click(e.screenShare, true);
|
||||
}
|
||||
|
||||
async function getTestElement(element) {
|
||||
(await document.querySelectorAll(element)[0]) !== null;
|
||||
}
|
||||
|
||||
async function waitForScreenshareContainer(test) {
|
||||
await test.waitForSelector(e.screenshareConnecting, ELEMENT_WAIT_TIME);
|
||||
await test.waitForSelector(e.screenShareVideo, VIDEO_LOADING_WAIT_TIME);
|
||||
@ -17,21 +14,16 @@ async function waitForScreenshareContainer(test) {
|
||||
|
||||
async function getScreenShareContainer(test) {
|
||||
await test.waitForSelector(e.screenShareVideo, VIDEO_LOADING_WAIT_TIME);
|
||||
const screenShareContainer = await test.page.evaluate(getTestElement, e.screenShareVideo);
|
||||
const response = screenShareContainer !== null;
|
||||
return response;
|
||||
return test.page.evaluate(checkElement, e.screenShareVideo);
|
||||
}
|
||||
|
||||
async function getScreenShareBreakoutContainer(test) {
|
||||
await test.waitForSelector(e.screenshareConnecting, { timeout: VIDEO_LOADING_WAIT_TIME });
|
||||
await test.waitForSelector(e.screenShareVideo, { timeout: VIDEO_LOADING_WAIT_TIME });
|
||||
const screenShareContainer = await test.evaluate(getTestElement, e.screenShareVideo);
|
||||
const response = screenShareContainer !== null;
|
||||
return response;
|
||||
return test.evaluate(checkElement, e.screenShareVideo);
|
||||
}
|
||||
|
||||
exports.getScreenShareBreakoutContainer = getScreenShareBreakoutContainer;
|
||||
exports.getScreenShareContainer = getScreenShareContainer;
|
||||
exports.getTestElement = getTestElement;
|
||||
exports.startScreenshare = startScreenshare;
|
||||
exports.waitForScreenshareContainer = waitForScreenshareContainer;
|
||||
|
@ -1,10 +1,11 @@
|
||||
const Page = require('../core/page');
|
||||
const { checkIncludeClass, checkUniqueElement } = require('./util');
|
||||
const c = require('../core/constants');
|
||||
const params = require('../params');
|
||||
const c = require('../core/constants');
|
||||
const ne = require('../notifications/elements');
|
||||
const ue = require('../user/elements');
|
||||
const e = require('../core/elements');
|
||||
const util = require('./util');
|
||||
const { checkElementLengthEqualTo } = require('../core/util');
|
||||
|
||||
class Stress extends Page {
|
||||
constructor() {
|
||||
@ -19,9 +20,9 @@ class Stress extends Page {
|
||||
await this.init(Page.getArgs(), undefined, { ...params, fullName: `Moderator-${i}` }, undefined, testName);
|
||||
await this.closeAudioModal();
|
||||
await this.page.waitForSelector(ue.statusIcon, { timeout: c.ELEMENT_WAIT_TIME });
|
||||
const hasPresenterClass = await this.page.evaluate(checkIncludeClass, ue.statusIcon, e.presenterClassName);
|
||||
const hasPresenterClass = await this.page.evaluate(util.checkIncludeClass, ue.statusIcon, e.presenterClassName);
|
||||
await this.click(e.actions);
|
||||
const canStartPoll = await this.page.evaluate(checkUniqueElement, ne.polling);
|
||||
const canStartPoll = await this.page.evaluate(checkElementLengthEqualTo, ne.polling, 1);
|
||||
if (!hasPresenterClass || !canStartPoll) {
|
||||
failureCount++;
|
||||
await this.screenshot(`${testName}`, `loop-${i}-failure-${testName}`);
|
||||
|
@ -1,9 +1,5 @@
|
||||
function checkIncludeClass(selector, className) {
|
||||
return document.querySelectorAll(selector)[0]?.className.includes(className);
|
||||
}
|
||||
function checkUniqueElement(selector) {
|
||||
return document.querySelectorAll(selector).length === 1;
|
||||
}
|
||||
|
||||
exports.checkIncludeClass = checkIncludeClass;
|
||||
exports.checkUniqueElement = checkUniqueElement;
|
||||
exports.checkIncludeClass = checkIncludeClass;
|
@ -32,3 +32,5 @@ exports.chatButton = '[accesskey="P"]';
|
||||
exports.chatPanel = 'section[data-test="chatPanel"]';
|
||||
exports.userListButton = '[accesskey="U"]';
|
||||
exports.userListPanel = 'div[data-test="userListPanel"]';
|
||||
exports.multiWhiteboardTool = 'span[data-test="multiWhiteboardTool"]'
|
||||
exports.connectionStatusBtn = 'button[data-test="connectionStatusButton"]';
|
@ -2,15 +2,16 @@ const Page = require('../core/page');
|
||||
const params = require('../params');
|
||||
const util = require('../chat/util');
|
||||
const utilUser = require('./util');
|
||||
const utilCustomParams = require('../customparameters/util');
|
||||
const pe = require('../core/elements');
|
||||
const ne = require('../notifications/elements');
|
||||
const ple = require('../polling/elemens');
|
||||
const we = require('../whiteboard/elements');
|
||||
const ue = require('./elements');
|
||||
const ce = require('../chat/elements');
|
||||
const cu = require('../customparameters/elements');
|
||||
const { ELEMENT_WAIT_TIME } = require('../core/constants');
|
||||
const { sleep } = require('../core/helper');
|
||||
const { getElementLength, checkElementLengthEqualTo, checkElementLengthDifferentTo } = require('../core/util');
|
||||
|
||||
class MultiUsers {
|
||||
constructor() {
|
||||
@ -32,8 +33,8 @@ class MultiUsers {
|
||||
|
||||
// Run the test for the page
|
||||
async checkForOtherUser() {
|
||||
const firstCheck = await this.page1.page.evaluate(() => document.querySelectorAll('[data-test="userListItem"]').length > 0);
|
||||
const secondCheck = await this.page2.page.evaluate(() => document.querySelectorAll('[data-test="userListItem"]').length > 0);
|
||||
const firstCheck = await this.page1.page.evaluate(getElementLength, ue.userListItem) > 0;
|
||||
const secondCheck = await this.page1.page.evaluate(getElementLength, ue.userListItem) > 0;
|
||||
return {
|
||||
firstCheck,
|
||||
secondCheck,
|
||||
@ -42,9 +43,9 @@ class MultiUsers {
|
||||
|
||||
async multiUsersPublicChat() {
|
||||
try {
|
||||
const chat0 = await this.page1.page.evaluate(() => document.querySelectorAll('p[data-test="chatUserMessageText"]').length);
|
||||
const chat0 = await this.page1.page.evaluate(getElementLength, ce.chatUserMessageText);
|
||||
await util.sendPublicChatMessage(this.page1, this.page2);
|
||||
const chat1 = await this.page1.page.evaluate(() => document.querySelectorAll('p[data-test="chatUserMessageText"]').length);
|
||||
const chat1 = await this.page1.page.evaluate(getElementLength, ce.chatUserMessageText);
|
||||
return chat0 !== chat1;
|
||||
} catch (err) {
|
||||
await this.page1.logger(err);
|
||||
@ -55,10 +56,10 @@ class MultiUsers {
|
||||
async multiUsersPrivateChat() {
|
||||
try {
|
||||
await util.openPrivateChatMessage(this.page1, this.page2);
|
||||
const chat0 = await this.page1.page.evaluate(() => document.querySelectorAll('p[data-test="chatUserMessageText"]').length);
|
||||
const chat0 = await this.page1.page.evaluate(getElementLength, ce.chatUserMessageText);
|
||||
await util.sendPrivateChatMessage(this.page1, this.page2);
|
||||
await sleep(2000);
|
||||
const chat1 = await this.page1.page.evaluate(() => document.querySelectorAll('p[data-test="chatUserMessageText"]').length);
|
||||
const chat1 = await this.page1.page.evaluate(getElementLength, ce.chatUserMessageText);
|
||||
return chat0 !== chat1;
|
||||
} catch (err) {
|
||||
await this.page1.logger(err);
|
||||
@ -90,15 +91,15 @@ class MultiUsers {
|
||||
await this.page1.page.focus(ple.pollQuestionArea);
|
||||
await this.page1.page.keyboard.type(ple.pollQuestion);
|
||||
|
||||
const chosenRandomNb = await this.page1.page.evaluate(() => {
|
||||
const responseTypesDiv = document.querySelector('div[data-test="responseTypes"]');
|
||||
const chosenRandomNb = await this.page1.page.evaluate((responseTypes) => {
|
||||
const responseTypesDiv = document.querySelector(responseTypes);
|
||||
const buttons = responseTypesDiv.querySelectorAll('button');
|
||||
const countButtons = buttons.length;
|
||||
const randomNb = Math.floor(Math.random() * countButtons) + 1;
|
||||
const chosenRandomNb = randomNb - 1;
|
||||
responseTypesDiv.querySelectorAll('button')[chosenRandomNb].click();
|
||||
return chosenRandomNb;
|
||||
});
|
||||
}, ple.responseTypes);
|
||||
|
||||
const customs = {
|
||||
0: ple.uncertain,
|
||||
@ -158,7 +159,7 @@ class MultiUsers {
|
||||
await this.page1.waitForSelector(ple.publishLabel, ELEMENT_WAIT_TIME);
|
||||
await this.page1.click(ple.publishLabel, true);
|
||||
await this.page1.waitForSelector(ple.restartPoll, ELEMENT_WAIT_TIME);
|
||||
const receivedAnswerFound = await this.page1.page.evaluate(utilCustomParams.countTestElements, ple.receivedAnswer);
|
||||
const receivedAnswerFound = await this.page1.page.evaluate(checkElementLengthDifferentTo, ple.receivedAnswer, 0);
|
||||
return receivedAnswerFound;
|
||||
} catch (err) {
|
||||
await this.page1.logger(err);
|
||||
@ -175,7 +176,9 @@ class MultiUsers {
|
||||
await this.page1.clickNItem(we.userListItem, true, 1);
|
||||
await this.page1.clickNItem(we.changeWhiteboardAccess, true, 1);
|
||||
await sleep(2000);
|
||||
const resp = await this.page1.page.evaluate(async () => await document.querySelector('[data-test="multiWhiteboardTool"]').children[0].innerText === '1');
|
||||
const resp = await this.page1.page.evaluate((multiWhiteboardTool) => {
|
||||
return document.querySelector(multiWhiteboardTool).children[0].innerText === '1';
|
||||
}, ue.multiWhiteboardTool);
|
||||
return resp === true;
|
||||
} catch (err) {
|
||||
await this.page1.logger(err);
|
||||
@ -191,7 +194,7 @@ class MultiUsers {
|
||||
await this.page2.waitForSelector(we.raiseHandLabel, ELEMENT_WAIT_TIME);
|
||||
await this.page2.click(we.raiseHandLabel, true);
|
||||
await sleep(2000);
|
||||
const resp = await this.page2.page.evaluate(utilCustomParams.countTestElements, we.lowerHandLabel);
|
||||
const resp = await this.page2.page.evaluate(checkElementLengthDifferentTo, we.lowerHandLabel, 0);
|
||||
return resp === true;
|
||||
} catch (err) {
|
||||
await this.page1.logger(err);
|
||||
@ -205,7 +208,7 @@ class MultiUsers {
|
||||
await this.page2.waitForSelector(we.lowerHandLabel, ELEMENT_WAIT_TIME);
|
||||
await this.page2.click(we.lowerHandLabel, true);
|
||||
await sleep(2000);
|
||||
const resp = await this.page2.page.evaluate(utilCustomParams.countTestElements, we.raiseHandLabel);
|
||||
const resp = await this.page2.page.evaluate(checkElementLengthDifferentTo, we.raiseHandLabel, 0);
|
||||
return resp === true;
|
||||
} catch (err) {
|
||||
await this.page2.logger(err);
|
||||
@ -217,7 +220,7 @@ class MultiUsers {
|
||||
async getAvatarColorAndCompareWithUserListItem() {
|
||||
try {
|
||||
const avatarInToastElementColor = await this.page1.page.$eval(we.avatarsWrapperAvatar, (elem) => getComputedStyle(elem).backgroundColor);
|
||||
const avatarInUserListColor = await this.page1.page.$eval('[data-test="userListItem"] > div [data-test="userAvatar"]', (elem) => getComputedStyle(elem).backgroundColor);
|
||||
const avatarInUserListColor = await this.page1.page.$eval(`${ue.userListItem} > div ${ue.statusIcon}`, (elem) => getComputedStyle(elem).backgroundColor);
|
||||
return avatarInToastElementColor === avatarInUserListColor;
|
||||
} catch (err) {
|
||||
await this.page1.logger(err);
|
||||
@ -236,8 +239,8 @@ class MultiUsers {
|
||||
await sleep(5000);
|
||||
await utilUser.connectionStatus(this.page1);
|
||||
await sleep(5000);
|
||||
const connectionStatusItemEmpty = await this.page1.page.evaluate(utilUser.countTestElements, ue.connectionStatusItemEmpty) === false;
|
||||
const connectionStatusOfflineUser = await this.page1.page.evaluate(utilUser.countTestElements, ue.connectionStatusOfflineUser) === true;
|
||||
const connectionStatusItemEmpty = await this.page1.page.evaluate(checkElementLengthEqualTo, ue.connectionStatusItemEmpty, 0);
|
||||
const connectionStatusOfflineUser = await this.page1.page.evaluate(checkElementLengthDifferentTo, ue.connectionStatusOfflineUser, 0) === true;
|
||||
return connectionStatusOfflineUser && connectionStatusItemEmpty;
|
||||
} catch (err) {
|
||||
await this.page1.logger(err);
|
||||
@ -249,8 +252,8 @@ class MultiUsers {
|
||||
try {
|
||||
await this.page1.closeAudioModal();
|
||||
await this.page2.closeAudioModal();
|
||||
const userlistPanel = await this.page1.page.evaluate(utilUser.countTestElements, ue.chatButton) === false;
|
||||
const chatPanel = await this.page2.page.evaluate(utilUser.countTestElements, ue.chatButton) === false;
|
||||
const userlistPanel = await this.page1.page.evaluate(checkElementLengthEqualTo, ue.chatButton, 0);
|
||||
const chatPanel = await this.page2.page.evaluate(checkElementLengthEqualTo, ue.chatButton, 0);
|
||||
return userlistPanel && chatPanel;
|
||||
} catch (err) {
|
||||
await this.page1.logger(err);
|
||||
@ -266,7 +269,7 @@ class MultiUsers {
|
||||
await this.page2.click(ue.userListButton, true);
|
||||
await this.page2.click(ue.chatButton, true);
|
||||
const onUserListPanel = await this.page1.isNotVisible(cu.hidePresentation, ELEMENT_WAIT_TIME) === true;
|
||||
const onChatPanel = await this.page2.page.evaluate(utilUser.countTestElements, cu.hidePresentation) === false;
|
||||
const onChatPanel = await this.page2.page.evaluate(checkElementLengthEqualTo, cu.hidePresentation, 0);
|
||||
await sleep(2000);
|
||||
return onUserListPanel && onChatPanel;
|
||||
} catch (err) {
|
||||
@ -281,7 +284,7 @@ class MultiUsers {
|
||||
await this.page2.closeAudioModal();
|
||||
await this.page2.click(ue.userListButton, true);
|
||||
await this.page2.click(ue.chatButton, true);
|
||||
const whiteboard = await this.page1.page.evaluate(utilUser.countTestElements, ue.chatButton) === false;
|
||||
const whiteboard = await this.page1.page.evaluate(checkElementLengthEqualTo, ue.chatButton, 0);
|
||||
const onChatPanel = await this.page2.isNotVisible(ue.chatButton, ELEMENT_WAIT_TIME) === true;
|
||||
await sleep(2000);
|
||||
return whiteboard && onChatPanel;
|
||||
|
@ -4,8 +4,8 @@ const e = require('./elements');
|
||||
const util = require('./util');
|
||||
const utilWebcam = require('../webcam/util');
|
||||
const utilScreenshare = require('../screenshare/util');
|
||||
const utilB = require('../breakout/util');
|
||||
const { sleep } = require('../core/helper');
|
||||
const { clickElement, checkElementLengthEqualTo, checkElementLengthDifferentTo } = require('../core/util');
|
||||
|
||||
class Status extends Page {
|
||||
constructor() {
|
||||
@ -15,9 +15,9 @@ class Status extends Page {
|
||||
async test() {
|
||||
try {
|
||||
await util.setStatus(this, e.applaud);
|
||||
const resp1 = await this.page.evaluate(util.countTestElements, e.applauseIcon);
|
||||
const resp1 = await this.page.evaluate(checkElementLengthDifferentTo, e.applauseIcon, 0);
|
||||
await util.setStatus(this, e.away);
|
||||
const resp2 = await this.page.evaluate(util.countTestElements, e.awayIcon);
|
||||
const resp2 = await this.page.evaluate(checkElementLengthDifferentTo, e.awayIcon, 0);
|
||||
|
||||
await this.click(e.firstUser, true);
|
||||
await this.waitForSelector(e.clearStatus, ELEMENT_WAIT_TIME);
|
||||
@ -35,7 +35,7 @@ class Status extends Page {
|
||||
await this.page.click(e.userList, true);
|
||||
await this.page.waitForSelector(e.firstUser, ELEMENT_WAIT_TIME);
|
||||
|
||||
const response = await this.page.evaluate(util.countTestElements, e.mobileUser) === true;
|
||||
const response = await this.page.evaluate(checkElementLengthDifferentTo, e.mobileUser, 0);
|
||||
return response === true;
|
||||
} catch (err) {
|
||||
await this.logger(err);
|
||||
@ -46,7 +46,7 @@ class Status extends Page {
|
||||
async findConnectionStatusModal() {
|
||||
try {
|
||||
await util.connectionStatus(this.page);
|
||||
const resp = await this.page.evaluate(util.countTestElements, e.connectionStatusModal) === true;
|
||||
const resp = await this.page.evaluate(checkElementLengthDifferentTo, e.connectionStatusModal, 0);
|
||||
return resp === true;
|
||||
} catch (err) {
|
||||
await this.logger(err);
|
||||
@ -60,11 +60,11 @@ class Status extends Page {
|
||||
await utilWebcam.enableWebcam(this, ELEMENT_WAIT_LONGER_TIME);
|
||||
await util.connectionStatus(this);
|
||||
await this.waitForSelector(e.dataSavingWebcams, ELEMENT_WAIT_TIME);
|
||||
await this.page.evaluate(utilB.clickTestElement, e.dataSavingWebcams);
|
||||
await this.page.evaluate(clickElement, e.dataSavingWebcams);
|
||||
await this.waitForSelector(e.closeConnectionStatusModal, ELEMENT_WAIT_TIME);
|
||||
await this.page.evaluate(utilB.clickTestElement, e.closeConnectionStatusModal);
|
||||
await this.page.evaluate(clickElement, e.closeConnectionStatusModal);
|
||||
await sleep(2000);
|
||||
const webcamsIsDisabledInDataSaving = await this.page.evaluate(util.countTestElements, e.webcamsIsDisabledInDataSaving) === true;
|
||||
const webcamsIsDisabledInDataSaving = await this.page.evaluate(checkElementLengthDifferentTo, e.webcamsIsDisabledInDataSaving, 0);
|
||||
return webcamsIsDisabledInDataSaving === true;
|
||||
} catch (err) {
|
||||
await this.logger(err);
|
||||
@ -79,11 +79,11 @@ class Status extends Page {
|
||||
await utilScreenshare.waitForScreenshareContainer(this);
|
||||
await util.connectionStatus(this);
|
||||
await this.waitForSelector(e.dataSavingScreenshare, ELEMENT_WAIT_TIME);
|
||||
await this.page.evaluate(utilB.clickTestElement, e.dataSavingScreenshare);
|
||||
await this.page.evaluate(clickElement, e.dataSavingScreenshare);
|
||||
await this.waitForSelector(e.closeConnectionStatusModal, ELEMENT_WAIT_TIME);
|
||||
await this.page.evaluate(utilB.clickTestElement, e.closeConnectionStatusModal);
|
||||
await this.page.evaluate(clickElement, e.closeConnectionStatusModal);
|
||||
await sleep(2000);
|
||||
const webcamsIsDisabledInDataSaving = await this.page.evaluate(util.countTestElements, e.screenshareLocked) === true;
|
||||
const webcamsIsDisabledInDataSaving = await this.page.evaluate(checkElementLengthEqualTo, e.screenshareLocked, 0);
|
||||
return webcamsIsDisabledInDataSaving === true;
|
||||
} catch (err) {
|
||||
await this.logger(err);
|
||||
@ -100,8 +100,8 @@ class Status extends Page {
|
||||
await utilScreenshare.waitForScreenshareContainer(this);
|
||||
await util.connectionStatus(this);
|
||||
await sleep(5000);
|
||||
const connectionStatusItemEmpty = await this.page.evaluate(util.countTestElements, e.connectionStatusItemEmpty) === false;
|
||||
const connectionStatusItemUser = await this.page.evaluate(util.countTestElements, e.connectionStatusItemUser) === true;
|
||||
const connectionStatusItemEmpty = await this.page.evaluate(checkElementLengthEqualTo, e.connectionStatusItemEmpty, 0);
|
||||
const connectionStatusItemUser = await this.page.evaluate(checkElementLengthDifferentTo, e.connectionStatusItemUser, 0);
|
||||
return connectionStatusItemUser && connectionStatusItemEmpty;
|
||||
} catch (err) {
|
||||
await this.logger(err);
|
||||
|
@ -10,15 +10,10 @@ async function setStatus(test, status) {
|
||||
await test.click(status, true);
|
||||
}
|
||||
|
||||
async function countTestElements(element) {
|
||||
return document.querySelectorAll(element).length !== 0;
|
||||
}
|
||||
|
||||
async function connectionStatus(test) {
|
||||
await test.click('button[data-test="connectionStatusButton"]', true);
|
||||
await test.waitForSelector('div[aria-label="Connection status modal"]', ELEMENT_WAIT_TIME);
|
||||
await test.click(e.connectionStatusBtn, true);
|
||||
await test.waitForSelector(e.connectionStatusModal, ELEMENT_WAIT_TIME);
|
||||
}
|
||||
|
||||
exports.countTestElements = countTestElements;
|
||||
exports.setStatus = setStatus;
|
||||
exports.connectionStatus = connectionStatus;
|
||||
|
@ -2,6 +2,7 @@ const Page = require('../core/page');
|
||||
const params = require('../params');
|
||||
const { USER_LIST_VLIST_BOTS_LISTENING, ELEMENT_WAIT_TIME } = require('../core/constants');
|
||||
const ue = require('../user/elements');
|
||||
const { getElementLength } = require('../core/util')
|
||||
|
||||
class VirtualizeList {
|
||||
constructor() {
|
||||
@ -31,7 +32,7 @@ class VirtualizeList {
|
||||
|
||||
async test() {
|
||||
try {
|
||||
const USER_LIST_VLIST_VISIBLE_USERS = await this.page1.page.evaluate(async () => await document.querySelectorAll('[data-test^="userListItem"]').length);
|
||||
const USER_LIST_VLIST_VISIBLE_USERS = await this.page1.page.evaluate(getElementLength, ue.anyUser);
|
||||
const totalNumberOfUsersMongo = await this.page1.page.evaluate(() => {
|
||||
const collection = require('/imports/api/users/index.js');
|
||||
const users = collection.default._collection.find().count();
|
||||
|
@ -1,8 +1,9 @@
|
||||
const Page = require('../core/page');
|
||||
const util = require('./util');
|
||||
const wle = require('./elements');
|
||||
const { checkElementLengthDifferentTo } = require('../core/util');
|
||||
const { VIDEO_LOADING_WAIT_TIME } = require('../core/constants'); // core constants (Timeouts vars imported)
|
||||
const e = require('../core/elements');
|
||||
const { ELEMENT_WAIT_TIME, VIDEO_LOADING_WAIT_TIME } = require('../core/constants'); // core constants (Timeouts vars imported)
|
||||
|
||||
class Share extends Page {
|
||||
constructor() {
|
||||
@ -37,7 +38,7 @@ class Share extends Page {
|
||||
await this.waitForSelector(wle.webcamVideo, VIDEO_LOADING_WAIT_TIME);
|
||||
await this.waitForSelector(wle.stopSharingWebcam, VIDEO_LOADING_WAIT_TIME);
|
||||
await this.waitForSelector(e.isTalking);
|
||||
const foundTestElement = await this.page.evaluate(util.countTestElements, wle.webcamItemTalkingUser) !== 0;
|
||||
const foundTestElement = await this.page.evaluate(checkElementLengthDifferentTo, wle.webcamItemTalkingUser, 0);
|
||||
if (foundTestElement === true) {
|
||||
await this.screenshot(`${testName}`, `success-${testName}`);
|
||||
this.logger(testName, ' passed');
|
||||
|
@ -1,32 +1,29 @@
|
||||
const we = require('./elements');
|
||||
const { sleep } = require('../core/helper');
|
||||
const { checkElement, clickElement , checkElementLengthDifferentTo } = require('../core/util');
|
||||
const {
|
||||
LOOP_INTERVAL, ELEMENT_WAIT_TIME, VIDEO_LOADING_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME,
|
||||
LOOP_INTERVAL,
|
||||
ELEMENT_WAIT_TIME,
|
||||
VIDEO_LOADING_WAIT_TIME,
|
||||
ELEMENT_WAIT_LONGER_TIME,
|
||||
} = require('../core/constants');
|
||||
|
||||
async function enableWebcam(test, videoPreviewTimeout) {
|
||||
// Enabling webcam
|
||||
await test.waitForSelector(we.joinVideo, ELEMENT_WAIT_TIME);
|
||||
await test.page.evaluate(clickTestElement, we.joinVideo);
|
||||
await test.page.evaluate(clickElement, we.joinVideo);
|
||||
await test.waitForSelector(we.videoPreview, videoPreviewTimeout);
|
||||
await test.waitForSelector(we.startSharingWebcam, ELEMENT_WAIT_TIME);
|
||||
await test.page.evaluate(clickTestElement, we.startSharingWebcam);
|
||||
await test.page.evaluate(clickElement, we.startSharingWebcam);
|
||||
await test.waitForSelector(we.webcamConnecting, ELEMENT_WAIT_TIME);
|
||||
await test.waitForSelector(we.webcamVideo, VIDEO_LOADING_WAIT_TIME);
|
||||
await test.waitForSelector(we.leaveVideo, VIDEO_LOADING_WAIT_TIME);
|
||||
const resp = await test.page.evaluate(countTestElements, we.webcamVideo) !== 0;
|
||||
return resp;
|
||||
}
|
||||
|
||||
async function getFullScreenWebcamButton(element) {
|
||||
return await document.querySelectorAll(element)[1] !== null;
|
||||
return test.page.evaluate(checkElementLengthDifferentTo, we.webcamVideo, 0);
|
||||
}
|
||||
|
||||
async function evaluateCheck(test) {
|
||||
await test.waitForSelector(we.videoContainer, ELEMENT_WAIT_TIME);
|
||||
const videoContainer = await test.page.evaluate(getFullScreenWebcamButton, we.presentationFullscreenButton);
|
||||
const response = videoContainer !== false;
|
||||
return response;
|
||||
return test.page.evaluate(checkElement, we.presentationFullscreenButton, 1);
|
||||
}
|
||||
|
||||
async function startAndCheckForWebcams(test) {
|
||||
@ -72,11 +69,6 @@ async function webcamContentCheck(test) {
|
||||
return check === true;
|
||||
}
|
||||
|
||||
|
||||
async function clickTestElement(element) {
|
||||
document.querySelectorAll(element)[0].click();
|
||||
}
|
||||
|
||||
async function countTestElements(element) {
|
||||
const respCount = await document.querySelectorAll(element).length;
|
||||
return respCount;
|
||||
@ -85,6 +77,5 @@ async function countTestElements(element) {
|
||||
exports.startAndCheckForWebcams = startAndCheckForWebcams;
|
||||
exports.webcamContentCheck = webcamContentCheck;
|
||||
exports.evaluateCheck = evaluateCheck;
|
||||
exports.getFullScreenWebcamButton = getFullScreenWebcamButton;
|
||||
exports.enableWebcam = enableWebcam;
|
||||
exports.countTestElements = countTestElements;
|
||||
|
2
record-and-playback/core/.gitignore
vendored
Normal file
2
record-and-playback/core/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.bundle
|
||||
vendor/bundle
|
@ -34,7 +34,9 @@ gem 'rubyzip', '~> 2.0'
|
||||
gem 'trollop', '2.1.3'
|
||||
gem 'resque', '~> 2.0.0'
|
||||
gem 'bbbevents', '~> 1.2'
|
||||
gem 'rake', '>= 12.3', '<14'
|
||||
|
||||
group :test, optional: true do
|
||||
gem 'rubocop', '~> 0.79.0'
|
||||
gem 'minitest', '~> 5.14.1'
|
||||
end
|
||||
|
@ -45,6 +45,7 @@ GEM
|
||||
rack-protection (2.0.8.1)
|
||||
rack
|
||||
rainbow (3.0.0)
|
||||
rake (13.0.6)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
redis (4.1.3)
|
||||
@ -93,8 +94,10 @@ DEPENDENCIES
|
||||
jwt (~> 2.2)
|
||||
locale (~> 2.1)
|
||||
loofah (~> 2.3)
|
||||
minitest (~> 5.14.1)
|
||||
nokogiri (~> 1.11)
|
||||
open4 (~> 1.3)
|
||||
rake (>= 12.3, < 14)
|
||||
rb-inotify (~> 0.10)
|
||||
redis (~> 4.1)
|
||||
resque (~> 2.0.0)
|
||||
|
@ -1,6 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'resque/tasks'
|
||||
require 'rake/testtask'
|
||||
|
||||
task 'resque:setup' => :environment do
|
||||
props = BigBlueButton.read_props
|
||||
@ -17,3 +18,9 @@ task :environment do
|
||||
require_relative 'lib/boot'
|
||||
require 'recordandplayback/workers'
|
||||
end
|
||||
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'test'
|
||||
t.libs << 'lib'
|
||||
t.test_files = FileList['test/**/test_*.rb']
|
||||
end
|
||||
|
@ -21,13 +21,14 @@
|
||||
|
||||
|
||||
require 'rubygems'
|
||||
require 'time'
|
||||
require 'nokogiri'
|
||||
require 'loofah'
|
||||
require 'set'
|
||||
|
||||
module BigBlueButton
|
||||
module Events
|
||||
|
||||
|
||||
# Get the total number of participants
|
||||
def self.get_num_participants(events)
|
||||
participants_ids = Set.new
|
||||
@ -75,31 +76,31 @@ module BigBlueButton
|
||||
external_meeting_id = metadata['meetingId'] if !metadata['meetingId'].nil?
|
||||
external_meeting_id
|
||||
end
|
||||
|
||||
|
||||
# Get the timestamp of the first event.
|
||||
def self.first_event_timestamp(events)
|
||||
first_event = events.at_xpath('/recording/event[position() = 1]')
|
||||
first_event['timestamp'].to_i if first_event && first_event.key?('timestamp')
|
||||
end
|
||||
|
||||
|
||||
# Get the timestamp of the last event.
|
||||
def self.last_event_timestamp(events)
|
||||
last_event = events.at_xpath('/recording/event[position() = last()]')
|
||||
last_event['timestamp'].to_i if last_event && last_event.key?('timestamp')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Determine if the start and stop event matched.
|
||||
def self.find_video_event_matched(start_events, stop)
|
||||
def self.find_video_event_matched(start_events, stop)
|
||||
BigBlueButton.logger.info("Task: Finding video events that match")
|
||||
start_events.each do |start|
|
||||
if (start[:stream] == stop[:stream])
|
||||
return start
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
# Get start video events
|
||||
|
||||
# Get start video events
|
||||
def self.get_start_video_events(events)
|
||||
start_events = []
|
||||
events.xpath("/recording/event[@eventname='StartWebcamShareEvent']").each do |start_event|
|
||||
@ -235,7 +236,7 @@ module BigBlueButton
|
||||
end
|
||||
|
||||
def self.get_stop_deskshare_events(events)
|
||||
BigBlueButton.logger.info("Task: Getting stop DESKSHARE events")
|
||||
BigBlueButton.logger.info("Task: Getting stop DESKSHARE events")
|
||||
stop_events = []
|
||||
events.xpath('/recording/event[@module="Deskshare" or (@module="bbb-webrtc-sfu" and @eventname="StopWebRTCDesktopShareEvent")]').each do |stop_event|
|
||||
case stop_event['eventname']
|
||||
@ -476,12 +477,134 @@ module BigBlueButton
|
||||
node['href'] = node['href'][6..-1] if node.name == 'a' && node['href'] && node['href'].start_with?('event:')
|
||||
end
|
||||
|
||||
def self.linkify( text )
|
||||
def self.linkify(text)
|
||||
html = Loofah.fragment(text)
|
||||
html.scrub!(@remove_link_event_prefix).scrub!(:strip).scrub!(:nofollow).scrub!(:unprintable)
|
||||
html.to_html
|
||||
end
|
||||
|
||||
# Build a map of internal user IDs to anonymized names. This can be used to anonymize users in
|
||||
# chat, cursor overlays, etc.
|
||||
def self.anonymous_user_map(events, moderators: false)
|
||||
viewer_count = 0
|
||||
moderator_count = 0
|
||||
|
||||
external_map = {}
|
||||
map = {}
|
||||
|
||||
events.xpath('/recording/event[@module="PARTICIPANT" and @eventname="ParticipantJoinEvent"]').each do |event|
|
||||
internal_id = event.at_xpath('./userId')&.content
|
||||
next if internal_id.nil?
|
||||
|
||||
external_id = event.at_xpath('./externalUserId')&.content || internal_id
|
||||
name = external_map.fetch(external_id) do
|
||||
role = event.at_xpath('./role').content
|
||||
new_name = \
|
||||
if role == 'MODERATOR' && moderators
|
||||
moderator_count += 1
|
||||
"Moderator #{moderator_count}"
|
||||
elsif role == 'MODERATOR'
|
||||
event.at_xpath('./name')&.content
|
||||
else
|
||||
viewer_count += 1
|
||||
"Viewer #{viewer_count}"
|
||||
end
|
||||
external_map[external_id] = new_name unless new_name.nil?
|
||||
end
|
||||
map[internal_id] = name unless name.nil?
|
||||
end
|
||||
|
||||
map
|
||||
end
|
||||
|
||||
# Get a list of chat events, with start/end time for segments and recording marks applied.
|
||||
# Optionally anonymizes chat participant names.
|
||||
# Reads the keys 'anonymize_chat' and 'anonymize_chat_moderators' from bbb_props, but allows
|
||||
# per-meeting override using the create meta params 'meta_bbb-anonymize-chat' and
|
||||
# 'meta_bbb-anonymize-chat-moderators'
|
||||
# Each event in the return value has the following properties:
|
||||
# in: 0-based milliseconds timestamp of when chat was sent
|
||||
# out: 0-based milliseconds timestamp of when chat was cleared (or nil if chat was never cleared)
|
||||
# sender_id: The internal user id of the sender (can be nil on really old BBB versions)
|
||||
# sender: The display name of the sender
|
||||
# message: The chat message, with link cleanup already applied
|
||||
# date: The real time of when the message was sent (if available) as a DateTime
|
||||
# text_color: The RGB color value of the chat message text as an integer (old BBB versions only)
|
||||
# avatar_color: The color of the user's avatar (initials) box (newer BBB versions only)
|
||||
def self.get_chat_events(events, start_time, end_time, bbb_props = {})
|
||||
BigBlueButton.logger.info('Getting chat events')
|
||||
|
||||
initial_timestamp = first_event_timestamp(events)
|
||||
start_time -= initial_timestamp
|
||||
end_time -= initial_timestamp
|
||||
|
||||
last_stop_timestamp = start_time
|
||||
offset = start_time
|
||||
# Recordings without status events are assumed to have been recorded from the beginning
|
||||
record = events.at_xpath('/recording/event[@eventname="RecordStatusEvent"]').nil?
|
||||
|
||||
# Load the anonymize settings; defaults from bigbluebutton.yml, override with meta params
|
||||
metadata = events.at_xpath('/recording/metadata')
|
||||
anonymize_senders = metadata['bbb-anonymize-chat'] unless metadata.nil?
|
||||
anonymize_senders = bbb_props['anonymize_chat'] if anonymize_senders.nil?
|
||||
anonymize_senders = anonymize_senders.to_s.casecmp?('true')
|
||||
anonymize_moderators = metadata['bbb-anonymize-chat-moderators'] unless metadata.nil?
|
||||
anonymize_moderators = bbb_props['anonymize_chat_moderators'] if anonymize_moderators.nil?
|
||||
anonymize_moderators = anonymize_moderators.to_s.casecmp?('true')
|
||||
|
||||
user_map = anonymize_senders ? anonymous_user_map(events, moderators: anonymize_moderators) : {}
|
||||
|
||||
chats = []
|
||||
events.xpath('/recording/event').each do |event|
|
||||
timestamp = event[:timestamp].to_i - initial_timestamp
|
||||
break if timestamp >= end_time
|
||||
|
||||
case [event[:module], event[:eventname]]
|
||||
when %w[CHAT PublicChatEvent]
|
||||
next if timestamp < start_time || !record
|
||||
|
||||
date = event.at_xpath('./date')&.content
|
||||
date = DateTime.iso8601(date) unless date.nil?
|
||||
sender_id = event.at_xpath('./senderId')&.content
|
||||
color = event.at_xpath('./color')&.content
|
||||
if color&.start_with?('#')
|
||||
avatar_color = color
|
||||
else
|
||||
text_color = color.to_i
|
||||
end
|
||||
|
||||
chats << {
|
||||
in: timestamp - offset,
|
||||
out: nil,
|
||||
sender_id: sender_id,
|
||||
sender: user_map.fetch(sender_id) { event.at_xpath('./sender').content },
|
||||
message: linkify(event.at_xpath('./message').content.strip),
|
||||
avatar_color: avatar_color,
|
||||
text_color: text_color,
|
||||
date: date,
|
||||
}
|
||||
when %w[CHAT ClearPublicChatEvent]
|
||||
next if timestamp < start_time
|
||||
|
||||
clear_timestamp = (record ? timestamp : last_stop_timestamp) - offset
|
||||
chats.each do |chat|
|
||||
chat[:out] = clear_timestamp if chat[:out].nil?
|
||||
end
|
||||
when %w[PARTICIPANT RecordStatusEvent]
|
||||
record = event.at_xpath('status').content == 'true'
|
||||
next if timestamp < start_time
|
||||
|
||||
if record
|
||||
offset += timestamp - last_stop_timestamp
|
||||
else
|
||||
last_stop_timestamp = timestamp
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
chats
|
||||
end
|
||||
|
||||
def self.get_record_status_events(events_xml)
|
||||
BigBlueButton.logger.info "Getting record status events"
|
||||
rec_events = []
|
||||
@ -496,8 +619,8 @@ module BigBlueButton
|
||||
BigBlueButton.logger.info "Getting external video events"
|
||||
external_videos_events = []
|
||||
events_xml.xpath("//event[@eventname='StartExternalVideoRecordEvent']").each do |event|
|
||||
s = {
|
||||
:timestamp => event['timestamp'].to_i,
|
||||
s = {
|
||||
:timestamp => event['timestamp'].to_i,
|
||||
:external_video_url => event.at_xpath("externalVideoUrl").text
|
||||
}
|
||||
external_videos_events << s
|
||||
@ -523,7 +646,7 @@ module BigBlueButton
|
||||
end
|
||||
rec_events.sort_by {|a| a[:timestamp]}
|
||||
end
|
||||
|
||||
|
||||
# Get events when the moderator wants the recording to start or stop
|
||||
def self.get_start_and_stop_external_video_events(events_xml)
|
||||
BigBlueButton.logger.info "Getting start and stop externalvideo events"
|
||||
@ -534,7 +657,7 @@ module BigBlueButton
|
||||
end
|
||||
external_video_events.sort_by {|a| a[:timestamp]}
|
||||
end
|
||||
|
||||
|
||||
# Match recording start and stop events
|
||||
def self.match_start_and_stop_rec_events(rec_events)
|
||||
BigBlueButton.logger.info ("Matching record events")
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,422 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<recording meeting_id="2a1de53edf0543d950056bf3c0d4d357eba3383f-1630607370684" bbb_version="2.1.0">
|
||||
<meeting id="2a1de53edf0543d950056bf3c0d4d357eba3383f-1630607370684" externalId="random-9678161_calvin_" name="random-9678161" breakout="false"/>
|
||||
<metadata bbb-anonymize-chat="true" isBreakout="false" meetingId="random-9678161_calvin_" meetingName="random-9678161"/>
|
||||
<event timestamp="1131799575" module="PRESENTATION" eventname="CreatePresentationPodEvent">
|
||||
<currentPresenter/>
|
||||
<timestampUTC>1630607370704</timestampUTC>
|
||||
<podId>DEFAULT_PRESENTATION_POD</podId>
|
||||
<date>2021-09-02T14:29:30.704-04</date>
|
||||
</event>
|
||||
<event timestamp="1131799900" module="PAD" eventname="AddPadEvent">
|
||||
<timestampUTC>1630607371029</timestampUTC>
|
||||
<date>2021-09-02T14:29:31.029-04</date>
|
||||
<padId>[2]cfe107fd5780210103d9d4017f8c751d5594</padId>
|
||||
</event>
|
||||
<event timestamp="1131803050" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<name>User 7520456</name>
|
||||
<timestampUTC>1630607374179</timestampUTC>
|
||||
<role>MODERATOR</role>
|
||||
<date>2021-09-02T14:29:34.179-04</date>
|
||||
<externalUserId>w_jw2fcjeovwa6</externalUserId>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
</event>
|
||||
<event timestamp="1131803051" module="PARTICIPANT" eventname="AssignPresenterEvent">
|
||||
<name>User 7520456</name>
|
||||
<timestampUTC>1630607374180</timestampUTC>
|
||||
<userid>w_jw2fcjeovwa6</userid>
|
||||
<assignedBy>w_jw2fcjeovwa6</assignedBy>
|
||||
<date>2021-09-02T14:29:34.180-04</date>
|
||||
</event>
|
||||
<event timestamp="1131803066" module="PARTICIPANT" eventname="AssignPresenterEvent">
|
||||
<name>User 7520456</name>
|
||||
<timestampUTC>1630607374195</timestampUTC>
|
||||
<userid>w_jw2fcjeovwa6</userid>
|
||||
<assignedBy>w_jw2fcjeovwa6</assignedBy>
|
||||
<date>2021-09-02T14:29:34.195-04</date>
|
||||
</event>
|
||||
<event timestamp="1131803067" module="PRESENTATION" eventname="SetPresenterInPodEvent">
|
||||
<timestampUTC>1630607374196</timestampUTC>
|
||||
<podId>DEFAULT_PRESENTATION_POD</podId>
|
||||
<date>2021-09-02T14:29:34.196-04</date>
|
||||
<nextPresenterId>w_jw2fcjeovwa6</nextPresenterId>
|
||||
</event>
|
||||
<event timestamp="1131803071" module="PARTICIPANT" eventname="AssignPresenterEvent">
|
||||
<name>User 7520456</name>
|
||||
<timestampUTC>1630607374200</timestampUTC>
|
||||
<userid>w_jw2fcjeovwa6</userid>
|
||||
<assignedBy>w_jw2fcjeovwa6</assignedBy>
|
||||
<date>2021-09-02T14:29:34.200-04</date>
|
||||
</event>
|
||||
<event timestamp="1131803072" module="PRESENTATION" eventname="SetPresenterInPodEvent">
|
||||
<timestampUTC>1630607374201</timestampUTC>
|
||||
<podId>DEFAULT_PRESENTATION_POD</podId>
|
||||
<date>2021-09-02T14:29:34.201-04</date>
|
||||
<nextPresenterId>w_jw2fcjeovwa6</nextPresenterId>
|
||||
</event>
|
||||
<event timestamp="1131805474" module="PRESENTATION" eventname="ConversionCompletedEvent">
|
||||
<originalFilename>default.pdf</originalFilename>
|
||||
<timestampUTC>1630607376603</timestampUTC>
|
||||
<presentationName>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentationName>
|
||||
<podId>DEFAULT_PRESENTATION_POD</podId>
|
||||
<date>2021-09-02T14:29:36.603-04</date>
|
||||
</event>
|
||||
<event timestamp="1131805477" module="PRESENTATION" eventname="SharePresentationEvent">
|
||||
<timestampUTC>1630607376606</timestampUTC>
|
||||
<presentationName>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentationName>
|
||||
<podId>DEFAULT_PRESENTATION_POD</podId>
|
||||
<share>true</share>
|
||||
<date>2021-09-02T14:29:36.606-04</date>
|
||||
</event>
|
||||
<event timestamp="1131805479" module="PRESENTATION" eventname="SetPresentationDownloadable">
|
||||
<timestampUTC>1630607376608</timestampUTC>
|
||||
<presentationName>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentationName>
|
||||
<podId>DEFAULT_PRESENTATION_POD</podId>
|
||||
<date>2021-09-02T14:29:36.608-04</date>
|
||||
<downloadable>false</downloadable>
|
||||
</event>
|
||||
<event timestamp="1131824162" module="VOICE" eventname="ParticipantJoinedEvent">
|
||||
<participant>w_jw2fcjeovwa6</participant>
|
||||
<timestampUTC>1630607395291</timestampUTC>
|
||||
<bridge>578447737</bridge>
|
||||
<callername>User 7520456</callername>
|
||||
<talking>false</talking>
|
||||
<callernumber>w_jw2fcjeovwa6_1-bbbID-User 7520456</callernumber>
|
||||
<date>2021-09-02T14:29:55.291-04</date>
|
||||
<muted>false</muted>
|
||||
</event>
|
||||
<event timestamp="1131824186" module="VOICE" eventname="StartRecordingEvent">
|
||||
<filename>/var/freeswitch/meetings/2a1de53edf0543d950056bf3c0d4d357eba3383f-1630607370684-1131824162.opus</filename>
|
||||
<bridge>578447737</bridge>
|
||||
<timestampUTC>1630607395314</timestampUTC>
|
||||
<date>2021-09-02T14:29:55.314-04</date>
|
||||
<recordingTimestamp>1131824184</recordingTimestamp>
|
||||
</event>
|
||||
<event timestamp="1131824226" module="VOICE" eventname="ParticipantTalkingEvent">
|
||||
<participant>w_jw2fcjeovwa6</participant>
|
||||
<timestampUTC>1630607395355</timestampUTC>
|
||||
<bridge>578447737</bridge>
|
||||
<talking>true</talking>
|
||||
<date>2021-09-02T14:29:55.355-04</date>
|
||||
</event>
|
||||
<event timestamp="1131825122" module="VOICE" eventname="ParticipantMutedEvent">
|
||||
<participant>w_jw2fcjeovwa6</participant>
|
||||
<timestampUTC>1630607396250</timestampUTC>
|
||||
<bridge>578447737</bridge>
|
||||
<date>2021-09-02T14:29:56.250-04</date>
|
||||
<muted>true</muted>
|
||||
</event>
|
||||
<event timestamp="1131825327" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607396456</timestampUTC>
|
||||
<xOffset>42.81167030334473</xOffset>
|
||||
<date>2021-09-02T14:29:56.456-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>87.12742558232061</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131825473" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607396602</timestampUTC>
|
||||
<xOffset>-62.891248067220054</xOffset>
|
||||
<date>2021-09-02T14:29:56.602-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>-60.94213415075232</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131834887" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607406015</timestampUTC>
|
||||
<xOffset>34.58885828653971</xOffset>
|
||||
<date>2021-09-02T14:30:06.015-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>75.1026690447772</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131835039" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607406168</timestampUTC>
|
||||
<xOffset>-62.891248067220054</xOffset>
|
||||
<date>2021-09-02T14:30:06.168-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>-60.94213415075232</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131839891" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607411020</timestampUTC>
|
||||
<xOffset>40.557028452555336</xOffset>
|
||||
<date>2021-09-02T14:30:11.020-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>0.8321106875384296</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131840041" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607411169</timestampUTC>
|
||||
<xOffset>-62.891248067220054</xOffset>
|
||||
<date>2021-09-02T14:30:11.169-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>-60.94213415075232</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131841537" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607412665</timestampUTC>
|
||||
<xOffset>50.63660303751628</xOffset>
|
||||
<date>2021-09-02T14:30:12.665-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>9.084394949453849</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131841691" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607412819</timestampUTC>
|
||||
<xOffset>-62.891248067220054</xOffset>
|
||||
<date>2021-09-02T14:30:12.819-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>-60.94213415075232</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131841840" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607412969</timestampUTC>
|
||||
<xOffset>36.57824834187826</xOffset>
|
||||
<date>2021-09-02T14:30:12.969-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>33.60546818485967</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131842003" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607413131</timestampUTC>
|
||||
<xOffset>-62.891248067220054</xOffset>
|
||||
<date>2021-09-02T14:30:13.131-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>-60.94213415075232</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131882243" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<name>(guest) Calvin</name>
|
||||
<timestampUTC>1630607453372</timestampUTC>
|
||||
<role>VIEWER</role>
|
||||
<date>2021-09-02T14:30:53.372-04</date>
|
||||
<externalUserId>3ff859e3-1c2e-48e9-860d-cf230648cfca</externalUserId>
|
||||
<userId>w_tvumguamxhhs</userId>
|
||||
</event>
|
||||
<event timestamp="1131885821" module="VOICE" eventname="ParticipantJoinedEvent">
|
||||
<participant>w_tvumguamxhhs</participant>
|
||||
<timestampUTC>1630607456950</timestampUTC>
|
||||
<bridge>578447737</bridge>
|
||||
<callername>(guest) Calvin</callername>
|
||||
<talking>false</talking>
|
||||
<callernumber>(guest) Calvin</callernumber>
|
||||
<date>2021-09-02T14:30:56.950-04</date>
|
||||
<muted>true</muted>
|
||||
</event>
|
||||
<event timestamp="1131895190" module="CHAT" eventname="PublicChatEvent">
|
||||
<timestampUTC>1630607466319</timestampUTC>
|
||||
<color>#6a1b9a</color>
|
||||
<senderId>w_jw2fcjeovwa6</senderId>
|
||||
<date>2021-09-02T14:31:06.319-04</date>
|
||||
<sender>User 7520456</sender>
|
||||
<message>Hello, moderator chat message!</message>
|
||||
</event>
|
||||
<event timestamp="1131905701" module="CHAT" eventname="PublicChatEvent">
|
||||
<timestampUTC>1630607476829</timestampUTC>
|
||||
<color>#4a148c</color>
|
||||
<senderId>w_tvumguamxhhs</senderId>
|
||||
<date>2021-09-02T14:31:16.829-04</date>
|
||||
<sender>(guest) Calvin</sender>
|
||||
<message>Hello, guest chat message!</message>
|
||||
</event>
|
||||
<event timestamp="1131908051" module="CHAT" eventname="PublicChatEvent">
|
||||
<timestampUTC>1630607479180</timestampUTC>
|
||||
<color>#4a148c</color>
|
||||
<senderId>w_tvumguamxhhs</senderId>
|
||||
<date>2021-09-02T14:31:19.180-04</date>
|
||||
<sender>(guest) Calvin</sender>
|
||||
<message>yay!</message>
|
||||
</event>
|
||||
<event timestamp="1131949647" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607520776</timestampUTC>
|
||||
<xOffset>10.185674826304119</xOffset>
|
||||
<date>2021-09-02T14:32:00.776-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>96.79438838252314</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131949798" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607520927</timestampUTC>
|
||||
<xOffset>14.297080039978027</xOffset>
|
||||
<date>2021-09-02T14:32:00.927-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>90.1925602665654</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131949893" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607521022</timestampUTC>
|
||||
<xOffset>14.297080039978027</xOffset>
|
||||
<date>2021-09-02T14:32:01.022-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>89.95677806712963</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131950258" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607521387</timestampUTC>
|
||||
<xOffset>14.297080039978027</xOffset>
|
||||
<date>2021-09-02T14:32:01.387-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>90.1925602665654</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131950408" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607521537</timestampUTC>
|
||||
<xOffset>-62.891248067220054</xOffset>
|
||||
<date>2021-09-02T14:32:01.537-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>-60.94213415075232</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131955635" module="CHAT" eventname="ClearPublicChatEvent">
|
||||
<timestampUTC>1630607526763</timestampUTC>
|
||||
<date>2021-09-02T14:32:06.763-04</date>
|
||||
</event>
|
||||
<event timestamp="1131964123" module="CHAT" eventname="PublicChatEvent">
|
||||
<timestampUTC>1630607535252</timestampUTC>
|
||||
<color>#6a1b9a</color>
|
||||
<senderId>w_jw2fcjeovwa6</senderId>
|
||||
<date>2021-09-02T14:32:15.252-04</date>
|
||||
<sender>User 7520456</sender>
|
||||
<message>Chat was cleared</message>
|
||||
</event>
|
||||
<event timestamp="1131994645" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607565774</timestampUTC>
|
||||
<xOffset>43.34217389424642</xOffset>
|
||||
<date>2021-09-02T14:32:45.774-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>96.55861183449073</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131994767" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607565896</timestampUTC>
|
||||
<xOffset>-62.891248067220054</xOffset>
|
||||
<date>2021-09-02T14:32:45.896-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>-60.94213415075232</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131997197" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607568326</timestampUTC>
|
||||
<xOffset>32.20158894856771</xOffset>
|
||||
<date>2021-09-02T14:32:48.326-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>96.55861183449073</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131997346" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607568475</timestampUTC>
|
||||
<xOffset>-62.891248067220054</xOffset>
|
||||
<date>2021-09-02T14:32:48.475-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>-60.94213415075232</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1131999450" module="PARTICIPANT" eventname="RecordStatusEvent">
|
||||
<timestampUTC>1630607570579</timestampUTC>
|
||||
<date>2021-09-02T14:32:50.579-04</date>
|
||||
<status>true</status>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
</event>
|
||||
<event timestamp="1131999466" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607570595</timestampUTC>
|
||||
<xOffset>13.501324653625488</xOffset>
|
||||
<date>2021-09-02T14:32:50.595-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>59.77699562355324</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1132001481" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607572610</timestampUTC>
|
||||
<xOffset>13.103446960449219</xOffset>
|
||||
<date>2021-09-02T14:32:52.610-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>59.77699562355324</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1132001799" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607572927</timestampUTC>
|
||||
<xOffset>-62.891248067220054</xOffset>
|
||||
<date>2021-09-02T14:32:52.927-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>-60.94213415075232</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1132011085" module="CHAT" eventname="PublicChatEvent">
|
||||
<timestampUTC>1630607582214</timestampUTC>
|
||||
<color>#4a148c</color>
|
||||
<senderId>w_tvumguamxhhs</senderId>
|
||||
<date>2021-09-02T14:33:02.214-04</date>
|
||||
<sender>(guest) Calvin</sender>
|
||||
<message>whoops, forgot to start recording…</message>
|
||||
</event>
|
||||
<event timestamp="1132049253" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607620382</timestampUTC>
|
||||
<xOffset>36.180369059244796</xOffset>
|
||||
<date>2021-09-02T14:33:40.382-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>97.9732824254919</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1132049403" module="WHITEBOARD" eventname="WhiteboardCursorMoveEvent">
|
||||
<timestampUTC>1630607620531</timestampUTC>
|
||||
<xOffset>-62.891248067220054</xOffset>
|
||||
<date>2021-09-02T14:33:40.531-04</date>
|
||||
<whiteboardId>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702/1</whiteboardId>
|
||||
<pageNumber>0</pageNumber>
|
||||
<userId>w_jw2fcjeovwa6</userId>
|
||||
<yOffset>-60.94213415075232</yOffset>
|
||||
<presentation>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1630607370702</presentation>
|
||||
</event>
|
||||
<event timestamp="1132053637" module="PARTICIPANT" eventname="EndAndKickAllEvent">
|
||||
<timestampUTC>1630607624766</timestampUTC>
|
||||
<reason>ENDED_AFTER_USER_LOGGED_OUT</reason>
|
||||
<date>2021-09-02T14:33:44.766-04</date>
|
||||
</event>
|
||||
</recording>
|
344
record-and-playback/core/resources/raw/chat_0_9.xml
Normal file
344
record-and-playback/core/resources/raw/chat_0_9.xml
Normal file
@ -0,0 +1,344 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<recording meeting_id="afa22bf4e2a55835006a0016776f700dcf8e981e-1630339972856" bbb_version="0.9.0">
|
||||
<meeting
|
||||
id="afa22bf4e2a55835006a0016776f700dcf8e981e-1630339972856"
|
||||
externalId="chat_0_9" name="Chat 0.9 Test"
|
||||
breakout="false"/>
|
||||
<metadata
|
||||
meetingName="Chat 0.9 Test"
|
||||
meetingId="chat_0_9"
|
||||
isBreakout="false"/>
|
||||
<event timestamp="1061316615" module="PRESENTATION" eventname="SharePresentationEvent">
|
||||
<presentationName>d2d9a672040fbde2a47a10bf6c37b6a4b5ae187f-1503524575790</presentationName>
|
||||
<share>true</share>
|
||||
<originalFilename>default.pdf</originalFilename>
|
||||
</event>
|
||||
<event timestamp="1061329979" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<name>Marinda Collins</name>
|
||||
<role>MODERATOR</role>
|
||||
<userId>9izxq660i7vr_1</userId>
|
||||
<externalUserId>1000</externalUserId>
|
||||
</event>
|
||||
<event timestamp="1061397065" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<userId>vvyha6umxoyt_1</userId>
|
||||
<externalUserId>1001</externalUserId>
|
||||
<name>Phelix Fishman</name>
|
||||
<role>VIEWER</role>
|
||||
</event>
|
||||
<event timestamp="1061511972" module="PARTICIPANT" eventname="RecordStatusEvent">
|
||||
<userId>9izxq660i7vr_1</userId>
|
||||
<status>true</status>
|
||||
</event>
|
||||
<event timestamp="1061536072" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<role>VIEWER</role>
|
||||
<externalUserId>1002</externalUserId>
|
||||
<userId>hs7iskkr7xrt_1</userId>
|
||||
<name>Isaías Seelen</name>
|
||||
</event>
|
||||
<event timestamp="1061574575" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<role>VIEWER</role>
|
||||
<userId>7m940cic73r3_1</userId>
|
||||
<name>Mireia Castell</name>
|
||||
<externalUserId>1003</externalUserId>
|
||||
</event>
|
||||
<event timestamp="1061629575" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<role>VIEWER</role>
|
||||
<externalUserId>1004</externalUserId>
|
||||
<userId>tgfbj6f828sp_1</userId>
|
||||
<name>Liborius Hayes</name>
|
||||
</event>
|
||||
<event timestamp="1061703579" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<role>VIEWER</role>
|
||||
<externalUserId>1005</externalUserId>
|
||||
<userId>bepguk6d7dza_1</userId>
|
||||
<name>Eva Aquino</name>
|
||||
</event>
|
||||
<event timestamp="1061749302" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<role>VIEWER</role>
|
||||
<externalUserId>1006</externalUserId>
|
||||
<userId>66ntqzexswc2_1</userId>
|
||||
<name>Rodge Palazzo</name>
|
||||
</event>
|
||||
<event timestamp="1061825270" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<externalUserId>1007</externalUserId>
|
||||
<role>VIEWER</role>
|
||||
<name>Elias Stablum</name>
|
||||
<userId>0q1hkmla9asu_1</userId>
|
||||
</event>
|
||||
<event timestamp="1061881172" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<userId>yyynfpyca09g_1</userId>
|
||||
<externalUserId>1008</externalUserId>
|
||||
<role>VIEWER</role>
|
||||
<name>Evelina Keller</name>
|
||||
</event>
|
||||
<event timestamp="1061933105" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<userId>dmsj3897dwss_1</userId>
|
||||
<role>VIEWER</role>
|
||||
<name>Xhesika De Lange</name>
|
||||
<externalUserId>1009</externalUserId>
|
||||
</event>
|
||||
<event timestamp="1061952342" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<name>Nimue Harlan</name>
|
||||
<role>VIEWER</role>
|
||||
<externalUserId>1010</externalUserId>
|
||||
<userId>42dnty7rovjt_1</userId>
|
||||
</event>
|
||||
<event timestamp="1061962737" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<name>Elpidio O'Gorman</name>
|
||||
<role>VIEWER</role>
|
||||
<externalUserId>1011</externalUserId>
|
||||
<userId>7ur69btts657_1</userId>
|
||||
</event>
|
||||
<event timestamp="1061998179" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>dmsj3897dwss_1</userId>
|
||||
</event>
|
||||
<event timestamp="1062008158" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>66ntqzexswc2_1</userId>
|
||||
</event>
|
||||
<event timestamp="1062013094" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<externalUserId>1012</externalUserId>
|
||||
<role>VIEWER</role>
|
||||
<userId>23uydbo9nauq_1</userId>
|
||||
<name>Asa Darby</name>
|
||||
</event>
|
||||
<event timestamp="1062017073" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<externalUserId>1006</externalUserId>
|
||||
<userId>12ipastd9pw1_1</userId>
|
||||
<role>VIEWER</role>
|
||||
<name>Rodge Palazzo</name>
|
||||
</event>
|
||||
<event timestamp="1062026555" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<name>Xhesika De Lange</name>
|
||||
<role>VIEWER</role>
|
||||
<externalUserId>1009</externalUserId>
|
||||
<userId>ainnu65fiycz_1</userId>
|
||||
</event>
|
||||
<event timestamp="1062058796" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<externalUserId>1013</externalUserId>
|
||||
<role>VIEWER</role>
|
||||
<name>Arethusa Mann</name>
|
||||
<userId>j73nq5k8xcaa_1</userId>
|
||||
</event>
|
||||
<event timestamp="1062142085" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<name>Ninel Mac Ruaidhrí</name>
|
||||
<role>VIEWER</role>
|
||||
<userId>nfuklna24flg_1</userId>
|
||||
<externalUserId>1014</externalUserId>
|
||||
</event>
|
||||
<event timestamp="1062159696" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>ainnu65fiycz_1</userId>
|
||||
</event>
|
||||
<event timestamp="1062170527" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<externalUserId>1009</externalUserId>
|
||||
<name>Xhesika De Lange</name>
|
||||
<role>VIEWER</role>
|
||||
<userId>2dc8jctma0nj_1</userId>
|
||||
</event>
|
||||
<event timestamp="1062260997" module="CHAT" eventname="PublicChatEvent">
|
||||
<sender>Xhesika De Lange</sender>
|
||||
<senderId>2dc8jctma0nj_1</senderId>
|
||||
<message>
|
||||
<![CDATA[Public chat 1]]>
|
||||
</message>
|
||||
<color>0</color>
|
||||
</event>
|
||||
<event timestamp="1062483994" module="CHAT" eventname="PublicChatEvent">
|
||||
<color>0</color>
|
||||
<senderId>23uydbo9nauq_1</senderId>
|
||||
<message>
|
||||
<![CDATA[Public chat 2]]>
|
||||
</message>
|
||||
<sender>Asa Darby</sender>
|
||||
</event>
|
||||
<event timestamp="1062500000" module="CHAT" eventname="ClearPublicChatEvent">
|
||||
</event>
|
||||
<event timestamp="1062914576" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>j73nq5k8xcaa_1</userId>
|
||||
</event>
|
||||
<event timestamp="1063007465" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<userId>fzlsahcijxo4_1</userId>
|
||||
<externalUserId>1013</externalUserId>
|
||||
<role>VIEWER</role>
|
||||
<name>Arethusa Mann</name>
|
||||
</event>
|
||||
<event timestamp="1063309296" module="CHAT" eventname="PublicChatEvent">
|
||||
<color>0</color>
|
||||
<senderId>hs7iskkr7xrt_1</senderId>
|
||||
<message>
|
||||
<![CDATA[Public chat 3]]>
|
||||
</message>
|
||||
<sender>Isaías Seelen</sender>
|
||||
</event>
|
||||
<event timestamp="1064118099" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>fzlsahcijxo4_1</userId>
|
||||
</event>
|
||||
<event timestamp="1064118099" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<userId>fzlsahcijxo4_1</userId>
|
||||
<externalUserId>1013</externalUserId>
|
||||
<name>Arethusa Mann</name>
|
||||
<role>VIEWER</role>
|
||||
</event>
|
||||
<event timestamp="1064123456" module="PARTICIPANT" eventname="RecordStatusEvent">
|
||||
<userId>9izxq660i7vr_1</userId>
|
||||
<status>false</status>
|
||||
</event>
|
||||
<event timestamp="1064181418" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>hs7iskkr7xrt_1</userId>
|
||||
</event>
|
||||
<event timestamp="1064370077" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<externalUserId>1002</externalUserId>
|
||||
<role>VIEWER</role>
|
||||
<userId>y096bmb53yu5_1</userId>
|
||||
<name>Isaías Seelen</name>
|
||||
</event>
|
||||
<event timestamp="1064621935" module="CHAT" eventname="PublicChatEvent">
|
||||
<color>0</color>
|
||||
<senderId>nfuklna24flg_1</senderId>
|
||||
<message>
|
||||
<![CDATA[Public chat 4]]>
|
||||
</message>
|
||||
<sender>Ninel Mac Ruaidhrí</sender>
|
||||
</event>
|
||||
<event timestamp="1064635147" module="CHAT" eventname="PublicChatEvent">
|
||||
<senderId>bepguk6d7dza_1</senderId>
|
||||
<sender>Eva Aquino</sender>
|
||||
<message>
|
||||
<![CDATA[Public chat 5]]>
|
||||
</message>
|
||||
<color>0</color>
|
||||
</event>
|
||||
<event timestamp="1064645678" module="PARTICIPANT" eventname="RecordStatusEvent">
|
||||
<userId>9izxq660i7vr_1</userId>
|
||||
<status>true</status>
|
||||
</event>
|
||||
<event timestamp="1064656291" module="CHAT" eventname="PublicChatEvent">
|
||||
<sender>Elias Stablum</sender>
|
||||
<senderId>0q1hkmla9asu_1</senderId>
|
||||
<color>0</color>
|
||||
<message>
|
||||
<![CDATA[Public chat 6]]>
|
||||
</message>
|
||||
</event>
|
||||
<event timestamp="1064660118" module="CHAT" eventname="PublicChatEvent">
|
||||
<senderId>fzlsahcijxo4_1</senderId>
|
||||
<message>
|
||||
<![CDATA[Public chat 7]]>
|
||||
</message>
|
||||
<sender>Arethusa Mann</sender>
|
||||
<color>0</color>
|
||||
</event>
|
||||
<event timestamp="1064669521" module="CHAT" eventname="PublicChatEvent">
|
||||
<message>
|
||||
<![CDATA[Public chat 8]]>
|
||||
</message>
|
||||
<senderId>nfuklna24flg_1</senderId>
|
||||
<sender>Ninel Mac Ruaidhrí</sender>
|
||||
<color>0</color>
|
||||
</event>
|
||||
<event timestamp="1064671034" module="CHAT" eventname="PublicChatEvent">
|
||||
<message>
|
||||
<![CDATA[Public chat 9]]>
|
||||
</message>
|
||||
<color>0</color>
|
||||
<sender>Mireia Castell</sender>
|
||||
<senderId>7m940cic73r3_1</senderId>
|
||||
</event>
|
||||
<event timestamp="1064679602" module="CHAT" eventname="PublicChatEvent">
|
||||
<sender>Ninel Mac Ruaidhrí</sender>
|
||||
<message>
|
||||
<![CDATA[Public chat 10]]>
|
||||
</message>
|
||||
<color>0</color>
|
||||
<senderId>nfuklna24flg_1</senderId>
|
||||
</event>
|
||||
<event timestamp="1066752701" module="CHAT" eventname="PublicChatEvent">
|
||||
<sender>Xhesika De Lange</sender>
|
||||
<color>0</color>
|
||||
<senderId>2dc8jctma0nj_1</senderId>
|
||||
<message>
|
||||
<![CDATA[Public chat 11]]>
|
||||
</message>
|
||||
</event>
|
||||
<event timestamp="1066777963" module="CHAT" eventname="PublicChatEvent">
|
||||
<sender>Arethusa Mann</sender>
|
||||
<senderId>fzlsahcijxo4_1</senderId>
|
||||
<color>0</color>
|
||||
<message>
|
||||
<![CDATA[Public chat 12]]>
|
||||
</message>
|
||||
</event>
|
||||
<event timestamp="1066909573" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<userId>y096bmb53yu5_2</userId>
|
||||
<role>VIEWER</role>
|
||||
<name>Isaías Seelen</name>
|
||||
<externalUserId>1002</externalUserId>
|
||||
</event>
|
||||
<event timestamp="1066966371" module="CHAT" eventname="PublicChatEvent">
|
||||
<message>
|
||||
<![CDATA[Public chat 13]]>
|
||||
</message>
|
||||
<color>0</color>
|
||||
<senderId>2dc8jctma0nj_1</senderId>
|
||||
<sender>Xhesika De Lange</sender>
|
||||
</event>
|
||||
<event timestamp="1069500636" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>0q1hkmla9asu_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069502806" module="PARTICIPANT" eventname="ParticipantJoinEvent">
|
||||
<role>VIEWER</role>
|
||||
<externalUserId>1008</externalUserId>
|
||||
<userId>yyynfpyca09g_1</userId>
|
||||
<name>Evelina Keller</name>
|
||||
</event>
|
||||
<event timestamp="1069502545" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>nfuklna24flg_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069502806" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>yyynfpyca09g_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069504995" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>2dc8jctma0nj_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069505733" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>bepguk6d7dza_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069507663" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>fzlsahcijxo4_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069508668" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>7ur69btts657_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069509022" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>23uydbo9nauq_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069512636" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>12ipastd9pw1_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069514445" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>7m940cic73r3_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069595144" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>42dnty7rovjt_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069686925" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>vvyha6umxoyt_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069700912" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>y096bmb53yu5_2</userId>
|
||||
</event>
|
||||
<event timestamp="1069717589" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>tgfbj6f828sp_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069722053" module="PARTICIPANT" eventname="RecordStatusEvent">
|
||||
<userId>9izxq660i7vr_1</userId>
|
||||
<status>false</status>
|
||||
</event>
|
||||
<event timestamp="1069746114" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>9izxq660i7vr_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069802390" module="PARTICIPANT" eventname="ParticipantLeftEvent">
|
||||
<userId>yyynfpyca09g_1</userId>
|
||||
</event>
|
||||
<event timestamp="1069897986" module="PARTICIPANT" eventname="EndAndKickAllEvent">
|
||||
</event>
|
||||
</recording>
|
@ -28,6 +28,16 @@ redis_port: 6379
|
||||
# and have another script process it.
|
||||
store_recording_status: false
|
||||
|
||||
# Whether to anonymize the sender of chat messages in the processed
|
||||
# recordings. The settings here are the defaults; they can be overridden
|
||||
# by passing meta parameters on the meeting create call.
|
||||
# meta param: meta_bbb-anonymize-chat (true/false)
|
||||
anonymize_chat: false
|
||||
# By default only names of viewers are anonymized - if you would also
|
||||
# like to anonymize moderators, you can set this to true:
|
||||
# meta param: meta_bbb-anonymize-chat-moderators (true/false)
|
||||
anonymize_chat_moderators: false
|
||||
|
||||
# Sequence of recording steps. Keys are the current step, values
|
||||
# are the next step(s). Examples:
|
||||
# current_step: next_step
|
||||
|
@ -0,0 +1,273 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'minitest/autorun'
|
||||
require 'nokogiri'
|
||||
|
||||
require 'recordandplayback'
|
||||
|
||||
class TestEvents < Minitest::Test
|
||||
def setup
|
||||
@events_legacy = File.open('resources/raw/1b199e88-7df7-4842-a5f1-0e84b781c5c8/events.xml') do |io|
|
||||
Nokogiri::XML(io)
|
||||
end
|
||||
@events_chat09 = File.open('resources/raw/chat_0_9.xml') do |io|
|
||||
Nokogiri::XML(io)
|
||||
end
|
||||
@events_devcall = File.open('resources/raw/183f0bf3a0982a127bdb8161e0c44eb696b3e75c-1630430006889/events.xml') do |io|
|
||||
Nokogiri::XML(io)
|
||||
end
|
||||
@events_meta_edt = File.open('resources/raw/2a1de53edf0543d950056bf3c0d4d357eba3383f-1630607370684/events.xml') do |io|
|
||||
Nokogiri::XML(io)
|
||||
end
|
||||
end
|
||||
|
||||
def test_anonymous_user_map_legacy
|
||||
map = BigBlueButton::Events.anonymous_user_map(@events_legacy)
|
||||
assert_empty(map)
|
||||
end
|
||||
|
||||
def test_anonymous_user_map_legacy_no_viewer_only
|
||||
map = BigBlueButton::Events.anonymous_user_map(@events_legacy, moderators: true)
|
||||
assert_equal(1, map.length)
|
||||
assert_equal('Moderator 1', map['1'])
|
||||
end
|
||||
|
||||
def test_anonymous_user_map_bbb_0_9
|
||||
map = BigBlueButton::Events.anonymous_user_map(@events_chat09)
|
||||
assert_equal(21, map.length)
|
||||
assert_equal('Marinda Collins', map['9izxq660i7vr_1']) # Moderator
|
||||
assert_equal('Viewer 1', map['vvyha6umxoyt_1'])
|
||||
assert_equal('Viewer 2', map['hs7iskkr7xrt_1'])
|
||||
assert_equal('Viewer 3', map['7m940cic73r3_1'])
|
||||
assert_equal('Viewer 4', map['tgfbj6f828sp_1'])
|
||||
assert_equal('Viewer 5', map['bepguk6d7dza_1'])
|
||||
assert_equal('Viewer 6', map['66ntqzexswc2_1'])
|
||||
assert_equal('Viewer 7', map['0q1hkmla9asu_1'])
|
||||
assert_equal('Viewer 8', map['yyynfpyca09g_1'])
|
||||
assert_equal('Viewer 9', map['dmsj3897dwss_1'])
|
||||
assert_equal('Viewer 10', map['42dnty7rovjt_1'])
|
||||
assert_equal('Viewer 11', map['7ur69btts657_1'])
|
||||
assert_equal('Viewer 12', map['23uydbo9nauq_1'])
|
||||
assert_equal('Viewer 6', map['12ipastd9pw1_1'])
|
||||
assert_equal('Viewer 9', map['ainnu65fiycz_1'])
|
||||
assert_equal('Viewer 13', map['j73nq5k8xcaa_1'])
|
||||
assert_equal('Viewer 14', map['nfuklna24flg_1'])
|
||||
assert_equal('Viewer 9', map['2dc8jctma0nj_1'])
|
||||
assert_equal('Viewer 13', map['fzlsahcijxo4_1'])
|
||||
assert_equal('Viewer 2', map['y096bmb53yu5_1'])
|
||||
assert_equal('Viewer 2', map['y096bmb53yu5_2'])
|
||||
assert_equal('Viewer 8', map['yyynfpyca09g_1'])
|
||||
end
|
||||
|
||||
def test_anonymous_user_map_bbb_0_9_no_viewer_only
|
||||
map = BigBlueButton::Events.anonymous_user_map(@events_chat09, moderators: true)
|
||||
assert_equal(21, map.length)
|
||||
assert_equal('Moderator 1', map['9izxq660i7vr_1'])
|
||||
assert_equal('Viewer 1', map['vvyha6umxoyt_1'])
|
||||
assert_equal('Viewer 2', map['hs7iskkr7xrt_1'])
|
||||
assert_equal('Viewer 3', map['7m940cic73r3_1'])
|
||||
assert_equal('Viewer 4', map['tgfbj6f828sp_1'])
|
||||
assert_equal('Viewer 5', map['bepguk6d7dza_1'])
|
||||
assert_equal('Viewer 6', map['66ntqzexswc2_1'])
|
||||
assert_equal('Viewer 7', map['0q1hkmla9asu_1'])
|
||||
assert_equal('Viewer 8', map['yyynfpyca09g_1'])
|
||||
assert_equal('Viewer 9', map['dmsj3897dwss_1'])
|
||||
assert_equal('Viewer 10', map['42dnty7rovjt_1'])
|
||||
assert_equal('Viewer 11', map['7ur69btts657_1'])
|
||||
assert_equal('Viewer 12', map['23uydbo9nauq_1'])
|
||||
assert_equal('Viewer 6', map['12ipastd9pw1_1'])
|
||||
assert_equal('Viewer 9', map['ainnu65fiycz_1'])
|
||||
assert_equal('Viewer 13', map['j73nq5k8xcaa_1'])
|
||||
assert_equal('Viewer 14', map['nfuklna24flg_1'])
|
||||
assert_equal('Viewer 9', map['2dc8jctma0nj_1'])
|
||||
assert_equal('Viewer 13', map['fzlsahcijxo4_1'])
|
||||
assert_equal('Viewer 2', map['y096bmb53yu5_1'])
|
||||
assert_equal('Viewer 2', map['y096bmb53yu5_2'])
|
||||
assert_equal('Viewer 8', map['yyynfpyca09g_1'])
|
||||
end
|
||||
|
||||
def test_get_chat_events_legacy
|
||||
start_time = BigBlueButton::Events.first_event_timestamp(@events_legacy)
|
||||
end_time = BigBlueButton::Events.last_event_timestamp(@events_legacy)
|
||||
bbb_props = { 'anonymize_chat' => true, 'anonymize_chat_moderators' => true }
|
||||
chats_enum = BigBlueButton::Events.get_chat_events(@events_legacy, start_time, end_time, bbb_props).each
|
||||
chat = chats_enum.next
|
||||
assert_equal(34_876, chat[:in])
|
||||
assert_nil(chat.fetch(:out))
|
||||
assert_nil(chat.fetch(:sender_id))
|
||||
# Anonymization doesn't work on really old recordings since there's no connection between
|
||||
# chat user names and user ids
|
||||
assert_equal('FRED', chat[:sender])
|
||||
assert_equal('hello', chat[:message])
|
||||
assert_nil(chat.fetch(:date))
|
||||
assert_equal(0, chat[:text_color])
|
||||
chat = chats_enum.next
|
||||
assert_equal(42_388, chat[:in])
|
||||
assert_nil(chat.fetch(:out))
|
||||
assert_equal('FRED', chat[:sender])
|
||||
assert_equal('how are you?', chat[:message])
|
||||
chat = chats_enum.next
|
||||
assert_equal(90_561, chat[:in])
|
||||
assert_nil(chat.fetch(:out))
|
||||
assert_equal('FRED', chat[:sender])
|
||||
assert_equal('hi fred', chat[:message])
|
||||
assert_raises(StopIteration) { chats_enum.next }
|
||||
end
|
||||
|
||||
def test_get_chat_events_0_9
|
||||
start_time = BigBlueButton::Events.first_event_timestamp(@events_chat09)
|
||||
end_time = BigBlueButton::Events.last_event_timestamp(@events_chat09)
|
||||
chats_enum = BigBlueButton::Events.get_chat_events(@events_chat09, start_time, end_time).each
|
||||
chat = chats_enum.next
|
||||
assert_equal(749_025, chat[:in])
|
||||
assert_equal(988_028, chat[:out])
|
||||
assert_equal('2dc8jctma0nj_1', chat[:sender_id])
|
||||
assert_equal('Xhesika De Lange', chat[:sender])
|
||||
assert_equal('Public chat 1', chat[:message])
|
||||
assert_nil(chat.fetch(:date))
|
||||
assert_equal(0, chat[:text_color])
|
||||
chat = chats_enum.next
|
||||
assert_equal(972_022, chat[:in])
|
||||
assert_equal(988_028, chat[:out])
|
||||
assert_equal('23uydbo9nauq_1', chat[:sender_id])
|
||||
assert_equal('Asa Darby', chat[:sender])
|
||||
assert_equal('Public chat 2', chat[:message])
|
||||
chat = chats_enum.next
|
||||
assert_equal(1_797_324, chat[:in])
|
||||
assert_nil(chat.fetch(:out))
|
||||
assert_equal('hs7iskkr7xrt_1', chat[:sender_id])
|
||||
assert_equal('Isaías Seelen', chat[:sender])
|
||||
assert_equal('Public chat 3', chat[:message])
|
||||
chat = chats_enum.next
|
||||
assert_equal(3_144_319 - 522_222, chat[:in])
|
||||
assert_equal('0q1hkmla9asu_1', chat[:sender_id])
|
||||
assert_equal('Elias Stablum', chat[:sender])
|
||||
assert_equal('Public chat 6', chat[:message])
|
||||
chat = chats_enum.next
|
||||
assert_equal(3_148_146 - 522_222, chat[:in])
|
||||
assert_equal('fzlsahcijxo4_1', chat[:sender_id])
|
||||
assert_equal('Arethusa Mann', chat[:sender])
|
||||
assert_equal('Public chat 7', chat[:message])
|
||||
chat = chats_enum.next
|
||||
assert_equal(3_157_549 - 522_222, chat[:in])
|
||||
assert_equal('nfuklna24flg_1', chat[:sender_id])
|
||||
assert_equal('Ninel Mac Ruaidhrí', chat[:sender])
|
||||
assert_equal('Public chat 8', chat[:message])
|
||||
chat = chats_enum.next
|
||||
assert_equal(3_159_062 - 522_222, chat[:in])
|
||||
assert_equal('7m940cic73r3_1', chat[:sender_id])
|
||||
assert_equal('Mireia Castell', chat[:sender])
|
||||
assert_equal('Public chat 9', chat[:message])
|
||||
chat = chats_enum.next
|
||||
assert_equal(3_167_630 - 522_222, chat[:in])
|
||||
assert_equal('nfuklna24flg_1', chat[:sender_id])
|
||||
assert_equal('Ninel Mac Ruaidhrí', chat[:sender])
|
||||
assert_equal('Public chat 10', chat[:message])
|
||||
chat = chats_enum.next
|
||||
assert_equal(5_240_729 - 522_222, chat[:in])
|
||||
assert_equal('2dc8jctma0nj_1', chat[:sender_id])
|
||||
assert_equal('Xhesika De Lange', chat[:sender])
|
||||
assert_equal('Public chat 11', chat[:message])
|
||||
chat = chats_enum.next
|
||||
assert_equal(5_265_991 - 522_222, chat[:in])
|
||||
assert_equal('fzlsahcijxo4_1', chat[:sender_id])
|
||||
assert_equal('Arethusa Mann', chat[:sender])
|
||||
assert_equal('Public chat 12', chat[:message])
|
||||
chat = chats_enum.next
|
||||
assert_equal(5_454_399 - 522_222, chat[:in])
|
||||
assert_equal('2dc8jctma0nj_1', chat[:sender_id])
|
||||
assert_equal('Xhesika De Lange', chat[:sender])
|
||||
assert_equal('Public chat 13', chat[:message])
|
||||
assert_raises(StopIteration) { chats_enum.next }
|
||||
end
|
||||
|
||||
def test_get_chat_events_0_9_anonymized
|
||||
start_time = BigBlueButton::Events.first_event_timestamp(@events_chat09)
|
||||
end_time = BigBlueButton::Events.last_event_timestamp(@events_chat09)
|
||||
bbb_props = { 'anonymize_chat' => true }
|
||||
chats_enum = BigBlueButton::Events.get_chat_events(@events_chat09, start_time, end_time, bbb_props).each
|
||||
assert_equal('Viewer 9', chats_enum.next[:sender])
|
||||
assert_equal('Viewer 12', chats_enum.next[:sender])
|
||||
assert_equal('Viewer 2', chats_enum.next[:sender])
|
||||
assert_equal('Viewer 7', chats_enum.next[:sender])
|
||||
assert_equal('Viewer 13', chats_enum.next[:sender])
|
||||
assert_equal('Viewer 14', chats_enum.next[:sender])
|
||||
assert_equal('Viewer 3', chats_enum.next[:sender])
|
||||
assert_equal('Viewer 14', chats_enum.next[:sender])
|
||||
assert_equal('Viewer 9', chats_enum.next[:sender])
|
||||
assert_equal('Viewer 13', chats_enum.next[:sender])
|
||||
assert_equal('Viewer 9', chats_enum.next[:sender])
|
||||
assert_raises(StopIteration) { chats_enum.next }
|
||||
end
|
||||
|
||||
def test_get_chat_events_0_9_start_time
|
||||
end_time = BigBlueButton::Events.last_event_timestamp(@events_chat09)
|
||||
chats = BigBlueButton::Events.get_chat_events(@events_chat09, 1_063_007_465, end_time)
|
||||
chat = chats.first
|
||||
assert_equal(301_831, chat[:in])
|
||||
assert_equal('hs7iskkr7xrt_1', chat[:sender_id])
|
||||
assert_equal('Isaías Seelen', chat[:sender])
|
||||
assert_equal('Public chat 3', chat[:message])
|
||||
end
|
||||
|
||||
def test_get_chat_events_0_9_end_time
|
||||
start_time = BigBlueButton::Events.first_event_timestamp(@events_chat09)
|
||||
chats = BigBlueButton::Events.get_chat_events(@events_chat09, start_time, 1_062_490_000)
|
||||
chat = chats.last
|
||||
assert_equal(972_022, chat[:in])
|
||||
assert_nil(chat.fetch(:out))
|
||||
assert_equal('23uydbo9nauq_1', chat[:sender_id])
|
||||
assert_equal('Asa Darby', chat[:sender])
|
||||
assert_equal('Public chat 2', chat[:message])
|
||||
end
|
||||
|
||||
def test_get_chat_events_devcall
|
||||
start_time = BigBlueButton::Events.first_event_timestamp(@events_devcall)
|
||||
end_time = BigBlueButton::Events.last_event_timestamp(@events_devcall)
|
||||
chats = BigBlueButton::Events.get_chat_events(@events_devcall, start_time, end_time)
|
||||
|
||||
assert_equal(11, chats.length)
|
||||
|
||||
chat = chats[0]
|
||||
assert_equal(17_013, chat[:in])
|
||||
assert_equal(148_701, chat[:out])
|
||||
assert_equal('w_kmm96j1as24f', chat[:sender_id])
|
||||
assert_equal('Mario', chat[:sender])
|
||||
assert_equal('#7b1fa2', chat[:avatar_color])
|
||||
assert_nil(chat.fetch(:text_color))
|
||||
assert_equal(DateTime.rfc3339('2021-08-31T18:06:14.330+00:00'), chat[:date])
|
||||
# rubocop:disable Layout/LineLength
|
||||
assert_equal(
|
||||
"i get logs of these: \n\n ERROR: clientLogger: Camera VIEWER failed. Reconnecting. <a href=\"https://develop.bigbluebutton.org/html5client/8fb14b479570f65105c7ff9a2960b679501f34ff.js?meteor_js_resource=true:348:579447\" rel=\"nofollow\"><u>https://develop.bigbluebutton.org/html5client/8fb14b479570f65105c7ff9a2960b679501f34ff.js?meteor_js_resource=true:348:579447</u></a>",
|
||||
chat[:message]
|
||||
)
|
||||
# rubocop:enable Layout/LineLength
|
||||
|
||||
chat = chats[7]
|
||||
assert_equal(1_241_014, chat[:in])
|
||||
assert_nil(chat.fetch(:out))
|
||||
assert_equal('w_vk0ebqjxox9d', chat[:sender_id])
|
||||
assert_equal('Anton G', chat[:sender])
|
||||
assert_equal('#0277bd', chat[:avatar_color])
|
||||
assert_nil(chat.fetch(:text_color))
|
||||
assert_equal(DateTime.rfc3339('2021-08-31T18:26:38.332+00:00'), chat[:date])
|
||||
assert_equal('Nice!', chat[:message])
|
||||
end
|
||||
|
||||
def test_get_chat_events_meta_edt
|
||||
start_time = BigBlueButton::Events.first_event_timestamp(@events_meta_edt)
|
||||
end_time = BigBlueButton::Events.last_event_timestamp(@events_meta_edt)
|
||||
chats = BigBlueButton::Events.get_chat_events(@events_meta_edt, start_time, end_time)
|
||||
|
||||
assert_equal(1, chats.length)
|
||||
|
||||
chat = chats[0]
|
||||
assert_equal(11_635, chat[:in])
|
||||
assert_nil(chat.fetch(:out))
|
||||
assert_equal('w_tvumguamxhhs', chat[:sender_id])
|
||||
# This recording has the meta_bbb-anonymize-chat param set
|
||||
assert_equal('Viewer 1', chat[:sender])
|
||||
assert_equal(DateTime.rfc3339('2021-09-02T14:33:02.214-04:00'), chat[:date])
|
||||
assert_equal('whoops, forgot to start recording…', chat[:message])
|
||||
end
|
||||
end
|
@ -1056,33 +1056,21 @@ def processPresentation(package_dir)
|
||||
File.write("#{package_dir}/#{$cursor_xml_filename}", cursors_doc.to_xml)
|
||||
end
|
||||
|
||||
def processChatMessages
|
||||
def processChatMessages(events, bbb_props)
|
||||
BigBlueButton.logger.info("Processing chat events")
|
||||
# Create slides.xml and chat.
|
||||
$slides_doc = Nokogiri::XML::Builder.new do |xml|
|
||||
$xml = xml
|
||||
$xml.popcorn {
|
||||
# Process chat events.
|
||||
current_time = 0
|
||||
$rec_events.each do |re|
|
||||
$chat_events.each do |node|
|
||||
if (node[:timestamp].to_i >= re[:start_timestamp] and node[:timestamp].to_i <= re[:stop_timestamp])
|
||||
chat_timestamp = node[:timestamp]
|
||||
chat_sender = node.xpath(".//sender")[0].text()
|
||||
chat_message = BigBlueButton::Events.linkify(node.xpath(".//message")[0].text())
|
||||
chat_start = ( translateTimestamp(chat_timestamp) / 1000).to_i
|
||||
# Creates a list of the clear timestamps that matter for this message
|
||||
next_clear_timestamps = $clear_chat_timestamps.select{ |e| e >= node[:timestamp] }
|
||||
# If there is none we skip it, or else we add the out time that will remove a message
|
||||
if next_clear_timestamps.empty?
|
||||
$xml.chattimeline(:in => chat_start, :direction => :down, :name => chat_sender, :message => chat_message, :target => :chat )
|
||||
else
|
||||
chat_end = ( translateTimestamp( next_clear_timestamps.first ) / 1000).to_i
|
||||
$xml.chattimeline(:in => chat_start, :out => chat_end, :direction => :down, :name => chat_sender, :message => chat_message, :target => :chat )
|
||||
end
|
||||
end
|
||||
end
|
||||
current_time += re[:stop_timestamp] - re[:start_timestamp]
|
||||
Nokogiri::XML::Builder.new do |xml|
|
||||
xml.popcorn {
|
||||
BigBlueButton::Events.get_chat_events(events, $meeting_start.to_i, $meeting_end.to_i, bbb_props).each do |chat|
|
||||
chattimeline = {
|
||||
in: (chat[:in] / 1000.0).round(1),
|
||||
direction: 'down',
|
||||
name: chat[:sender],
|
||||
message: chat[:message],
|
||||
target: 'chat'
|
||||
}
|
||||
chattimeline[:out] = (chat[:out] / 1000.0).round(1) unless chat[:out].nil?
|
||||
xml.chattimeline(**chattimeline)
|
||||
end
|
||||
}
|
||||
end
|
||||
@ -1216,7 +1204,7 @@ def processExternalVideoEvents(events, package_dir)
|
||||
timestamp = (translateTimestamp(event[:start_timestamp]) / 1000).to_i
|
||||
# do not add same external_video twice
|
||||
if (external_videos.find {|ev| ev[:timestamp] == timestamp}.nil?)
|
||||
if ((event[:start_timestamp] >= re[:start_timestamp] and event[:start_timestamp] <= re[:stop_timestamp]) ||
|
||||
if ((event[:start_timestamp] >= re[:start_timestamp] and event[:start_timestamp] <= re[:stop_timestamp]) ||
|
||||
(event[:start_timestamp] < re[:start_timestamp] and event[:stop_timestamp] >= re[:start_timestamp]))
|
||||
external_videos << {
|
||||
:timestamp => timestamp,
|
||||
@ -1414,18 +1402,11 @@ begin
|
||||
#Create slides.xml
|
||||
BigBlueButton.logger.info("Generating xml for slides and chat")
|
||||
|
||||
# Gathering all the events from the events.xml
|
||||
$chat_events = @doc.xpath("//event[@eventname='PublicChatEvent']")
|
||||
|
||||
# Create a list of timestamps when the moderator cleared the public chat
|
||||
$clear_chat_timestamps = [ ]
|
||||
clear_chat_events = @doc.xpath("//event[@eventname='ClearPublicChatEvent']")
|
||||
clear_chat_events.each { |clear| $clear_chat_timestamps << clear[:timestamp] }
|
||||
$clear_chat_timestamps.sort!
|
||||
|
||||
calculateRecordEventsOffset()
|
||||
|
||||
processChatMessages()
|
||||
# Write slides.xml to file
|
||||
slides_doc = processChatMessages(@doc, bbb_props)
|
||||
File.open("#{package_dir}/slides_new.xml", 'w') { |f| f.puts slides_doc.to_xml }
|
||||
|
||||
processPresentation(package_dir)
|
||||
|
||||
@ -1435,9 +1416,6 @@ begin
|
||||
|
||||
processExternalVideoEvents(@doc, package_dir)
|
||||
|
||||
# Write slides.xml to file
|
||||
File.open("#{package_dir}/slides_new.xml", 'w') { |f| f.puts $slides_doc.to_xml }
|
||||
|
||||
# Write deskshare.xml to file
|
||||
File.open("#{package_dir}/#{$deskshare_xml_filename}", 'w') { |f| f.puts $deskshare_xml.to_xml }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user