Merge branch 'v2.4.x-release' into fix-13242

This commit is contained in:
Mario Jr 2021-09-29 09:20:58 -03:00
commit 7ed1cbfc30
84 changed files with 2187 additions and 1943 deletions

View File

@ -339,7 +339,8 @@ class MeetingActor(
state = state.update(tracker)
}
} else {
if (state.expiryTracker.moderatorHasJoined == true) {
if (state.expiryTracker.moderatorHasJoined == true &&
state.expiryTracker.lastModeratorLeftOnInMs == 0) {
log.info("All moderators have left. Setting setLastModeratorLeftOn(). meetingId=" + props.meetingProp.intId)
val tracker = state.expiryTracker.setLastModeratorLeftOn(TimeUtil.timeNowInMs())
state = state.update(tracker)

View File

@ -1 +1 @@
BIGBLUEBUTTON_RELEASE=2.4-rc-1
BIGBLUEBUTTON_RELEASE=2.4-rc-2

View File

@ -45,7 +45,7 @@ export ROOT_URL=http://127.0.0.1/html5client
export MONGO_OPLOG_URL=mongodb://127.0.1.1/local
export MONGO_URL=mongodb://127.0.1.1/meteor
export NODE_ENV=production
export NODE_VERSION=node-v12.16.1-linux-x64
export NODE_VERSION=node-v14.17.6-linux-x64
export SERVER_WEBSOCKET_COMPRESSION=0
export BIND_IP=127.0.0.1
PORT=$PORT /usr/share/$NODE_VERSION/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js NODEJS_BACKEND_INSTANCE_ID=$INSTANCE_ID

View File

@ -45,7 +45,7 @@ export ROOT_URL=http://127.0.0.1/html5client
export MONGO_OPLOG_URL=mongodb://127.0.1.1/local
export MONGO_URL=mongodb://127.0.1.1/meteor
export NODE_ENV=production
export NODE_VERSION=node-v12.16.1-linux-x64
export NODE_VERSION=node-v14.17.6-linux-x64
export SERVER_WEBSOCKET_COMPRESSION=0
export BIND_IP=127.0.0.1
PORT=$PORT /usr/share/$NODE_VERSION/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js

View File

@ -11,6 +11,7 @@ import getFromMeetingSettings from '/imports/ui/services/meeting-settings';
const SFU_URL = Meteor.settings.public.kurento.wsUrl;
const DEFAULT_LISTENONLY_MEDIA_SERVER = Meteor.settings.public.kurento.listenOnlyMediaServer;
const SIGNAL_CANDIDATES = Meteor.settings.public.kurento.signalCandidates;
const MEDIA = Meteor.settings.public.media;
const MEDIA_TAG = MEDIA.mediaTag.replace(/#/g, '');
const GLOBAL_AUDIO_PREFIX = 'GLOBAL_AUDIO_';
@ -265,6 +266,7 @@ export default class KurentoAudioBridge extends BaseAudioBridge {
iceServers,
offering: OFFERING,
mediaServer: getMediaServerAdapter(),
signalCandidates: SIGNAL_CANDIDATES,
};
this.broker = new ListenOnlyBroker(

View File

@ -8,6 +8,7 @@ import { SCREENSHARING_ERRORS } from './errors';
const SFU_CONFIG = Meteor.settings.public.kurento;
const SFU_URL = SFU_CONFIG.wsUrl;
const OFFERING = SFU_CONFIG.screenshare.subscriberOffering;
const SIGNAL_CANDIDATES = Meteor.settings.public.kurento.signalCandidates;
const BRIDGE_NAME = 'kurento'
const SCREENSHARE_VIDEO_TAG = 'screenshareVideo';
@ -225,6 +226,7 @@ export default class KurentoScreenshareBridge {
hasAudio,
offering: OFFERING,
mediaServer: BridgeService.getMediaServerAdapter(),
signalCandidates: SIGNAL_CANDIDATES,
};
this.broker = new ScreenshareBroker(
@ -284,6 +286,7 @@ export default class KurentoScreenshareBridge {
bitrate: BridgeService.BASE_BITRATE,
offering: true,
mediaServer: BridgeService.getMediaServerAdapter(),
signalCandidates: SIGNAL_CANDIDATES,
};
this.broker = new ScreenshareBroker(

View File

@ -175,6 +175,7 @@ const ScreenshareButton = ({
className={cx(isVideoBroadcasting || styles.btn)}
disabled={(!isMeteorConnected && !isVideoBroadcasting) || !screenshareDataSavingSetting}
icon={isVideoBroadcasting ? 'desktop' : 'desktop_off'}
data-test={isVideoBroadcasting ? 'stopScreenShare' : 'startScreenShare'}
label={intl.formatMessage(vLabel)}
description={intl.formatMessage(vDescr)}
color={isVideoBroadcasting ? 'primary' : 'default'}

View File

@ -61,6 +61,7 @@ const AppContainer = (props) => {
pushLayoutToEveryone,
currentUserId,
shouldShowPresentation: propsShouldShowPresentation,
presentationRestoreOnUpdate,
...otherProps
} = props;
const {
@ -76,7 +77,8 @@ const AppContainer = (props) => {
const sidebarNavigationIsOpen = sidebarNavigation.isOpen;
const sidebarContentIsOpen = sidebarContent.isOpen;
const presentationIsOpen = presentation.isOpen;
const shouldShowPresentation = propsShouldShowPresentation && presentationIsOpen;
const shouldShowPresentation = propsShouldShowPresentation
&& (presentationIsOpen || presentationRestoreOnUpdate);
return currentUserId
? (
@ -199,6 +201,10 @@ export default injectIntl(withModalMounter(withTracker(({ intl, baseControls })
shouldShowPresentation: !shouldShowScreenshare && !shouldShowExternalVideo,
shouldShowExternalVideo,
isLargeFont: Session.get('isLargeFont'),
presentationRestoreOnUpdate: getFromUserSettings(
'bbb_force_restore_presentation_on_new_events',
Meteor.settings.public.presentation.restoreOnUpdate,
),
};
})(AppContainer)));

View File

@ -171,6 +171,7 @@ class BreakoutRoom extends PureComponent {
this.setState(
{
waiting: true,
generated: false,
requestedBreakoutId: breakoutId,
},
() => requestJoinURL(breakoutId),
@ -489,7 +490,7 @@ class BreakoutRoom extends PureComponent {
messageDuration={intlMessages.breakoutDuration}
breakoutRoom={breakoutRooms[0]}
/>
{!visibleExtendTimeForm
{amIModerator && !visibleExtendTimeForm
? (
<Button
onClick={this.showExtendTimeForm}

View File

@ -165,7 +165,7 @@ class CustomLayout extends Component {
type: ACTIONS.SET_LAYOUT_INPUT,
value: _.defaultsDeep({
sidebarNavigation: {
isOpen: true,
isOpen: input.sidebarNavigation.isOpen || false,
},
sidebarContent: {
isOpen: sidebarContentPanel !== PANELS.NONE,
@ -472,7 +472,7 @@ class CustomLayout extends Component {
cameraDockBounds.width = mediaAreaBounds.width;
cameraDockBounds.maxWidth = mediaAreaBounds.width;
cameraDockBounds.minHeight = DEFAULT_VALUES.cameraDockMinHeight;
cameraDockBounds.height = cameraDockHeight - camerasMargin;
cameraDockBounds.height = cameraDockHeight;
cameraDockBounds.maxHeight = mediaAreaBounds.height * 0.8;
break;
}
@ -497,10 +497,10 @@ class CustomLayout extends Component {
const sizeValue = input.presentation.isOpen
? (mediaAreaBounds.left + mediaAreaBounds.width) - cameraDockWidth
: mediaAreaBounds.left;
cameraDockBounds.left = !isRTL ? sizeValue + camerasMargin : 0;
cameraDockBounds.right = isRTL ? sizeValue + sidebarSize + camerasMargin : null;
cameraDockBounds.left = !isRTL ? sizeValue - camerasMargin : 0;
cameraDockBounds.right = isRTL ? sizeValue + sidebarSize - camerasMargin : null;
cameraDockBounds.minWidth = DEFAULT_VALUES.cameraDockMinWidth;
cameraDockBounds.width = cameraDockWidth - (camerasMargin * 2);
cameraDockBounds.width = cameraDockWidth;
cameraDockBounds.maxWidth = mediaAreaBounds.width * 0.8;
cameraDockBounds.presenterMaxWidth = mediaAreaBounds.width
- DEFAULT_VALUES.presentationToolbarMinWidth
@ -539,7 +539,7 @@ class CustomLayout extends Component {
cameraDockBounds.width = mediaAreaBounds.width;
cameraDockBounds.maxWidth = mediaAreaBounds.width;
cameraDockBounds.minHeight = DEFAULT_VALUES.cameraDockMinHeight;
cameraDockBounds.height = cameraDockHeight - camerasMargin;
cameraDockBounds.height = cameraDockHeight;
cameraDockBounds.maxHeight = mediaAreaBounds.height * 0.8;
break;
}
@ -564,7 +564,7 @@ class CustomLayout extends Component {
cameraDockBounds.left = mediaAreaBounds.left + camerasMargin;
cameraDockBounds.right = isRTL ? sidebarSize + (camerasMargin * 2) : null;
cameraDockBounds.minWidth = DEFAULT_VALUES.cameraDockMinWidth;
cameraDockBounds.width = cameraDockWidth - (camerasMargin * 2);
cameraDockBounds.width = cameraDockWidth;
cameraDockBounds.maxWidth = mediaAreaBounds.width * 0.8;
cameraDockBounds.presenterMaxWidth = mediaAreaBounds.width
- DEFAULT_VALUES.presentationToolbarMinWidth
@ -677,7 +677,7 @@ class CustomLayout extends Component {
break;
}
case CAMERADOCK_POSITION.CONTENT_RIGHT: {
mediaBounds.width = mediaAreaWidth - cameraDockBounds.width - camerasMargin;
mediaBounds.width = mediaAreaWidth - cameraDockBounds.width - (camerasMargin * 2);
mediaBounds.height = mediaAreaHeight;
mediaBounds.top = navBarHeight + bannerAreaHeight;
mediaBounds.left = !isRTL ? sidebarSize : null;
@ -693,7 +693,7 @@ class CustomLayout extends Component {
break;
}
case CAMERADOCK_POSITION.CONTENT_LEFT: {
mediaBounds.width = mediaAreaWidth - cameraDockBounds.width - camerasMargin;
mediaBounds.width = mediaAreaWidth - cameraDockBounds.width - (camerasMargin * 2);
mediaBounds.height = mediaAreaHeight;
mediaBounds.top = navBarHeight + bannerAreaHeight;
const sizeValue = sidebarNavWidth

View File

@ -99,7 +99,7 @@ class PresentationFocusLayout extends Component {
type: ACTIONS.SET_LAYOUT_INPUT,
value: defaultsDeep({
sidebarNavigation: {
isOpen: true,
isOpen: input.sidebarNavigation.isOpen || false,
},
sidebarContent: {
isOpen: sidebarContentPanel !== PANELS.NONE,

View File

@ -101,7 +101,7 @@ class SmartLayout extends Component {
type: ACTIONS.SET_LAYOUT_INPUT,
value: _.defaultsDeep({
sidebarNavigation: {
isOpen: true,
isOpen: input.sidebarNavigation.isOpen || false,
},
sidebarContent: {
isOpen: sidebarContentPanel !== PANELS.NONE,

View File

@ -104,7 +104,7 @@ class VideoFocusLayout extends Component {
value: defaultsDeep(
{
sidebarNavigation: {
isOpen: true,
isOpen: input.sidebarNavigation.isOpen || false,
},
sidebarContent: {
isOpen: sidebarContentPanel !== PANELS.NONE,

View File

@ -823,7 +823,7 @@ class Presentation extends PureComponent {
const { presentationToolbarMinWidth } = DEFAULT_VALUES;
const isLargePresentation = (svgWidth > presentationToolbarMinWidth || isMobile)
&& !(layoutType === LAYOUT_TYPE.VIDEO_FOCUS && numCameras > 0);
&& !(layoutType === LAYOUT_TYPE.VIDEO_FOCUS && numCameras > 0 && !fullscreenContext);
const containerWidth = isLargePresentation
? svgWidth

View File

@ -269,7 +269,7 @@ class ScreenshareComponent extends React.Component {
{
isGloballyBroadcasting
? (
<div>
<div data-test="isSharingScreen">
{!switched
&& ScreenshareComponent.renderScreenshareContainerInside(
intl.formatMessage(intlMessages.presenterSharingLabel),

View File

@ -309,6 +309,7 @@ class UserOptions extends PureComponent {
if (canInviteUsers) {
this.menuItems.push({
icon: 'rooms',
dataTest: 'inviteBreakoutRooms',
label: intl.formatMessage(intlMessages.invitationItem),
key: this.createBreakoutId,
onClick: this.onInvitationUsers,
@ -322,7 +323,6 @@ class UserOptions extends PureComponent {
// description: intl.formatMessage(intlMessages.captionsDesc),
key: this.captionsId,
onClick: this.handleCaptionsClick,
dataTest: 'inviteBreakoutRooms',
});
}
if (amIModerator) {

View File

@ -52,6 +52,7 @@ const WaitingUsers = ({
<div className={styles.list}>
<div
role="button"
data-test="waitingUsersBtn"
tabIndex={0}
className={styles.listItem}
onClick={toggleWaitingPanel}

View File

@ -28,6 +28,7 @@ const {
} = Meteor.settings.public.kurento.cameraTimeouts || {};
const CAMERA_QUALITY_THRESHOLDS_ENABLED = Meteor.settings.public.kurento.cameraQualityThresholds.enabled;
const PING_INTERVAL = 15000;
const SIGNAL_CANDIDATES = Meteor.settings.public.kurento.signalCandidates;
const intlClientErrors = defineMessages({
permissionError: {
@ -782,17 +783,21 @@ class VideoProvider extends Component {
}
_getOnIceCandidateCallback(stream, isLocal) {
return (candidate) => {
const peer = this.webRtcPeers[stream];
const role = VideoService.getRole(isLocal);
if (SIGNAL_CANDIDATES) {
return (candidate) => {
const peer = this.webRtcPeers[stream];
const role = VideoService.getRole(isLocal);
if (peer && !peer.didSDPAnswered) {
this.outboundIceQueues[stream].push(candidate);
return;
}
if (peer && !peer.didSDPAnswered) {
this.outboundIceQueues[stream].push(candidate);
return;
}
this.sendIceCandidateToSFU(peer, role, candidate, stream);
};
this.sendIceCandidateToSFU(peer, role, candidate, stream);
};
}
return null;
}
sendIceCandidateToSFU(peer, role, candidate, stream) {

View File

@ -22,6 +22,7 @@ class ListenOnlyBroker extends BaseBroker {
this.offering = true;
// Optional parameters are: userName, caleeName, iceServers, offering, mediaServer
// signalCandidates
Object.assign(this, options);
}
@ -32,9 +33,7 @@ class ListenOnlyBroker extends BaseBroker {
audio: true,
video: false,
},
onicecandidate: (candidate) => {
this.onIceCandidate(candidate, this.role);
},
onicecandidate: this.signalCandidates ? this.onIceCandidate.bind(this) : null,
};
this.addIceServers(options);
@ -179,10 +178,10 @@ class ListenOnlyBroker extends BaseBroker {
this.sendStartReq(sdpOffer);
}
onIceCandidate (candidate, role) {
onIceCandidate (candidate) {
const message = {
id: ON_ICE_CANDIDATE_MSG,
role,
role: this.role,
type: this.sfuComponent,
voiceBridge: this.voiceBridge,
candidate,

View File

@ -23,8 +23,10 @@ class ScreenshareBroker extends BaseBroker {
this.webRtcPeer = null;
this.hasAudio = false;
this.offering = true;
this.signalCandidates = true;
// Optional parameters are: userName, caleeName, iceServers, hasAudio, bitrate, offering, mediaServer
// Optional parameters are: userName, caleeName, iceServers, hasAudio,
// bitrate, offering, mediaServer, signalCandidates
Object.assign(this, options);
}
@ -153,9 +155,7 @@ class ScreenshareBroker extends BaseBroker {
startScreensharing () {
return new Promise((resolve, reject) => {
const options = {
onicecandidate: (candidate) => {
this.onIceCandidate(candidate, this.role);
},
onicecandidate: this.signalCandidates ? this.onIceCandidate.bind(this) : null,
videoStream: this.stream,
};
@ -206,10 +206,10 @@ class ScreenshareBroker extends BaseBroker {
});
}
onIceCandidate (candidate, role) {
onIceCandidate (candidate) {
const message = {
id: ON_ICE_CANDIDATE_MSG,
role,
role: this.role,
type: this.sfuComponent,
voiceBridge: this.voiceBridge,
candidate,
@ -225,9 +225,7 @@ class ScreenshareBroker extends BaseBroker {
mediaConstraints: {
audio: !!this.hasAudio,
},
onicecandidate: (candidate) => {
this.onIceCandidate(candidate, this.role);
},
onicecandidate: this.signalCandidates ? this.onIceCandidate.bind(this) : null,
};
this.addIceServers(options);

View File

@ -197,6 +197,9 @@ public:
wsConnectionTimeout: 4000
# Time in milis to wait for the browser to return a gUM call (used in video-preview)
gUMTimeout: 20000
# Experiment(al). Controls whether ICE candidates should be signaled.
# Applies to webcams, listen only and screen sharing. True is "stable behavior".
signalCandidates: true
cameraTimeouts:
# Base camera timeout: used as the camera *sharing* timeout and
# as the minimum camera subscribe reconnection timeout

View File

@ -2,7 +2,7 @@
<html>
<head>
<title>Guest Lobby</title>
<title>BigBlueButton - Guest Lobby</title>
<meta charset="UTF-8">
<style>
:root {
@ -26,6 +26,10 @@
font-family: arial, sans-serif;
}
#content h1 {
font-size: 2rem;
}
.spinner {
margin: 20px auto;
}
@ -149,6 +153,8 @@
url.search = overrideLocale
? `locale=${overrideLocale}`
: `locale=${navigator.language}&init=true`;
document.getElementsByTagName('html')[0].lang = overrideLocale || navigator.language;
const localesPath = 'locales';
@ -320,12 +326,13 @@
<body>
<div id="content">
<h1>Guest Lobby</h1>
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
<p>Please wait for a moderator to approve you joining the meeting.</p>
<p aria-live="polite">Please wait for a moderator to approve you joining the meeting.</p>
</div>
</body>

View File

@ -591,7 +591,7 @@
"app.guest.missingMeeting": "Konferenz existiert nicht.",
"app.guest.meetingEnded": "Konferenz beendet.",
"app.guest.guestWait": "Bitte warten Sie, bis ein Moderator Ihre Teilnahme an der Konferenz freigibt.",
"app.guest.guestDeny": "Gast verweigert die Teilnahme an der Konferenz.",
"app.guest.guestDeny": "Der Moderator hat die Teilnahme an der Konferenz abgelehnt.",
"app.guest.seatWait": "Gast wartet auf die Teilnahme an der Konferenz.",
"app.userList.guest.waitingUsers": "Wartende Teilnehmer",
"app.userList.guest.waitingUsersTitle": "Teilnehmerverwaltung",

View File

@ -53,6 +53,7 @@
"app.captions.pad.dictationOffDesc": "Lülitab kõnetuvastuse välja",
"app.captions.pad.speechRecognitionStop": "Kõnetuvastus peatatud brauseri mitteühilduvuse või pika vaikuse tõttu",
"app.textInput.sendLabel": "Saada",
"app.title.defaultViewLabel": "Vaikeesitlus",
"app.note.title": "Jagatud märkmed",
"app.note.label": "Märge",
"app.note.hideNoteLabel": "Peida märge",
@ -232,6 +233,7 @@
"app.presentationUploder.itemPlural" : "elementi",
"app.presentationUploder.clearErrors": "Kustuta vead",
"app.presentationUploder.clearErrorsDesc": "Kustutab esitluste ebaõnnestunud üleslaadimised",
"app.presentationUploder.uploadViewTitle": "Laadi esitlus üles",
"app.poll.pollPaneTitle": "Küsitlus",
"app.poll.quickPollTitle": "Kiirküsitlus",
"app.poll.hidePollDesc": "Peidab küsitluse paneeli",
@ -290,6 +292,8 @@
"app.poll.liveResult.usersTitle": "Kasutaja",
"app.poll.liveResult.responsesTitle": "Vastus",
"app.poll.liveResult.secretLabel": "See on anonüümne küsitlus. Üksikvastused ei ole nähtavad",
"app.poll.removePollOpt": "Eemaldatud vastusevariant {0}",
"app.poll.emptyPollOpt": "Tühi",
"app.polling.pollingTitle": "Küsitluse valikud",
"app.polling.pollQuestionTitle": "Küsitluse küsimus",
"app.polling.submitLabel": "Saada",
@ -664,6 +668,7 @@
"app.guest-policy.button.askModerator": "Küsi moderaatorilt",
"app.guest-policy.button.alwaysAccept": "Luba alati",
"app.guest-policy.button.alwaysDeny": "Keela alati",
"app.guest-policy.policyBtnDesc": "Määrab koosoleku külaliste reeglid",
"app.connection-status.ariaTitle": "Ühenduse staatuse aken",
"app.connection-status.title": "Ühenduse staatus",
"app.connection-status.description": "Vaata kasutajate ühenduse staatust",
@ -744,6 +749,7 @@
"app.video.virtualBackground.blur": "Hägustatud",
"app.video.virtualBackground.genericError": "Kaameraefekti rakendamine ebaõnnestus. Proovi uuesti.",
"app.video.virtualBackground.camBgAriaDesc": "Määrab {0} veebikaamera virtuaalseks taustaks",
"app.video.dropZoneLabel": "Aseta siia",
"app.fullscreenButton.label": "Laienda {0} täisekraanile",
"app.fullscreenUndoButton.label": "Loobu {0} täisekraanist",
"app.switchButton.expandLabel": "Laienda ekraanijagamise videot",
@ -791,6 +797,7 @@
"app.whiteboard.toolbar.palmRejectionOn": "Lülita käelaba hülgamine sisse",
"app.whiteboard.toolbar.palmRejectionOff": "Lülita käelaba hülgamine välja",
"app.whiteboard.toolbar.fontSize": "Tekstisuuruste nimikiri",
"app.whiteboard.toolbarAriaLabel": "Esitluse tööriistad",
"app.feedback.title": "Oled konverentsist välja logitud",
"app.feedback.subtitle": "Tahaksime teada, mida arvad BigBlueButtonist (vabatahtlik)",
"app.feedback.textarea": "Kuidas saaksime BigBlueButtonit paremaks muuta?",
@ -845,6 +852,7 @@
"app.createBreakoutRoom.extendTimeLabel": "Pikenda",
"app.createBreakoutRoom.extendTimeCancel": "Tühista",
"app.createBreakoutRoom.extendTimeHigherThanMeetingTimeError": "Eraldatud ruumi kestus ei või ületada koosolekul järelejäänud aega.",
"app.createBreakoutRoom.roomNameInputDesc": "Uuendab eraldatud ruumi nime",
"app.externalVideo.start": "Jaga uut videot",
"app.externalVideo.title": "Jaga välist videot",
"app.externalVideo.input": "Välise video URL",
@ -900,16 +908,33 @@
"playback.player.thumbnails.wrapper.aria": "Pisipiltide ala",
"playback.player.video.wrapper.aria": "Video ala",
"app.learningDashboard.dashboardTitle": "Õppetöö ülevaateleht",
"app.learningDashboard.user": "Kasutaja",
"app.learningDashboard.indicators.meetingStatusEnded": "Lõppenud",
"app.learningDashboard.indicators.meetingStatusActive": "Kestab",
"app.learningDashboard.indicators.usersOnline": "Aktiivsed kasutajad",
"app.learningDashboard.indicators.usersTotal": "Kasutajate koguarv",
"app.learningDashboard.indicators.polls": "Küsitlused",
"app.learningDashboard.indicators.raiseHand": "Tõsta käsi",
"app.learningDashboard.indicators.activityScore": "Aktiivsusskoor",
"app.learningDashboard.indicators.duration": "Kestus",
"app.learningDashboard.usersTable.title": "Ülevaade",
"app.learningDashboard.usersTable.colOnline": "Kohaloldud aeg",
"app.learningDashboard.usersTable.colTalk": "Rääkimisaeg",
"app.learningDashboard.usersTable.colWebcam": "Veebikaamera aeg",
"app.learningDashboard.usersTable.colMessages": "Sõnumid",
"app.learningDashboard.usersTable.colEmojis": "Emojid",
"app.learningDashboard.usersTable.colRaiseHands": "Tõstetud käed",
"app.learningDashboard.usersTable.colActivityScore": "Aktiivsusskoor",
"app.learningDashboard.usersTable.colStatus": "Staatus",
"app.learningDashboard.usersTable.userStatusOnline": "Kohal",
"app.learningDashboard.usersTable.userStatusOffline": "Väljas",
"app.learningDashboard.usersTable.noUsers": "Pole veel kasutajaid",
"app.learningDashboard.pollsTable.title": "Küsitlus",
"app.learningDashboard.pollsTable.anonymousAnswer": "Anonüümne küsitlus (vastused viimases reas)",
"app.learningDashboard.pollsTable.anonymousRowName": "Anonüümne",
"app.learningDashboard.statusTimelineTable.title": "Staatuse ajajoon"
"app.learningDashboard.statusTimelineTable.title": "Staatuse ajajoon",
"app.learningDashboard.errors.invalidToken": "Kehtetu sessioonitõend",
"app.learningDashboard.errors.dataUnavailable": "Andmed ei ole enam kättesaadavad"
}

View File

@ -1,21 +1,21 @@
{
"app.home.greeting": "המצגת שלך תתחיל בקרוב ...",
"app.chat.submitLabel": "שלח הודעה",
"app.chat.submitLabel": "שליחת הודעה",
"app.chat.errorMaxMessageLength": "ההודעה ארוכה מדי ב {0} תוו(ים)",
"app.chat.disconnected": "התנתקת מהמפגש, אי אפשר לשלוח הודעות",
"app.chat.locked": "המפגש ננעל, אי אפשר לשלוח הודעות",
"app.chat.inputLabel": "תוכן הודעה למפגש {0}",
"app.chat.inputPlaceholder": "שלח הודעה ל {0}",
"app.chat.inputPlaceholder": "שליחת הודעה ל {0}",
"app.chat.titlePublic": "צ'אט ציבורי",
"app.chat.titlePrivate": "צ'אט פרטי עם {0}",
"app.chat.partnerDisconnected": "{0} עזב את המפגש",
"app.chat.closeChatLabel": "סגור {0}",
"app.chat.hideChatLabel": "הסתר {0}",
"app.chat.partnerDisconnected": "{0} עזב את המפגש",
"app.chat.closeChatLabel": "סגירה {0}",
"app.chat.hideChatLabel": "הסתרה {0}",
"app.chat.moreMessages": "הודעות נוספות מתחת",
"app.chat.dropdown.options": "אפשרויות צ'אט",
"app.chat.dropdown.clear": קה",
"app.chat.dropdown.copy": "העתק",
"app.chat.dropdown.save": "שמור",
"app.chat.dropdown.clear": יקוי",
"app.chat.dropdown.copy": "העתקה",
"app.chat.dropdown.save": "שמירה",
"app.chat.label": "צ'אט",
"app.chat.offline": "לא מקוון",
"app.chat.pollResult": "תוצאות סקר",
@ -24,37 +24,41 @@
"app.chat.multi.typing": "מספר משתתפים מקלידים...",
"app.chat.one.typing": "{0} מקליד..",
"app.chat.two.typing": "{0} ו {1} מקלידים..",
"app.chat.copySuccess": "תמליל הצ'אט הועתק",
"app.captions.label": "כתוביות",
"app.captions.menu.close": "סגור",
"app.captions.menu.start": "התחל",
"app.captions.menu.ariaStart": "התחל לכתוב כתוביות",
"app.captions.menu.ariaStartDesc": ותח את עורך הכתוביות וסוגר את ההודעה",
"app.captions.menu.select": "בחר שפה",
"app.captions.menu.close": "סגירה",
"app.captions.menu.start": "התחלה",
"app.captions.menu.ariaStart": "התחלת כתיבת כתוביות",
"app.captions.menu.ariaStartDesc": תיחת עורך הכתוביות וסגירת ההודעה",
"app.captions.menu.select": "בחירת שפה",
"app.captions.menu.ariaSelect": "שפת כתוביות",
"app.captions.menu.subtitle": "בחר שפה ועיצוב לכתוביות במפגש.",
"app.captions.menu.subtitle": "בחירת שפה ועיצוב לכתוביות במפגש.",
"app.captions.menu.title": "כתוביות",
"app.captions.menu.fontSize": "גודל",
"app.captions.menu.fontColor": "צבע טקסט",
"app.captions.menu.fontFamily": "פונט",
"app.captions.menu.fontFamily": "גופן",
"app.captions.menu.backgroundColor": "צבע רקע",
"app.captions.menu.previewLabel": "תצוגה מקדימה",
"app.captions.menu.cancelLabel": טל",
"app.captions.pad.hide": "הסתר כתוביות",
"app.captions.menu.cancelLabel": יטול",
"app.captions.pad.hide": "הסתרת כתוביות",
"app.captions.pad.tip": "לחץ Esc למעבר לסרגל הכלים",
"app.captions.pad.ownership": "השתלט",
"app.captions.pad.ownership": "השתלטות",
"app.captions.pad.ownershipTooltip": "הוגדרת כבעלים של {0} כתוביות",
"app.captions.pad.interimResult": "Interim results",
"app.captions.pad.dictationStart": "Start dictation",
"app.captions.pad.dictationStop": "Stop dictation",
"app.captions.pad.dictationOnDesc": "Turns speech recognition on",
"app.captions.pad.dictationOffDesc": "Turns speech recognition off",
"app.captions.pad.interimResult": "תוצאות ביניים",
"app.captions.pad.dictationStart": "התחלת הכתבה",
"app.captions.pad.dictationStop": "סיום הכתבה",
"app.captions.pad.dictationOnDesc": "הפעלת זיהוי דיבור",
"app.captions.pad.dictationOffDesc": "כיבוי זיהוי דיבור",
"app.textInput.sendLabel": "נשלח",
"app.title.defaultViewLabel": "ברירת מחדל לצפייה במצגת",
"app.note.title": "פנקס משותף",
"app.note.label": "פתקית",
"app.note.hideNoteLabel": "הסתר פתקית",
"app.note.hideNoteLabel": "הסתרת פתקית",
"app.note.tipLabel": "לחץ Esc למעבר לסרגל הכלים",
"app.note.locked": "נעול",
"app.user.activityCheck": "בדיקת זמינות משתמש",
"app.user.activityCheck.label": "בדוק אם המשתמש עדיין במפגש ({0})",
"app.user.activityCheck.check": "בדוק",
"app.user.activityCheck.label": "בדיקה אם המשתמש עדיין במפגש ({0})",
"app.user.activityCheck.check": "בדיקה",
"app.userList.usersTitle": "משתתפים",
"app.userList.participantsTitle": "משתתפים",
"app.userList.messagesTitle": "הודעות",
@ -65,31 +69,36 @@
"app.userList.you": "את/ה",
"app.userList.locked": "נעול",
"app.userList.label": "משתתפים",
"app.userList.toggleCompactView.label": "עבור למצב צפיה מצומצם",
"app.userList.toggleCompactView.label": "מעבר למצב צפיה מצומצם",
"app.userList.guest": "אורח",
"app.userList.sharingWebcam": "מצלמה",
"app.userList.menuTitleContext": "אפשרויות",
"app.userList.menu.chat.label": "התחל שיחה פרטית",
"app.userList.menu.clearStatus.label": "נקה סטטוס",
"app.userList.menu.removeUser.label": "הוצא משתתף",
"app.userList.menu.muteUserAudio.label": "השתק",
"app.userList.menu.unmuteUserAudio.label": "בטל השתקת משתמש",
"app.userList.chatListItem.unreadSingular": "הודעה חדשה",
"app.userList.chatListItem.unreadPlural": "{0} הודעות חדשות",
"app.userList.menu.chat.label": "התחלת שיחה פרטית",
"app.userList.menu.clearStatus.label": "איפוס מצב",
"app.userList.menu.removeUser.label": "הוצאת משתתף",
"app.userList.menu.removeConfirmation.label": "הסרת משתתף ({0})",
"app.userList.menu.muteUserAudio.label": "השתקה",
"app.userList.menu.unmuteUserAudio.label": "ביטול השתקת משתמש",
"app.userList.menu.giveWhiteboardAccess.label" : "מתן גישה ללוח־ציור משותף",
"app.userList.userAriaLabel": "{0} {1} {2} במצב {3}",
"app.userList.menu.promoteUser.label": "הפוך למנחה",
"app.userList.menu.demoteUser.label": "הפוך לצופה",
"app.userList.menu.unlockUser.label": "בטל נעילה ל {0} ",
"app.userList.menu.lockUser.label": "נעל {0}",
"app.userList.menu.promoteUser.label": "עדכון תפקיד למנחה",
"app.userList.menu.demoteUser.label": "עדכון תפקיד לצופה",
"app.userList.menu.unlockUser.label": יטול נעילה ל {0} ",
"app.userList.menu.lockUser.label": "נעילת {0}",
"app.userList.menu.directoryLookup.label": "חיפוש תיקיה",
"app.userList.menu.makePresenter.label": "הפוך למציג",
"app.userList.userOptions.manageUsersLabel": הל משתמשים",
"app.userList.userOptions.muteAllLabel": "השתק את כולם",
"app.userList.userOptions.muteAllDesc": "השתק את כולם",
"app.userList.userOptions.clearAllLabel": "נקה סטטוסים",
"app.userList.userOptions.clearAllDesc": "נקה סטטוסים",
"app.userList.userOptions.muteAllExceptPresenterLabel": "השתק את כל המשתתפים מלבד המנחה",
"app.userList.userOptions.muteAllExceptPresenterDesc": "השתק את כל המשתתפים מלבד המנחה",
"app.userList.userOptions.unmuteAllLabel": טל השתקה במפגש",
"app.userList.userOptions.unmuteAllDesc": טל השתקה במפגש",
"app.userList.userOptions.lockViewersLabel": "נעל מצב צופים",
"app.userList.menu.makePresenter.label": "עדכון תפקיד למציג",
"app.userList.userOptions.manageUsersLabel": יהול משתמשים",
"app.userList.userOptions.muteAllLabel": "השתקת כולם",
"app.userList.userOptions.muteAllDesc": "השתקת כולם",
"app.userList.userOptions.clearAllLabel": "איפוס מצבים",
"app.userList.userOptions.clearAllDesc": "איפוס מצבים",
"app.userList.userOptions.muteAllExceptPresenterLabel": "השתקת כל המשתתפים מלבד המנחה",
"app.userList.userOptions.muteAllExceptPresenterDesc": "השתקת כל המשתתפים מלבד המנחה",
"app.userList.userOptions.unmuteAllLabel": יטול השתקה במפגש",
"app.userList.userOptions.unmuteAllDesc": יטול השתקה במפגש",
"app.userList.userOptions.lockViewersLabel": "נעילת מצב צופים",
"app.userList.userOptions.lockViewersDesc": "Lock certain functionalities for attendees of the meeting",
"app.userList.userOptions.disableCam": "מצלמות הצופים בוטלו",
"app.userList.userOptions.disableMic": "כל הצופים הושתקו",
@ -98,65 +107,65 @@
"app.userList.userOptions.disableNote": "פתקיות ציבוריות נעולות",
"app.userList.userOptions.hideUserList": "רשימת המשתתפים מוסתרת מהצופים כעת",
"app.userList.userOptions.webcamsOnlyForModerator": "רק מנחים יכולים לצפות במצלמות המשתתפים (בעקבות הגדרות הנעילה)",
"app.userList.content.participants.options.clearedStatus": "סטטוסים של כל הצופים אופסו",
"app.userList.content.participants.options.clearedStatus": "מצבים של כל הצופים אופסו",
"app.userList.userOptions.enableCam": "מצלמות כל הצופים הפכו לזמינות",
"app.userList.userOptions.enableMic": "בוטלה השתקת כל הצופים",
"app.userList.userOptions.enablePrivChat": "שיחה פרטית מאופשרת",
"app.userList.userOptions.enablePubChat": "שיחה ציבורית מאופשרת",
"app.userList.userOptions.enableNote": "פתקיות ציבוריות מאופשרות",
"app.userList.userOptions.showUserList": "רשימת המשתתפים גלויה לצופים",
"app.userList.userOptions.enableOnlyModeratorWebcam": "אתה יכול להדליק את מצלמת הרשת שלך כעת! כולם יראו אותך",
"app.userList.userOptions.enableOnlyModeratorWebcam": "ניתן להדליק את מצלמת הרשת שלך כעת! כולם יראו אותך",
"app.media.label": "מדיה",
"app.media.autoplayAlertDesc": "אפשר גישה",
"app.media.autoplayAlertDesc": "אפשרות גישה",
"app.media.screenshare.start": "שיתוף מסך החל",
"app.media.screenshare.end": "שיתוף מסך הסתיים",
"app.media.screenshare.autoplayBlockedDesc": "נדרש אישור להצגת מסך המנחה.",
"app.media.screenshare.autoplayAllowLabel": "צפה בשיתוף מסך",
"app.media.screenshare.autoplayAllowLabel": "צפייה בשיתוף מסך",
"app.meeting.ended": "המפגש הסתיים",
"app.meeting.meetingTimeRemaining": "זמן נותר למפגש: {0}",
"app.meeting.meetingTimeHasEnded": "המפגש הסתיים ויסגר בקרוב",
"app.meeting.endedMessage": "תופנה למסך הבית",
"app.presentation.hide": "הסתר מצגת",
"app.presentation.hide": "הסתרת מצגת",
"app.presentation.notificationLabel": "מצגת נוכחית",
"app.presentation.slideContent": "שקופיות",
"app.presentation.startSlideContent": "התחל הצגת שקופיות",
"app.presentation.startSlideContent": "התחלת הצגת שקופיות",
"app.presentation.endSlideContent": "סיום הצגת שקופיות",
"app.presentation.emptySlideContent": "שקופית נוכחית ללא תוכן",
"app.presentation.presentationToolbar.noNextSlideDesc": "סיום מצגת",
"app.presentation.presentationToolbar.noPrevSlideDesc": "התחלת מצגת",
"app.presentation.presentationToolbar.selectLabel": "בחר שקופיות",
"app.presentation.presentationToolbar.selectLabel": "בחירת שקופיות",
"app.presentation.presentationToolbar.prevSlideLabel": "שקופית קודמת",
"app.presentation.presentationToolbar.prevSlideDesc": "שנה את המצגת לשקופית הקודמת",
"app.presentation.presentationToolbar.prevSlideDesc": "מעבר המצגת לשקופית הקודמת",
"app.presentation.presentationToolbar.nextSlideLabel": "שקופית הבאה",
"app.presentation.presentationToolbar.nextSlideDesc": "שנה את המצגת לשקופית הבאה",
"app.presentation.presentationToolbar.skipSlideLabel": לג על שקופית",
"app.presentation.presentationToolbar.skipSlideDesc": "שנה את המצגת לשקופית הנבחרת",
"app.presentation.presentationToolbar.fitWidthLabel": "התאם רוחב",
"app.presentation.presentationToolbar.fitWidthDesc": "הצג רוחב שקופית מלא",
"app.presentation.presentationToolbar.fitScreenLabel": "התאם למסך",
"app.presentation.presentationToolbar.fitScreenDesc": "הצג את כל השקופית",
"app.presentation.presentationToolbar.zoomLabel": "זום",
"app.presentation.presentationToolbar.nextSlideDesc": "מעבר המצגת לשקופית הבאה",
"app.presentation.presentationToolbar.skipSlideLabel": ילוג על שקופית",
"app.presentation.presentationToolbar.skipSlideDesc": "מעבר המצגת לשקופית הנבחרת",
"app.presentation.presentationToolbar.fitWidthLabel": "התאמה רוחב",
"app.presentation.presentationToolbar.fitWidthDesc": "הצגת רוחב שקופית מלא",
"app.presentation.presentationToolbar.fitScreenLabel": "התאמה למסך",
"app.presentation.presentationToolbar.fitScreenDesc": "הצגת כל השקופית",
"app.presentation.presentationToolbar.zoomLabel": "תקריב",
"app.presentation.presentationToolbar.zoomDesc": "שנה את רמת הזום במצגת",
"app.presentation.presentationToolbar.zoomInLabel": "הגדלה",
"app.presentation.presentationToolbar.zoomInDesc": "הגדל זום המצגת",
"app.presentation.presentationToolbar.zoomInDesc": "הגדלת תוכן עמוד המצגת",
"app.presentation.presentationToolbar.zoomOutLabel": "הקטנה",
"app.presentation.presentationToolbar.zoomOutDesc": "הקטן זום המצגת",
"app.presentation.presentationToolbar.zoomReset": "איפוס זום",
"app.presentation.presentationToolbar.zoomIndicator": "Current zoom percentage",
"app.presentation.presentationToolbar.fitToWidth": "התאם רוחב",
"app.presentation.presentationToolbar.fitToPage": "Fit to page",
"app.presentation.presentationToolbar.goToSlide": "Slide {0}",
"app.presentation.presentationToolbar.zoomOutDesc": "הקטנת תוכן עמוד המצגת",
"app.presentation.presentationToolbar.zoomReset": "איפוס תקריב",
"app.presentation.presentationToolbar.zoomIndicator": "אחוז תקריב נוכחי",
"app.presentation.presentationToolbar.fitToWidth": "התאמת רוחב",
"app.presentation.presentationToolbar.fitToPage": "התאמה לעמוד",
"app.presentation.presentationToolbar.goToSlide": "עמוד {0}",
"app.presentationUploder.title": "מצגת",
"app.presentationUploder.message": "כמגיש יש לך יכולת להעלות כל מסמך אופיס או קובץ PDF. אנו ממליצים על קובץ PDF לתוצאות טובות ביותר. אנא ודא שמצגת נבחרת באמצעות תיבת הסימון המעגלית בצד ימין.",
"app.presentationUploder.uploadLabel": "העלאה",
"app.presentationUploder.confirmLabel": "אישור",
"app.presentationUploder.confirmDesc": "שמור שינויים והתחל המצגת",
"app.presentationUploder.dismissLabel": טל",
"app.presentationUploder.dismissDesc": "סגור ללא שמירה",
"app.presentationUploder.dropzoneLabel": "גרור קבצים לכאן",
"app.presentationUploder.dropzoneImagesLabel": "גרור תמונות לכאן",
"app.presentationUploder.browseFilesLabel": "או בחר קבצים כאן",
"app.presentationUploder.browseImagesLabel": "or browse/capture for images",
"app.presentationUploder.confirmDesc": "שמירת שינויים והתחל המצגת",
"app.presentationUploder.dismissLabel": יטול",
"app.presentationUploder.dismissDesc": "סגירה ללא שמירה",
"app.presentationUploder.dropzoneLabel": "גרירת קבצים לכאן",
"app.presentationUploder.dropzoneImagesLabel": "גרירת תמונות לכאן",
"app.presentationUploder.browseFilesLabel": "או בחירת קבצים כאן",
"app.presentationUploder.browseImagesLabel": "או בחירה/לכידת תמונה",
"app.presentationUploder.fileToUpload": "להעלאה ...",
"app.presentationUploder.currentBadge": "נוכחי",
"app.presentationUploder.rejectedError": "לא ניתן להעלות קבצים מסוג זה.",
@ -177,16 +186,18 @@
"app.presentationUploder.tableHeading.status": "מצב",
"app.poll.pollPaneTitle": "סקר",
"app.poll.quickPollTitle": "סקר מהיר",
"app.poll.hidePollDesc": "הסתר את תפריט הסקר",
"app.poll.quickPollInstruction": "בחר אופציה להתחלת הסקר.",
"app.poll.activePollInstruction": "צא ממסך זה על מנת לראות את התשובות לסקר בזמן אמת, כשאתה מוכן - לחץ על 'פרסם תוצאות סקר' כדי לפרסם את תוצאותיו לשר המשתתפים",
"app.poll.publishLabel": "פרסם תוצאות סקר",
"app.poll.closeLabel": "סגור",
"app.poll.hidePollDesc": "הסתרת תפריט הסקר",
"app.poll.quickPollInstruction": "בחירת אפשרות להתחלת הסקר.",
"app.poll.activePollInstruction": "יציאה ממסך זה על מנת לראות את התשובות לסקר בזמן אמת, כשאת/ה מוכן - יש לבחור 'פרסום תוצאות סקר' כדי לפרסם את תוצאותיו לשאר המשתתפים",
"app.poll.publishLabel": "פרסום תוצאות סקר",
"app.poll.backLabel": "התחלת סקר",
"app.poll.closeLabel": "סגירה",
"app.poll.waitingLabel": "מחכה למענה ({0}/{1})",
"app.poll.ariaInputCount": "אפשרות סקר {0} מתוך {1}",
"app.poll.customPlaceholder": "הוסף אפשרות מענה",
"app.poll.noPresentationSelected": "לא נבחרה מצגת! אנא בחר אחת.",
"app.poll.clickHereToSelect": "לחץ כאן לבחירה",
"app.poll.customPlaceholder": "הוספת אפשרות מענה",
"app.poll.noPresentationSelected": "לא נבחרה מצגת! אנא בחרו אחת.",
"app.poll.clickHereToSelect": "לחיצה כאן לבחירה",
"app.poll.optionDelete.label" : "מחיקה",
"app.poll.t": "אמת",
"app.poll.f": "שקר",
"app.poll.tf": "אמת / שקר",
@ -209,37 +220,37 @@
"app.poll.liveResult.responsesTitle": "תשובה",
"app.polling.pollingTitle": "אפשרויות סקר",
"app.polling.pollAnswerLabel": "מענה לסקר {0}",
"app.polling.pollAnswerDesc": "בחר באפשרות זו לבחירה ב {0}",
"app.polling.pollAnswerDesc": "בחירת אפשרות זו לבחירה ב {0}",
"app.failedMessage": "Apologies, trouble connecting to the server.",
"app.downloadPresentationButton.label": "הורד את המצגת המקורית",
"app.downloadPresentationButton.label": "הורדת המצגת המקורית",
"app.connectingMessage": "מתחבר ...",
"app.waitingMessage": "נותקת, מנסה להתחבר בעוד {0} שניות...",
"app.retryNow": "נסה שנית",
"app.retryNow": "נסו שנית",
"app.navBar.settingsDropdown.optionsLabel": "אפשרויות",
"app.navBar.settingsDropdown.fullscreenLabel": "מסך מלא",
"app.navBar.settingsDropdown.settingsLabel": "הגדרות",
"app.navBar.settingsDropdown.aboutLabel": "אודות",
"app.navBar.settingsDropdown.exitFullscreenLabel": "צא ממסך מלא",
"app.navBar.settingsDropdown.fullscreenDesc": "הפוך את מסך ההגדרות למסך מלא",
"app.navBar.settingsDropdown.settingsDesc": "שנה הגדרות כלליות",
"app.navBar.settingsDropdown.aboutDesc": "הצג מידע אודות הלקוח",
"app.navBar.settingsDropdown.leaveSessionDesc": "צא מהמפגש",
"app.navBar.settingsDropdown.exitFullscreenDesc": "צא ממסך מלא",
"app.navBar.settingsDropdown.exitFullscreenLabel": "יציאה ממסך מלא",
"app.navBar.settingsDropdown.fullscreenDesc": "מעבר ממסך ההגדרות למסך מלא",
"app.navBar.settingsDropdown.settingsDesc": "עדכון הגדרות כלליות",
"app.navBar.settingsDropdown.aboutDesc": "הצגת מידע אודות הלקוח",
"app.navBar.settingsDropdown.leaveSessionDesc": "יציאה מהמפגש",
"app.navBar.settingsDropdown.exitFullscreenDesc": "יציאה ממסך מלא",
"app.navBar.settingsDropdown.hotkeysLabel": "קיצורי מקלדת",
"app.navBar.settingsDropdown.hotkeysDesc": "רשימת קיצורי מקלדת",
"app.navBar.settingsDropdown.helpLabel": "עזרה",
"app.navBar.settingsDropdown.helpDesc": "הפניית משתמשים לסרטון עזרה (נפתח בחלונית חדשה)",
"app.navBar.settingsDropdown.endMeetingDesc": "מסיים את המפגש הנוכחי",
"app.navBar.settingsDropdown.endMeetingLabel": "סגור כיתה",
"app.navBar.settingsDropdown.endMeetingDesc": "סיום המפגש הנוכחי",
"app.navBar.settingsDropdown.endMeetingLabel": "סיום מפגש",
"app.navBar.userListToggleBtnLabel": "הצגת/הסתרת רשימת משתתפים",
"app.navBar.toggleUserList.ariaLabel": "הצגת/הסתרת רשימת הודעות ומשתתפים",
"app.navBar.toggleUserList.newMessages": "עם התראה על הודעות חדשות",
"app.navBar.recording": "מפגש זה מוקלט",
"app.navBar.recording.on": "מקליט",
"app.navBar.recording.off": "לא מקליט",
"app.navBar.emptyAudioBrdige": "לא נמצא מיקרופום פעיל.",
"app.leaveConfirmation.confirmLabel": "צא",
"app.leaveConfirmation.confirmDesc": "מנתק אותך מהמפגש",
"app.navBar.emptyAudioBrdige": "לא נמצא מיקרופון פעיל.",
"app.leaveConfirmation.confirmLabel": "יציאה",
"app.leaveConfirmation.confirmDesc": "התנתקות מהמפגש",
"app.endMeeting.yesLabel": "כן",
"app.endMeeting.noLabel": "לא",
"app.about.title": "אודות",
@ -247,44 +258,44 @@
"app.about.copyright": "Copyright:",
"app.about.confirmLabel": "אישור",
"app.about.confirmDesc": "אישור",
"app.about.dismissLabel": טל",
"app.about.dismissLabel": יטול",
"app.about.dismissDesc": "Close about client information",
"app.actionsBar.changeStatusLabel": "שנה מצב",
"app.actionsBar.muteLabel": "השתק",
"app.actionsBar.unmuteLabel": טל השתקה",
"app.actionsBar.camOffLabel": בה מצלמה",
"app.actionsBar.raiseLabel": רם",
"app.actionsBar.label": "Actions bar",
"app.actionsBar.changeStatusLabel": "עדכון מצב",
"app.actionsBar.muteLabel": "השתקה",
"app.actionsBar.unmuteLabel": יטול השתקה",
"app.actionsBar.camOffLabel": יבוי מצלמה",
"app.actionsBar.raiseLabel": גברה",
"app.actionsBar.label": "סרגל פעולות",
"app.actionsBar.actionsDropdown.restorePresentationLabel": "אחזר מצגת",
"app.actionsBar.actionsDropdown.restorePresentationDesc": "כפתור לאחזור מצגת לאחר שהיא נסגרה",
"app.screenshare.screenShareLabel" : "שיתוף מסך",
"app.submenu.application.applicationSectionTitle": "אפליקציה",
"app.submenu.application.animationsLabel": "אנימציה",
"app.submenu.application.fontSizeControlLabel": "גודל פונט",
"app.submenu.application.increaseFontBtnLabel": "הקטן גודל פונט",
"app.submenu.application.decreaseFontBtnLabel": "הגדל גודל פונט",
"app.submenu.application.fontSizeControlLabel": "גודל גופן",
"app.submenu.application.increaseFontBtnLabel": "הקטן גודל גופן",
"app.submenu.application.decreaseFontBtnLabel": "הגדל גודל גופן",
"app.submenu.application.currentSize": "גודל נוכחי {0}",
"app.submenu.application.languageLabel": "שפה",
"app.submenu.application.languageOptionLabel": "בחר שפה",
"app.submenu.application.languageOptionLabel": "בחירת שפה",
"app.submenu.application.noLocaleOptionLabel": "לא הוגדרה שפת ברירת מחדל",
"app.submenu.audio.micSourceLabel": "מיקרופון",
"app.submenu.audio.speakerSourceLabel": "רמקול",
"app.submenu.audio.streamVolumeLabel": "עוצמת שמע",
"app.submenu.video.title": "וידאו",
"app.submenu.video.videoSourceLabel": "מקור צפיה",
"app.submenu.video.videoOptionLabel": "בחר מקור צפיה",
"app.submenu.video.videoOptionLabel": "בחירת מקור צפיה",
"app.submenu.video.videoQualityLabel": "איכות וידאו",
"app.submenu.video.qualityOptionLabel": "בחר איכות וידאו",
"app.submenu.video.qualityOptionLabel": "בחירת איכות וידאו",
"app.submenu.video.participantsCamLabel": "מציג את מצלמות המשתתפים",
"app.settings.applicationTab.label": "אפליקציה",
"app.settings.audioTab.label": "קול",
"app.settings.videoTab.label": "וידאו",
"app.settings.usersTab.label": "משתתפים",
"app.settings.main.label": "הגדרות",
"app.settings.main.cancel.label": טל",
"app.settings.main.cancel.label.description": "התעלם מהשינויים וסגור את מסך ההגדרות",
"app.settings.main.save.label": "שמור",
"app.settings.main.save.label.description": "שמור את השינויים וסגור את מסך ההתראות",
"app.settings.main.cancel.label": יטול",
"app.settings.main.cancel.label.description": "ביטול שינויים וסגירת מסך ההגדרות",
"app.settings.main.save.label": "שמירה",
"app.settings.main.save.label.description": "שמירת השינויים וסגירת מסך ההתראות",
"app.settings.dataSavingTab.label": "חסכון בנתונים",
"app.settings.dataSavingTab.webcam": "אפשר מצלמות רשת",
"app.settings.dataSavingTab.screenShare": "אפשר שיתוף מסך",
@ -292,50 +303,50 @@
"app.settings.save-notification.label": "הגדרת נשמרו",
"app.switch.onLabel": "לא",
"app.switch.offLabel": "כן",
"app.talkingIndicator.ariaMuteDesc" : "בחר להשתקת משתמש",
"app.talkingIndicator.isTalking" : "{0} מדבר",
"app.talkingIndicator.ariaMuteDesc" : "בחירת השתקת משתמש",
"app.talkingIndicator.isTalking" : "{0} מדבר",
"app.talkingIndicator.wasTalking" : "{0} הפסיק לדבר",
"app.actionsBar.actionsDropdown.actionsLabel": "פעולות נוספות",
"app.actionsBar.actionsDropdown.initPollLabel": "התחל סקר",
"app.actionsBar.actionsDropdown.desktopShareLabel": תף את המסך",
"app.actionsBar.actionsDropdown.initPollLabel": "התחלת סקר",
"app.actionsBar.actionsDropdown.desktopShareLabel": יתוף מסך",
"app.actionsBar.actionsDropdown.lockedDesktopShareLabel": "שיתוף מסך לא מאופשר במפגש זה",
"app.actionsBar.actionsDropdown.stopDesktopShareLabel": "הפסת שיתוף מסך",
"app.actionsBar.actionsDropdown.presentationDesc": "העלה את המצגת שלך",
"app.actionsBar.actionsDropdown.initPollDesc": "התחל סקר",
"app.actionsBar.actionsDropdown.desktopShareDesc": "שיתוך מסך",
"app.actionsBar.actionsDropdown.stopDesktopShareDesc": "הפסקת שיתוך מסך",
"app.actionsBar.actionsDropdown.pollBtnLabel": "התחל סקר",
"app.actionsBar.actionsDropdown.pollBtnDesc": "הצג/הסתר את מסך הסקרים",
"app.actionsBar.actionsDropdown.saveUserNames": "שמור שמות משתמשים",
"app.actionsBar.actionsDropdown.createBreakoutRoom": "צור חדרים פרטיים",
"app.actionsBar.actionsDropdown.createBreakoutRoomDesc": "צור חדרים פרטיים לפיצול המפגש הראשי ",
"app.actionsBar.actionsDropdown.captionsLabel": "ערוך כתוביות",
"app.actionsBar.actionsDropdown.captionsDesc": "הצג/הסתר את מסך הכתוביות",
"app.actionsBar.actionsDropdown.presentationDesc": "העלאת המצגת שלך",
"app.actionsBar.actionsDropdown.initPollDesc": "התחלת סקר",
"app.actionsBar.actionsDropdown.desktopShareDesc": "שיתוף מסך",
"app.actionsBar.actionsDropdown.stopDesktopShareDesc": "הפסקת שיתוף מסך",
"app.actionsBar.actionsDropdown.pollBtnLabel": "התחלת סקר",
"app.actionsBar.actionsDropdown.pollBtnDesc": "הצגת/הסתרת מסך הסקרים",
"app.actionsBar.actionsDropdown.saveUserNames": "שמירת שמות משתמשים",
"app.actionsBar.actionsDropdown.createBreakoutRoom": "יצירת חדרים פרטיים",
"app.actionsBar.actionsDropdown.createBreakoutRoomDesc": "יצירת חדרים פרטיים לפיצול המפגש הראשי ",
"app.actionsBar.actionsDropdown.captionsLabel": "עריכת כתוביות",
"app.actionsBar.actionsDropdown.captionsDesc": "הצגת/הסתרת מסך הכתוביות",
"app.actionsBar.actionsDropdown.takePresenter": "הפוך עצמך למנחה המפגש",
"app.actionsBar.actionsDropdown.takePresenterDesc": "הפוך אצמך למנחה המפגש",
"app.actionsBar.emojiMenu.statusTriggerLabel": "ערוך סטטוס",
"app.actionsBar.actionsDropdown.takePresenterDesc": "הפוך עצמך למנחה המפגש",
"app.actionsBar.emojiMenu.statusTriggerLabel": "עריכת מצב",
"app.actionsBar.emojiMenu.awayLabel": "לא ליד המחשב",
"app.actionsBar.emojiMenu.awayDesc": "ערוך את המצב שלך ל'לא ליד המחשב'",
"app.actionsBar.emojiMenu.raiseHandDesc": "הרם יד לשאול שאלה",
"app.actionsBar.emojiMenu.awayDesc": "עריכת המצב שלך ל'לא ליד המחשב'",
"app.actionsBar.emojiMenu.raiseHandDesc": "הרמת יד לשאול שאלה",
"app.actionsBar.emojiMenu.neutralLabel": "לא החלטתי",
"app.actionsBar.emojiMenu.neutralDesc": "שנה את המצב שלך ל'לא החלטתי'",
"app.actionsBar.emojiMenu.neutralDesc": "עדכון המצב שלך ל'לא החלטתי'",
"app.actionsBar.emojiMenu.confusedLabel": "מבולבל",
"app.actionsBar.emojiMenu.confusedDesc": "שנה את המצב שלך ל'מבולבל'",
"app.actionsBar.emojiMenu.confusedDesc": "עדכון המצב שלך ל'מבולבל'",
"app.actionsBar.emojiMenu.sadLabel": "עצוב",
"app.actionsBar.emojiMenu.sadDesc": "שנה את המצב של ל'עצוב'",
"app.actionsBar.emojiMenu.sadDesc": "עדכון המצב של ל'עצוב'",
"app.actionsBar.emojiMenu.happyLabel": "שמח",
"app.actionsBar.emojiMenu.happyDesc": "שנה את המצב שלך ל'שמח'",
"app.actionsBar.emojiMenu.noneLabel": "נקה מצב",
"app.actionsBar.emojiMenu.noneDesc": "נקה מצב",
"app.actionsBar.emojiMenu.applauseLabel": "מחא כפיים",
"app.actionsBar.emojiMenu.applauseDesc": "שנה את המצב שלך ל'מחא כפיים'",
"app.actionsBar.emojiMenu.happyDesc": "עדכון המצב שלך ל'שמח'",
"app.actionsBar.emojiMenu.noneLabel": "איפוס מצב",
"app.actionsBar.emojiMenu.noneDesc": "איפוס מצב",
"app.actionsBar.emojiMenu.applauseLabel": "כפיים",
"app.actionsBar.emojiMenu.applauseDesc": "עדכון המצב שלך ל'כפיים'",
"app.actionsBar.emojiMenu.thumbsUpLabel": "אגודל למעלה",
"app.actionsBar.emojiMenu.thumbsUpDesc": "שנה את המצב שלך ל'אגודל למעלה'",
"app.actionsBar.emojiMenu.thumbsUpDesc": "עדכון המצב שלך ל'אגודל למעלה'",
"app.actionsBar.emojiMenu.thumbsDownLabel": "אגודל מטה",
"app.actionsBar.emojiMenu.thumbsDownDesc": "שנה את המצב שלך ל'אגודל מטה'",
"app.actionsBar.emojiMenu.thumbsDownDesc": "עדכון המצב שלך ל'אגודל מטה'",
"app.actionsBar.currentStatusDesc": "מצב נוכחי {0}",
"app.actionsBar.captions.start": "הצג כתוביות",
"app.actionsBar.captions.stop": "הסתר כתוביות",
"app.actionsBar.captions.start": "הצגת כתוביות",
"app.actionsBar.captions.stop": "הסתרת כתוביות",
"app.audioNotification.audioFailedError1001": "Error 1001: WebSocket disconnected",
"app.audioNotification.audioFailedError1002": "Error 1002: Could not make a WebSocket connection",
"app.audioNotification.audioFailedError1003": "Error 1003: Browser version not supported",
@ -350,33 +361,33 @@
"app.audioNotification.audioFailedError1012": "Error 1012: ICE connection closed",
"app.audioNotification.audioFailedMessage": "Your audio connection failed to connect",
"app.audioNotification.mediaFailedMessage": "getUserMicMedia failed as only secure origins are allowed",
"app.audioNotification.closeLabel": "סגור",
"app.audioNotification.closeLabel": "סגירה",
"app.audioNotificaion.reconnectingAsListenOnly": "דיבור לא מאופשר במפגש זה, אתה מחובר במצב האזנה בלבד",
"app.breakoutJoinConfirmation.title": "הצטרף לחדר צד",
"app.breakoutJoinConfirmation.message": "אתה רוצה להצטרף",
"app.breakoutJoinConfirmation.confirmDesc": "הצטרף לחדר צד",
"app.breakoutJoinConfirmation.dismissLabel": טל",
"app.breakoutJoinConfirmation.dismissDesc": "סגירה וביטול הצטרפות לחדר צד",
"app.breakoutJoinConfirmation.freeJoinMessage": "בחר חדר צד שברצונך להצטרף אליו",
"app.breakoutTimeRemainingMessage": "זמן נותר לחדר הצד: {0}",
"app.breakoutWillCloseMessage": "נגמר הזמן. חדר הצד יסגר בקרוב",
"app.breakoutJoinConfirmation.title": "הצטרפות לחדר למידה",
"app.breakoutJoinConfirmation.message": "האם להצטרף",
"app.breakoutJoinConfirmation.confirmDesc": "הצטרפות לחדר למידה",
"app.breakoutJoinConfirmation.dismissLabel": יטול",
"app.breakoutJoinConfirmation.dismissDesc": "סגירה וביטול הצטרפות לחדר למידה",
"app.breakoutJoinConfirmation.freeJoinMessage": "בחירת חדר למידה שברצונך להצטרף אליו",
"app.breakoutTimeRemainingMessage": "זמן נותר לחדר הלמידה: {0}",
"app.breakoutWillCloseMessage": "נגמר הזמן. חדר הלמידה יסגר בקרוב",
"app.calculatingBreakoutTimeRemaining": "מחשב זמן נותר ...",
"app.audioModal.ariaTitle": "הצטרפות למפגש מקוון",
"app.audioModal.microphoneLabel": "מיקרופון",
"app.audioModal.listenOnlyLabel": "האזנה בלבד",
"app.audioModal.audioChoiceLabel": "תרצה להצטרף למפגש הקולי?",
"app.audioModal.audioChoiceLabel": "האם להצטרף למפגש הקולי?",
"app.audioModal.iOSBrowser": "קול/וידאו לא נתמכים",
"app.audioModal.iOSErrorDescription": "כרגע וידאו וקול לא נתמכים בכרום למכשירי אפל",
"app.audioModal.iOSErrorRecommendation": "מומלץ להשתמש בספארי על מכשיר זה",
"app.audioModal.audioChoiceDesc": "איך ברצונך להצטרך למפגש הקולי?",
"app.audioModal.unsupportedBrowserLabel": "It looks like you're using a browser that is not fully supported. Please use either {0} or {1} for full support.",
"app.audioModal.closeLabel": "סגור",
"app.audioModal.closeLabel": "סגירה",
"app.audioModal.yes": "כן",
"app.audioModal.no": "לא",
"app.audioModal.yes.arialabel" : "ניתן לשמוע הד",
"app.audioModal.no.arialabel" : "לא ניתן לשמוע הד",
"app.audioModal.echoTestTitle": "זו בדיקת הד פרטית. אמור כמה מילים. האם שמעת הד ?",
"app.audioModal.settingsTitle": "שנה את הגדרות הקול שלך",
"app.audioModal.echoTestTitle": "זו בדיקת הד פרטית. יש להגיד כמה מילים. האם שמעת הד ?",
"app.audioModal.settingsTitle": "עדכון הגדרות הקול שלך",
"app.audioModal.helpTitle": "אירעה שגיאה בציוד הקול/וידאו",
"app.audioModal.helpText": "Did you give permission for access to your microphone? Note that a dialog should appear when you try to join audio, asking for your media device permissions, please accept that in order to join the audio conference. If that is not the case, try changing your microphone permissions in your browser's settings.",
"app.audioModal.help.noSSL": "This page is unsecured. For microphone access to be allowed the page must be served over HTTPS. Please contact the server administrator.",
@ -385,9 +396,9 @@
"app.audioDial.audioDialDescription": "Dial",
"app.audioDial.audioDialConfrenceText": "and enter the conference PIN number:",
"app.audioModal.autoplayBlockedDesc": "We need your permission to play audio.",
"app.audioModal.playAudio": "Play audio",
"app.audioModal.playAudio.arialabel" : "Play audio",
"app.audioDial.tipIndicator": "Tip",
"app.audioModal.playAudio": "נגינת צליל",
"app.audioModal.playAudio.arialabel" : "נגינת צליל",
"app.audioDial.tipIndicator": "עצה",
"app.audioDial.tipMessage": "Press the '0' key on your phone to mute/unmute yourself.",
"app.audioManager.joinedAudio": "You have joined the audio conference",
"app.audioManager.joinedEcho": "You have joined the echo test",
@ -398,20 +409,20 @@
"app.audioManager.requestTimeout": "Error: There was a timeout in the request",
"app.audioManager.invalidTarget": "Error: Tried to request something to an invalid target",
"app.audioManager.mediaError": "Error: There was an issue getting your media devices",
"app.audio.joinAudio": "הצטרף למפגש קולי",
"app.audio.leaveAudio": "עזוב את המפגש הקולי",
"app.audio.enterSessionLabel": "היכנס למפגש",
"app.audio.playSoundLabel": "נגן צליל",
"app.audio.backLabel": "חזור",
"app.audio.audioSettings.titleLabel": "בחר את הגדרות הקול",
"app.audio.joinAudio": "הצטרפות למפגש קולי",
"app.audio.leaveAudio": "עזיבת המפגש הקולי",
"app.audio.enterSessionLabel": "כניסה למפגש",
"app.audio.playSoundLabel": "נגינת צליל",
"app.audio.backLabel": "חזרה",
"app.audio.audioSettings.titleLabel": "בחירת הגדרות הקול",
"app.audio.audioSettings.descriptionLabel": "Please note, a dialog will appear in your browser, requiring you to accept sharing your microphone.",
"app.audio.audioSettings.microphoneSourceLabel": "מיקרופון",
"app.audio.audioSettings.speakerSourceLabel": "רמקולים",
"app.audio.audioSettings.microphoneStreamLabel": "עוצמת שמע",
"app.audio.audioSettings.retryLabel": סה שנית",
"app.audio.listenOnly.backLabel": "חזור",
"app.audio.listenOnly.closeLabel": "סגור",
"app.audio.permissionsOverlay.title": "אפשר גישה למיקרופון שלך",
"app.audio.audioSettings.retryLabel": יסיון חוזר",
"app.audio.listenOnly.backLabel": "חזרה",
"app.audio.listenOnly.closeLabel": "סגירה",
"app.audio.permissionsOverlay.title": "אפשרו גישה למיקרופון שלכם",
"app.audio.permissionsOverlay.hint": "We need you to allow us to use your media devices in order to join you to the voice conference :)",
"app.error.removed": "You have been removed from the conference",
"app.error.meeting.ended": "You have logged out of the conference",
@ -419,46 +430,46 @@
"app.meeting.logout.permissionEjectReason": "Ejected due to permission violation",
"app.meeting.logout.ejectedFromMeeting": "You have been removed from the meeting",
"app.meeting.logout.validateTokenFailedEjectReason": "Failed to validate authorization token",
"app.meeting.logout.userInactivityEjectReason": "User inactive for too long",
"app.meeting-ended.rating.legendLabel": "Feedback rating",
"app.meeting-ended.rating.starLabel": "Star",
"app.modal.close": "Close",
"app.modal.close.description": "Disregards changes and closes the modal",
"app.modal.confirm": "Done",
"app.modal.newTab": "(opens new tab)",
"app.modal.confirm.description": "Saves changes and closes the modal",
"app.dropdown.close": "Close",
"app.meeting.logout.userInactivityEjectReason": "המשתמש לא היה פעיל במשך זמן רב",
"app.meeting-ended.rating.legendLabel": "דרוג משוב",
"app.meeting-ended.rating.starLabel": "כוכב",
"app.modal.close": "סגירה",
"app.modal.close.description": "ביטול שינויים וסגירת חלונית",
"app.modal.confirm": "הושלם",
"app.modal.newTab": "(פתיחה בלשונית חדשה)",
"app.modal.confirm.description": "שמירת שינויים וסגירת חלונית",
"app.dropdown.close": "סגירה",
"app.error.400": "Bad Request",
"app.error.401": "Unauthorized",
"app.error.403": "You have been removed from the meeting",
"app.error.404": "Not found",
"app.error.410": "Meeting has ended",
"app.error.500": "Ops, something went wrong",
"app.error.leaveLabel": "Log in again",
"app.error.leaveLabel": "התחברו שוב",
"app.error.fallback.presentation.title": "An error occurred",
"app.error.fallback.presentation.description": "It has been logged. Please try reloading the page.",
"app.error.fallback.presentation.reloadButton": "טען מחדש",
"app.guest.waiting": "מחכים לאישורך להצטרף למפגש",
"app.userList.guest.waitingUsers": "משתמשים ממתינים",
"app.userList.guest.waitingUsersTitle": "ניהול משתמשים",
"app.userList.guest.optionTitle": "סקור משתמשים ממתינים",
"app.userList.guest.allowAllAuthenticated": שר את כל האורחים המאומתים",
"app.userList.guest.allowAllGuests": שר את כל האורחים",
"app.userList.guest.allowEveryone": שר לכולם",
"app.userList.guest.denyEveryone": "מנע מכולם",
"app.userList.guest.optionTitle": "סקירת משתמשים ממתינים",
"app.userList.guest.allowAllAuthenticated": ישור כל האורחים המאומתים",
"app.userList.guest.allowAllGuests": ישור כל האורחים",
"app.userList.guest.allowEveryone": ישור לכולם",
"app.userList.guest.denyEveryone": "מניעה מכולם",
"app.userList.guest.pendingUsers": "{0} משתמשים ממתינים",
"app.userList.guest.pendingGuestUsers": "{0} משתתפים ממתינים להצרף",
"app.userList.guest.pendingGuestAlert": "הצטרך למפגש ומחכה לאישורך.",
"app.userList.guest.rememberChoice": "זכור בחירה",
"app.userList.guest.pendingGuestUsers": "{0} משתתפים ממתינים להצטרף",
"app.userList.guest.pendingGuestAlert": "הצטרף למפגש ומחכה לאישורך.",
"app.userList.guest.rememberChoice": "זכירת בחירה",
"app.user-info.title": "חיפוש תיקיה",
"app.toast.breakoutRoomEnded": "מפגש חדר הצג הסתיים. בבקשה הצטרך מחדש למפגש הקולי.",
"app.toast.chat.public": "הודעת צ'אט פומבי חדשה",
"app.toast.breakoutRoomEnded": "מפגש חדר למידה הסתיים. בבקשה הצטרפו מחדש למפגש הקולי.",
"app.toast.chat.public": "הודעת צ'אט ציבורי חדשה",
"app.toast.chat.private": "הודעת צ'אט פרטי חדשה",
"app.toast.chat.system": "מערכת",
"app.toast.clearedEmoji.label": "אמוג'י סטטוס נמחק",
"app.toast.setEmoji.label": "סטטוס הוחלף ל {0}",
"app.toast.clearedEmoji.label": "אמוג'י מצב נמחק",
"app.toast.setEmoji.label": "מצב הוחלף ל {0}",
"app.toast.meetingMuteOn.label": "כל המשתתפים הושתקו",
"app.toast.meetingMuteOff.label": "השתקהת מפגש בוטלה",
"app.toast.meetingMuteOff.label": "השתקת מפגש בוטלה",
"app.notification.recordingStart": "מפגש זה מוקלט כעת",
"app.notification.recordingStop": "מפגש זה אינו מוקלט",
"app.notification.recordingPaused": "מפגש זה אינו מוקלט החל מרגע זה",
@ -481,40 +492,40 @@
"app.shortcut-help.togglePan": "Activate Pan tool (Presenter)",
"app.shortcut-help.nextSlideDesc": "שקופית הבאה (מנחה)",
"app.shortcut-help.previousSlideDesc": "שקופית קודמת (מנחה)",
"app.lock-viewers.title": "נעל הגדרות משתתפים",
"app.lock-viewers.title": "נעינת הגדרות משתתפים",
"app.lock-viewers.description": "מסך זה מאפשר לך לקבע את מצב השיתוף של הצופים.",
"app.lock-viewers.featuresLable": "הרשאה",
"app.lock-viewers.lockStatusLabel": "נעול/פתוח לשינוי",
"app.lock-viewers.webcamLabel": "שיתוף וידאו",
"app.lock-viewers.otherViewersWebcamLabel": "צפיה בווידאו שאחרים משתפים",
"app.lock-viewers.microphoneLable": "שיתוף קול",
"app.lock-viewers.PublicChatLabel": "שליחת הודעות פומביות",
"app.lock-viewers.PublicChatLabel": "שליחת הודעות ציבוריות",
"app.lock-viewers.PrivateChatLable": "שליחת הודעות פרטיות",
"app.lock-viewers.notesLabel": "עריכת פתקיות ציבוריות",
"app.lock-viewers.userListLabel": "צפיה ברשימת המשתתפים במפגש",
"app.lock-viewers.ariaTitle": "נעילת אפשרויות שיתוף למשתתפים",
"app.lock-viewers.button.apply": "אישור",
"app.lock-viewers.button.cancel": טל",
"app.lock-viewers.button.cancel": יטול",
"app.lock-viewers.locked": "לא מאופשר",
"app.lock-viewers.unlocked": "מאופשר",
"app.recording.startTitle": "התחל הקלטה",
"app.recording.stopTitle": "השהה הקלטה",
"app.recording.resumeTitle": "הפעל הקלטה מחדש",
"app.recording.startTitle": "התחלת הקלטה",
"app.recording.stopTitle": "השהית הקלטה",
"app.recording.resumeTitle": "הפעלת הקלטה מחדש",
"app.recording.startDescription": "ניתן להפעיל את ההקלטה במועד מואחר יותר על ידי לחיצה על כפתור ההקלטה.",
"app.recording.stopDescription": "אתה בטוח כי ברצונך לעצור את ההקלטה? ניתצן להמשיך אותה על ידי לחיצה על כפתור ההקלטה.",
"app.videoPreview.cameraLabel": "מצלמה",
"app.videoPreview.profileLabel": "איכות",
"app.videoPreview.cancelLabel": טל",
"app.videoPreview.closeLabel": "סגור",
"app.videoPreview.cancelLabel": יטול",
"app.videoPreview.closeLabel": "סגירה",
"app.videoPreview.findingWebcamsLabel": "מחפש מצלמות רשת",
"app.videoPreview.startSharingLabel": "התחל שיתוף",
"app.videoPreview.webcamOptionLabel": "בחר מצלמה",
"app.videoPreview.startSharingLabel": "התחלת שיתוף",
"app.videoPreview.webcamOptionLabel": "בחירת מצלמה",
"app.videoPreview.webcamPreviewLabel": "תצוגה מקדימה",
"app.videoPreview.webcamSettingsTitle": "הגדרות מצלמה",
"app.videoPreview.webcamNotFoundLabel": "לא נמצאה מצלמת רשת",
"app.videoPreview.profileNotFoundLabel": "אין פרופילי מצלמה מתאימים",
"app.video.joinVideo": תף ווידאו",
"app.video.leaveVideo": "הפסק שיתוף וידאו",
"app.video.joinVideo": יתוף ווידאו",
"app.video.leaveVideo": "הפסקת שיתוף וידאו",
"app.video.iceCandidateError": "Error on adding ICE candidate",
"app.video.iceConnectionStateError": "Error 1107: ICE negotiation failed",
"app.video.permissionError": "Error on sharing webcam. Please check permissions",
@ -527,11 +538,11 @@
"app.video.suggestWebcamLock": "Enforce lock setting to viewers webcams?",
"app.video.suggestWebcamLockReason": "(this will improve the stability of the meeting)",
"app.video.enable": "אפשר",
"app.video.cancel": טל",
"app.video.swapCam": "החלף",
"app.video.swapCamDesc": "החלף את כיווני המצלמות",
"app.video.cancel": יטול",
"app.video.swapCam": "החלפת",
"app.video.swapCamDesc": "החלפת כיווני המצלמות",
"app.video.videoLocked": "שיתוף וידאו נעול",
"app.video.videoButtonDesc": תף וידאו",
"app.video.videoButtonDesc": יתוף וידאו",
"app.video.videoMenu": "תפריט וידאו",
"app.video.videoMenuDisabled": "Video menu Webcam is disabled in settings",
"app.video.videoMenuDesc": "Open video menu dropdown",
@ -570,59 +581,59 @@
"app.whiteboard.toolbar.color.violet": "סגול",
"app.whiteboard.toolbar.color.magenta": "סגלגל",
"app.whiteboard.toolbar.color.silver": "כסף",
"app.whiteboard.toolbar.undo": טל הערות",
"app.whiteboard.toolbar.clear": "נקה את כל ההארות",
"app.whiteboard.toolbar.multiUserOn": "הפעל גישה מרובת משתתפים ללוח",
"app.whiteboard.toolbar.multiUserOff": טל גישה מרובת משתתפים ללוח",
"app.whiteboard.toolbar.fontSize": "רשימת גדלי פונט",
"app.whiteboard.toolbar.undo": יטול הערות",
"app.whiteboard.toolbar.clear": "מחיקת כל ההערות",
"app.whiteboard.toolbar.multiUserOn": "הפעלת גישה מרובת משתתפים ללוח",
"app.whiteboard.toolbar.multiUserOff": יטול גישה מרובת משתתפים ללוח",
"app.whiteboard.toolbar.fontSize": "רשימת גדלי גופן",
"app.feedback.title": "התנתקת מהמפגש המקוון",
"app.feedback.subtitle": "We'd love to hear about your experience with BigBlueButton (optional)",
"app.feedback.textarea": "How can we make BigBlueButton better?",
"app.feedback.sendFeedback": "Send Feedback",
"app.feedback.sendFeedbackDesc": "Send a feedback and leave the meeting",
"app.videoDock.webcamFocusLabel": "פוקוס",
"app.videoDock.webcamFocusDesc": "קבע פוקוס למצלמה שנבחרה",
"app.videoDock.webcamUnfocusLabel": טל פוקוס",
"app.videoDock.webcamUnfocusDesc": טל פוקוס למצלמה שנבחרה",
"app.videoDock.webcamFocusLabel": "מיקוד",
"app.videoDock.webcamFocusDesc": "קביעת מיקוד למצלמה שנבחרה",
"app.videoDock.webcamUnfocusLabel": יטול מיקוד",
"app.videoDock.webcamUnfocusDesc": יטול מיקוד למצלמה שנבחרה",
"app.videoDock.autoplayBlockedDesc": "נדרש אישורך להצגת וידאו של שאר המשתתפים.",
"app.videoDock.autoplayAllowLabel": "הצג מצלמות רשת",
"app.invitation.title": "Breakout room invitation",
"app.invitation.confirm": "Invite",
"app.createBreakoutRoom.title": "Breakout Rooms",
"app.createBreakoutRoom.ariaTitle": "Hide Breakout Rooms",
"app.createBreakoutRoom.breakoutRoomLabel": "Breakout Rooms {0}",
"app.createBreakoutRoom.generatingURL": "Generating URL",
"app.createBreakoutRoom.generatedURL": "Generated",
"app.createBreakoutRoom.duration": "Duration {0}",
"app.createBreakoutRoom.room": "Room {0}",
"app.createBreakoutRoom.notAssigned": "Not assigned ({0})",
"app.createBreakoutRoom.join": "Join room",
"app.createBreakoutRoom.joinAudio": "Join audio",
"app.createBreakoutRoom.returnAudio": "Return audio",
"app.createBreakoutRoom.alreadyConnected": "Already in room",
"app.createBreakoutRoom.confirm": "Create",
"app.createBreakoutRoom.record": "Record",
"app.createBreakoutRoom.numberOfRooms": "Number of rooms",
"app.createBreakoutRoom.durationInMinutes": "Duration (minutes)",
"app.createBreakoutRoom.randomlyAssign": "Randomly assign",
"app.createBreakoutRoom.endAllBreakouts": "End all breakout rooms",
"app.createBreakoutRoom.roomName": "{0} (Room - {1})",
"app.createBreakoutRoom.doneLabel": "Done",
"app.createBreakoutRoom.nextLabel": "Next",
"app.createBreakoutRoom.minusRoomTime": "Decrease breakout room time to",
"app.createBreakoutRoom.addRoomTime": "Increase breakout room time to",
"app.createBreakoutRoom.addParticipantLabel": "+ Add participant",
"app.createBreakoutRoom.freeJoin": "Allow users to choose a breakout room to join",
"app.createBreakoutRoom.leastOneWarnBreakout": "You must place at least one user in a breakout room.",
"app.videoDock.autoplayAllowLabel": "הצגת מצלמות רשת",
"app.invitation.title": "הזמנה לחדרי למידה",
"app.invitation.confirm": "הזמנה",
"app.createBreakoutRoom.title": "חדרי למידה",
"app.createBreakoutRoom.ariaTitle": "הסתרת חדרי למידה",
"app.createBreakoutRoom.breakoutRoomLabel": "חדרי למידה {0}",
"app.createBreakoutRoom.generatingURL": "מחולל URL",
"app.createBreakoutRoom.generatedURL": "כתובה חוללה",
"app.createBreakoutRoom.duration": "משך זמן {0}",
"app.createBreakoutRoom.room": "חדר {0}",
"app.createBreakoutRoom.notAssigned": "לא הוקצא ({0})",
"app.createBreakoutRoom.join": "הצטרפות לחדר",
"app.createBreakoutRoom.joinAudio": "הצטרפות לשמיעה",
"app.createBreakoutRoom.returnAudio": "החזרת קול",
"app.createBreakoutRoom.alreadyConnected": "כבר נמצא בחדר",
"app.createBreakoutRoom.confirm": "יצירה",
"app.createBreakoutRoom.record": "הקלטה",
"app.createBreakoutRoom.numberOfRooms": "מספר חדרים",
"app.createBreakoutRoom.durationInMinutes": "משך זמן (בדקות)",
"app.createBreakoutRoom.randomlyAssign": "הקצאה אקראית",
"app.createBreakoutRoom.endAllBreakouts": "סיום כל חדרי הלימוד",
"app.createBreakoutRoom.roomName": "{0} (חדר - {1})",
"app.createBreakoutRoom.doneLabel": "הושלם",
"app.createBreakoutRoom.nextLabel": "הבא",
"app.createBreakoutRoom.minusRoomTime": "צמצום משך זמן לחדר הלימוד",
"app.createBreakoutRoom.addRoomTime": "הוספת משך זמן לחדר הלימוד",
"app.createBreakoutRoom.addParticipantLabel": "+ הוספת משתתפים",
"app.createBreakoutRoom.freeJoin": "אפשרות למשתמשים בחירת חדר לימוד",
"app.createBreakoutRoom.leastOneWarnBreakout": "יש לשייך משתמש אחד לפחות לחדר לימוד כלשהו.",
"app.createBreakoutRoom.modalDesc": "Tip: You can drag-and-drop a user's name to assign them to a specific breakout room.",
"app.createBreakoutRoom.roomTime": "{0} minutes",
"app.createBreakoutRoom.numberOfRoomsError": "The number of rooms is invalid.",
"app.externalVideo.start": "Share a new video",
"app.externalVideo.title": "Share an external video",
"app.externalVideo.input": "External Video URL",
"app.externalVideo.urlInput": "Add Video URL",
"app.createBreakoutRoom.roomTime": "{0} דקות",
"app.createBreakoutRoom.numberOfRoomsError": "מספר חדרי הלימוד לא תקין.",
"app.externalVideo.start": "שיתוף וידאו חדש",
"app.externalVideo.title": "שיתוף וידאו חיצוני",
"app.externalVideo.input": "כתובת וידאו חיצוני URL",
"app.externalVideo.urlInput": "הוספת כתובת וידאו URL",
"app.externalVideo.urlError": "This video URL isn't supported",
"app.externalVideo.close": "Close",
"app.externalVideo.close": "סגירה",
"app.externalVideo.autoPlayWarning": "Play the video to enable media synchronization",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Share an external video",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Stop sharing external video",

View File

@ -16,7 +16,7 @@
"app.chat.dropdown.options": "チャット設定",
"app.chat.dropdown.clear": "消去",
"app.chat.dropdown.copy": "コピー",
"app.chat.dropdown.save": "セーブ",
"app.chat.dropdown.save": "保存",
"app.chat.label": "チャット",
"app.chat.offline": "オフライン",
"app.chat.pollResult": "投票結果",
@ -147,10 +147,10 @@
"app.meeting.ended": "このセッションは終了しました",
"app.meeting.meetingTimeRemaining": "会議の残り時間:{0}",
"app.meeting.meetingTimeHasEnded": "時間終了。会議はまもなく終了します。",
"app.meeting.endedByUserMessage": "このセッションは{0}によって閉じられました",
"app.meeting.endedByUserMessage": "{0}さんがこのセッションを終えました",
"app.meeting.endedByNoModeratorMessageSingular": "一分たっても司会者が現れなかったため、会議は終了しました。",
"app.meeting.endedByNoModeratorMessagePlural": "{0}分たっても司会者が現れなかったため、会議は終了しました。",
"app.meeting.endedMessage": "ホームスクリーンに戻ります",
"app.meeting.endedMessage": "ホーム画面に戻ります",
"app.meeting.alertMeetingEndsUnderMinutesSingular": "会議はあと一分で終了します。",
"app.meeting.alertMeetingEndsUnderMinutesPlural": "会議はあと{0}分で終了します。",
"app.meeting.alertBreakoutEndsUnderMinutesPlural": "この小会議はあと{0}分で終了します。",
@ -188,7 +188,7 @@
"app.presentation.presentationToolbar.goToSlide": "スライド {0}",
"app.presentation.placeholder": "プレゼンのアップロードを待っています",
"app.presentationUploder.title": "プレゼンテーション",
"app.presentationUploder.message": "プレゼンタはドキュメントをアップロードすることができます。お勧めのファイル形式はPDFファイルです。右側のチェックボックスをクリックし、プレゼンテーションが選択されていることを確認してください。",
"app.presentationUploder.message": "プレゼンタはドキュメントをアップロードすることができます。お勧めのファイル形式はPDFファイルです。右側のチェックボックスをクリックし、プレゼンテーションが選択されていることを確認してください。",
"app.presentationUploder.uploadLabel": "アップロード",
"app.presentationUploder.confirmLabel": "確認",
"app.presentationUploder.confirmDesc": "変更を保存してプレゼンテーションを開始する",
@ -219,8 +219,8 @@
"app.presentationUploder.conversion.timeout": "エラー:変換に時間がかかりすぎました",
"app.presentationUploder.conversion.pageCountFailed": "ページ数の判定に失敗しました。",
"app.presentationUploder.conversion.unsupportedDocument": "この拡張子のファイルはサポートされていません",
"app.presentationUploder.isDownloadableLabel": "プレゼン資料のダウンロードは許可されていません - クリックするとプレゼン資料のダウンロードが許可されます",
"app.presentationUploder.isNotDownloadableLabel": "プレゼン資料のダウンロードが可能となっています - クリックするとプレゼン資料のダウンロードが禁止されます",
"app.presentationUploder.isDownloadableLabel": "プレゼン資料のダウンロードは現在許可されていません ー クリックすると許可されます",
"app.presentationUploder.isNotDownloadableLabel": "プレゼン資料のダウンロードが可能となっています ー クリックするとこれを禁止します",
"app.presentationUploder.removePresentationLabel": "プレゼンテーション削除",
"app.presentationUploder.setAsCurrentPresentation": "現在のプレゼンテーションを表示する",
"app.presentationUploder.tableHeading.filename": "ファイル名",
@ -361,7 +361,7 @@
"app.screenshare.screenShareLabel" : "画面共有",
"app.submenu.application.applicationSectionTitle": "アプリケーション",
"app.submenu.application.animationsLabel": "アニメーション効果",
"app.submenu.application.audioFilterLabel": "マイク音声の自動正",
"app.submenu.application.audioFilterLabel": "マイク音声の自動正",
"app.submenu.application.fontSizeControlLabel": "フォントサイズ",
"app.submenu.application.increaseFontBtnLabel": "アプリケーションのフォントサイズを大きくする",
"app.submenu.application.decreaseFontBtnLabel": "アプリケーションのフォントサイズを小さくする",
@ -371,7 +371,7 @@
"app.submenu.application.noLocaleOptionLabel": "アクティブなロケールがありません",
"app.submenu.application.paginationEnabledLabel": "ビデオのページ割",
"app.submenu.application.layoutOptionLabel": "レイアウトのタイプ",
"app.submenu.application.pushLayoutOptionLabel": "全員共通のレイアウトにする",
"app.submenu.application.pushLayoutOptionLabel": "レイアウトを全員共通にする",
"app.submenu.notification.SectionTitle": "通知",
"app.submenu.notification.Desc": "何をどのように通知するかを設定できます。",
"app.submenu.notification.audioAlertLabel": "音声通知",
@ -514,7 +514,7 @@
"app.audioModal.playAudio.arialabel" : "音声を再生する",
"app.audioDial.tipIndicator": "ヒント",
"app.audioDial.tipMessage": "電話の「0」キーでミュートの設定/解除が行えます",
"app.audioModal.connecting": "音声の接続を確立しています",
"app.audioModal.connecting": "音声接続を確立中",
"app.audioManager.joinedAudio": "音声会議に参加しました",
"app.audioManager.joinedEcho": "エコーテストに入りました",
"app.audioManager.leftAudio": "音声会議から退席しました",
@ -843,7 +843,7 @@
"app.createBreakoutRoom.freeJoin": "ユーザーに参加する小会議室を選択させる",
"app.createBreakoutRoom.leastOneWarnBreakout": "小会議室には最低1人のユーザーが必要です。",
"app.createBreakoutRoom.minimumDurationWarnBreakout": "小会議室の最小利用時間は{0}分です。",
"app.createBreakoutRoom.modalDesc": "ヒント:ユーザー名前をドラッグアンドドロップして、特定の小会議室に割り当てることができます。",
"app.createBreakoutRoom.modalDesc": "ヒント:ユーザーの名前をドラッグ&ドロップして、特定の小会議室に割り当てることができます。",
"app.createBreakoutRoom.roomTime": "{0} 分",
"app.createBreakoutRoom.numberOfRoomsError": "会議室の数が正しく設定されていません。",
"app.createBreakoutRoom.duplicatedRoomNameError": "会議室名を重複してつけることはできません。",
@ -911,16 +911,16 @@
"app.learningDashboard.user": "ユーザー",
"app.learningDashboard.indicators.meetingStatusEnded": "終了",
"app.learningDashboard.indicators.meetingStatusActive": "会議中",
"app.learningDashboard.indicators.usersOnline": "アクティブなユーザー",
"app.learningDashboard.indicators.usersOnline": "人のアクティブなユーザー",
"app.learningDashboard.indicators.usersTotal": "ユーザー総数",
"app.learningDashboard.indicators.polls": "投票",
"app.learningDashboard.indicators.raiseHand": "挙手",
"app.learningDashboard.indicators.polls": "回の投票",
"app.learningDashboard.indicators.raiseHand": "回の挙手",
"app.learningDashboard.indicators.activityScore": "アクティビティスコア",
"app.learningDashboard.indicators.duration": "時間",
"app.learningDashboard.usersTable.title": "概要",
"app.learningDashboard.usersTable.colOnline": "オンライン時間",
"app.learningDashboard.usersTable.colOnline": "オンライン時間",
"app.learningDashboard.usersTable.colTalk": "会話時間",
"app.learningDashboard.usersTable.colWebcam": "ウェブカメラ時間",
"app.learningDashboard.usersTable.colWebcam": "カメラオン時間",
"app.learningDashboard.usersTable.colMessages": "メッセージ",
"app.learningDashboard.usersTable.colEmojis": "絵文字",
"app.learningDashboard.usersTable.colRaiseHands": "挙手",
@ -933,8 +933,8 @@
"app.learningDashboard.pollsTable.anonymousAnswer": "匿名投票(回答は最終行)",
"app.learningDashboard.pollsTable.anonymousRowName": "匿名",
"app.learningDashboard.statusTimelineTable.title": "ステータスの履歴",
"app.learningDashboard.errors.invalidToken": "セッショントークンが無効",
"app.learningDashboard.errors.dataUnavailable": "データはもう閲覧不能です"
"app.learningDashboard.errors.invalidToken": "セッショントークンが無効です",
"app.learningDashboard.errors.dataUnavailable": "データはもう閲覧できません"
}

View File

@ -702,8 +702,8 @@
"app.videoPreview.closeLabel": "Закрыть",
"app.videoPreview.findingWebcamsLabel": "Ищем веб-камеры",
"app.videoPreview.startSharingLabel": "Начать трансляцию с веб-камеры",
"app.videoPreview.stopSharingLabel": "Остановить демонстрацию экрана",
"app.videoPreview.stopSharingAllLabel": "Прекратить всё",
"app.videoPreview.stopSharingLabel": "Выключить свою веб-камеру",
"app.videoPreview.stopSharingAllLabel": "Выключить все веб-камеры",
"app.videoPreview.sharedCameraLabel": "Эта камера уже транслируется",
"app.videoPreview.webcamOptionLabel": "Выбрать веб-камеру",
"app.videoPreview.webcamPreviewLabel": "Предварительный просмотр веб-камеры",
@ -797,6 +797,7 @@
"app.whiteboard.toolbar.palmRejectionOn": "Включить предотвращение случайного рисования ладонью",
"app.whiteboard.toolbar.palmRejectionOff": "Отключить предотвращение случайного рисования ладонью",
"app.whiteboard.toolbar.fontSize": "Выбор размера шрифта",
"app.whiteboard.toolbarAriaLabel": "Инструменты доски",
"app.feedback.title": "Вы вышли из конференции",
"app.feedback.subtitle": "Мы бы хотели услышать о вашем опыте работы с BigBlueButton (необязательно)",
"app.feedback.textarea": "Как мы можем сделать BigBlueButton лучше?",
@ -921,8 +922,8 @@
"app.learningDashboard.usersTable.colTalk": "Время разговора",
"app.learningDashboard.usersTable.colWebcam": "Время с вкл. веб-камерой",
"app.learningDashboard.usersTable.colMessages": "Сообщений",
"app.learningDashboard.usersTable.colEmojis": "Смайлики",
"app.learningDashboard.usersTable.colRaiseHands": "Поднятые руки",
"app.learningDashboard.usersTable.colEmojis": "Смайликов",
"app.learningDashboard.usersTable.colRaiseHands": "Поднятых рук",
"app.learningDashboard.usersTable.colActivityScore": "Оценка активности",
"app.learningDashboard.usersTable.colStatus": "Статус",
"app.learningDashboard.usersTable.userStatusOnline": "Онлайн",

View File

@ -53,6 +53,7 @@
"app.captions.pad.dictationOffDesc": " Konuşma tanımayı kapatır",
"app.captions.pad.speechRecognitionStop": "Sesli algılama tarayıcı uyumsuzluğu ya da belirli bir süre sessizlikten dolayı durduruldu.",
"app.textInput.sendLabel": "Gönderildi",
"app.title.defaultViewLabel": "Varsayılan Sunum Görünümü",
"app.note.title": "Notlar",
"app.note.label": "Not",
"app.note.hideNoteLabel": "Notu gizle",
@ -232,6 +233,7 @@
"app.presentationUploder.itemPlural" : "öğeler",
"app.presentationUploder.clearErrors": "Hataları temizle",
"app.presentationUploder.clearErrorsDesc": "Başarısız sunum yüklemelerini temizler",
"app.presentationUploder.uploadViewTitle": "Sunum Yükle",
"app.poll.pollPaneTitle": "Anket",
"app.poll.quickPollTitle": "Hızlı Anket",
"app.poll.hidePollDesc": "Anket menüsü bölmesini gizler",
@ -290,6 +292,8 @@
"app.poll.liveResult.usersTitle": "Kullanıcılar",
"app.poll.liveResult.responsesTitle": "Yanıt",
"app.poll.liveResult.secretLabel": "Bu isimsiz bir ankettir. Bireysel cevaplar gösterilmez.",
"app.poll.removePollOpt": "Kaldırılan Anket seçenekleri [0]",
"app.poll.emptyPollOpt": "Boş",
"app.polling.pollingTitle": "Anket seçenekleri",
"app.polling.pollQuestionTitle": "Anket Sorusu",
"app.polling.submitLabel": "Teslim Et",
@ -664,6 +668,7 @@
"app.guest-policy.button.askModerator": "Moderatöre sorun",
"app.guest-policy.button.alwaysAccept": "Her zaman kabul edin",
"app.guest-policy.button.alwaysDeny": "Her zaman reddedin",
"app.guest-policy.policyBtnDesc": "Toplantı misafir politikasını ayarla",
"app.connection-status.ariaTitle": "Bağlantı durumu modeli",
"app.connection-status.title": "Bağlantı Durumu",
"app.connection-status.description": "Kullanıcıların bağlantı durumunu görüntüle",
@ -744,6 +749,7 @@
"app.video.virtualBackground.blur": "Bulanık",
"app.video.virtualBackground.genericError": "Kamera efekti uygulanamadı. Tekrar deneyin.",
"app.video.virtualBackground.camBgAriaDesc": "Web kamerası sanal arka planını {0} olarak ayarlar",
"app.video.dropZoneLabel": "Buraya bırakın",
"app.fullscreenButton.label": "{0} tam ekran yap",
"app.fullscreenUndoButton.label": "{0} tam ekranı geri al",
"app.switchButton.expandLabel": "Ekran paylaşım videosunu genişlet",
@ -791,6 +797,7 @@
"app.whiteboard.toolbar.palmRejectionOn": "Reddini açın",
"app.whiteboard.toolbar.palmRejectionOff": "Reddini kapatın",
"app.whiteboard.toolbar.fontSize": "Yazı tipi boyutu listesi",
"app.whiteboard.toolbarAriaLabel": "Sunum araçları",
"app.feedback.title": "Konferanstan ayrıldınız",
"app.feedback.subtitle": "BigBlueButton deneyiminizi bizimle paylaşın (zorunlu değil)",
"app.feedback.textarea": "BigBlueButton'ı nasıl daha iyi yapabiliriz?",
@ -845,6 +852,7 @@
"app.createBreakoutRoom.extendTimeLabel": "Uzat",
"app.createBreakoutRoom.extendTimeCancel": "İptal",
"app.createBreakoutRoom.extendTimeHigherThanMeetingTimeError": "Çalışma odalarının süresi, kalan toplantı süresini aşamaz.",
"app.createBreakoutRoom.roomNameInputDesc": "Tenefüs odasının ismini güncelle",
"app.externalVideo.start": "Yeni bir video paylaş",
"app.externalVideo.title": "Harici Video Paylaş",
"app.externalVideo.input": "Harici Video URL",
@ -900,16 +908,33 @@
"playback.player.thumbnails.wrapper.aria": "Küçük resim alanı",
"playback.player.video.wrapper.aria": "Video alanı",
"app.learningDashboard.dashboardTitle": "Katılım Panosu",
"app.learningDashboard.user": "Kullanıcı",
"app.learningDashboard.indicators.meetingStatusEnded": "Sonlandı",
"app.learningDashboard.indicators.meetingStatusActive": "Devam Ediyor",
"app.learningDashboard.indicators.usersOnline": "Aktif Kullanıcı",
"app.learningDashboard.indicators.usersTotal": "Katılımcıların Toplam Sayısı",
"app.learningDashboard.indicators.polls": "Anket",
"app.learningDashboard.indicators.raiseHand": "El Kaldırma",
"app.learningDashboard.indicators.activityScore": "Etkinlik Puanı",
"app.learningDashboard.indicators.duration": "Süre",
"app.learningDashboard.usersTable.title": "Genel bakış",
"app.learningDashboard.usersTable.colOnline": "Online süresi",
"app.learningDashboard.usersTable.colTalk": "Konuşma süresi",
"app.learningDashboard.usersTable.colWebcam": "Webkamera süresi",
"app.learningDashboard.usersTable.colMessages": "Mesaj",
"app.learningDashboard.usersTable.colEmojis": "Emojiler",
"app.learningDashboard.usersTable.colRaiseHands": "El Kaldır",
"app.learningDashboard.usersTable.colActivityScore": "Etkinlik skoru",
"app.learningDashboard.usersTable.colStatus": "Durum",
"app.learningDashboard.usersTable.userStatusOnline": "Çevrimiçi",
"app.learningDashboard.usersTable.userStatusOffline": "Çevrimdışı",
"app.learningDashboard.usersTable.noUsers": "Henüz kullanıcı yok",
"app.learningDashboard.pollsTable.title": "Anket",
"app.learningDashboard.pollsTable.anonymousAnswer": "İsimsiz Anket (cevaplar son satırda)",
"app.learningDashboard.pollsTable.anonymousRowName": "İsimsiz",
"app.learningDashboard.statusTimelineTable.title": "Durum Zaman Çizelgesi"
"app.learningDashboard.statusTimelineTable.title": "Durum Zaman Çizelgesi",
"app.learningDashboard.errors.invalidToken": "Geçersiz oturum tokenı",
"app.learningDashboard.errors.dataUnavailable": "Veri artık erişilebilir değil"
}

View File

@ -1,7 +1,8 @@
{
"app.home.greeting": "Вітаємо! Ваша презентація почнеться найближчим часом... ",
"app.chat.submitLabel": "Надіслати повідомлення",
"app.chat.errorMaxMessageLength": "Повідомлення з {0} символів є занадто довгим",
"app.chat.loading": "Завантажено повідомлень чату: {0}%",
"app.chat.errorMaxMessageLength": "Повідомлення є довшим допустимого на {0} символів",
"app.chat.disconnected": "Ви від'єднались, повідомлення не можуть бути надіслані",
"app.chat.locked": "Чат заблоковано, неможливо надіслати повідомлення",
"app.chat.inputLabel": "Текст повідомлення у чаті з {0}",
@ -20,10 +21,12 @@
"app.chat.offline": "Не в мережі",
"app.chat.pollResult": "Результати опитування",
"app.chat.emptyLogLabel": "Журнал чату порожній",
"app.chat.clearPublicChatMessage": "Історію загального чату очищено ведучим",
"app.chat.clearPublicChatMessage": "Історію загального чату очищено модератором",
"app.chat.multi.typing": "Учасники пишуть",
"app.chat.one.typing": "{0} набирає",
"app.chat.two.typing": "{0} і {1} набирають",
"app.chat.copySuccess": "Стенограму чату скопійовано",
"app.chat.copyErr": "Скопіювати стенограму чату не вдалось",
"app.captions.label": "Субтитри",
"app.captions.menu.close": "Закрити",
"app.captions.menu.start": "Почати",
@ -48,11 +51,13 @@
"app.captions.pad.dictationStop": "Зупинити диктування",
"app.captions.pad.dictationOnDesc": "Включити розпізнавання мови",
"app.captions.pad.dictationOffDesc": "Вимкнути розпізнавання мови",
"app.captions.pad.speechRecognitionStop": "Розпізнавання мови зупинено через несумісність переглядача чи чи певний час тиші",
"app.textInput.sendLabel": "Відіслати",
"app.note.title": "Спільні нотатки",
"app.note.label": "Нотатки",
"app.note.hideNoteLabel": "Сховати нотатки",
"app.note.tipLabel": "Натисніть Esc, щоб сфокусувати панель інструментів редактора",
"app.note.locked": "Заблоковано",
"app.user.activityCheck": "Перевірка активності учасника",
"app.user.activityCheck.label": "Перевірте, чи учасник зараз на зустрiчi ({0})",
"app.user.activityCheck.check": "Перевірка",
@ -65,13 +70,16 @@
"app.userList.presenter": "Ведучий",
"app.userList.you": "Ви",
"app.userList.locked": "Обмежено",
"app.userList.byModerator": "(ведучий)",
"app.userList.byModerator": "(модератор)",
"app.userList.label": "Список учасників",
"app.userList.toggleCompactView.label": "Увімкнути/вимкнути компактний вид",
"app.userList.moderator": "Модератор",
"app.userList.mobile": "Мобільний",
"app.userList.guest": "Гість",
"app.userList.sharingWebcam": "Вебкамера",
"app.userList.menuTitleContext": "Доступні параметри",
"app.userList.chatListItem.unreadSingular": "Одне нове повідомлення",
"app.userList.chatListItem.unreadPlural": "{0} нових повідомлень",
"app.userList.menu.chat.label": "Почати приватний чат",
"app.userList.menu.clearStatus.label": "Зняти статус",
"app.userList.menu.removeUser.label": "Вилучити учасника",
@ -82,7 +90,7 @@
"app.userList.menu.giveWhiteboardAccess.label" : "Надати доступ до дошки",
"app.userList.menu.removeWhiteboardAccess.label": "Заборонити доступ до дошки",
"app.userList.userAriaLabel": "{0} {1} {2} Статус {3}",
"app.userList.menu.promoteUser.label": "Зробити ведучим",
"app.userList.menu.promoteUser.label": "Зробити модератором",
"app.userList.menu.demoteUser.label": "Понизити до глядача",
"app.userList.menu.unlockUser.label": "Зняти обмеження для {0}",
"app.userList.menu.lockUser.label": "Обмежити можливості для {0}",
@ -127,6 +135,9 @@
"app.media.screenshare.notSupported": "Трансляція екрану не підтримується переглядачем.",
"app.media.screenshare.autoplayBlockedDesc": "Нам потрібен дозвіл, щоб показати вам екран ведучого.",
"app.media.screenshare.autoplayAllowLabel": "Показати екран, який демонструється",
"app.screenshare.presenterLoadingLabel": "Демонстрація екрану завантажується",
"app.screenshare.viewerLoadingLabel": "Демонстрація екрану ведучого завантажується",
"app.screenshare.presenterSharingLabel": "Тепер ви демонструєте свій екран",
"app.screenshare.screenshareFinalError": "Код {0}. Неможливо відобразити екран",
"app.screenshare.screenshareRetryError": "Код {0}. Спробуйте показати екран знову",
"app.screenshare.screenshareRetryOtherEnvError": "Код {0}. Неможливо відобразити екран. Спробуйте знову з іншим браузером або пристроєм",
@ -134,7 +145,10 @@
"app.screenshare.screensharePermissionError": "Код {0}. Необхідно надати дозвіл на показ екрану.",
"app.meeting.ended": "Цей сеанс завершився",
"app.meeting.meetingTimeRemaining": "Залишилось часу зустрічі: {0}",
"app.meeting.meetingTimeHasEnded": "Час закінчився. Зустріч буде закрито незабаром",
"app.meeting.meetingTimeHasEnded": "Час закінчився. Зустріч незабаром буде закрито",
"app.meeting.endedByUserMessage": "{0} закінчив зустріч",
"app.meeting.endedByNoModeratorMessageSingular": "Зустріч закінчено через відсутність хоча б одного модератора більше хвилини",
"app.meeting.endedByNoModeratorMessagePlural": "Зустріч закінчено через відсутність хоча б одного модератора більше {0} хвилин",
"app.meeting.endedMessage": "Вас буде перенаправлено на головну сторінку",
"app.meeting.alertMeetingEndsUnderMinutesSingular": "Зустріч завершується за 1 хв.",
"app.meeting.alertMeetingEndsUnderMinutesPlural": "Зустріч завершується за {0} хв.",
@ -171,6 +185,7 @@
"app.presentation.presentationToolbar.fitToWidth": "Умістити за шириною",
"app.presentation.presentationToolbar.fitToPage": "Умістити на сторінку",
"app.presentation.presentationToolbar.goToSlide": "Слайд {0}",
"app.presentation.placeholder": "Очікується завантаження презентації",
"app.presentationUploder.title": "Презентація",
"app.presentationUploder.message": "Ведучий може завантажувати будь-який документ офісного формату, включно PDF. Ми рекомендуємо завантажувати презентації саме у форматі PDF. Після завантаження поставте прапорець навпроти імені файлу, який ви хочете показати учасникам.",
"app.presentationUploder.uploadLabel": "Завантажити",
@ -186,6 +201,7 @@
"app.presentationUploder.currentBadge": "Поточний",
"app.presentationUploder.rejectedError": "Неможливо завантажити вибрані файл(и). Перевірте тип файлу(iв).",
"app.presentationUploder.upload.progress": "Завантаження ({0}%)",
"app.presentationUploder.upload.413": "Файл надто великий, розмір перевищує допустимі {0} МБ",
"app.presentationUploder.genericError": "Ой лишенько! Щось пішло не так ...",
"app.presentationUploder.upload.408": "Вичерпано час запиту дії токену для завантаження.",
"app.presentationUploder.upload.404": "404: Неправильний токен для завантаження",
@ -195,10 +211,13 @@
"app.presentationUploder.conversion.generatingThumbnail": "Створення мініатюр...",
"app.presentationUploder.conversion.generatedSlides": "Слайди створюються...",
"app.presentationUploder.conversion.generatingSvg": "Створення зображень SVG...",
"app.presentationUploder.conversion.pageCountExceeded": "Кількість сторінок перевищує максимальну кількість {0}",
"app.presentationUploder.conversion.officeDocConversionInvalid": "Не вийшло опрацювати документ. Будь ласка, завантажте файл у форматі PDF.",
"app.presentationUploder.conversion.officeDocConversionFailed": "Не вийшло опрацювати документ. Будь ласка, завантажте файл у форматі PDF.",
"app.presentationUploder.conversion.pdfHasBigPage": "Не вдалось конвертувати файл PDF, будь ласка, спробуйте його покращити. Максимальний розмір сторінки {0} ",
"app.presentationUploder.conversion.timeout": "Ой, перетворення займає надто багато часу",
"app.presentationUploder.conversion.pageCountFailed": "Не вийшло визначити кількість сторінок.",
"app.presentationUploder.conversion.unsupportedDocument": "Файли з таким розширенням не підтримуються",
"app.presentationUploder.isDownloadableLabel": "Завантаження презентації заборонене - клікніть щоб дозволити завантажити презентацію",
"app.presentationUploder.isNotDownloadableLabel": "Завантаження презентації дозволено - клікніть щоб заборонити завантажити презентацію",
"app.presentationUploder.removePresentationLabel": "Вилучити презентацію",
@ -213,6 +232,7 @@
"app.presentationUploder.itemPlural" : "елементів",
"app.presentationUploder.clearErrors": "Очистити помилки",
"app.presentationUploder.clearErrorsDesc": "Очищує помилки завантажень презентацій",
"app.presentationUploder.uploadViewTitle": "Завантажити презентацію",
"app.poll.pollPaneTitle": "Опитування",
"app.poll.quickPollTitle": "Швидке опитування",
"app.poll.hidePollDesc": "Ховає панель меню опитувань",
@ -225,7 +245,7 @@
"app.poll.closeLabel": "Закрити",
"app.poll.waitingLabel": "Очікування на відповіді ({0} / {1})",
"app.poll.ariaInputCount": "Опція спеціального опитування {0} з {1}",
"app.poll.customPlaceholder": "Додати варіант опитування",
"app.poll.customPlaceholder": "Додати варіант відповіді",
"app.poll.noPresentationSelected": "Не вибрано жодної презентації! Виберіть щонайменше одну.",
"app.poll.clickHereToSelect": "Клацніть тут для вибору",
"app.poll.panel.desc" : "Заповніть деталі вашого голосування нижче",
@ -238,15 +258,22 @@
"app.poll.addItem.label" : "Додати",
"app.poll.question.title": "Поставити питання",
"app.poll.start.label" : "Почати голосування",
"app.poll.secretPoll.label" : "Анонімне опитування",
"app.poll.secretPoll.isSecretLabel": "Опитування анонімне - ви не будете бачити окремих відповідей",
"app.poll.secretPoll.notSecretLabel": "Опитування не анонімне - ви зможете бачити окремі відповіді",
"app.poll.questionErr": "Введіть питання",
"app.poll.optionErr": "Введіть варіант опитування",
"app.poll.startPollDesc": "Розпочинає опитування",
"app.poll.showRespDesc": "Показує налаштування відповідей",
"app.poll.addRespDesc": "Додати поле відповіді в опитування",
"app.poll.deleteRespDesc": "Видаляє варіант {0}",
"app.poll.t": "Дійсно",
"app.poll.f": "Хибно",
"app.poll.tf": "Дійсно / хибно",
"app.poll.y": "Так",
"app.poll.n": "Ні",
"app.poll.abstention": "Утримання",
"app.poll.yna": "Так / Ні / Утримання",
"app.poll.abstention": "Утримуюсь",
"app.poll.yna": "Так / Ні / Утримуюсь",
"app.poll.a2": "A / B",
"app.poll.a3": "A / B / C",
"app.poll.a4": "A / B / C / D",
@ -255,7 +282,7 @@
"app.poll.answer.false": "Хибно",
"app.poll.answer.yes": "Так",
"app.poll.answer.no": "Ні",
"app.poll.answer.abstention": "Утримання",
"app.poll.answer.abstention": "Утримуюсь",
"app.poll.answer.a": "А",
"app.poll.answer.b": "Б",
"app.poll.answer.c": "В",
@ -263,11 +290,15 @@
"app.poll.answer.e": "Ґ",
"app.poll.liveResult.usersTitle": "Учасники",
"app.poll.liveResult.responsesTitle": "Відповідь",
"app.poll.liveResult.secretLabel": "Це анонімне опитування. Окремі відповіді не показано.",
"app.poll.removePollOpt": "Видалено варіант відповіді {0}",
"app.polling.pollingTitle": "Варіанти опитування",
"app.polling.pollQuestionTitle": "Питання голосування",
"app.polling.submitLabel": "Відправити",
"app.polling.submitAriaLabel": "Відправити відповідь на голосування",
"app.polling.responsePlaceholder": "Введіть відповідь",
"app.polling.responseSecret": "Анонімне опитування - ведучий не може бачити вашої відповіді.",
"app.polling.responseNotSecret": "Звичайне опитування - ведучий може бачити вашу відповідь.",
"app.polling.pollAnswerLabel": "Відповідь опитування {0}",
"app.polling.pollAnswerDesc": "Виберіть цей варіант щоб проголосувати за {0}",
"app.failedMessage": "Вибачте, проблеми з підключенням до сервера.",
@ -276,6 +307,8 @@
"app.waitingMessage": "Втрачено з'єднання. Спроба повторного з'єднання через {0} секунд...",
"app.retryNow": "Повторити",
"app.muteWarning.label": "Натисніть {0} щоб вас почули інші",
"app.muteWarning.disableMessage": "Сповіщення про вимкнення мікрофона вимкнено до його увімкнення",
"app.muteWarning.tooltip": "Натисніть, щоб зачинити та вимкнути сповіщення до увімкнення мікрофона",
"app.navBar.settingsDropdown.optionsLabel": "Параметри",
"app.navBar.settingsDropdown.fullscreenLabel": "На весь екран",
"app.navBar.settingsDropdown.settingsLabel": "Налаштування",
@ -290,7 +323,7 @@
"app.navBar.settingsDropdown.hotkeysLabel": "Гарячі клавіші",
"app.navBar.settingsDropdown.hotkeysDesc": "Перелік гарячих клавiш",
"app.navBar.settingsDropdown.helpLabel": "Допомога",
"app.navBar.settingsDropdown.helpDesc": "Переспрямовує учасника до відео з інструкціями (нова вкладка)",
"app.navBar.settingsDropdown.helpDesc": "Переспрямовує учасника до навчального відео (нова вкладка)",
"app.navBar.settingsDropdown.endMeetingDesc": "Завершує поточну зустріч",
"app.navBar.settingsDropdown.endMeetingLabel": "Завершити зустріч",
"app.navBar.userListToggleBtnLabel": "Перемкнути список учасників",
@ -303,8 +336,9 @@
"app.leaveConfirmation.confirmLabel": "Вийти",
"app.leaveConfirmation.confirmDesc": "Виводить вас із зустрічі",
"app.endMeeting.title": "Завершено {0}",
"app.endMeeting.description": "Ця дія завершить сессію для {0} активних користувачів(користувача). Ви певні що хочете завершити цю сессію?",
"app.endMeeting.description": "Ця дія завершить сеанс для {0} активних користувачів(користувача). Ви певні що хочете завершити цей сеанс?",
"app.endMeeting.noUserDescription": "Ви певні щодо завершення зустрічі?",
"app.endMeeting.contentWarning": "Повідомлення чату, спільні нотатки, вміст дошки та спільні документи більше не будуть безпосередньо доступними",
"app.endMeeting.yesLabel": "Так",
"app.endMeeting.noLabel": "Ні",
"app.about.title": "Про застосунок",
@ -334,16 +368,19 @@
"app.submenu.application.languageOptionLabel": "Вибрати мову",
"app.submenu.application.noLocaleOptionLabel": "Відсутні переклади",
"app.submenu.application.paginationEnabledLabel": "Відео посторінково",
"app.submenu.application.layoutOptionLabel": "Тип компонування",
"app.submenu.application.pushLayoutOptionLabel": "Встановити тип компонування всім учасникам",
"app.submenu.notification.SectionTitle": "Сповіщення",
"app.submenu.notification.Desc": "Оберіть як та про що вас буде сповіщено",
"app.submenu.notification.audioAlertLabel": "Звукові сповіщення",
"app.submenu.notification.pushAlertLabel": "Виринаючі сповіщення",
"app.submenu.notification.messagesLabel": "Повідомлення у чаті",
"app.submenu.notification.userJoinLabel": "Приєднався учасник",
"app.submenu.notification.userLeaveLabel": "Учасник від'єднався",
"app.submenu.notification.guestWaitingLabel": "Гість чекає на підтвердження",
"app.submenu.audio.micSourceLabel": "Джерело мікрофона",
"app.submenu.audio.speakerSourceLabel": "Пристрій відтворення",
"app.submenu.audio.streamVolumeLabel": "Гучність звука",
"app.submenu.audio.streamVolumeLabel": "Гучність звуку",
"app.submenu.video.title": "Відео",
"app.submenu.video.videoSourceLabel": "Джерело відео",
"app.submenu.video.videoOptionLabel": "Виберіть джерело відео",
@ -364,8 +401,10 @@
"app.settings.dataSavingTab.screenShare": "Демонстрація екрану",
"app.settings.dataSavingTab.description": "Для заощадження передачі даних, будь ласка, вимкніть функції, які пов'язані з демонстрацією відео:",
"app.settings.save-notification.label": "Налаштування збережено",
"app.statusNotifier.lowerHands": "Опущені руки",
"app.statusNotifier.lowerHands": "Опустити руки",
"app.statusNotifier.raisedHandsTitle": "Підняті руки",
"app.statusNotifier.raisedHandDesc": "{0} підняли руки",
"app.statusNotifier.raisedHandDescOneUser": "{0} підняв руку",
"app.statusNotifier.and": "та",
"app.switch.onLabel": "УВІМК",
"app.switch.offLabel": "ВИМК",
@ -389,8 +428,9 @@
"app.actionsBar.actionsDropdown.createBreakoutRoomDesc": "створити кімнати і розділити учасників між ними ",
"app.actionsBar.actionsDropdown.captionsLabel": "Створити приховані субтитри",
"app.actionsBar.actionsDropdown.captionsDesc": "Вмикає панель субтитрів",
"app.actionsBar.actionsDropdown.takePresenter": "Стати презентатором",
"app.actionsBar.actionsDropdown.takePresenter": "Стати ведучим",
"app.actionsBar.actionsDropdown.takePresenterDesc": "Встановити себе ведучим/презентатором",
"app.actionsBar.actionsDropdown.selectRandUserLabel": "Вибрати випадкового учасника",
"app.actionsBar.actionsDropdown.selectRandUserDesc": "Обирає випадкового користувача серед активних глядачів",
"app.actionsBar.emojiMenu.statusTriggerLabel": "Статус",
"app.actionsBar.emojiMenu.awayLabel": "Відійшов",
@ -422,7 +462,7 @@
"app.audioNotification.audioFailedError1003": "Версія переглядача не підтримується (Помилка 1003)",
"app.audioNotification.audioFailedError1004": "Помилка у виклилику (reason={0}) (Помилка 1004)",
"app.audioNotification.audioFailedError1005": "Виклик несподівано скінчився (Помилка 1005)",
"app.audioNotification.audioFailedError1006": "Час виклика закінчився (Помилка 1006)",
"app.audioNotification.audioFailedError1006": "Час виклику закінчився (Помилка 1006)",
"app.audioNotification.audioFailedError1007": "Не вдалося з'єднатися (ICE помилка 1007)",
"app.audioNotification.audioFailedError1008": "Трансфер не вдався (Помилка 1008)",
"app.audioNotification.audioFailedError1009": "Не можу отримати інфо з STUN/TURN сервера (Помилка 1009)",
@ -445,6 +485,8 @@
"app.audioModal.ariaTitle": "Вікно підключення до голосової конференції",
"app.audioModal.microphoneLabel": "Мікрофон",
"app.audioModal.listenOnlyLabel": "Тільки слухати",
"app.audioModal.microphoneDesc": "Приєднатись до голосової конференції з мікрофоном",
"app.audioModal.listenOnlyDesc": "Приєднатись до голосової конференції лише як слухач",
"app.audioModal.audioChoiceLabel": "Як ви хочете приєднатися до голосової конференції?",
"app.audioModal.iOSBrowser": "Звук/відео не підтримується",
"app.audioModal.iOSErrorDescription": "Поки що звук та відео у Chrome для iOS не підтримуються.",
@ -456,7 +498,7 @@
"app.audioModal.no": "Ні",
"app.audioModal.yes.arialabel" : "Чутно луну",
"app.audioModal.no.arialabel" : "Луну не чутно",
"app.audioModal.echoTestTitle": "Перевірка звука. Будь ласка, скажіть щось. Чи ви чуєте себе?",
"app.audioModal.echoTestTitle": "Перевірка звуку. Будь ласка, скажіть щось. Чи ви чуєте себе?",
"app.audioModal.settingsTitle": "Налаштування звуку",
"app.audioModal.helpTitle": "З'явилися проблеми з вашими медіа пристроями",
"app.audioModal.helpText": "Чи ви надали дозвіл на доступ до мікрофона? Зверніть увагу, що коли ви намагаєтеся приєднатися до голосової конференції, має з'явитися діалогове вікно, в якому вас запитають про дозвіл на під'єднання мультимедійних пристроїв. Будь ласка, прийміть це, щоб встановити голосовий зв'язок. Якщо цього не відбулося спробуйте змінити дозволи мікрофона у налаштуваннях вашого переглядача.",
@ -470,6 +512,7 @@
"app.audioModal.playAudio.arialabel" : "Відтворювати звук",
"app.audioDial.tipIndicator": "Підказка",
"app.audioDial.tipMessage": "Натисніть кнопку '0' на телефоні, щоб вимкнути чи увімкнути мікрофон",
"app.audioModal.connecting": "Встановлення голосового зв'язку",
"app.audioManager.joinedAudio": "Ви приєдналися до голосової конференції",
"app.audioManager.joinedEcho": "Зараз відбуватиметься перевірка звуку",
"app.audioManager.leftAudio": "Ви вийшли з голосової конференції",
@ -481,6 +524,7 @@
"app.audioManager.mediaError": "Помилка: Виникли проблеми з пристроями відтворення звуку",
"app.audio.joinAudio": "Приєднатися до голосової конференції ",
"app.audio.leaveAudio": "Вийти з аудіо конференції",
"app.audio.changeAudioDevice": "Змінити аудіопристрій",
"app.audio.enterSessionLabel": "Приєднатися до сеансу",
"app.audio.playSoundLabel": "Відтворити звук",
"app.audio.backLabel": "Назад",
@ -515,6 +559,8 @@
"app.modal.randomUser.noViewers.description": "Нема доступних глядачів для випадкового вибору",
"app.modal.randomUser.selected.description": "Вас було вибрано випадком",
"app.modal.randomUser.title": "Випадково обраний користувач",
"app.modal.randomUser.who": "Кого б обрати?..",
"app.modal.randomUser.alone": "Є лише один глядач",
"app.modal.randomUser.reselect.label": "Оберіть знову",
"app.modal.randomUser.ariaLabel.title": "Меню вибору випадкового користувача",
"app.dropdown.close": "Закрити",
@ -523,6 +569,7 @@
"app.error.401": "Неавторизований",
"app.error.403": "Ви були вилучені з зустрiчi",
"app.error.404": "Не знайдено",
"app.error.408": "Помилка автентифікації",
"app.error.410": "Зустріч закінчилася",
"app.error.500": "Ой, щось пішло не так",
"app.error.userLoggedOut": "Користувач має невірний sessionToken через те що вилогінився",
@ -533,6 +580,17 @@
"app.error.fallback.presentation.description": "Уже увійшли. Спробуйте перезавантажити сторінку.",
"app.error.fallback.presentation.reloadButton": "Перезавантажити",
"app.guest.waiting": "Очікування схвалення приєднання",
"app.guest.errorSeeConsole": "Помилка: більш детально в консолі",
"app.guest.noModeratorResponse": "Немає відповіді модератора.",
"app.guest.noSessionToken": "Не отримано лексему сеансу",
"app.guest.windowTitle": "Кімната очікування для гостей",
"app.guest.missingToken": "Для гостя не вказано лексему сеансу",
"app.guest.missingSession": "Для гостя не вказано сеанс",
"app.guest.missingMeeting": "Зустріч не існує",
"app.guest.meetingEnded": "Зустріч закінчилась.",
"app.guest.guestWait": "Будь ласка, зачекайте, поки модератор схвалить приєднання вас до зустрічі.",
"app.guest.guestDeny": "Гостю відмовлено у приєднанні до зустрічі.",
"app.guest.seatWait": "Гість очікує на вільне місце у зустрічі.",
"app.userList.guest.waitingUsers": "Учасники у очікуванні",
"app.userList.guest.waitingUsersTitle": "Керування учасниками",
"app.userList.guest.optionTitle": "Переглянути учасників, які очікують",
@ -549,7 +607,7 @@
"app.userList.guest.acceptLabel": "Прийняти",
"app.userList.guest.denyLabel": "Відмовити",
"app.user-info.title": "Пошук у каталозі",
"app.toast.breakoutRoomEnded": "Конференція закінчилася. Будь ласка, приєднайтесь знову до аудіо конференції.",
"app.toast.breakoutRoomEnded": "Час роботи в кімнаті для учасників закінчилася. Будь ласка, приєднайтесь знову до аудіо конференції.",
"app.toast.chat.public": "Нове повідомлення у загальному чаті",
"app.toast.chat.private": "Нове повідомлення у приватному чаті",
"app.toast.chat.system": "Система",
@ -564,7 +622,8 @@
"app.notification.recordingPaused": "Цей сеанс більше не записується",
"app.notification.recordingAriaLabel": "Записано часу ",
"app.notification.userJoinPushAlert": "{0} приєднався до сеансу",
"app.submenu.notification.raiseHandLabel": "Підняти руку",
"app.notification.userLeavePushAlert": "{0} залишив до сеанс",
"app.submenu.notification.raiseHandLabel": "Піднято руку",
"app.shortcut-help.title": "Гарячі клавіші",
"app.shortcut-help.accessKeyNotAvailable": "Клавіші швидкого доступу недоступні",
"app.shortcut-help.comboLabel": "Комбо",
@ -579,15 +638,15 @@
"app.shortcut-help.closePrivateChat": "Закрити приватний чат",
"app.shortcut-help.openActions": "Відкрити меню дій",
"app.shortcut-help.raiseHand": "Переключити - піднята/опущена рука",
"app.shortcut-help.openDebugWindow": "Відкрити вікно дебагу",
"app.shortcut-help.openDebugWindow": "Відкрити вікно зневадження",
"app.shortcut-help.openStatus": "Відкрити статус меню ",
"app.shortcut-help.togglePan": "Включити Інструмент - Переміщення (ведучий)",
"app.shortcut-help.toggleFullscreen": "Переключити - На весь екран (режим презентатора)",
"app.shortcut-help.toggleFullscreen": "Переключити - На весь екран (ведучий)",
"app.shortcut-help.nextSlideDesc": "Наступний слайд (ведучий)",
"app.shortcut-help.previousSlideDesc": "Попередній слайд (ведучий)",
"app.lock-viewers.title": "Обмежити глядачів",
"app.lock-viewers.description": "Ці налаштування дозволяють обмежити учасників у доступі до певних функцій",
"app.lock-viewers.featuresLable": "Особливість",
"app.lock-viewers.featuresLable": "Властивість",
"app.lock-viewers.lockStatusLabel": "Стан",
"app.lock-viewers.webcamLabel": "Увімкнути вебкамеру",
"app.lock-viewers.otherViewersWebcamLabel": "Дивитися вебкамери інших учасників",
@ -601,19 +660,31 @@
"app.lock-viewers.button.cancel": "Скасувати",
"app.lock-viewers.locked": "Заблокований",
"app.lock-viewers.unlocked": "Розблокований",
"app.guest-policy.ariaTitle": "Наслідування гостьової політики",
"app.guest-policy.ariaTitle": "Вікно налаштування політики для гостей",
"app.guest-policy.title": "Гостьова політика",
"app.guest-policy.description": "Змінити налаштування гостьової політики зустрічі",
"app.guest-policy.button.askModerator": "Запитати модератора",
"app.guest-policy.button.alwaysAccept": "Завжди приймати",
"app.guest-policy.button.alwaysDeny": "Завжди ігнорувати",
"app.guest-policy.button.alwaysDeny": "Завжди відхиляти",
"app.guest-policy.policyBtnDesc": "Встановлює політику для гостей зустрічі",
"app.connection-status.ariaTitle": "Вікно умов стану з'єднання",
"app.connection-status.title": "Стан з'єднання",
"app.connection-status.description": "Перегляд стану з'єднання користувачів",
"app.connection-status.empty": "Немає проблем із зв'язком",
"app.connection-status.more": "докладно",
"app.connection-status.copy": "Копіювати дані мережевого з'єднання",
"app.connection-status.copied": "Скопійовано!",
"app.connection-status.jitter": "Тремтіння",
"app.connection-status.label": "Стан з'єднання",
"app.connection-status.no": "Ні",
"app.connection-status.notification": "Ваше під'єднання має втрати",
"app.connection-status.offline": "не в мережі",
"app.connection-status.lostPackets": "Втрачені пакети",
"app.connection-status.usingTurn": "Використання TURN",
"app.connection-status.yes": "Так",
"app.learning-dashboard.label": "Панель навчання",
"app.learning-dashboard.description": "Відкрити панель обліку активності учасників",
"app.learning-dashboard.clickHereToOpen": "Відкрити панель навчання",
"app.recording.startTitle": "Почати запис",
"app.recording.stopTitle": "Призупинити запис",
"app.recording.resumeTitle": "Відновити запис",
@ -635,17 +706,19 @@
"app.videoPreview.webcamOptionLabel": "Виберіть вебкамеру",
"app.videoPreview.webcamPreviewLabel": "Попередній перегляд вебкамери",
"app.videoPreview.webcamSettingsTitle": "Налаштування вебкамери",
"app.videoPreview.webcamVirtualBackgroundLabel": "Налаштування віртуального тла",
"app.videoPreview.webcamVirtualBackgroundDisabledLabel": "Цей пристрій не підтримує віртуального тла",
"app.videoPreview.webcamNotFoundLabel": "Вебкамеру не знайдено",
"app.videoPreview.profileNotFoundLabel": "Камера не відповідає підтримуваним",
"app.videoPreview.profileNotFoundLabel": "Для цієї камери немає підтримуваних профілів",
"app.video.joinVideo": "Увімкнути вебкамеру",
"app.video.connecting": "Веб камера підключається ...",
"app.video.leaveVideo": "Вимкнути вебкамеру",
"app.video.iceCandidateError": "Помилка додавання ICE кандидату",
"app.video.iceCandidateError": "Помилка додавання ICE кандидата",
"app.video.iceConnectionStateError": "Не вдалося з'єднатися (ICE помилка 1107)",
"app.video.permissionError": "Помилка при трансляції вебкамери. Будь ласка перевірте дозволи",
"app.video.sharingError": "Помилка при трансляції вебкамери",
"app.video.abortError": "Є деякі проблеми з тим щоб пристрій було використано",
"app.video.overconstrainedError": "Немає кандидатів щоб відповідали необхідним критеріям",
"app.video.abortError": "Виникла невідома проблема, що унеможливлює використання камери",
"app.video.overconstrainedError": "Ваша камера не підтримує цей профіль якості",
"app.video.securityError": "Підтримка медіа забороненя на рівні документа",
"app.video.typeError": "Перелік обмежень порожній чи усі опції встановлено - немає",
"app.video.notFoundError": "Не вдалося знайти вебкамеру. Переконайтеся, що її під'єднано",
@ -654,6 +727,7 @@
"app.video.notReadableError": "Не вдалося отримати відео з вебкамери. Будь ласка, переконайтеся, що інша програма не використовує її",
"app.video.timeoutError": "Браузер не відповів вчасно",
"app.video.genericError": "Невідома помилка з пристроєм (Помилка {0})",
"app.video.mediaTimedOutError": "Потік відео від вашої камери перервався. Спробуйте приєднати її знову.",
"app.video.mediaFlowTimeout1020": "Потоки не досягають сервера (помилка 1020)",
"app.video.suggestWebcamLock": "Примусово заблокувати налаштування для глядачів?",
"app.video.suggestWebcamLockReason": "(це підвищить стабільність конференції)",
@ -669,8 +743,15 @@
"app.video.pagination.prevPage": "Відео на попередній сторінці",
"app.video.pagination.nextPage": "Відео на наступній сторінці",
"app.video.clientDisconnected": "Вебкамера не може бути показана через проблеми підключення",
"app.video.virtualBackground.none": "Немає",
"app.video.virtualBackground.blur": "Розмивання",
"app.video.virtualBackground.genericError": "Не вдалось застосувати ефект для камери. Спробуйте знову.",
"app.video.virtualBackground.camBgAriaDesc": "Встановлює віртуальне тло для вебкамери: {0}",
"app.video.dropZoneLabel": "Перетягніть сюди",
"app.fullscreenButton.label": "Вивести {0} на весь екран",
"app.fullscreenUndoButton.label": "Вимкнути {0} режим на весь екран",
"app.switchButton.expandLabel": "Розгорнути відео демонстрації екрану",
"app.switchButton.shrinkLabel": "Згорнути відео демонстрації екрану",
"app.sfu.mediaServerConnectionError2000": "Не можливо з'єднатися з мультимедійним сервером (помилка 2000)",
"app.sfu.mediaServerOffline2001": "Мультимедійний сервер недоступний. Будь ласка спробуйте пізніше (помилка 2001)",
"app.sfu.mediaServerNoResources2002": "На мультимедійному сервері немає доступних ресурсів (помилка 2002)",
@ -711,7 +792,10 @@
"app.whiteboard.toolbar.clear": "Стерти усі нотатки",
"app.whiteboard.toolbar.multiUserOn": "Увімкнути спільний доступ до дошки",
"app.whiteboard.toolbar.multiUserOff": "Вимкнути спільний доступ до дошки",
"app.whiteboard.toolbar.palmRejectionOn": "Увімкнути захист від випадкових дотиків",
"app.whiteboard.toolbar.palmRejectionOff": "Вимкнути захист від випадкових дотиків",
"app.whiteboard.toolbar.fontSize": "Список розмірів шрифтів",
"app.whiteboard.toolbarAriaLabel": "Засоби презентації",
"app.feedback.title": "Ви вийшли з конференції",
"app.feedback.subtitle": "Будь ласка, поділіться вашим досвідом користування BigBlueButton (необов'язково)",
"app.feedback.textarea": "Як можна покращити BigBlueButton?",
@ -730,7 +814,9 @@
"app.createBreakoutRoom.title": "Кімнати для перерв",
"app.createBreakoutRoom.ariaTitle": "Приховати кімнати для перерв",
"app.createBreakoutRoom.breakoutRoomLabel": "Кімнати для перерв {0}",
"app.createBreakoutRoom.generateURL": "Створити адресу URL",
"app.createBreakoutRoom.generatingURL": "Створення URL",
"app.createBreakoutRoom.generatingURLMessage": "Ми створюємо адресу URL для приєднання до обраної кімнати. Це може тривати декілька секунд...",
"app.createBreakoutRoom.generatedURL": "Створено",
"app.createBreakoutRoom.duration": "Тривалість {0}",
"app.createBreakoutRoom.room": "Кімната {0}",
@ -744,6 +830,7 @@
"app.createBreakoutRoom.numberOfRooms": "Кількість кімнат",
"app.createBreakoutRoom.durationInMinutes": "Тривалість (хвилини)",
"app.createBreakoutRoom.randomlyAssign": "Випадково призначити",
"app.createBreakoutRoom.randomlyAssignDesc": "Випадково розподілити користувачів по кімнатах",
"app.createBreakoutRoom.endAllBreakouts": "Закрити усі перервні кімнати ",
"app.createBreakoutRoom.roomName": "{0} (Кімната - {1})",
"app.createBreakoutRoom.doneLabel": "Готово",
@ -753,9 +840,17 @@
"app.createBreakoutRoom.addParticipantLabel": "+ Додати учасника",
"app.createBreakoutRoom.freeJoin": "Дозволити учасникам обирати кімнату самостійно",
"app.createBreakoutRoom.leastOneWarnBreakout": "Щонайменше один учасник має бути присутнім у кімнаті.",
"app.createBreakoutRoom.minimumDurationWarnBreakout": "Мінімальна тривалість кімнати для учасників {0} хвилин",
"app.createBreakoutRoom.modalDesc": "Примітка: Щоб призначити учасників до певної кімнати, будь ласка, перетягніть їхні імена до комірок кімнат.",
"app.createBreakoutRoom.roomTime": "{0} хвилин",
"app.createBreakoutRoom.numberOfRoomsError": "Кількість кімнат є неправильною.",
"app.createBreakoutRoom.duplicatedRoomNameError": "Назва кімнати не може повторюватись",
"app.createBreakoutRoom.emptyRoomNameError": "Назва кімнати не може бути порожньою",
"app.createBreakoutRoom.extendTimeInMinutes": "Додати час (хвилин)",
"app.createBreakoutRoom.extendTimeLabel": "Додати час",
"app.createBreakoutRoom.extendTimeCancel": "Скасувати",
"app.createBreakoutRoom.extendTimeHigherThanMeetingTimeError": "Тривалість кімнати для учасників не може перевищувати час, що залишився до кінця зустрічі",
"app.createBreakoutRoom.roomNameInputDesc": "Оновлює назву кімнати для учасників",
"app.externalVideo.start": "Поділитися новим відео",
"app.externalVideo.title": "Поділитися зовнішнім відео",
"app.externalVideo.input": "Посилання на зовнішню адресу відео",
@ -763,6 +858,7 @@
"app.externalVideo.urlError": "Ця адреса відео не підтримується",
"app.externalVideo.close": "Закрити",
"app.externalVideo.autoPlayWarning": "Відтворити відео для синхронізації медіа",
"app.externalVideo.refreshLabel": "Оновити програвач відео",
"app.externalVideo.noteLabel": "Примітка: Зовнішні відеозаписи не з'являються у записі сеансу. Підтримуються: YouTube, Vimeo, Instructure Media, Twitch, Dailymotion та посилання на відео ( наприклад : https://example.com/xy.mp4 )",
"app.actionsBar.actionsDropdown.shareExternalVideo": "Демонстрація зовнішнього відео",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "Припинити показ зовнішнього відео",
@ -770,11 +866,73 @@
"app.legacy.unsupportedBrowser": "Схоже, ви використовуєте браузер, який в повному обсязі не підтримується. Будь ласка, використовуйте {0} або {1} для повної підтримки.",
"app.legacy.upgradeBrowser": "Схоже, ви використовуєте старішу версію браузера, який підтримується. Будь ласка, оновіть його для повної підтримки.",
"app.legacy.criosBrowser": "Будь ласка, використовуйте браузер Safari на пристрої з iOS для повної підтримки.",
"app.debugWindow.windowTitle": "Debug",
"app.debugWindow.form.userAgentLabel": "User Agent",
"app.debugWindow.windowTitle": "Зневадження",
"app.debugWindow.form.userAgentLabel": "Агент користувача",
"app.debugWindow.form.button.copy": "Копіювати",
"app.debugWindow.form.enableAutoarrangeLayoutLabel": "Дозволити режим Авторозташування",
"app.debugWindow.form.enableAutoarrangeLayoutDescription": "(буде відключено якщо ви перемістите або зміните розмір зони відображення вебкамер)"
"app.debugWindow.form.enableAutoarrangeLayoutDescription": "(буде відключено якщо ви перемістите або зміните розмір зони відображення вебкамер)",
"app.debugWindow.form.chatLoggerLabel": "Рівень протоколювання тестового чату",
"app.debugWindow.form.button.apply": "Застосувати",
"app.layout.style.custom": "Власне компонування",
"app.layout.style.smart": "\"Розумне\" компонування",
"app.layout.style.presentationFocus": "Фокус не презентації",
"app.layout.style.videoFocus": "Фокус на відео",
"playback.button.about.aria": "Про застосунок",
"playback.button.clear.aria": "Очистити пошук",
"playback.button.close.aria": "Закрити",
"playback.button.fullscreen.aria": "Вміст на повний екран",
"playback.button.restore.aria": "Відновити вміст",
"playback.button.search.aria": "Пошук",
"playback.button.section.aria": "Бічна частина",
"playback.button.swap.aria": "Перемкнути вміст",
"playback.error.wrapper.aria": "Область помилок",
"playback.loader.wrapper.aria": "Область завантажувача",
"playback.player.wrapper.aria": "Область програвача",
"playback.player.chat.message.poll.name": "Результати опитування",
"playback.player.chat.message.poll.question": "Питання",
"playback.player.chat.message.poll.options": "Варіанти",
"playback.player.chat.message.poll.option.yes": "Так",
"playback.player.chat.message.poll.option.no": "Ні",
"playback.player.chat.message.poll.option.abstention": "Утримався",
"playback.player.chat.message.poll.option.true": "Вірно",
"playback.player.chat.message.poll.option.false": "Хибно",
"playback.player.chat.message.externalVideo.name": "Зовнішнє відео",
"playback.player.chat.wrapper.aria": "Область чату",
"playback.player.notes.wrapper.aria": "Область спільних нотаток",
"playback.player.presentation.wrapper.aria": "Область презентації",
"playback.player.screenshare.wrapper.aria": "Область демонстрації екрану",
"playback.player.search.modal.title": "Пошук",
"playback.player.search.modal.subtitle": "Знайти вміст слайдів презентації",
"playback.player.thumbnails.wrapper.aria": "Область мініатюр",
"playback.player.video.wrapper.aria": "Область відео",
"app.learningDashboard.dashboardTitle": "Панель навчання",
"app.learningDashboard.user": "Користувач",
"app.learningDashboard.indicators.meetingStatusEnded": "Закінчилась",
"app.learningDashboard.indicators.meetingStatusActive": "Активна",
"app.learningDashboard.indicators.usersOnline": "Користувачі онлайн",
"app.learningDashboard.indicators.usersTotal": "Загальна кількість користувачів",
"app.learningDashboard.indicators.polls": "Опитування",
"app.learningDashboard.indicators.raiseHand": "Підняті руки",
"app.learningDashboard.indicators.activityScore": "Рахунок активності",
"app.learningDashboard.indicators.duration": "Тривалість",
"app.learningDashboard.usersTable.title": "Огляд",
"app.learningDashboard.usersTable.colOnline": "Час онлайн",
"app.learningDashboard.usersTable.colTalk": "Час виступів",
"app.learningDashboard.usersTable.colWebcam": "Час відео",
"app.learningDashboard.usersTable.colMessages": "Повідомлення",
"app.learningDashboard.usersTable.colEmojis": "Смайлики",
"app.learningDashboard.usersTable.colRaiseHands": "Підняті руки",
"app.learningDashboard.usersTable.colActivityScore": "Активність",
"app.learningDashboard.usersTable.colStatus": "Статус",
"app.learningDashboard.usersTable.userStatusOnline": "Онлайн",
"app.learningDashboard.usersTable.userStatusOffline": "Відсутній",
"app.learningDashboard.usersTable.noUsers": "Поки ще нікого немає",
"app.learningDashboard.pollsTable.title": "Опитування",
"app.learningDashboard.pollsTable.anonymousAnswer": "Анонімні опитування (відповіді в останньому рядку)",
"app.learningDashboard.pollsTable.anonymousRowName": "Анонім",
"app.learningDashboard.statusTimelineTable.title": "Хронологія стану",
"app.learningDashboard.errors.invalidToken": "Недійсна лексема сеансу",
"app.learningDashboard.errors.dataUnavailable": "Дані більше недоступні"
}

View File

@ -6,7 +6,7 @@
"app.chat.disconnected": "Bạn đang mất kết nối, tin nhắn không thể gửi đi",
"app.chat.locked": "Cuộc trò chuyện bị khóa, các tin nhắn không thể gửi đi",
"app.chat.inputLabel": "Nhập tin nhắn để trò chuyện {0}",
"app.chat.inputPlaceholder": "Tin nhắn",
"app.chat.inputPlaceholder": "Tin nhắn tới {0}",
"app.chat.titlePublic": "Chat",
"app.chat.titlePrivate": "Chat với {0}",
"app.chat.partnerDisconnected": "{0} đã rời cuộc họp",
@ -315,8 +315,8 @@
"app.endMeeting.contentWarning": "Tin nhắn trò chuyện, ghi chú được chia sẻ, nội dung bảng trắng và tài liệu được chia sẻ cho phiên này sẽ không thể truy cập trực tiếp được nữa",
"app.endMeeting.yesLabel": "Có",
"app.endMeeting.noLabel": "Không",
"app.about.title": "Về Tuvnord meet",
"app.about.version": "Khách hàng xây dựng:",
"app.about.title": "Giới thiệu",
"app.about.version": "Phiên bản:",
"app.about.copyright": "Bản quyền:",
"app.about.confirmLabel": "OK",
"app.about.confirmDesc": "OK",
@ -723,7 +723,7 @@
"app.whiteboard.toolbar.multiUserOff": "Tắt bảng trắng nhiều người dùng",
"app.whiteboard.toolbar.fontSize": "Danh sách kích thước phông chữ",
"app.feedback.title": "Bạn đã đăng xuất khỏi cuộc họp",
"app.feedback.subtitle": "Chúng tôi rất muốn nghe về trải nghiệm của bạn với TUV NORD MEET (tùy chọn)",
"app.feedback.subtitle": "Chúng tôi rất muốn nghe về trải nghiệm của bạn với hệ thống này (tùy chọn)",
"app.feedback.textarea": "Làm thế nào chúng tôi có thể cải thiện TUV NORD MEET?",
"app.feedback.sendFeedback": "Gửi thông tin phản hồi",
"app.feedback.sendFeedbackDesc": "Gửi phản hồi và rời khỏi cuộc họp",

View File

@ -3,7 +3,7 @@ const util = require('./util');
class Audio extends Page {
constructor() {
super('audio-test');
super();
}
async test() {

View File

@ -1,12 +0,0 @@
exports.joinAudio = 'button[aria-label="Join audio"]';
exports.leaveAudio = 'button[aria-label="Leave audio"]';
exports.disconnectAudio = 'li[data-test="disconnectAudio"]';
exports.listen = 'button[aria-label="Listen only"]';
exports.connectingStatus = 'div[class^="connecting-"]';
exports.connecting = 'span[data-test="connecting"]';
exports.connectingToEchoTest = 'span[data-test="connectingToEchoTest"]';
exports.audioAudible = 'button[aria-label="Echo is audible"]';
exports.microphone = 'button[aria-label="Microphone"]';
exports.muteMicrophoneBtn = 'button[aria-label="Mute"]';
exports.whiteboard = 'svg[data-test="whiteboard"]';
exports.talkingIndicator = 'div[class^="isTalkingWrapper--"] > div[class^="speaking--"]';

View File

@ -1,36 +1,25 @@
const ae = require('./elements');
const { clickElement, getElementLength } = require('../core/util');
const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const e = require('../core/elements');
const { getElementLength } = require('../core/util');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
async function joinAudio(test) {
await test.waitForSelector(ae.joinAudio, ELEMENT_WAIT_TIME);
await test.page.evaluate(clickElement, ae.joinAudio);
await test.waitForSelector(ae.listen, ELEMENT_WAIT_TIME);
await test.page.evaluate(clickElement, ae.listen);
await test.waitForSelector(ae.connectingStatus, ELEMENT_WAIT_TIME);
await test.waitForElementHandleToBeRemoved(ae.connectingStatus, ELEMENT_WAIT_LONGER_TIME);
await test.waitAndClick(e.listenOnlyButton);
await test.waitForElementHandleToBeRemoved(e.connectingStatus);
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(getElementLength, ae.leaveAudio) >= 1;
return resp;
await test.waitForSelector(e.leaveAudio, listenOnlyCallTimeout);
await test.waitForSelector(e.whiteboard);
return test.page.evaluate(getElementLength, e.leaveAudio) >= 1;
}
async function joinMicrophone(test) {
await test.waitForSelector(ae.joinAudio, ELEMENT_WAIT_TIME);
await test.page.evaluate(clickElement, ae.joinAudio);
await test.waitForSelector(ae.microphone, ELEMENT_WAIT_TIME);
await test.page.evaluate(clickElement, ae.microphone);
await test.waitForSelector(ae.connectingStatus, ELEMENT_WAIT_TIME);
await test.waitForElementHandleToBeRemoved(ae.connectingStatus, ELEMENT_WAIT_LONGER_TIME);
await test.waitAndClick(e.microphoneButton);
await test.waitForElementHandleToBeRemoved(e.connectingStatus, ELEMENT_WAIT_LONGER_TIME);
const parsedSettings = await test.getSettingsYaml();
const listenOnlyCallTimeout = parseInt(parsedSettings.public.media.listenOnlyCallTimeout);
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(getElementLength, ae.audioAudible) >= 1;
return resp;
await test.waitAndClick(e.echoYesButton, listenOnlyCallTimeout);
await test.waitForSelector(e.whiteboard);
return test.page.evaluate(getElementLength, e.echoYesButton) >= 1;
}
exports.joinAudio = joinAudio;

View File

@ -18,18 +18,18 @@ const breakoutTest = () => {
let screenshot;
try {
const testName = 'createBreakoutrooms';
await test.page1.logger('begin of ', testName);
await test.modPage1.logger('begin of ', testName);
await test.init(undefined, testName);
await test.page1.startRecording(testName);
await test.modPage1.startRecording(testName);
await test.create(testName);
response = await test.testCreatedBreakout(testName);
const page2 = await test.page2.browser.pages();
await page2[2].bringToFront();
await test.page1.stopRecording();
screenshot = await page2[2].screenshot();
await test.page1.logger('end of ', testName);
const breakoutUserPage1 = await test.userPage1.getLastTargetPage();
await breakoutUserPage1.bringToFront();
await test.modPage1.stopRecording();
screenshot = await breakoutUserPage1.page.screenshot();
await test.modPage1.logger('end of ', testName);
} catch (err) {
await test.page1.logger(err);
await test.modPage1.logger(err);
} finally {
await test.close();
}
@ -44,19 +44,19 @@ const breakoutTest = () => {
let screenshot;
try {
const testName = 'joinBreakoutroomsWithoutFeatures';
await test.page1.logger('begin of ', testName);
await test.modPage1.logger('begin of ', testName);
await test.init(undefined, testName);
await test.page1.startRecording(testName);
await test.modPage1.startRecording(testName);
await test.create(testName);
await test.join(testName);
response = await test.testJoined(testName);
const page2 = await test.page2.browser.pages();
await page2[2].bringToFront();
await test.page1.stopRecording();
screenshot = await page2[2].screenshot();
await test.page1.logger('end of ', testName);
const breakoutUserPage1 = await test.userPage1.getLastTargetPage();
await breakoutUserPage1.bringToFront();
await test.modPage1.stopRecording();
screenshot = await breakoutUserPage1.page.screenshot();
await test.modPage1.logger('end of ', testName);
} catch (err) {
await test.page1.logger(err);
await test.modPage1.logger(err);
} finally {
await test.close();
}
@ -71,19 +71,19 @@ const breakoutTest = () => {
let screenshot;
try {
const testName = 'joinBreakoutroomsWithVideo';
await test.page1.logger('begin of ', testName);
await test.modPage1.logger('begin of ', testName);
await test.init(undefined, testName);
await test.page1.startRecording(testName);
await test.modPage1.startRecording(testName);
await test.create(testName);
await test.join(testName);
response = await test.testJoined(testName);
const page2 = await test.page2.browser.pages();
await page2[2].bringToFront();
await test.page1.stopRecording();
screenshot = await page2[2].screenshot();
await test.page1.logger('end of ', testName);
const breakoutUserPage1 = await test.userPage1.getLastTargetPage();
await breakoutUserPage1.bringToFront();
await test.modPage1.stopRecording();
screenshot = await breakoutUserPage1.page.screenshot();
await test.modPage1.logger('end of ', testName);
} catch (err) {
await test.page1.logger(err);
await test.modPage1.logger(err);
} finally {
await test.close();
}
@ -98,19 +98,19 @@ const breakoutTest = () => {
let screenshot;
try {
const testName = 'joinBreakoutroomsAndShareScreen';
await test.page1.logger('begin of ', testName);
await test.modPage1.logger('begin of ', testName);
await test.init(undefined, testName);
await test.page1.startRecording(testName);
await test.modPage1.startRecording(testName);
await test.create(testName);
await test.join(testName);
response = await test.testJoined(testName);
const page2 = await test.page2.browser.pages();
await page2[2].bringToFront();
await test.page1.stopRecording();
screenshot = await page2[2].screenshot();
await test.page1.logger('end of ', testName);
const breakoutUserPage1 = await test.userPage1.getLastTargetPage();
await breakoutUserPage1.bringToFront();
await test.modPage1.stopRecording();
screenshot = await breakoutUserPage1.page.screenshot();
await test.modPage1.logger('end of ', testName);
} catch (err) {
await test.page1.logger(err);
await test.modPage1.logger(err);
} finally {
await test.close();
}
@ -125,19 +125,19 @@ const breakoutTest = () => {
let screenshot;
try {
const testName = 'joinBreakoutroomsWithAudio';
await test.page1.logger('begin of ', testName);
await test.modPage1.logger('begin of ', testName);
await test.init(undefined, testName);
await test.page1.startRecording(testName);
await test.modPage1.startRecording(testName);
await test.create(testName);
await test.join(testName);
response = await test.testJoined(testName);
const page2 = await test.page2.browser.pages();
await page2[2].bringToFront();
await test.page1.stopRecording();
screenshot = await page2[2].screenshot();
await test.page1.logger('end of ', testName);
const breakoutUserPage1 = await test.userPage1.getLastTargetPage();
await breakoutUserPage1.bringToFront();
await test.modPage1.stopRecording();
screenshot = await breakoutUserPage1.page.screenshot();
await test.modPage1.logger('end of ', testName);
} catch (err) {
await test.page1.logger(err);
await test.modPage1.logger(err);
} finally {
await test.close();
}

View File

@ -1,154 +1,63 @@
const moment = require('moment');
const path = require('path');
const Page = require('../core/page');
const params = require('../params');
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
const { checkElement, clickElement } = require('../core/util');
const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const today = moment().format('DD-MM-YYYY');
const e = require('../core/elements');
const { checkElement } = require('../core/util');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
class Create {
constructor() {
this.page1 = new Page();
this.page2 = new Page();
this.page3 = new Page();
this.modPage1 = new Page();
this.modPage2 = new Page();
this.userPage1 = new Page();
}
// Join BigBlueButton meeting with a Moderator and a Viewer
async init(meetingId, testName) {
await this.page1.init(Page.getArgs(), meetingId, { ...params, fullName: 'Moderator1' }, undefined, testName);
await this.page2.init(Page.getArgs(), this.page1.meetingId, { ...params, fullName: 'Viewer1', moderatorPW: '' }, undefined, testName);
await this.modPage1.init(Page.getArgs(), meetingId, { ...params, fullName: 'Moderator1' }, undefined, testName);
await this.userPage1.init(Page.getArgs(), this.modPage1.meetingId, { ...params, fullName: 'Viewer1', moderatorPW: '' }, undefined, testName);
}
// Join BigBlueButton meeting with a Viewer only
async initViewer(testName) {
await this.page3.init(Page.getArgs(), this.page1.meetingId, { ...params, fullName: 'Viewer2', moderatorPW: '' }, undefined, testName);
}
async askModeratorGuestPolicy(testName) {
try {
await this.page1.screenshot(`${testName}`, `01-before-closing-audio-modal-[${this.page1.meetingId}]`);
await this.page1.closeAudioModal();
await this.page2.closeAudioModal();
await this.page1.screenshot(`${testName}`, `02-after-closing-audio-modal-[${this.page1.meetingId}]`);
await this.page1.waitForSelector(ue.manageUsers, ELEMENT_WAIT_TIME);
await this.page1.click(ue.manageUsers, true);
await this.page1.screenshot(`${testName}`, `03-opened-users-managing-[${this.page1.meetingId}]`);
await this.page1.waitForSelector(ue.guestPolicyLabel, ELEMENT_WAIT_TIME);
await this.page1.click(ue.guestPolicyLabel, true);
await this.page1.screenshot(`${testName}`, `04-opened-guest-policy-[${this.page1.meetingId}]`);
await this.page1.waitForSelector(ue.askModerator, ELEMENT_WAIT_TIME);
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(checkElement, ue.waitingUsersBtn);
await this.page1.screenshot(`${testName}`, `06-after-viewer-acceptance-[${this.page1.meetingId}]`);
return responseLoggedIn;
} catch (err) {
await this.page1.logger(err);
return false;
}
}
async alwaysAcceptGuestPolicy(testName) {
try {
await this.page1.screenshot(`${testName}`, `01-before-closing-audio-modal-[${this.page1.meetingId}]`);
await this.page1.closeAudioModal();
await this.page2.closeAudioModal();
await this.page1.screenshot(`${testName}`, `02-after-closing-audio-modal-[${this.page1.meetingId}]`);
await this.page1.waitForSelector(ue.manageUsers, ELEMENT_WAIT_TIME);
await this.page1.click(ue.manageUsers, true);
await this.page1.screenshot(`${testName}`, `03-opened-users-managing-[${this.page1.meetingId}]`);
await this.page1.waitForSelector(ue.guestPolicyLabel, ELEMENT_WAIT_TIME);
await this.page1.click(ue.guestPolicyLabel, true);
await this.page1.screenshot(`${testName}`, `04-opened-guest-policy-[${this.page1.meetingId}]`);
await this.page1.waitForSelector(ue.alwaysAccept, ELEMENT_WAIT_TIME);
await this.page1.click(ue.alwaysAccept, true);
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(checkElement, e.whiteboard);
await this.page3.screenshot(`${testName}`, `06-after-viewer-connection-[${this.page1.meetingId}]`);
return responseLoggedIn;
} catch (err) {
await this.page1.logger(err);
return false;
}
}
async alwaysDenyGuestPolicy(testName) {
try {
await this.page1.screenshot(`${testName}`, `01-before-closing-audio-modal-[${this.page1.meetingId}]`);
await this.page1.closeAudioModal();
await this.page2.closeAudioModal();
await this.page1.screenshot(`${testName}`, `02-after-closing-audio-modal-[${this.page1.meetingId}]`);
await this.page1.waitForSelector(ue.manageUsers, ELEMENT_WAIT_TIME);
await this.page1.click(ue.manageUsers, true);
await this.page1.screenshot(`${testName}`, `03-opened-users-managing-[${this.page1.meetingId}]`);
await this.page1.waitForSelector(ue.guestPolicyLabel, ELEMENT_WAIT_TIME);
await this.page1.click(ue.guestPolicyLabel, true);
await this.page1.screenshot(`${testName}`, `04-opened-guest-policy-[${this.page1.meetingId}]`);
await this.page1.waitForSelector(ue.alwaysAccept, ELEMENT_WAIT_TIME);
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(checkElement, ue.joinMeetingDemoPage);
await this.page3.screenshot(`${testName}`, `06-after-viewer-gets-denied-[${this.page1.meetingId}]`);
return responseLoggedIn;
} catch (err) {
await this.page1.logger(err);
return false;
}
await this.userPage2.init(Page.getArgs(), this.modPage1.meetingId, { ...params, fullName: 'Viewer2', moderatorPW: '' }, undefined, testName);
}
// Create Breakoutrooms
async create(testName) {
try {
await this.page1.closeAudioModal();
await this.page2.closeAudioModal();
await this.page1.screenshot(`${testName}`, `01-page01-initialized-${testName}`);
await this.page2.screenshot(`${testName}`, `01-page02-initialized-${testName}`);
await this.modPage1.closeAudioModal();
await this.userPage1.closeAudioModal();
await this.modPage1.screenshot(testName, '01-page01-initialized');
await this.userPage1.screenshot(testName, '01-page02-initialized');
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.modPage1.waitAndClick(e.manageUsers);
await this.modPage1.waitAndClick(e.createBreakoutRooms);
await this.modPage1.screenshot(testName, '02-page01-creating-breakoutrooms');
await this.page1.waitForSelector(be.randomlyAssign, ELEMENT_WAIT_TIME);
await this.page1.page.evaluate(clickElement, be.randomlyAssign);
await this.page1.screenshot(`${testName}`, `03-page01-randomly-assign-user-${testName}`);
await this.modPage1.waitAndClick(e.randomlyAssign);
await this.modPage1.screenshot(testName, '03-page01-randomly-assign-user');
await this.page1.waitForSelector(be.modalConfirmButton, ELEMENT_WAIT_LONGER_TIME);
await this.page1.page.evaluate(clickElement, be.modalConfirmButton);
await this.page1.screenshot(`${testName}`, `04-page01-confirm-breakoutrooms-creation-${testName}`);
await this.modPage1.waitAndClick(e.modalConfirmButton, ELEMENT_WAIT_LONGER_TIME);
await this.modPage1.screenshot(testName, '04-page01-confirm-breakoutrooms-creation');
await this.page2.waitForSelector(be.modalConfirmButton, ELEMENT_WAIT_LONGER_TIME);
await this.page2.page.evaluate(clickElement, be.modalConfirmButton);
await this.page2.screenshot(`${testName}`, `02-page02-accept-invite-breakoutrooms-${testName}`);
// Join breakout room
await this.userPage1.waitAndClick(e.modalConfirmButton, ELEMENT_WAIT_LONGER_TIME);
await this.userPage1.screenshot(testName, '02-page02-accept-invite-breakoutrooms');
await this.page2.page.bringToFront();
await this.page2.waitForSelector(be.breakoutRoomsItem, ELEMENT_WAIT_TIME);
await this.page2.waitForSelector(be.chatButton, ELEMENT_WAIT_TIME);
await this.page2.click(be.chatButton, true);
await this.page2.click(be.breakoutRoomsItem, true);
await this.page2.waitForSelector(be.alreadyConnected, ELEMENT_WAIT_LONGER_TIME);
const page2 = await this.page2.browser.pages();
await page2[2].bringToFront();
if (process.env.GENERATE_EVIDENCES === 'true') {
await page2[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/03-breakout-page02-before-closing-audio-modal.png`) });
}
await page2[2].waitForSelector(e.closeAudio, { timeout: ELEMENT_WAIT_TIME });
await page2[2].click(e.closeAudio);
if (process.env.GENERATE_EVIDENCES === 'true') {
await page2[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/04-breakout-page02-after-closing-audio-modal.png`) });
}
await this.userPage1.bringToFront();
await this.userPage1.waitAndClick(e.chatButton);
await this.userPage1.waitAndClick(e.breakoutRoomsItem);
await this.userPage1.waitForSelector(e.alreadyConnected, ELEMENT_WAIT_LONGER_TIME);
const breakoutUserPage1 = await this.userPage1.getLastTargetPage();
await breakoutUserPage1.bringToFront();
await breakoutUserPage1.screenshot(testName, '03-breakout-page02-before-closing-audio-modal');
await breakoutUserPage1.closeAudioModal();
await breakoutUserPage1.screenshot(testName, '04-breakout-page02-after-closing-audio-modal');
} catch (err) {
await this.page1.logger(err);
await this.modPage1.logger(err);
return false;
}
}
@ -156,141 +65,108 @@ class Create {
// Check if Breakoutrooms have been created
async testCreatedBreakout(testName) {
try {
const resp = await this.page1.page.evaluate(checkElement, be.breakoutRoomsItem);
const resp = await this.modPage1.page.evaluate(checkElement, e.breakoutRoomsItem);
if (resp === true) {
await this.page1.screenshot(`${testName}`, `05-page01-success-${testName}`);
await this.modPage1.screenshot(`${testName}`, `05-page01-success-${testName}`);
return true;
}
await this.page1.screenshot(`${testName}`, `05-page01-fail-${testName}`);
await this.modPage1.screenshot(`${testName}`, `05-page01-fail-${testName}`);
return false;
} catch (err) {
await this.page1.logger(err);
await this.modPage1.logger(err);
return false;
}
}
// Initialize a Moderator session
async joinWithUser3(testName) {
async joinWithMod2(testName) {
try {
if (testName === 'joinBreakoutroomsWithAudio') {
await this.page3.init(Page.getArgs(), this.page1.meetingId, { ...params, fullName: 'Moderator3' }, undefined, testName);
await this.page3.closeAudioModal();
await this.page3.waitForSelector(be.breakoutRoomsButton, ELEMENT_WAIT_TIME);
await this.page3.click(be.breakoutRoomsButton, true);
await this.modPage2.init(Page.getArgs(), this.modPage1.meetingId, { ...params, fullName: 'Moderator3' }, undefined, testName);
await this.modPage2.closeAudioModal();
await this.modPage2.waitAndClick(e.breakoutRoomsButton);
await this.page3.waitForSelector(be.breakoutRoomsItem, ELEMENT_WAIT_TIME);
await this.page3.waitForSelector(be.chatButton, ELEMENT_WAIT_TIME);
await this.page3.click(be.chatButton, true);
await this.page3.click(be.breakoutRoomsItem, true);
await this.modPage2.waitForSelector(e.breakoutRoomsItem);
await this.modPage2.waitAndClick(e.chatButton);
await this.modPage2.waitAndClick(e.breakoutRoomsItem);
await this.page3.waitForSelector(be.joinRoom1, ELEMENT_WAIT_TIME);
await this.page3.click(be.joinRoom1);
// wait to generate URL and click again to join
await this.page3.click(be.joinRoom1, true);
await this.page3.waitForSelector(be.alreadyConnected, ELEMENT_WAIT_LONGER_TIME);
await this.modPage2.waitAndClick(e.generateRoom1);
await this.modPage2.waitAndClick(e.joinGeneratedRoom1);
await this.modPage2.waitForSelector(e.alreadyConnected, ELEMENT_WAIT_LONGER_TIME);
const page3 = await this.page3.browser.pages();
const breakoutModPage2 = await this.modPage2.getLastTargetPage();
await breakoutModPage2.screenshot(testName, `00-breakout-page03-user-joined-no-mic-before-check`);
if (process.env.GENERATE_EVIDENCES === 'true') {
await page3[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/00-breakout-page03-user-joined-no-mic-before-check-${testName}.png`) });
}
await page3[2].bringToFront();
await page3[2].waitForSelector(ae.microphone, { timeout: ELEMENT_WAIT_TIME });
await page3[2].click(ae.microphone);
await page3[2].waitForSelector(ae.connectingStatus, { timeout: ELEMENT_WAIT_TIME });
const parsedSettings = await this.page1.getSettingsYaml();
await breakoutModPage2.bringToFront();
await breakoutModPage2.waitAndClick(e.microphoneButton);
await breakoutModPage2.waitForSelector(e.connectingStatus);
const parsedSettings = await this.modPage1.getSettingsYaml();
const listenOnlyCallTimeout = parseInt(parsedSettings.public.media.listenOnlyCallTimeout);
await page3[2].waitForSelector(ae.audioAudible, { timeout: listenOnlyCallTimeout });
await page3[2].click(ae.audioAudible);
await page3[2].waitForSelector(e.whiteboard, { timeout: ELEMENT_WAIT_TIME });
await breakoutModPage2.waitAndClick(e.echoYesButton, listenOnlyCallTimeout);
await breakoutModPage2.waitForSelector(e.whiteboard);
if (process.env.GENERATE_EVIDENCES === 'true') {
await page3[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/00-breakout-page03-user-joined-with-mic-before-check-${testName}.png`) });
}
await breakoutModPage2.screenshot(testName, '00-breakout-page03-user-joined-with-mic-before-check');
} else if (testName === 'joinBreakoutroomsWithVideo') {
await this.page3.init(Page.getArgs(), this.page1.meetingId, { ...params, fullName: 'Moderator3' }, undefined, testName);
await this.page3.closeAudioModal();
await this.page3.waitForSelector(be.breakoutRoomsButton, ELEMENT_WAIT_TIME);
await this.page3.click(be.breakoutRoomsButton, true);
await this.page3.waitForSelector(be.joinRoom1, ELEMENT_WAIT_TIME);
await this.page3.click(be.joinRoom1);
// wait to generate URL and click again to join
await this.page3.click(be.joinRoom1, true);
await this.page3.waitForSelector(be.alreadyConnected, ELEMENT_WAIT_TIME);
await this.modPage2.init(Page.getArgs(), this.modPage1.meetingId, { ...params, fullName: 'Moderator3' }, undefined, testName);
await this.modPage2.closeAudioModal();
await this.modPage2.waitAndClick(e.breakoutRoomsButton);
await this.modPage2.waitAndClick(e.generateRoom1);
await this.modPage2.waitAndClick(e.joinGeneratedRoom1);
await this.modPage2.waitForSelector(e.alreadyConnected);
const page3 = await this.page3.browser.pages();
const breakoutModPage2 = await this.modPage2.getLastTargetPage();
await breakoutModPage2.screenshot(testName, '00-breakout-page03-user-joined-no-webcam-before-check');
if (process.env.GENERATE_EVIDENCES === 'true') {
await page3[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/00-breakout-page03-user-joined-no-webcam-before-check-${testName}.png`) });
}
await page3[2].bringToFront();
await page3[2].waitForSelector(e.audioDialog, { timeout: ELEMENT_WAIT_TIME });
await page3[2].waitForSelector(e.closeAudio, { timeout: ELEMENT_WAIT_TIME });
await page3[2].click(e.closeAudio);
await page3[2].waitForSelector(we.joinVideo, { timeout: ELEMENT_WAIT_TIME });
await page3[2].click(we.joinVideo);
const parsedSettings = await this.page3.getSettingsYaml();
await breakoutModPage2.bringToFront();
await breakoutModPage2.closeAudioModal();
await breakoutModPage2.waitAndClick(e.joinVideo);
const parsedSettings = await this.modPage2.getSettingsYaml();
const videoPreviewTimeout = parseInt(parsedSettings.public.kurento.gUMTimeout);
await page3[2].waitForSelector(we.videoPreview, { timeout: videoPreviewTimeout });
await page3[2].click(we.videoPreview);
await page3[2].waitForSelector(we.startSharingWebcam, { timeout: ELEMENT_WAIT_TIME });
await page3[2].click(we.startSharingWebcam);
if (process.env.GENERATE_EVIDENCES === 'true') {
await page3[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/00-breakout-page03-user-joined-with-webcam-before-check-${testName}.png`) });
}
} else if (testName === 'joinBreakoutroomsAndShareScreen') {
await this.page3.init(Page.getArgs(), this.page1.meetingId, { ...params, fullName: 'Moderator3' }, undefined, testName);
await this.page3.closeAudioModal();
await this.page3.waitForSelector(be.breakoutRoomsButton, ELEMENT_WAIT_TIME);
await this.page3.click(be.breakoutRoomsButton, true);
await this.page3.waitForSelector(be.joinRoom1, ELEMENT_WAIT_TIME);
await this.page3.click(be.joinRoom1);
// wait to generate URL and click again to join
await this.page3.click(be.joinRoom1, true);
await this.page3.waitForSelector(be.alreadyConnected, ELEMENT_WAIT_TIME);
const page3 = await this.page3.browser.pages();
await breakoutModPage2.waitAndClick(e.videoPreview, videoPreviewTimeout);
await breakoutModPage2.waitAndClick(e.startSharingWebcam);
if (process.env.GENERATE_EVIDENCES === 'true') {
await page3[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/00-breakout-page03-user-joined-with-screenshare-before-check-${testName}.png`) });
}
await page3[2].bringToFront();
await page3[2].waitForSelector(e.audioDialog, { timeout: ELEMENT_WAIT_TIME });
await page3[2].waitForSelector(e.closeAudio, { timeout: ELEMENT_WAIT_TIME });
await page3[2].click(e.closeAudio);
await breakoutModPage2.screenshot(testName, '00-breakout-page03-user-joined-with-webcam-before-check');
} else if (testName === 'joinBreakoutroomsAndShareScreen') {
await this.modPage2.init(Page.getArgs(), this.modPage1.meetingId, { ...params, fullName: 'Moderator3' }, undefined, testName);
await this.modPage2.closeAudioModal();
await this.modPage2.waitAndClick(e.breakoutRoomsButton);
await this.modPage2.waitAndClick(e.generateRoom1);
await this.modPage2.waitAndClick(e.joinGeneratedRoom1);
await this.modPage2.waitForSelector(e.alreadyConnected);
const breakoutModPage2 = await this.modPage2.getLastTargetPage();
await breakoutModPage2.screenshot(testName, '00-breakout-page03-user-joined-with-screenshare-before-check');
await breakoutModPage2.bringToFront();
await breakoutModPage2.closeAudioModal();
// Take Presenter
await page3[2].waitForSelector(ue.firstUser, { timeout: ELEMENT_WAIT_TIME });
await page3[2].click(ue.firstUser);
await page3[2].waitForSelector(ue.setPresenter, { timeout: ELEMENT_WAIT_TIME });
await page3[2].click(ue.setPresenter);
await breakoutModPage2.waitAndClick(e.firstUser);
await breakoutModPage2.waitAndClick(e.setPresenter);
// Start Share Screen
await page3[2].waitForSelector(ce.screenShareButton, { timeout: ELEMENT_WAIT_TIME });
await page3[2].click(ce.screenShareButton);
await page3[2].on('dialog', async (dialog) => {
await breakoutModPage2.waitAndClick(e.startScreenSharing);
await breakoutModPage2.page.on('dialog', async (dialog) => {
await dialog.accept();
});
if (process.env.GENERATE_EVIDENCES === 'true') {
await page3[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/00-breakout-page03-user-joined-with-screenshare-after-check-${testName}.png`) });
}
await breakoutModPage2.screenshot(testName, '00-breakout-page03-user-joined-with-screenshare-after-check');
} else {
await this.page3.init(Page.getArgs(), this.page1.meetingId, { ...params, fullName: 'Moderator3' }, undefined, testName);
await this.page3.closeAudioModal();
await this.modPage2.init(Page.getArgs(), this.modPage1.meetingId, { ...params, fullName: 'Moderator3' }, undefined, testName);
await this.modPage2.closeAudioModal();
}
} catch (err) {
await this.page3.logger(err);
await this.modPage2.logger(err);
}
}
// Close pages
async close() {
try {
await this.page1.close();
await this.page2.close();
await this.modPage1.close();
await this.userPage1.close();
} catch (err) {
await this.page1.logger(err);
await this.modPage1.logger(err);
}
}
@ -299,7 +175,7 @@ class Create {
try {
await page.close();
} catch (err) {
await this.page1.logger(err);
await this.modPage1.logger(err);
}
}
}

View File

@ -1,13 +0,0 @@
exports.manageUsers = 'button[data-test="manageUsers"]';
exports.createBreakoutRooms = '[data-test="createBreakoutRooms"]';
exports.inviteBreakoutRooms = '[data-test="inviteBreakoutRooms"]';
exports.randomlyAssign = '[data-test="randomlyAssign"]';
exports.modalConfirmButton = '[data-test="modalConfirmButton"]';
exports.breakoutRemainingTime = '[data-test="breakoutRemainingTime"]';
exports.breakoutRoomsItem = '[data-test="breakoutRoomsItem"]';
exports.alreadyConnected = 'span[class^="alreadyConnected--"]';
exports.breakoutJoin = '[data-test="breakoutJoin"]';
exports.userJoined = 'div[aria-label^="Moderator3"]';
exports.breakoutRoomsButton = 'div[aria-label="Breakout Rooms"]';
exports.joinRoom1 = 'button[aria-label="Join room 1"]';
exports.chatButton = 'div[data-test="chatButton"]';

View File

@ -1,98 +1,77 @@
const path = require('path');
const moment = require('moment');
const Create = require('./create');
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');
const e = require('../core/elements');
const { VIDEO_LOADING_WAIT_TIME } = require('../core/constants'); // core constants (Timeouts vars imported)
class Join extends Create {
constructor() {
super('join-breakout');
super();
}
// Join Existing Breakoutrooms
async join(testName) {
await this.joinWithUser3(testName);
await this.joinWithMod2(testName);
}
// Check if User Joined in Breakoutrooms
async testJoined(testName) {
await this.page3.logger('Now executing: ', testName);
await this.modPage2.logger('Now executing: ', testName);
try {
if (testName === 'joinBreakoutroomsWithAudio') {
await this.page3.logger('logged in to breakout with audio');
await this.modPage2.logger('logged in to breakout with audio');
const page2 = await this.page2.browser.pages();
await page2[2].bringToFront();
const breakoutUserPage1 = await this.userPage1.getLastTargetPage();
await breakoutUserPage1.bringToFront();
// Talking indicator bar
await page2[2].waitForSelector(ae.talkingIndicator, { timeout: ELEMENT_WAIT_TIME });
await breakoutUserPage1.waitForSelector(e.talkingIndicator);
await breakoutUserPage1.screenshot(testName, '05-breakout-page02-user-joined-with-audio-before-check');
if (process.env.GENERATE_EVIDENCES === 'true') {
await page2[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/05-breakout-page02-user-joined-with-audio-before-check-${testName}.png`) });
}
await this.page3.logger('before pages check');
await this.modPage2.logger('before pages check');
const resp = await page2[2].evaluate(checkElement, pe.isTalking);
const resp = await breakoutUserPage1.hasElement(e.isTalking);
await breakoutUserPage1.screenshot(testName, '06-breakout-page02-user-joined-with-audio-after-check');
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`) });
}
await this.page3.logger('after pages check');
await this.modPage2.logger('after pages check');
return resp === true;
} else if (testName === 'joinBreakoutroomsWithVideo') {
await this.page3.logger('logged in to breakout with video');
await this.modPage2.logger('logged in to breakout with video');
const page2 = await this.page2.browser.pages();
await page2[2].waitForSelector(we.videoContainer, { timeout: VIDEO_LOADING_WAIT_TIME });
if (process.env.GENERATE_EVIDENCES === 'true') {
await page2[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/05-breakout-page02-user-joined-with-webcam-success-${testName}.png`) });
}
await this.page3.logger('before pages check');
const breakoutUserPage1 = await this.userPage1.getLastTargetPage();
await breakoutUserPage1.bringToFront();
await breakoutUserPage1.screenshot(testName, '05-breakout-page02-user-joined-with-webcam-success');
await this.modPage2.logger('before pages check');
const resp = await page2[2].evaluate(checkElement, we.videoContainer);
const resp = await breakoutUserPage1.hasElement(e.videoContainer, true, VIDEO_LOADING_WAIT_TIME);
await breakoutUserPage1.screenshot(testName, '06-breakout-page02-user-joined-webcam-before-check');
await this.modPage2.logger('after pages check');
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`) });
}
await this.page3.logger('after pages check');
return resp === true;
} else if (testName === 'joinBreakoutroomsAndShareScreen') {
await this.page3.logger('logged in to breakout with screenshare');
const page2 = await this.page2.browser.pages();
const page3 = await this.page3.browser.pages();
await this.modPage2.logger('logged in to breakout with screenshare');
const breakoutUserPage1 = await this.userPage1.getLastTargetPage();
await breakoutUserPage1.bringToFront();
if (process.env.GENERATE_EVIDENCES === 'true') {
await page2[2].screenshot({ path: path.join(__dirname, `../${process.env.TEST_FOLDER}/test-${today}-${testName}/screenshots/05-breakout-page02-user-joined-screenshare-before-check-${testName}.png`) });
}
await this.page3.logger('before pages check');
const resp = await utilScreenShare.getScreenShareBreakoutContainer(page2[2]);
await breakoutUserPage1.screenshot(testName, '05-breakout-page02-user-joined-screenshare-before-check');
await this.modPage2.logger('before pages check');
const resp = await utilScreenShare.getScreenShareBreakoutContainer(breakoutUserPage1);
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-screenshare-after-check-${testName}.png`) });
}
await breakoutUserPage1.screenshot(testName, '06-breakout-page02-user-joined-screenshare-after-check');
this.userPage1.logger('after pages check');
this.page2.logger('after pages check');
return resp === true;
} else {
await this.page3.page.bringToFront();
await this.page3.waitForSelector(e.breakoutRoomsItem, ELEMENT_WAIT_TIME);
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(checkElement, e.alreadyConnected);
await this.userPage1.page.bringToFront();
await this.userPage1.waitForSelector(e.breakoutRoomsItem);
await this.userPage1.waitAndClick(e.chatButton);
await this.userPage1.waitAndClick(e.breakoutRoomsItem);
await this.userPage1.waitForSelector(e.alreadyConnected);
return resp === true;
return true;
}
} catch (err) {
await this.page3.logger(err);
await this.modPage2.logger(err);
return false;
}
}
@ -100,11 +79,11 @@ class Join extends Create {
// Close pages
async close() {
try {
await this.page1.close();
await this.page2.close();
await this.page3.close();
await this.modPage1.close();
await this.userPage1.close();
await this.modPage2.close();
} catch (err) {
await this.page3.logger(err);
await this.modPage2.logger(err);
}
}
}

View File

@ -1,15 +1,11 @@
const e = require('./elements');
const { ELEMENT_WAIT_TIME } = require('../core/constants'); // core constants (Timeouts vars imported)
const e = require('../core/elements');
async function createBreakoutRooms(page1, page2) {
await page1.click(e.manageUsers, true);
await page1.click(e.createBreakoutRooms, true);
await page1.waitForSelector(e.randomlyAssign, ELEMENT_WAIT_TIME);
await page1.click(e.randomlyAssign, true);
await page1.waitForSelector(e.modalConfirmButton, ELEMENT_WAIT_TIME);
await page1.click(e.modalConfirmButton, true);
await page2.waitForSelector(e.modalConfirmButton, ELEMENT_WAIT_TIME);
await page2.click(e.modalConfirmButton, true);
await page1.waitAndClick(e.manageUsers);
await page1.waitAndClick(e.createBreakoutRooms);
await page1.waitAndClick(e.randomlyAssign);
await page1.waitAndClick(e.modalConfirmButton);
await page2.waitAndClick(e.modalConfirmButton);
}
exports.createBreakoutRooms = createBreakoutRooms;

View File

@ -1,14 +1,13 @@
// Test: Cleaning a chat message
const Page = require('../core/page');
const e = require('./elements');
const e = require('../core/elements');
const util = require('./util');
const { checkElementLengthEqualTo } = require('../core/util');
const { ELEMENT_WAIT_TIME } = require('../core/constants');
class Clear extends Page {
constructor() {
super('chat-clear');
super();
}
async test(testName) {
@ -18,7 +17,7 @@ class Clear extends Page {
// sending a message
await this.type(e.chatBox, e.message);
await this.click(e.sendButton, true);
await this.waitAndClick(e.sendButton);
await this.screenshot(`${testName}`, `02-after-chat-message-send-[${this.meetingId}]`);
@ -26,15 +25,15 @@ class Clear extends Page {
const chat0 = await this.page.evaluate(checkElementLengthEqualTo, e.chatClearMessageText, 0);
// clear
await this.click(e.chatOptions, true);
await this.waitAndClick(e.chatOptions);
await this.screenshot(`${testName}`, `03-chat-options-clicked-[${this.meetingId}]`);
await this.click(e.chatClear, true);
await this.waitAndClick(e.chatClear);
await this.screenshot(`${testName}`, `04-chat-cleared-[${this.meetingId}]`);
const chatResp = await this.waitForSelector(e.chatClearMessageText, ELEMENT_WAIT_TIME).then(() => true);
const chatResp = await this.waitForSelector(e.chatClearMessageText).then(() => true);
return chat0 && chatResp;
} catch (err) {

View File

@ -1,14 +1,13 @@
// Test: Cleaning a chat message
const Page = require('../core/page');
const e = require('./elements');
const e = require('../core/elements');
const p = require('../params');
const util = require('./util');
const { ELEMENT_WAIT_TIME } = require('../core/constants');
class Copy extends Page {
constructor() {
super('chat-copy');
super();
}
async test(testName) {
@ -18,14 +17,14 @@ class Copy extends Page {
// sending a message
await this.type(e.chatBox, e.message);
await this.click(e.sendButton);
await this.waitAndClick(e.sendButton);
await this.screenshot(`${testName}`, `02-chat-message-sent-[${this.meetingId}]`);
await this.click(e.chatOptions);
await this.waitAndClick(e.chatOptions);
await this.screenshot(`${testName}`, `03-chat-options-clicked-[${this.meetingId}]`);
await this.waitForSelector(e.chatUserMessageText, ELEMENT_WAIT_TIME);
await this.click(e.chatCopy);
await this.waitForSelector(e.chatUserMessageText);
await this.waitAndClick(e.chatCopy);
// enable access to browser context clipboard
const context = await this.browser.defaultBrowserContext();
await context.overridePermissions(process.env.BBB_SERVER_URL, ['clipboard-read']);

View File

@ -1,25 +0,0 @@
exports.chatButton = '[data-test="chatButton"]';
exports.chatBox = '#message-input';
exports.sendButton = '[data-test="sendMessageButton"]';
exports.chatMessages = '[data-test="chatMessages"]';
exports.chatOptions = '[data-test="chatOptionsMenu"]';
exports.chatClear = '[data-test="chatClear"]';
exports.chatCopy = '[data-test="chatCopy"]';
exports.chatSave = '[data-test="chatSave"]';
exports.chatUserMessage = 'span[data-test="chatUserMessage"]';
exports.chatUserMessageText = 'p[data-test="chatUserMessageText"]';
exports.chatClearMessageText = 'p[data-test="chatClearMessageText"]';
exports.chatPollMessageText = 'p[data-test="chatPollMessageText"]';
exports.chatWelcomeMessageText = 'p[data-test="chatWelcomeMessageText"]';
exports.activeChat = '[data-test="activeChat"]';
exports.publicChat = '[data-test="publicChat"]';
exports.privateChat = '[data-test="privateChat"]';
exports.message = 'Hello World!';
exports.message1 = 'Hello User2';
exports.message2 = 'Hello User1';
exports.publicMessage1 = 'This is a Public Message from User1';
exports.publicMessage2 = 'This is a Public Message from User2';

View File

@ -1,13 +1,12 @@
// Test: Sending a chat message
const Notifications = require('../notifications/notifications');
const e = require('./elements');
const e = require('../core/elements');
const { checkElementLengthEqualTo } = require('../core/util');
const { ELEMENT_WAIT_TIME } = require('../core/constants');
class Poll extends Notifications {
constructor() {
super('poll-result-message');
super();
}
async test(testName) {
@ -18,9 +17,8 @@ class Poll extends Notifications {
await this.publishPollResults(testName);
await this.page3.waitForSelector(e.chatButton, ELEMENT_WAIT_TIME);
await this.page3.click(e.chatButton, true);
await this.page3.waitForSelector(e.chatPollMessageText, ELEMENT_WAIT_TIME);
await this.page3.waitAndClick(e.chatButton);
await this.page3.waitForSelector(e.chatPollMessageText);
// 1 message
const chat1 = await this.page3.page.evaluate(checkElementLengthEqualTo, e.chatPollMessageText, 1);

View File

@ -1,12 +1,12 @@
// Test: Cleaning a chat message
const Page = require('../core/page');
const e = require('./elements');
const e = require('../core/elements');
const util = require('./util');
class Save extends Page {
constructor() {
super('chat-save');
super();
}
async test(testName) {
@ -14,10 +14,10 @@ class Save extends Page {
await util.openChat(this);
await this.screenshot(`${testName}`, `01-before-chat-options-click-[${this.meetingId}]`);
await this.click(e.chatOptions, true);
await this.waitAndClick(e.chatOptions);
await this.screenshot(`${testName}`, `02-chat-options-clicked-[${this.meetingId}]`);
await this.click(e.chatSave, true);
await this.waitAndClick(e.chatSave);
let clicked = '';
clicked = await this.page.addListener('click', () => document.addEventListener('click'));
return clicked !== '';

View File

@ -1,13 +1,13 @@
// Test: Sending a chat message
const Page = require('../core/page');
const e = require('./elements');
const e = require('../core/elements');
const util = require('./util');
const { checkElementLengthEqualTo } = require('../core/util');
class Send extends Page {
constructor() {
super('chat-send');
super();
}
async test(testName) {
@ -22,7 +22,7 @@ class Send extends Page {
await this.type(e.chatBox, e.message);
await this.screenshot(`${testName}`, `02-typing-chat-message-[${this.meetingId}]`);
await this.click(e.sendButton, true);
await this.waitAndClick(e.sendButton);
await this.screenshot(`${testName}`, `03-after-chat-message-send-[${this.meetingId}]`);
await this.waitForSelector(e.chatUserMessageText);

View File

@ -1,45 +1,40 @@
const e = require('./elements');
const ule = require('../user/elements');
const { clickElement } = require('../core/util');
const { ELEMENT_WAIT_TIME } = require('../core/constants');
const e = require('../core/elements');
async function openChat(test) {
await test.waitForSelector(e.chatBox, ELEMENT_WAIT_TIME);
await test.waitForSelector(e.chatMessages, ELEMENT_WAIT_TIME);
await test.waitForSelector(e.chatBox);
await test.waitForSelector(e.chatMessages);
}
async function sendPublicChatMessage(page1, page2) {
async function sendPublicChatMessage(page1, page2, testName) {
// send a public message
await page1.page.type(e.publicChat, e.publicMessage1);
await page1.page.click(e.sendButton, true);
await page1.page.screenshot(true);
await page2.page.type(e.publicChat, e.publicMessage2);
await page2.page.click(e.sendButton, true);
await page2.page.screenshot(true);
await page1.type(e.chatBox, e.publicMessage1);
await page1.screenshot(testName, '01-before-User1-sends-message');
await page1.waitAndClick(e.sendButton);
await page2.type(e.chatBox, e.publicMessage2);
await page2.screenshot(testName, '02-before-User2-sends-message');
await page2.waitAndClick(e.sendButton);
}
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(clickElement, ule.userListItem);
await page2.page.evaluate(clickElement, ule.userListItem);
await page1.page.waitForSelector(e.activeChat, ELEMENT_WAIT_TIME);
await page1.page.evaluate(clickElement, e.activeChat);
await page2.page.waitForSelector(e.activeChat, ELEMENT_WAIT_TIME);
await page2.page.evaluate(clickElement, e.activeChat);
await page1.waitAndClick(e.userListItem);
await page2.waitAndClick(e.userListItem);
await page1.waitAndClick(e.activeChat);
await page2.waitAndClick(e.activeChat);
}
async function sendPrivateChatMessage(page1, page2) {
async function sendPrivateChatMessage(page1, page2, testName) {
// send a private message
await page1.page.$$('[aria-label="Hide Private Chat with User2]');
await page2.page.$$('[aria-label="Hide Private Chat with User1]');
await page1.waitForSelector(e.hidePrivateChat);
await page2.waitForSelector(e.hidePrivateChat);
await page1.page.type(e.privateChat, e.message1);
await page1.page.click(e.sendButton, true);
await page1.page.screenshot(true);
await page2.page.type(e.privateChat, e.message2);
await page2.page.click(e.sendButton, true);
await page2.page.screenshot(true);
await page1.type(e.chatBox, e.message1);
await page1.screenshot(testName, '01-before-User1-sends-message');
await page1.waitAndClick(e.sendButton);
await page2.type(e.chatBox, e.message2);
await page2.waitForSelector(e.chatUserMessageText);
await page2.screenshot(testName, '02-before-User2-sends-message');
await page2.waitAndClick(e.sendButton);
}
async function checkForPublicMessageReception(page1, page2) {

View File

@ -1,38 +1,229 @@
exports.audioDialog = 'div[aria-label="Join audio modal"]';
exports.closeAudio = 'button[aria-label="Close Join audio modal"]';
exports.microphoneButton = 'button[aria-label="Microphone"]';
exports.listenButton = 'button[aria-label="Listen Only"]';
exports.echoYes = 'button[aria-label="Echo is audible"]';
// Common
exports.actions = 'button[aria-label="Actions"]';
exports.options = 'button[aria-label="Options"]';
exports.screenshareConnecting = 'div[data-test="screenshareConnecting"]';
exports.screenShareVideo = 'video[id="screenshareVideo"]';
exports.isSharingScreen = 'div[data-test="isSharingScreen"]';
exports.raiseHandLabel = 'button[data-test="raiseHandLabel"]';
exports.lowerHandLabel = 'button[data-test="lowerHandLabel"]';
exports.logout = 'li[data-test="logout"]';
exports.meetingEndedModal = 'div[data-test="meetingEndedModal"]';
exports.rating = 'div[data-test="rating"]';
exports.pollMenuButton = 'div[data-test="pollMenuButton"]';
exports.unauthorized = 'h1[data-test="unauthorized"]';
exports.videoMenu = 'button[aria-label="Open video menu dropdown"]';
exports.settings = 'li[data-test="settings"]';
exports.settingsModal = 'div[aria-label="Settings"]';
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';
// Accesskey
exports.chatButtonKey = '[accesskey="P"]';
exports.userListButton = '[accesskey="U"]';
// Audio
exports.audioModal = 'div[aria-label="Join audio modal"]';
exports.audioModalHeader = '[data-test="audioModalHeader"]';
exports.closeAudioButton = 'button[aria-label="Close Join audio modal"]';
exports.microphoneButton = 'button[aria-label="Microphone"]';
exports.listenOnlyButton = 'button[aria-label="Listen only"]';
exports.echoYesButton = 'button[aria-label="Echo is audible"]';
exports.echoNoButton = 'button[aria-label="Echo is inaudible"]';
exports.isTalking = '[data-test="isTalking"]';
exports.wasTalking = '[data-test="wasTalking"]';
exports.joinAudio = 'button[data-test="joinAudio"]';
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.connectingStatus = 'div[class^="connecting--"]';
exports.videoMenu = 'button[aria-label="Open video menu dropdown"]';
exports.screenShare = 'button[aria-label="Share your screen"]';
exports.screenshareConnecting = 'div[data-test="screenshareConnecting"]';
exports.screenShareVideo = 'video[id="screenshareVideo"]';
exports.stopScreenSharing = 'button[aria-label="Stop sharing your screen"]';
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 = 'div[data-test="pollMenuButton"]';
exports.unauthorized = 'h1[data-test="unauthorized"]';
exports.connecting = 'span[data-test="connecting"]';
exports.connectingToEchoTest = 'span[data-test="connectingToEchoTest"]';
exports.muteMicrophoneBtn = 'button[aria-label="Mute"]';
exports.talkingIndicator = 'div[class^="isTalkingWrapper--"] > div[class^="speaking--"]';
// Breakout
exports.createBreakoutRooms = 'li[data-test="createBreakoutRooms"]';
exports.inviteBreakoutRooms = 'li[data-test="inviteBreakoutRooms"]';
exports.randomlyAssign = '[data-test="randomlyAssign"]';
exports.breakoutRemainingTime = '[data-test="breakoutRemainingTime"]';
exports.breakoutRoomsItem = '[data-test="breakoutRoomsItem"]';
exports.alreadyConnected = 'span[class^="alreadyConnected--"]';
exports.breakoutJoin = '[data-test="breakoutJoin"]';
exports.userJoined = 'div[aria-label^="Moderator3"]';
exports.breakoutRoomsButton = 'div[aria-label="Breakout Rooms"]';
exports.generateRoom1 = 'button[aria-label="Generate URL Room 1"]';
exports.joinGeneratedRoom1 = 'button[aria-label="Generated Room 1"]';
exports.joinRoom1 = 'button[aria-label="Join room Room 1"]';
// Chat
exports.chatButton = 'div[data-test="chatButton"]';
exports.chatTitle = 'div[data-test="chatTitle"]';
exports.chatBox = '#message-input';
exports.sendButton = 'button[data-test="sendMessageButton"]';
exports.chatMessages = 'div[data-test="chatMessages"]';
exports.chatOptions = 'button[data-test="chatOptionsMenu"]';
exports.chatClear = 'li[data-test="chatClear"]';
exports.chatCopy = 'li[data-test="chatCopy"]';
exports.chatSave = 'li[data-test="chatSave"]';
exports.chatUserMessage = 'span[data-test="chatUserMessage"]';
exports.chatUserMessageText = 'p[data-test="chatUserMessageText"]';
exports.chatClearMessageText = 'p[data-test="chatClearMessageText"]';
exports.chatPollMessageText = 'p[data-test="chatPollMessageText"]';
exports.chatWelcomeMessageText = 'p[data-test="chatWelcomeMessageText"]';
exports.activeChat = 'li[data-test="activeChat"]';
exports.publicChat = 'div[data-test="publicChat"]';
exports.privateChat = 'div[data-test="privateChat"]';
exports.hidePrivateChat = 'button[aria-label^="Hide Private Chat with"]';
// Messages
exports.message = 'Hello World!';
exports.message1 = 'Hello User2';
exports.message2 = 'Hello User1';
exports.publicMessage1 = 'This is a Public Message from User1';
exports.publicMessage2 = 'This is a Public Message from User2';
// CustomParameters
exports.audioOverlay = 'div[class^="ReactModal__Overlay"]';
exports.brandingAreaLogo = 'div[class^="branding--"]';
exports.verticalListOptions = 'div[aria-expanded="true"] > div[class^="scrollable--"] > ul[class^="verticalList"]';
exports.multiUsersWhiteboard = 'button[aria-label="Turn multi-user whiteboard on"]';
exports.defaultContent = 'div[class^="defaultContent--"]';
exports.notificationBar = 'div[class^="notificationsBar--"]';
exports.chat = 'section[aria-label="Chat"]';
exports.recordingIndicator = 'div[class^="recordingIndicator--"]';
exports.webcamMirroredVideoContainer = 'video[data-test="mirroredVideoContainer"]';
exports.userslistContainer = 'div[aria-label="User list"]';
exports.userListContent = 'div[data-test="userListContent"]';
exports.confirmBtn = 'button[aria-label="Confirm "]';
exports.zoomIn = 'button[aria-label="Zoom in"]';
exports.audioOptionsButtons = '[class^="audioOptions"] > button';
exports.startWebcamSharingConfirm = 'button[aria-label="Start sharing"]';
exports.toolbarListClass = '[class^="toolbarList--"]';
// Notes
exports.sharedNotes = 'div[data-test="sharedNotes"]';
exports.hideNoteLabel = 'button[data-test="hideNoteLabel"]';
exports.etherpad = 'iframe[title="etherpad"]';
// Notifications
exports.chatPushAlerts = 'input[aria-label="Chat Message Popup Alerts"]';
exports.smallToastMsg = 'div[data-test="toastSmallMsg"]';
exports.toastContainer = 'div[class^="toastContainer--"]';
exports.savedSettingsToast = 'Settings have been saved';
exports.publicChatToast = 'New Public Chat message';
exports.privateChatToast = 'New Private Chat message';
exports.userListNotifiedIcon = '[class^=btnWithNotificationDot]';
exports.hasUnreadMessages = 'button[data-test="hasUnreadMessages"]';
exports.modalConfirmButton = 'button[data-test="modalConfirmButton"]';
exports.userJoinPushAlerts = '[aria-label="User Join Popup Alerts"]';
exports.dropdownContent = '[data-test="dropdownContent"]';
exports.fileUploadDropZone = '[data-test="fileUploadDropZone"]';
exports.polling = 'li[data-test="polling"]';
exports.pollYesNoAbstentionBtn = 'button[aria-label="Yes / No / Abstention"]';
exports.yesBtn = 'button[aria-label="Yes"]';
exports.publishPollingResults = 'button[aria-label="Publish polling results"]';
exports.hidePollDesc = 'button[data-test="hidePollDesc"]';
exports.joinAudioToast = 'You have joined the audio conference';
exports.notificationsTab = 'span[id="notificationTab"]';
// Polling
exports.pollingContainer = 'div[data-test="pollingContainer"]';
exports.pollQuestionArea = 'textarea[data-test="pollQuestionArea"]';
exports.pollQuestion = 'Are we good ?';
exports.responseTypes = 'div[data-test="responseTypes"]';
exports.responseChoices = 'div[data-test="responseChoices"]';
exports.addItem = 'button[data-test="addItem"]';
exports.pollOptionItem = 'input[data-test="pollOptionItem"]';
exports.uncertain = 'Uncertain';
exports.deletePollOption = 'button[data-test="deletePollOption"]';
exports.pollAnswerOptionBtn = 'button[data-test="pollAnswerOption"]';
exports.pollAnswerOptionInput = 'input[data-test="pollAnswerOption"]';
exports.pollSubmitAnswer = 'button[data-test="submitAnswer"]';
exports.startPoll = 'button[data-test="startPoll"]';
exports.restartPoll = 'button[data-test="restartPoll"]';
exports.receivedAnswer = 'td[data-test="receivedAnswer"]';
exports.publishLabel = 'button[data-test="publishLabel"]';
exports.pollResults = 'g[data-test="pollResultAria"]';
// Presentation
exports.startScreenSharing = 'button[data-test="startScreenShare"]';
exports.stopScreenSharing = 'button[data-test="stopScreenShare"]';
exports.presentationToolbarWrapper = '#presentationToolbarWrapper';
exports.presentationTitle = '[class^="presentationTitle--"]';
exports.hidePresentation = 'button[data-test="hidePresentationButton"]';
exports.restorePresentation = 'button[data-test="restorePresentationButton"]';
exports.nextSlide = '[data-test="nextSlide"]';
exports.prevSlide = '[data-test="prevSlide"]';
exports.fileUpload = 'input[type="file"]';
exports.upload = 'button[aria-label="Upload"]';
exports.cancel = 'button[aria-label="Cancel]';
exports.uploadPresentation = '[data-test="uploadPresentation"]';
exports.skipSlide = '[data-test="skipSlide"]';
exports.removePresentation = 'button[data-test="removePresentation"]';
exports.presentationPlaceholder = 'div[data-test="presentationPlaceholder"]';
exports.presentationPlaceholderLabel = 'Waiting for a presentation to be uploaded';
exports.presentationDownloadBtn = 'button[data-test="presentationDownload"]';
exports.toastDownload = 'a[data-test="toastDownload"]';
exports.confirmManagePresentation = 'button[data-test="confirmManagePresentation"]';
exports.allowPresentationDownload = 'button[data-test="allowPresentationDownload"]';
exports.disallowPresentationDownload = 'button[data-test="disallowPresentationDownload"]';
// User
exports.firstUser = '[data-test="userListItemCurrent"]';
exports.userListItem = 'div[data-test="userListItem"]';
exports.anyUser = '[data-test^="userListItem"]';
exports.userAvatar = 'div[data-test="userAvatar"]'
exports.avatarsWrapperAvatar = 'div[data-test="avatarsWrapperAvatar"]';
exports.firstUserAvatar = `${this.firstUser} > ${this.userAvatar}`;
exports.secondUserAvatar = `${this.userListItem} > ${this.userAvatar}`;
exports.applauseIcon = `${this.userAvatar} > div > i[class="icon-bbb-applause"]`;
exports.awayIcon = `${this.userAvatar} > div > i[class="icon-bbb-time"]`;
exports.presenterClassName = 'presenter--';
exports.setStatus = '[data-test="setstatus"]';
exports.away = '[data-test="away"]';
exports.applaud = '[data-test="applause"]';
exports.clearStatus = '[data-test="clearStatus"]';
exports.setPresenter = 'li[data-test="setPresenter"]';
exports.connectionStatusModal = 'div[aria-label="Connection status modal"]';
exports.dataSavingWebcams = 'input[data-test="dataSavingWebcams"]';
exports.dataSavingScreenshare = 'input[data-test="dataSavingScreenshare"]';
exports.closeConnectionStatusModal = 'button[aria-label="Close Connection status modal"]';
exports.webcamsIsDisabledInDataSaving = 'button[aria-label="Webcam sharing is disabled in Data Saving"]';
exports.screenshareLocked = 'button[aria-label="Screenshare locked"]';
exports.connectionStatusItemEmpty = 'div[data-test="connectionStatusItemEmpty"]';
exports.connectionStatusItemUser = 'div[data-test="connectionStatusItemUser"]';
exports.connectionStatusOfflineUser = 'div[data-test="offlineUser"]';
exports.mobileUser = 'span[data-test="mobileUser"]';
exports.userList = 'button[aria-label="Users and messages toggle"]';
exports.manageUsers = 'button[data-test="manageUsers"]';
exports.guestPolicyLabel = 'li[data-test="guestPolicyLabel"]';
exports.guestPolicySettingsModal = 'div[data-test="guestPolicySettingsModal"]';
exports.askModerator = 'button[data-test="askModerator"]';
exports.alwaysAccept = 'button[data-test="alwaysAccept"]';
exports.alwaysDeny = 'button[data-test="alwaysDeny"]';
exports.waitingUsersBtn = 'div[data-test="waitingUsersBtn"]';
exports.joinMeetingDemoPage = 'div[class^="join-meeting"]';
exports.chatPanel = 'section[data-test="chatPanel"]';
exports.userListPanel = 'div[data-test="userListPanel"]';
exports.multiWhiteboardTool = 'span[data-test="multiWhiteboardTool"]'
exports.connectionStatusBtn = 'button[data-test="connectionStatusButton"]';
// Webcam
exports.joinVideo = 'button[data-test="joinVideo"]';
exports.leaveVideo = 'button[data-test="leaveVideo"]';
exports.videoPreview = 'video[data-test="videoPreview"]';
exports.startSharingWebcam = 'button[data-test="startSharingWebcam"]';
exports.webcamSettingsModal = 'div[aria-label="Webcam settings"]';
exports.webcamMirroredVideoPreview = 'video[data-test="mirroredVideoPreview"]';
exports.videoContainer = 'div[class^="videoListItem"]';
exports.webcamConnecting = 'div[data-test="webcamConnecting"]';
exports.presentationFullscreenButton = 'button[data-test="presentationFullscreenButton"]';
exports.webcamItemTalkingUser = 'div[data-test="webcamItemTalkingUser"]';
exports.webcamVideo = 'video[data-test="videoContainer"]';
// Whiteboard
exports.whiteboard = 'svg[data-test="whiteboard"]';
exports.tools = 'button[aria-label="Tools"]';
exports.pencil = 'button[aria-label="Pencil"]';
exports.rectangle = 'button[aria-label="Rectangle"]';
exports.drawnRectangle = 'svg g[clip-path] > g:nth-child(2) rect[data-test="drawnRectangle"]';
exports.changeWhiteboardAccess = 'li[data-test="changeWhiteboardAccess"]';
exports.whiteboardViewBox = 'svg g[clip-path="url(#viewBox)"]';

View File

@ -6,9 +6,6 @@ const axios = require('axios');
const httpPath = path.join(path.dirname(require.resolve('axios')), 'lib/adapters/http');
const http = require(httpPath);
const params = require('../params');
const e = require('./elements');
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);

View File

@ -11,14 +11,13 @@ 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');
const devices = require('./devices');
const linuxDesktop = devices['Linux Desktop'];
class Page {
constructor(name) {
this.name = name;
constructor(page) {
this.page = page;
this.screenshotIndex = 0;
this.meetingId;
this.parentDir = this.getParentDir(__dirname);
@ -84,7 +83,7 @@ class Page {
await this.page.goto(joinURL, { waitUntil: 'networkidle2' });
if (process.env.BBB_COLLECT_METRICS === 'true' && process.env.IS_MOBILE !== 'true') {
await this.waitForSelector(ue.anyUser, ELEMENT_WAIT_TIME);
await this.waitForSelector(e.anyUser);
await this.getMetrics(testFolderName);
}
} catch (err) {
@ -94,56 +93,44 @@ class Page {
// Joining audio with microphone
async joinMicrophone() {
await this.waitForSelector(e.audioDialog, ELEMENT_WAIT_TIME);
await this.waitForSelector(e.microphoneButton, ELEMENT_WAIT_TIME);
await this.click(e.microphoneButton, true);
await this.waitForSelector(e.connectingStatus, ELEMENT_WAIT_TIME);
await this.waitForSelector(e.audioModal);
await this.waitAndClick(e.microphoneButton);
await this.waitForSelector(e.connectingStatus);
const parsedSettings = await this.getSettingsYaml();
const listenOnlyCallTimeout = parseInt(parsedSettings.public.media.listenOnlyCallTimeout);
await this.waitForSelector(e.echoYes, listenOnlyCallTimeout);
await this.click(e.echoYes, true);
await this.waitForSelector(e.isTalking, ELEMENT_WAIT_TIME);
await this.waitAndClick(e.echoYesButton, listenOnlyCallTimeout);
await this.waitForSelector(e.isTalking);
}
// Joining audio with microphone
async joinMicrophoneWithoutEchoTest() {
await this.waitForSelector(e.joinAudio, ELEMENT_WAIT_TIME);
await this.click(e.joinAudio, true);
await this.waitAndClick(e.joinAudio);
const parsedSettings = await this.getSettingsYaml();
const listenOnlyCallTimeout = parseInt(parsedSettings.public.media.listenOnlyCallTimeout);
await this.waitForSelector(e.leaveAudio, listenOnlyCallTimeout);
await this.click(e.leaveAudio, ELEMENT_WAIT_TIME);
await this.waitForSelector(e.disconnectAudio, ELEMENT_WAIT_TIME);
await this.click(e.disconnectAudio, true);
await this.waitAndClick(e.leaveAudio, listenOnlyCallTimeout);
}
// Leave audio
async leaveAudio() {
await this.waitForSelector(e.leaveAudio, ELEMENT_WAIT_TIME);
await this.click(e.leaveAudio, true);
await this.waitForSelector(e.disconnectAudio, ELEMENT_WAIT_TIME);
await this.click(e.disconnectAudio, true);
await this.waitForSelector(e.joinAudio, ELEMENT_WAIT_TIME);
await this.waitAndClick(e.leaveAudio);
await this.waitForSelector(e.joinAudio);
}
// Logout from meeting
async logoutFromMeeting() {
await this.waitForSelector(e.options, ELEMENT_WAIT_TIME);
await this.click(e.options, true);
await this.waitForSelector(e.logout, ELEMENT_WAIT_TIME);
await this.click(e.logout, true);
await this.waitAndClick(e.options);
await this.waitAndClick(e.logout);
}
// Joining audio with Listen Only mode
async listenOnly() {
await this.waitForSelector(e.audioDialog, ELEMENT_WAIT_TIME);
await this.waitForSelector(e.listenButton, ELEMENT_WAIT_TIME);
await this.click(e.listenButton);
await this.waitForSelector(e.audioModal);
await this.waitAndClick(e.listenOnlyButton);
}
async closeAudioModal() {
await this.waitForSelector(e.audioDialog, ELEMENT_WAIT_TIME);
await this.click(e.closeAudio, true);
await this.waitForSelector(e.audioModal);
await this.waitAndClick(e.closeAudioButton);
}
async setDownloadBehavior(downloadPath) {
@ -225,9 +212,9 @@ class Page {
}
}
async isNotVisible(el, timeout) {
async isNotVisible(element, timeout = ELEMENT_WAIT_TIME) {
try {
await this.page.waitForSelector(el, { visible: false, timeout: timeout });
await this.hasElement(element, false, timeout);
return true;
} catch (err) {
await this.logger(err);
@ -240,9 +227,28 @@ class Page {
// }
// Returns a Promise that resolves when an element does not exist/is removed from the DOM
async waitForElementHandleToBeRemoved(element) {
await this.page.waitForTimeout(1000);
await this.page.waitForSelector(element, { hidden: true });
async waitForElementHandleToBeRemoved(element, timeout = ELEMENT_WAIT_TIME) {
await this.page.waitForSelector(element, { timeout, hidden: true });
}
async wasRemoved(element, timeout = ELEMENT_WAIT_TIME) {
try {
await this.waitForElementHandleToBeRemoved(element, timeout);
return true;
} catch (err) {
this.logger(err);
return false;
}
}
async hasElement(element, visible = false, timeout = ELEMENT_WAIT_TIME) {
try {
await this.page.waitForSelector(element, { visible, timeout });
return true;
} catch (err) {
await this.logger(err);
return false;
}
}
// Presses a hotkey (Ctrl, Alt and Shift can be held down while pressing the key)
@ -299,21 +305,40 @@ class Page {
await this.page.keyboard.up(key);
}
async click(element, relief = false) {
async bringToFront() {
await this.page.bringToFront();
}
async getLastTargetPage() {
const browserPages = await this.browser.pages();
return new Page(browserPages[browserPages.length - 1]);
}
async waitAndClick(element, timeout = ELEMENT_WAIT_TIME, relief = false) {
if (relief) await helper.sleep(1000);
await this.waitForSelector(element, ELEMENT_WAIT_TIME);
await this.waitForSelector(element, timeout);
await this.page.focus(element);
await this.page.click(element, true);
}
async clickNItem(element, relief = false, n) {
async waitAndClickElement(element, index = 0, timeout = ELEMENT_WAIT_TIME, relief = false) {
if (relief) await helper.sleep(1000);
await this.waitForSelector(element, timeout);
await this.page.evaluate((elem, i) => {
document.querySelectorAll(elem)[i].click();
}, element, index);
}
async clickNItem(element, n, relief = false) {
if (relief) await helper.sleep(1000);
await this.waitForSelector(element);
const elementHandle = await this.page.$$(element);
await elementHandle[n].click();
}
async type(element, text, relief = false) {
if (relief) await helper.sleep(1000);
await this.waitForSelector(element, ELEMENT_WAIT_TIME);
await this.waitForSelector(element);
await this.page.type(element, text);
}
@ -380,13 +405,13 @@ class Page {
}
async paste(element) {
await this.click(element);
await this.waitAndClick(element);
await this.page.keyboard.down('ControlLeft');
await this.page.keyboard.press('KeyV');
await this.page.keyboard.up('ControlLeft');
}
async waitForSelector(element, timeout) {
async waitForSelector(element, timeout = ELEMENT_WAIT_TIME) {
await this.page.waitForSelector(element, { timeout });
}
@ -405,13 +430,13 @@ class Page {
if (!fs.existsSync(metricsFolder)) {
fs.mkdirSync(metricsFolder);
}
await this.waitForSelector(ue.anyUser, ELEMENT_WAIT_TIME);
await this.waitForSelector(e.anyUser);
const totalNumberOfUsersMongo = await this.page.evaluate(() => {
const collection = require('/imports/api/users-persistent-data/index.js');
const users = collection.default._collection.find({}, {}, {}, {}, {}, { loggedOut: 'false' }).count();
return users;
});
const totalNumberOfUsersDom = await this.page.evaluate(getElementLength, '[data-test^="userListItem"]');
const totalNumberOfUsersDom = await this.page.evaluate(getElementLength, e.anyUser);
await this.logger({ totalNumberOfUsersDom, totalNumberOfUsersMongo });
const metric = await this.page.metrics();
pageMetricsObj.totalNumberOfUsersMongoObj = totalNumberOfUsersMongo;

View File

@ -3,10 +3,6 @@ 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;
@ -35,7 +31,6 @@ function getElementLength(element) {
}
exports.checkElement = checkElement;
exports.clickElement = clickElement;
exports.checkElementText = checkElementText;
exports.checkElementTextIncludes = checkElementTextIncludes;
exports.getElementText = getElementText;

View File

@ -554,11 +554,13 @@ const customParametersTest = () => {
const test = new CustomParameters();
const page = new Page();
let response;
let screenshot;
try {
const testName = 'recordMeeting';
await page.logger('before ', testName);
response = await test.recordMeeting(testName, Page.getArgs(), undefined, `${c.recordMeeting}`);
await test.page1.stopRecording();
screenshot = await test.page1.page.screenshot();
await page.logger('after ', testName);
} catch (err) {
await page.logger(err);
@ -575,11 +577,13 @@ const customParametersTest = () => {
const test = new CustomParameters();
const page = new Page();
let response;
let screenshot;
try {
const testName = 'skipVideoPreview';
await page.logger('before ', testName);
response = await test.skipVideoPreview(testName, Page.getArgs(), undefined, `${c.skipVideoPreview}`);
await test.page1.stopRecording();
screenshot = await test.page1.page.screenshot();
await page.logger('after ', testName);
} catch (err) {
await page.logger(err);
@ -596,11 +600,13 @@ const customParametersTest = () => {
const test = new CustomParameters();
const page = new Page();
let response;
let screenshot;
try {
const testName = 'skipVideoPreviewOnFirstJoin';
await page.logger('before ', testName);
response = await test.skipVideoPreviewOnFirstJoin(testName, Page.getArgs(), undefined, `${c.skipVideoPreviewOnFirstJoin}`);
await test.page1.stopRecording();
screenshot = await test.page1.page.screenshot();
await page.logger('after ', testName);
} catch (err) {
await page.logger(err);
@ -618,11 +624,13 @@ const customParametersTest = () => {
const test = new CustomParameters();
const page = new Page();
let response;
let screenshot;
try {
const testName = 'mirrorOwnWebcam';
await page.logger('before ', testName);
response = await test.mirrorOwnWebcam(testName, Page.getArgs(), undefined, `${c.mirrorOwnWebcam}`);
await test.page1.stopRecording();
screenshot = await test.page1.page.screenshot();
await page.logger('after ', testName);
} catch (err) {
await page.logger(err);
@ -639,11 +647,13 @@ const customParametersTest = () => {
const test = new CustomParameters();
const page = new Page();
let response;
let screenshot;
try {
const testName = 'showParticipantsOnLogin';
await page.logger('before ', testName);
response = await test.showParticipantsOnLogin(testName, Page.getArgs(), undefined, `${c.showParticipantsOnLogin}`);
await test.page1.stopRecording();
screenshot = await test.page1.page.screenshot();
await page.logger('after ', testName);
} catch (err) {
await page.logger(err);

View File

@ -1,39 +0,0 @@
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"]';
exports.toastContainer = 'div[class^="toastContainer--"]';
exports.muteBtn = 'button[aria-label="Mute"]';
exports.options = 'button[aria-label="Options"]';
exports.logout = 'li[data-test="logout"]';
exports.meetingEndedModal = 'div[data-test="meetingEndedModal"]';
exports.rating = 'div[data-test="rating"]';
exports.brandingAreaLogo = 'div[class^="branding--"]';
exports.verticalListOptions = 'div[aria-expanded="true"] > div[class^="scrollable--"] > ul[class^="verticalList"]';
exports.screenShareButton = 'button[aria-label="Share your screen"]';
exports.shareWebcamButton = 'button[data-test="joinVideo"]';
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.presentationTitle = '[class^="presentationTitle--"]';
exports.defaultContent = 'div[class^="defaultContent--"]';
exports.notificationBar = 'div[class^="notificationsBar--"]';
exports.chat = 'section[aria-label="Chat"]';
exports.recordingIndicator = 'div[class^="recordingIndicator--"]';
exports.startSharingWebcamButton = 'button[data-test="startSharingWebcam"]';
exports.webcamVideoPreview = 'video[data-test="videoPreview"]';
exports.webcamMirroredVideoPreview = 'video[data-test="mirroredVideoPreview"]';
exports.webcamVideoContainer = 'video[data-test="videoContainer"]';
exports.webcamMirroredVideoContainer = 'video[data-test="mirroredVideoContainer"]';
exports.userslistContainer = 'div[aria-label="User list"]';
exports.userListContent = 'div[data-test="userListContent"]';
exports.confirmBtn = 'button[aria-label="Confirm "]';

View File

@ -1,16 +1,11 @@
const path = require('path');
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 { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { checkElementLengthEqualTo, checkElementLengthDifferentTo, checkElementText } = require('../core/util');
async function autoJoinTest(test) {
try {
const resp = await test.page.evaluate(checkElementLengthEqualTo, e.audioDialog, 0);
const resp = await test.page.evaluate(checkElementLengthEqualTo, e.audioModal, 0);
return resp === true;
} catch (err) {
console.log(err);
@ -21,10 +16,10 @@ async function autoJoinTest(test) {
async function listenOnlyMode(test) {
// maybe not used
try {
const resp = await test.page.evaluate(async (connectionSelector, echoYes) => {
const resp = await test.page.evaluate(async (connectionSelector, echoYesButton) => {
await document.querySelectorAll(connectionSelector)[0];
return document.querySelectorAll(echoYes).length !== 0;
}, e.connectingStatus, e.echoYes);
return document.querySelectorAll(echoYesButton).length !== 0;
}, e.connectingStatus, e.echoYesButton);
return resp === true;
} catch (err) {
console.log(err);
@ -33,9 +28,9 @@ async function listenOnlyMode(test) {
async function forceListenOnly(test) {
try {
const checkEchoYes = await test.page.evaluate(checkElementLengthEqualTo, e.echoYes, 0);
const checkEchoYes = await test.page.evaluate(checkElementLengthEqualTo, e.echoYesButton, 0);
if (!checkEchoYes) return false;
const resp = await test.page.evaluate(checkElementText, ce.toastContainer, 'You have joined the audio conference');
const resp = await test.page.evaluate(checkElementText, e.toastContainer, 'You have joined the audio conference');
return resp === true;
} catch (err) {
@ -47,10 +42,10 @@ async function forceListenOnly(test) {
async function skipCheck(test) {
// maybe not used
try {
await test.waitForSelector(ce.toastContainer, ELEMENT_WAIT_TIME);
await test.waitForSelector(e.toastContainer);
const resp1 = await test.page.evaluate(checkElementLengthDifferentTo, e.toastContainer, 0);
await test.waitForSelector(ce.muteBtn, ELEMENT_WAIT_TIME);
const resp2 = await test.page.evaluate(checkElementLengthDifferentTo, ce.muteBtn, 0);
await test.waitForSelector(e.muteMicrophoneBtn);
const resp2 = await test.page.evaluate(checkElementLengthDifferentTo, e.muteMicrophoneBtn, 0);
return resp1 === true && resp2 === true;
} catch (err) {
console.log(err);
@ -96,19 +91,14 @@ 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.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);
await page1.click(ne.pollYesNoAbstentionBtn, true);
await page1.waitForSelector(ne.startPoll, ELEMENT_WAIT_TIME);
await page1.click(ne.startPoll, true);
await page2.waitForSelector(poe.pollingContainer, ELEMENT_WAIT_TIME);
await page2.waitForSelector(ne.yesBtn, ELEMENT_WAIT_TIME);
await page2.click(ne.yesBtn, true);
await page1.waitForSelector(ne.publishPollingResults, ELEMENT_WAIT_TIME);
await page1.click(ne.publishPollingResults, true);
await page1.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await page1.waitAndClick(e.actions);
await page1.waitAndClick(e.polling);
await page1.waitAndClick(e.pollYesNoAbstentionBtn);
await page1.waitAndClick(e.startPoll);
await page2.waitForSelector(e.pollingContainer);
await page2.waitAndClick(e.yesBtn);
await page1.waitAndClick(e.publishPollingResults);
return true;
} catch (err) {
console.log(err);
@ -118,8 +108,7 @@ async function poll(page1, page2) {
async function previousSlide(test) {
try {
await test.waitForSelector(pe.prevSlide, ELEMENT_WAIT_TIME);
await test.click(pe.prevSlide, true);
await test.waitAndClick(e.prevSlide);
return true;
} catch (err) {
console.log(err);
@ -129,8 +118,7 @@ async function previousSlide(test) {
async function nextSlide(test) {
try {
await test.waitForSelector(pe.nextSlide, ELEMENT_WAIT_TIME);
await test.click(pe.nextSlide, true);
await test.waitAndClick(e.nextSlide);
return true;
} catch (err) {
console.log(err);
@ -139,11 +127,9 @@ async function nextSlide(test) {
}
async function annotation(test) {
await test.waitForSelector(ce.tools, ELEMENT_WAIT_TIME);
await test.click(ce.tools, true);
await test.waitForSelector(we.pencil, ELEMENT_WAIT_TIME);
await test.click(we.pencil, true);
await test.click(ce.whiteboard, true);
await test.waitAndClick(e.tools);
await test.waitAndClick(e.pencil);
await test.waitAndClick(e.whiteboard);
const annoted = await test.page.evaluate((whiteboard) => {
return document.querySelectorAll(`${whiteboard} > g > g`)[1].innerHTML !== '';
}, e.whiteboard);
@ -152,13 +138,11 @@ async function annotation(test) {
async function presetationUpload(test) {
try {
await test.waitForSelector(ce.actions, ELEMENT_WAIT_TIME);
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.$(pe.fileUpload);
await test.waitAndClick(e.actions);
await test.waitAndClick(e.uploadPresentation);
const elementHandle = await test.page.$(e.fileUpload);
await elementHandle.uploadFile(path.join(__dirname, `../media/${e.pdfFileName}.pdf`));
await test.click(ce.confirmBtn, true);
await test.waitAndClick(e.confirmBtn);
return true;
} catch (err) {
console.log(err);

View File

@ -7,7 +7,7 @@ const { checkElementLengthDifferentTo } = require('../core/util');
class Trigger extends Page {
constructor() {
super('trigger-events');
super();
}
async triggerMeteorDisconnect(testName) {
@ -25,9 +25,9 @@ class Trigger extends Page {
const meteorStatus = await this.page.evaluate(() => Meteor.status());
const meteorStatusConfirm = await meteorStatus.status === "offline";
await this.logger('Check if Meteor is Offline => ', meteorStatusConfirm);
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 this.page.evaluate(() => Meteor.reconnect());
await sleep(3000);

View File

@ -1,3 +0,0 @@
exports.sharedNotes = 'div[data-test="sharedNotes"]';
exports.hideNoteLabel = 'button[data-test="hideNoteLabel"]';
exports.etherpad = 'iframe[title="etherpad"]';

View File

@ -3,7 +3,7 @@ const util = require('./util');
class SharedNotes extends Create {
constructor() {
super('shared-notes');
super();
}
async test() {

View File

@ -1,17 +1,16 @@
const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const se = require('./elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const e = require('../core/elements');
const { getElementLength } = require('../core/util');
async function startSharedNotes(test) {
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);
await test.waitAndClick(e.sharedNotes);
await test.waitForSelector(e.hideNoteLabel, ELEMENT_WAIT_LONGER_TIME);
const resp = await test.page.evaluate(getElementLength, e.etherpad) >= 1;
await test.waitForSelector(e.etherpad);
return resp === true;
} catch (e) {
await test.logger(e);
} catch (err) {
await test.logger(err);
return false;
}
}

View File

@ -1,6 +1,4 @@
const Notifications = require('./notifications/notifications');
const ShareScreen = require('./screenshare/screenshare');
const Audio = require('./audio/audio');
const Page = require('./core/page');
const { toMatchImageSnapshot } = require('jest-image-snapshot');
const { MAX_NOTIFICATIONS_TEST_TIMEOUT } = require('./core/constants'); // core constants (Timeouts vars imported)

View File

@ -1,26 +0,0 @@
exports.settings = 'li[data-test="settings"]';
exports.settingsModal = 'div[aria-label="Settings"]';
exports.chatPushAlerts = 'input[aria-label="Chat Message Popup Alerts"]';
exports.smallToastMsg = 'div[data-test="toastSmallMsg"]';
exports.saveSettings = '[data-test="modalConfirmButton"]';
exports.savedSettingsToast = 'Settings have been saved';
exports.publicChatToast = 'New Public Chat message';
exports.privateChatToast = 'New Private Chat message';
exports.userListNotifiedIcon = '[class^=btnWithNotificationDot]';
exports.hasUnreadMessages = 'button[data-test="hasUnreadMessages"]';
exports.modalConfirmButton = 'button[data-test="modalConfirmButton"]';
exports.userJoinPushAlerts = '[aria-label="User Join Popup Alerts"]';
exports.uploadPresentation = '[data-test="uploadPresentation"]';
exports.dropdownContent = '[data-test="dropdownContent"]';
exports.fileUploadDropZone = '[data-test="fileUploadDropZone"]';
exports.polling = 'li[data-test="polling"]';
exports.pollYesNoAbstentionBtn = 'button[aria-label="Yes / No / Abstention"]';
exports.yesBtn = 'button[aria-label="Yes"]';
exports.startPoll = 'button[aria-label="Start Poll"]';
exports.publishPollingResults = 'button[aria-label="Publish polling results"]';
exports.hidePollDesc = 'button[data-test="hidePollDesc"]';
exports.publishLabel = 'button[data-test="publishLabel"]';
exports.joinAudioToast = 'You have joined the audio conference';
exports.notificationsTab = 'span[id="notificationTab"]';

View File

@ -5,15 +5,12 @@ const params = require('../params');
const util = require('./util');
const utilScreenShare = require('../screenshare/util'); // utils imported from screenshare folder
const e = require('../core/elements');
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 { ELEMENT_WAIT_LONGER_TIME, UPLOAD_PDF_WAIT_TIME } = require('../core/constants');
const { checkElementTextIncludes } = require('../core/util');
class Notifications extends MultiUsers {
constructor() {
super('notifications');
super();
this.page1 = new Page();
this.page2 = new Page();
this.page3 = new Page();
@ -45,7 +42,7 @@ class Notifications extends MultiUsers {
await this.page1.screenshot(`${testName}`, `02-page01-popupMenu-${testName}`);
await util.saveSettings(this.page1);
await this.page1.screenshot(`${testName}`, `03-page01-save-settings-${testName}`);
const resp = await util.getLastToastValue(this.page1) === ne.savedSettingsToast;
const resp = await util.getLastToastValue(this.page1) === e.savedSettingsToast;
await this.page1.screenshot(`${testName}`, `04-page01-saved-Settings-toast-${testName}`);
return resp === true;
} catch (err) {
@ -68,8 +65,9 @@ class Notifications extends MultiUsers {
await this.page1.screenshot(`${testName}`, `04-page01-applied-settings-${testName}`);
const expectedToastValue = await util.publicChatMessageToast(this.page1, this.page2);
await this.page1.screenshot(`${testName}`, `05-page01-public-chat-message-sent-${testName}`);
await this.page1.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
await this.page1.waitForSelector(ne.hasUnreadMessages, ELEMENT_WAIT_TIME);
await this.page1.waitAndClick(e.chatTitle);
await this.page1.waitForSelector(e.smallToastMsg);
await this.page1.waitForSelector(e.hasUnreadMessages);
const lastToast = await util.getLastToastValue(this.page1);
await this.page1.screenshot(`${testName}`, `06-page01-public-chat-toast-${testName}`);
return expectedToastValue === lastToast;
@ -93,8 +91,8 @@ class Notifications extends MultiUsers {
await this.page1.screenshot(`${testName}`, `04-page01-applied-settings-${testName}`);
const expectedToastValue = await util.privateChatMessageToast(this.page2);
await this.page1.screenshot(`${testName}`, `05-page01-private-chat-message-sent-${testName}`);
await this.page1.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
await this.page1.waitForSelector(ne.hasUnreadMessages, ELEMENT_WAIT_TIME);
await this.page1.waitForSelector(e.smallToastMsg);
await this.page1.waitForSelector(e.hasUnreadMessages);
const lastToast = await util.getLastToastValue(this.page1);
await this.page1.screenshot(`${testName}`, `06-page01-public-chat-toast-${testName}`);
return expectedToastValue === lastToast;
@ -127,7 +125,7 @@ class Notifications extends MultiUsers {
await this.page3.screenshot(`${testName}`, `03-page03-after-user-join-notification-activation-${testName}`);
await this.initUser4(testName);
await this.page4.closeAudioModal();
await this.page3.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
await this.page3.waitForSelector(e.smallToastMsg, ELEMENT_WAIT_LONGER_TIME);
await this.page3.page.waitForFunction(checkElementTextIncludes, {},
'body', 'User joined the session'
);
@ -149,20 +147,19 @@ class Notifications extends MultiUsers {
await this.page3.screenshot(`${testName}`, `02-page03-audio-modal-closed-${testName}`);
await util.uploadFileMenu(this.page3);
await this.page3.screenshot(`${testName}`, `03-page03-upload-file-menu-${testName}`);
await this.page3.waitForSelector(pe.fileUpload, ELEMENT_WAIT_TIME);
const fileUpload = await this.page3.page.$(pe.fileUpload);
await this.page3.waitForSelector(e.fileUpload);
const fileUpload = await this.page3.page.$(e.fileUpload);
await fileUpload.uploadFile(path.join(__dirname, `../media/${e.pdfFileName}.pdf`));
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.waitAndClick(e.upload);
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.waitForSelector(e.smallToastMsg, UPLOAD_PDF_WAIT_TIME);
await this.page3.waitForSelector(e.whiteboard);
await this.page3.screenshot(`${testName}`, `05-page03-presentation-changed-${testName}`);
await this.page3.page.waitForFunction(checkElementTextIncludes, {},
'body', 'Current presentation'
@ -181,10 +178,10 @@ class Notifications extends MultiUsers {
await this.page3.screenshot(`${testName}`, `01-page03-initialized-${testName}`);
await this.page3.closeAudioModal();
await this.page3.screenshot(`${testName}`, `02-page03-audio-modal-closed-${testName}`);
await this.page3.waitForSelector(we.whiteboard, ELEMENT_WAIT_TIME);
await this.page3.waitForSelector(e.whiteboard);
await util.startPoll(this.page3);
await this.page3.screenshot(`${testName}`, `03-page03-started-poll-${testName}`);
await this.page3.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
await this.page3.waitForSelector(e.smallToastMsg);
const resp = await util.getLastToastValue(this.page3);
await this.page3.screenshot(`${testName}`, `04-page03-poll-toast-${testName}`);
return resp;
@ -201,7 +198,7 @@ class Notifications extends MultiUsers {
await this.page3.screenshot(`${testName}`, `01-page03-initialized-${testName}`);
await this.page3.joinMicrophone();
await this.page3.screenshot(`${testName}`, `02-page03-joined-microphone-${testName}`);
const resp = await util.getLastToastValue(this.page3) === ne.joinAudioToast;
const resp = await util.getLastToastValue(this.page3) === e.joinAudioToast;
await this.page3.screenshot(`${testName}`, `03-page03-audio-toast-${testName}`);
return resp;
} catch (err) {

View File

@ -1,96 +1,80 @@
const ne = require('./elements');
const ule = require('../user/elements');
const ce = require('../chat/elements');
const e = require('../core/elements');
const { ELEMENT_WAIT_TIME } = require('../core/constants');
const { clickElement, getElementText, checkElement, checkElementLengthEqualTo } = require('../core/util');
const { getElementText, checkElement, checkElementLengthEqualTo } = require('../core/util');
async function popupMenu(test) {
await test.page.evaluate(clickElement, e.options);
await test.page.evaluate(clickElement, ne.settings);
await test.waitAndClick(e.options);
await test.waitAndClick(e.settings);
}
async function enableChatPopup(test) {
await test.waitForSelector(ne.notificationsTab, ELEMENT_WAIT_TIME);
await test.page.evaluate(clickElement, ne.notificationsTab);
await test.waitForSelector(ne.chatPushAlerts, ELEMENT_WAIT_TIME);
await test.page.evaluate(clickElement, ne.chatPushAlerts);
await test.waitAndClick(e.notificationsTab);
await test.waitAndClickElement(e.chatPushAlerts);
}
async function enableUserJoinPopup(test) {
await test.waitForSelector(ne.notificationsTab, ELEMENT_WAIT_TIME);
await test.page.evaluate(clickElement, ne.notificationsTab);
await test.waitForSelector(ne.userJoinPushAlerts, ELEMENT_WAIT_TIME);
await test.page.evaluate(clickElement, ne.userJoinPushAlerts);
await test.waitAndClick(e.notificationsTab);
await test.waitAndClickElement(e.userJoinPushAlerts);
}
async function saveSettings(page) {
await page.waitForSelector(ne.saveSettings, ELEMENT_WAIT_TIME);
await page.click(ne.saveSettings, true);
await page.waitAndClick(e.modalConfirmButton);
}
async function waitForToast(test) {
await test.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
const resp = await test.page.evaluate(checkElement, ne.smallToastMsg, 1);
return resp;
await test.waitForSelector(e.smallToastMsg);
return test.page.evaluate(checkElement, e.smallToastMsg, 1);
}
async function getLastToastValue(test) {
await test.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
const toast = test.page.evaluate(getElementText, ne.smallToastMsg);
return toast;
await test.waitForSelector(e.smallToastMsg);
return test.page.evaluate(getElementText, e.smallToastMsg);
}
async function getOtherToastValue(test) {
await test.waitForSelector(ne.smallToastMsg, ELEMENT_WAIT_TIME);
const toast = test.page.evaluate(getElementText, ne.smallToastMsg, 1);
return toast;
await test.waitForSelector(e.smallToastMsg);
return test.page.evaluate(getElementText, e.smallToastMsg, 1);
}
async function publicChatMessageToast(page1, page2) {
// Open private Chat with the other User
await page1.page.evaluate(clickElement, ule.userListItem);
await page1.page.evaluate(clickElement, ce.activeChat);
await page1.waitAndClick(e.userListItem);
await page1.waitAndClick(e.activeChat);
// send a public message
await page2.page.type(ce.publicChat, ce.publicMessage1);
await page2.click(ce.sendButton, true);
return ne.publicChatToast;
await page2.type(e.chatBox, e.publicMessage1);
await page2.waitAndClick(e.sendButton);
return e.publicChatToast;
}
async function privateChatMessageToast(page2) {
// Open private Chat with the other User
await page2.page.evaluate(clickElement, ule.userListItem);
await page2.page.evaluate(clickElement, ce.activeChat);
await page2.waitAndClick(e.userListItem);
await page2.waitAndClick(e.activeChat);
// wait for the private chat to be ready
await page2.page.waitForFunction(
checkElementLengthEqualTo,
{ timeout: ELEMENT_WAIT_TIME },
ce.chatButton, 2
e.chatButton, 2
);
// send a private message
await page2.page.type(ce.privateChat, ce.message1);
await page2.click(ce.sendButton, true);
return ne.privateChatToast;
await page2.type(e.chatBox, e.message1);
await page2.waitAndClick(e.sendButton);
return e.privateChatToast;
}
// File upload notification
async function uploadFileMenu(test) {
await test.click(e.actions);
await test.click(ne.uploadPresentation);
await test.waitAndClick(e.actions);
await test.waitAndClick(e.uploadPresentation);
}
async function startPoll(test) {
await test.click(e.actions);
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(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(clickElement, ne.publishLabel);
await test.waitAndClick(e.actions);
await test.waitAndClick(e.polling);
await test.waitForSelector(e.hidePollDesc);
await test.waitAndClick(e.pollYesNoAbstentionBtn);
await test.waitAndClick(e.startPoll);
await test.waitAndClick(e.publishLabel);
}
exports.privateChatMessageToast = privateChatMessageToast;

View File

@ -1,17 +0,0 @@
exports.pollingContainer = 'div[data-test="pollingContainer"]';
exports.pollQuestionArea = 'textarea[data-test="pollQuestionArea"]';
exports.pollQuestion = 'Are we good ?';
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"]';
exports.uncertain = 'Uncertain';
exports.deletePollOption = 'button[data-test="deletePollOption"]';
exports.pollAnswerOptionBtn = 'button[data-test="pollAnswerOption"]';
exports.pollAnswerOptionInput = 'input[data-test="pollAnswerOption"]';
exports.pollSubmitAnswer = 'button[data-test="submitAnswer"]';
exports.startPoll = 'button[data-test="startPoll"]';
exports.restartPoll = 'button[data-test="restartPoll"]';
exports.receivedAnswer = 'td[data-test="receivedAnswer"]';
exports.publishLabel = 'button[data-test="publishLabel"]';

View File

@ -1,16 +1,16 @@
const Page = require('../core/page');
const e = require('../core/elements');
const utilNotification = require('../notifications/util');
const util = require('../notifications/util');
const { checkElementLengthEqualTo } = require('../core/util');
class Polling extends Page {
constructor() {
super('polling-test');
super();
}
async test(testName) {
try {
await utilNotification.startPoll(this);
await util.startPoll(this);
await this.screenshot(`${testName}`, `01-before-chat-message-send-[${this.meetingId}]`);
const resp = this.page.evaluate(checkElementLengthEqualTo, e.pollMenuButton, 1);

View File

@ -1,11 +0,0 @@
exports.presentationToolbarWrapper = '#presentationToolbarWrapper';
exports.nextSlide = '[data-test="nextSlide"]';
exports.prevSlide = '[data-test="prevSlide"]';
exports.fileUpload = 'input[type="file"]';
exports.upload = 'button[aria-label="Upload"]';
exports.cancel = 'button[aria-label="Cancel]';
exports.uploadPresentation = 'li[data-test="uploadPresentation"]';
exports.removePresentation = 'button[data-test="removePresentation"]';
exports.presentationPlaceholder = 'div[data-test="presentationPlaceholder"]';
exports.presentationPlaceholderLabel = 'Waiting for a presentation to be uploaded';
exports.skipSlide = '[data-test="skipSlide"]';

View File

@ -1,11 +1,8 @@
const Page = require('../core/page');
const e = require('./elements');
const ne = require('../notifications/elements');
const ce = require('../core/elements');
const we = require('../whiteboard/elements');
const e = require('../core/elements');
const params = require('../params');
const util = require('./util');
const { ELEMENT_WAIT_LONGER_TIME, ELEMENT_WAIT_TIME } = require('../core/constants');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { checkElement, checkElementTextIncludes, checkElementText } = require('../core/util');
class Presentation {
@ -36,21 +33,19 @@ class Presentation {
async skipSlide() {
try {
await this.modPage.waitForSelector(we.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.waitForSelector(e.presentationToolbarWrapper, ELEMENT_WAIT_TIME);
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.waitForSelector(e.presentationToolbarWrapper);
const svg0 = await this.modPage.page.evaluate(util.checkSvgIndex, '/svg/1');
await this.modPage.waitForSelector(e.nextSlide, ELEMENT_WAIT_TIME);
await this.modPage.click(e.nextSlide, true);
await this.modPage.waitForSelector(we.whiteboard, ELEMENT_WAIT_TIME);
await this.modPage.waitAndClick(e.nextSlide);
await this.modPage.waitForSelector(e.whiteboard);
await this.modPage.page.waitForTimeout(1000);
const svg1 = await this.modPage.page.evaluate(util.checkSvgIndex, '/svg/2');
await this.modPage.waitForSelector(e.prevSlide, ELEMENT_WAIT_TIME);
await this.modPage.click(e.prevSlide, true);
await this.modPage.waitForSelector(we.whiteboard, ELEMENT_WAIT_TIME);
await this.modPage.waitAndClick(e.prevSlide);
await this.modPage.waitForSelector(e.whiteboard);
await this.modPage.page.waitForTimeout(1000);
const svg2 = await this.modPage.page.evaluate(util.checkSvgIndex, '/svg/1');
@ -64,25 +59,25 @@ class Presentation {
async uploadPresentation(testName) {
try {
await this.modPage.waitForSelector(we.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.waitForSelector(e.skipSlide, ELEMENT_WAIT_TIME);
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.waitForSelector(e.skipSlide);
const slides0 = await this.modPage.page.evaluate(util.getSvgOuterHtml);
await this.modPage.click(ce.actions, true);
await this.modPage.click(e.uploadPresentation, true);
await this.modPage.waitAndClick(e.actions);
await this.modPage.waitAndClick(e.uploadPresentation);
await this.modPage.screenshot(`${testName}`, `01-before-presentation-upload-[${testName}]`);
await this.modPage.waitForSelector(e.fileUpload, ELEMENT_WAIT_TIME);
await this.modPage.waitForSelector(e.fileUpload);
const fileUpload = await this.modPage.page.$(e.fileUpload);
await fileUpload.uploadFile(`${__dirname}/upload-test.png`);
await this.modPage.page.waitForFunction(checkElementTextIncludes, {},
'body', 'To be uploaded ...'
);
await this.modPage.page.waitForSelector(e.upload, ELEMENT_WAIT_TIME);
await this.modPage.page.waitForSelector(e.upload);
await this.modPage.page.click(e.upload, true);
await this.modPage.waitAndClick(e.upload);
await this.modPage.logger('\nWaiting for the new presentation to upload...');
await this.modPage.page.waitForFunction(checkElementTextIncludes, {},
'body', 'Converting file'
@ -110,29 +105,29 @@ class Presentation {
async allowAndDisallowDownload(testName) {
try {
// allow the presentation download
await this.modPage.waitForSelector(we.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.click(ce.actions);
await this.modPage.click(e.uploadPresentation);
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.waitAndClick(e.actions);
await this.modPage.waitAndClick(e.uploadPresentation);
await this.modPage.screenshot(testName, `1-modPage-before-allow-download-[${this.modPage.meetingId}]`);
await this.modPage.click(ce.allowPresentationDownload);
await this.modPage.waitAndClick(e.allowPresentationDownload);
await this.userPage.screenshot(testName, `2-userPage-after-allow-download-without-save-[${this.modPage.meetingId}]`);
await this.userPage.waitForElementHandleToBeRemoved(ne.smallToastMsg);
await this.modPage.click(ce.confirmManagePresentation);
await this.userPage.waitForElementHandleToBeRemoved(e.smallToastMsg);
await this.modPage.waitAndClick(e.confirmManagePresentation);
await this.userPage.screenshot(testName, `3-userPage-after-allow-download-and-save-[${this.modPage.meetingId}]`);
await this.userPage.waitForSelector(ce.toastDownload);
await this.userPage.waitForSelector(e.toastDownload);
// check download button in presentation after ALLOW it - should be true
const hasPresentationDownloadBtnAfterAllow = await this.userPage.page.evaluate(checkElement, ce.presentationDownloadBtn);
const hasPresentationDownloadBtnAfterAllow = await this.userPage.page.evaluate(checkElement, e.presentationDownloadBtn);
// disallow the presentation download
await this.modPage.click(ce.actions);
await this.modPage.click(e.uploadPresentation);
await this.modPage.waitAndClick(e.actions);
await this.modPage.waitAndClick(e.uploadPresentation);
await this.modPage.screenshot(testName, `4-modPage-before-disallow-download-[${this.modPage.meetingId}]`);
await this.modPage.click(ce.disallowPresentationDownload);
await this.modPage.click(ce.confirmManagePresentation);
await this.modPage.waitAndClick(e.disallowPresentationDownload);
await this.modPage.waitAndClick(e.confirmManagePresentation);
await this.modPage.screenshot(testName, `5-userPage-after-disallow-download-[${this.modPage.meetingId}]`);
await this.userPage.waitForElementHandleToBeRemoved(ce.toastDownload);
await this.userPage.waitForElementHandleToBeRemoved(e.toastDownload);
// check download button in presentation after DISALLOW it - should be false
const hasPresentationDownloadBtnAfterDisallow = await this.userPage.page.evaluate(checkElement, ce.presentationDownloadBtn);
const hasPresentationDownloadBtnAfterDisallow = await this.userPage.page.evaluate(checkElement, e.presentationDownloadBtn);
return hasPresentationDownloadBtnAfterAllow && !hasPresentationDownloadBtnAfterDisallow;
} catch (err) {
@ -143,13 +138,13 @@ class Presentation {
async removeAllPresentation(testName) {
try {
await this.modPage.waitForSelector(we.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.click(ce.actions);
await this.modPage.click(e.uploadPresentation);
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.waitAndClick(e.actions);
await this.modPage.waitAndClick(e.uploadPresentation);
await this.modPage.screenshot(testName, `1-modPage-before-remove-download-[${this.modPage.meetingId}]`);
await this.modPage.click(e.removePresentation);
await this.modPage.click(ce.confirmManagePresentation);
await this.modPage.waitForSelector(ce.actions, ELEMENT_WAIT_TIME);
await this.modPage.waitAndClick(e.removePresentation);
await this.modPage.waitAndClick(e.confirmManagePresentation);
await this.modPage.waitForSelector(e.actions);
await this.modPage.screenshot(testName, `2-modPage-after-remove-download-[${this.modPage.meetingId}]`);
await this.userPage.screenshot(testName, `3-userPage-after-remove-download-[${this.modPage.meetingId}]`);
const modPagePlaceholder = await this.modPage.page.evaluate(checkElementText, e.presentationPlaceholder, e.presentationPlaceholderLabel);

View File

@ -1,23 +1,22 @@
const Page = require('../core/page');
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 { VIDEO_LOADING_WAIT_TIME } = require('../core/constants');
const { checkElementLengthEqualTo } = require('../core/util');
class ShareScreen extends Page {
constructor() {
super('share-screen');
super();
}
async test() {
try {
await util.startScreenshare(this);
await this.page.waitForSelector(e.screenshareConnecting, ELEMENT_WAIT_TIME);
await this.page.waitForSelector(e.screenShareVideo, VIDEO_LOADING_WAIT_TIME);
await sleep(5000);
const response = await util.getScreenShareContainer(this);
return response;
await this.waitForSelector(e.screenshareConnecting);
await this.waitForSelector(e.screenShareVideo, VIDEO_LOADING_WAIT_TIME);
const response = await this.hasElement(e.isSharingScreen, true);
return response === true;
} catch (err) {
await this.logger(err);
return false;
@ -29,8 +28,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(checkElementLengthEqualTo, e.screenShare, 1);
return screenshareBtn;
return this.wasRemoved(e.startScreenSharing);
} catch (err) {
await this.logger(err);
return false;

View File

@ -1,29 +1,21 @@
const { ELEMENT_WAIT_TIME, VIDEO_LOADING_WAIT_TIME } = require('../core/constants');
const e = require('../core/elements');
const { VIDEO_LOADING_WAIT_TIME } = require('../core/constants');
const { checkElement } = require('../core/util');
async function startScreenshare(test) {
await test.waitForSelector(e.screenShare, ELEMENT_WAIT_TIME);
await test.click(e.screenShare, true);
await test.waitAndClick(e.startScreenSharing);
}
async function waitForScreenshareContainer(test) {
await test.waitForSelector(e.screenshareConnecting, ELEMENT_WAIT_TIME);
await test.waitForSelector(e.screenshareConnecting);
await test.waitForSelector(e.screenShareVideo, VIDEO_LOADING_WAIT_TIME);
}
async function getScreenShareContainer(test) {
await test.waitForSelector(e.screenShareVideo, VIDEO_LOADING_WAIT_TIME);
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 });
return test.evaluate(checkElement, e.screenShareVideo);
await test.waitForSelector(e.screenshareConnecting, VIDEO_LOADING_WAIT_TIME);
return test.hasElement(e.screenShareVideo, true, VIDEO_LOADING_WAIT_TIME);
}
exports.getScreenShareBreakoutContainer = getScreenShareBreakoutContainer;
exports.getScreenShareContainer = getScreenShareContainer;
exports.startScreenshare = startScreenshare;
exports.waitForScreenshareContainer = waitForScreenshareContainer;

View File

@ -1,3 +1,4 @@
const Page = require('./core/page');
const SharedNotes = require('./notes/sharednotes');
const { toMatchImageSnapshot } = require('jest-image-snapshot');
const { MAX_SHARED_NOTES_TEST_TIMEOUT } = require('./core/constants'); // core constants (Timeouts vars imported)

View File

@ -1,15 +1,13 @@
const Page = require('../core/page');
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 c = require('../core/constants');
const params = require('../params');
const util = require('./util');
const { checkElementLengthEqualTo } = require('../core/util');
class Stress extends Page {
constructor() {
super('stress');
super();
}
async moderatorAsPresenter(testName) {
@ -19,10 +17,10 @@ class Stress extends Page {
for (let i = 1; i <= c.JOIN_AS_MODERATOR_TEST_ROUNDS; i++) {
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(util.checkIncludeClass, ue.statusIcon, e.presenterClassName);
await this.click(e.actions);
const canStartPoll = await this.page.evaluate(checkElementLengthEqualTo, ne.polling, 1);
await this.waitForSelector(e.userAvatar);
const hasPresenterClass = await this.page.evaluate(util.checkIncludeClass, e.userAvatar, e.presenterClassName);
await this.waitAndClick(e.actions);
const canStartPoll = await this.page.evaluate(checkElementLengthEqualTo, e.polling, 1);
if (!hasPresenterClass || !canStartPoll) {
failureCount++;
await this.screenshot(`${testName}`, `loop-${i}-failure-${testName}`);

View File

@ -1,6 +1,6 @@
const Page = require('./page');
const helper = require('./helper');
const e = require('./elements');
const e = require('../core/elements');
class HotkeysMicFirstTestPage extends Page {
constructor() {
@ -24,7 +24,7 @@ class HotkeysMicFirstTestPage extends Page {
await this.page.waitFor(e.leaveAudio);
await this.page.waitFor(e.chatButton);
await this.page.waitFor(e.firstUser);
await this.page.waitFor(e.screenShare);
await this.page.waitFor(e.startScreenSharing);
await this.page.waitFor(e.videoMenu);
await this.page.waitFor(e.actions);
await this.page.waitFor(e.nextSlide);
@ -36,10 +36,10 @@ class HotkeysMicFirstTestPage extends Page {
await this.tab(this.tabCounts.audioMic);
await this.enter();
await this.enter();
await this.page.waitFor(e.listenButton);
await this.page.waitFor(e.listenOnlyButton);
await this.tab(3);
await this.enter();
await this.elementRemoved(e.audioDialog);
await this.elementRemoved(e.audioModal);
await helper.sleep(500);
await this.page.screenshot({ path: 'screenshots/test-hotkeys-mic-first-1.png' });
@ -52,11 +52,11 @@ class HotkeysMicFirstTestPage extends Page {
await this.page.waitFor(e.microphoneButton);
await this.tab(2);
await this.enter();
await this.page.waitFor(e.echoYes);
await this.page.waitFor(e.echoYesButton);
await helper.sleep(500); // Echo test confirmation sometimes fails without this
await this.tab(1);
await this.enter();
await this.elementRemoved(e.audioDialog);
await this.elementRemoved(e.audioModal);
await helper.sleep(500);
await this.page.screenshot({ path: 'screenshots/test-hotkeys-mic-first-2.png' });
}

View File

@ -1,6 +1,6 @@
const Page = require('./page');
const helper = require('./helper');
const e = require('./elements');
const e = require('../core/elements');
class HotkeysTestPage extends Page {
constructor() {
@ -30,7 +30,7 @@ class HotkeysTestPage extends Page {
await this.page.waitFor(e.leaveAudio);
await this.page.waitFor(e.chatButton);
await this.page.waitFor(e.firstUser);
await this.page.waitFor(e.screenShare);
await this.page.waitFor(e.startScreenSharing);
await this.page.waitFor(e.videoMenu);
await this.page.waitFor(e.actions);
await this.page.waitFor(e.nextSlide);
@ -108,11 +108,11 @@ class HotkeysTestPage extends Page {
await this.page.waitFor(e.microphoneButton);
await this.tab(2);
await this.enter();
await this.page.waitFor(e.echoYes);
await this.page.waitFor(e.echoYesButton);
await helper.sleep(500); // Echo test confirmation sometimes fails without this
await this.tab(1);
await this.enter();
await this.elementRemoved(e.audioDialog);
await this.elementRemoved(e.audioModal);
await helper.sleep(500);
await this.page.screenshot({ path: 'screenshots/test-hotkeys-audio-1.png' });

View File

@ -1,7 +1,6 @@
const { toMatchImageSnapshot } = require('jest-image-snapshot');
const Page = require('./core/page');
const Status = require('./user/status');
const Create = require('./breakout/create');
const MultiUsers = require('./user/multiusers');
const { MAX_MULTIUSERS_TEST_TIMEOUT, TEST_DURATION_TIME } = require('./core/constants'); // core constants (Timeouts vars imported)
const { NETWORK_PRESETS } = require('./core/profiles');
@ -243,25 +242,21 @@ const userTest = () => {
// Set Guest policy to ASK_MODERATOR
// and expect user in guest wait list
test('Guest policy: ASK_MODERATOR', async () => {
const test = new Create();
const test = new MultiUsers();
let response;
let screenshot;
try {
const testName = 'askModeratorGuestPolicy';
await test.page1.logger('begin of ', testName);
await test.init(undefined, testName);
await test.page1.startRecording(testName);
await test.page2.startRecording(testName);
response = await test.askModeratorGuestPolicy(testName);
await test.page1.stopRecording();
await test.page2.stopRecording();
screenshot = await test.page1.page.screenshot();
await test.page1.logger('end of ', testName);
} catch (err) {
await test.page1.logger(err);
} finally {
await test.close(test.page1, test.page2);
await test.closePage(test.page3);
await test.close(test.page1, test.userPage);
}
expect(response).toBe(true);
await Page.checkRegression(2.0, screenshot);
@ -270,25 +265,21 @@ const userTest = () => {
// Set Guest policy to ALWAYS_ACCEPT
// and expect user to get accepted automatically
test('Guest policy: ALWAYS_ACCEPT', async () => {
const test = new Create();
const test = new MultiUsers();
let response;
let screenshot;
try {
const testName = 'alwaysAcceptGuestPolicy';
await test.page1.logger('begin of ', testName);
await test.init(undefined, testName);
await test.page1.startRecording(testName);
await test.page2.startRecording(testName);
response = await test.alwaysAcceptGuestPolicy(testName);
await test.page1.stopRecording();
await test.page2.stopRecording();
screenshot = await test.page1.page.screenshot();
await test.page1.logger('end of ', testName);
} catch (err) {
await test.page1.logger(err);
} finally {
await test.close(test.page1, test.page2);
await test.closePage(test.page3);
await test.close(test.page1, test.userPage);
}
expect(response).toBe(true);
await Page.checkRegression(2.0, screenshot);
@ -297,25 +288,21 @@ const userTest = () => {
// Set Guest policy to ALWAYS_DENY
// and expect user to get denied
test('Guest policy: ALWAYS_DENY', async () => {
const test = new Create();
const test = new MultiUsers();
let response;
let screenshot;
try {
const testName = 'alwaysDenyGuestPolicy';
await test.page1.logger('begin of ', testName);
await test.init(undefined, testName);
await test.page1.startRecording(testName);
await test.page2.startRecording(testName);
response = await test.alwaysDenyGuestPolicy(testName);
await test.page1.stopRecording();
await test.page2.stopRecording();
screenshot = await test.page1.page.screenshot();
await test.page1.logger('end of ', testName);
} catch (err) {
await test.page1.logger(err);
} finally {
await test.close(test.page1, test.page2);
await test.closePage(test.page3);
await test.close(test.page1, test.userPage);
}
expect(response).toBe(true);
await Page.checkRegression(2.0, screenshot);

View File

@ -1,36 +0,0 @@
exports.firstUser = '[data-test="userListItemCurrent"]';
exports.userListItem = '[data-test="userListItem"]';
exports.anyUser = '[data-test^="userListItem"]';
exports.setStatus = '[data-test="setstatus"]';
exports.away = '[data-test="away"]';
exports.applaud = '[data-test="applause"]';
exports.applauseIcon = 'div[data-test="userAvatar"] > div > i[class="icon-bbb-applause"]';
exports.awayIcon = 'div[data-test="userAvatar"] > div > i[class="icon-bbb-time"]';
exports.clearStatus = '[data-test="clearStatus"]';
exports.statusIcon = '[data-test="userAvatar"]';
exports.setPresenter = 'li[data-test="setPresenter"]';
exports.connectionStatusModal = 'div[aria-label="Connection status modal"]';
exports.dataSavingWebcams = 'input[data-test="dataSavingWebcams"]';
exports.dataSavingScreenshare = 'input[data-test="dataSavingScreenshare"]';
exports.closeConnectionStatusModal = 'button[aria-label="Close Connection status modal"]';
exports.webcamsIsDisabledInDataSaving = 'button[aria-label="Webcam sharing is disabled in Data Saving"]';
exports.screenshareLocked = 'button[aria-label="Screenshare locked"]';
exports.connectionStatusItemEmpty = 'div[data-test="connectionStatusItemEmpty"]';
exports.connectionStatusItemUser = 'div[data-test="connectionStatusItemUser"]';
exports.connectionStatusOfflineUser = 'div[data-test="offlineUser"]';
exports.mobileUser = 'span[data-test="mobileUser"]';
exports.userList = '[aria-label="Users and messages toggle"]';
exports.manageUsers = 'button[data-test="manageUsers"]';
exports.guestPolicyLabel = 'li[data-test="guestPolicyLabel"]';
exports.guestPolicySettingsModal = 'div[data-test="guestPolicySettingsModal"]';
exports.askModerator = 'button[data-test="askModerator"]';
exports.alwaysAccept = 'button[data-test="alwaysAccept"]';
exports.alwaysDeny = 'button[data-test="alwaysDeny"]';
exports.waitingUsersBtn = 'div[data-test="waitingUsersBtn"]';
exports.joinMeetingDemoPage = 'div[class^="join-meeting"]';
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"]';

View File

@ -2,50 +2,48 @@ const Page = require('../core/page');
const params = require('../params');
const util = require('../chat/util');
const utilUser = require('./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 e = require('../core/elements');
const { ELEMENT_WAIT_TIME } = require('../core/constants');
const { sleep } = require('../core/helper');
const { getElementLength, checkElementLengthEqualTo, checkElementLengthDifferentTo } = require('../core/util');
class MultiUsers {
constructor() {
this.page1 = new Page();
this.page2 = new Page();
this.page3 = new Page();
this.userPage = new Page();
}
// Join BigBlueButton meeting
async init(meetingId, testFolderName) {
await this.page1.init(Page.getArgs(), meetingId, params, undefined, testFolderName);
await this.page2.init(Page.getArgs(), this.page1.meetingId, { ...params, fullName: 'User2' }, undefined, testFolderName);
await this.initMod1(meetingId, testFolderName);
await this.page2.init(Page.getArgs(), this.page1.meetingId, { ...params, fullName: 'Mod2' }, undefined, testFolderName);
}
async initMod1(meetingId, testFolderName) {
await this.page1.init(Page.getArgs(), meetingId, { ...params, fullName: 'Mod1'}, undefined, testFolderName);
}
// Join BigBlueButton meeting
async initUser3(testFolderName) {
await this.page3.init(Page.getArgs(), this.page1.meetingId, { ...params, fullName: 'User3' }, undefined, testFolderName);
async initUserPage(testFolderName) {
await this.userPage.init(Page.getArgs(), this.page1.meetingId, { ...params, fullName: 'Attendee', moderatorPW: '' }, undefined, testFolderName);
}
// Run the test for the page
async checkForOtherUser() {
const firstCheck = await this.page1.page.evaluate(getElementLength, ue.userListItem) > 0;
const secondCheck = await this.page1.page.evaluate(getElementLength, ue.userListItem) > 0;
const firstCheck = await this.page1.page.evaluate(getElementLength, e.userListItem) > 0;
const secondCheck = await this.page1.page.evaluate(getElementLength, e.userListItem) > 0;
return {
firstCheck,
secondCheck,
};
}
async multiUsersPublicChat() {
async multiUsersPublicChat(testName) {
try {
const chat0 = await this.page1.page.evaluate(getElementLength, ce.chatUserMessageText);
await util.sendPublicChatMessage(this.page1, this.page2);
const chat1 = await this.page1.page.evaluate(getElementLength, ce.chatUserMessageText);
const chat0 = await this.page1.page.evaluate(getElementLength, e.chatUserMessageText);
await util.sendPublicChatMessage(this.page1, this.page2, testName);
const chat1 = await this.page1.page.evaluate(getElementLength, e.chatUserMessageText);
return chat0 !== chat1;
} catch (err) {
await this.page1.logger(err);
@ -53,14 +51,15 @@ class MultiUsers {
}
}
async multiUsersPrivateChat() {
async multiUsersPrivateChat(testName) {
try {
await util.openPrivateChatMessage(this.page1, this.page2);
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(getElementLength, ce.chatUserMessageText);
return chat0 !== chat1;
const chat0 = await this.page1.page.evaluate(checkElementLengthEqualTo, e.chatUserMessageText, 0);
await util.sendPrivateChatMessage(this.page1, this.page2, testName);
const receivedMessages = await this.page1.hasElement(e.chatUserMessageText, true) && await this.page2.hasElement(e.chatUserMessageText, true);
return chat0 && receivedMessages;
} catch (err) {
await this.page1.logger(err);
return false;
@ -83,13 +82,11 @@ class MultiUsers {
await this.page1.closeAudioModal();
await this.page2.startRecording(testName);
await this.page2.closeAudioModal();
await this.page1.waitForSelector(pe.actions, ELEMENT_WAIT_TIME);
await this.page1.click(pe.actions, true);
await this.page1.waitForSelector(ne.polling, ELEMENT_WAIT_TIME);
await this.page1.click(ne.polling, true);
await this.page1.waitForSelector(ple.pollQuestionArea, ELEMENT_WAIT_TIME);
await this.page1.page.focus(ple.pollQuestionArea);
await this.page1.page.keyboard.type(ple.pollQuestion);
await this.page1.waitAndClick(e.actions);
await this.page1.waitAndClick(e.polling);
await this.page1.waitForSelector(e.pollQuestionArea);
await this.page1.page.focus(e.pollQuestionArea);
await this.page1.page.keyboard.type(e.pollQuestion);
const chosenRandomNb = await this.page1.page.evaluate((responseTypes) => {
const responseTypesDiv = document.querySelector(responseTypes);
@ -99,10 +96,10 @@ class MultiUsers {
const chosenRandomNb = randomNb - 1;
responseTypesDiv.querySelectorAll('button')[chosenRandomNb].click();
return chosenRandomNb;
}, ple.responseTypes);
}, e.responseTypes);
const customs = {
0: ple.uncertain,
0: e.uncertain,
1: 0,
2: 'ABSTENTION',
3: 'All good!',
@ -110,24 +107,23 @@ class MultiUsers {
switch (chosenRandomNb) {
case 0:
// Adding a poll option
await this.page1.waitForSelector(ple.responseChoices, ELEMENT_WAIT_TIME);
await this.page1.waitForSelector(ple.addItem, ELEMENT_WAIT_TIME);
await this.page1.click(ple.addItem, true);
await this.page1.click(ple.pollOptionItem, true);
await this.page1.waitForSelector(e.responseChoices);
await this.page1.waitAndClick(e.addItem);
await this.page1.waitAndClick(e.pollOptionItem);
await this.page1.tab(2);
await this.page1.page.keyboard.type(customs[0]);
break;
case 1:
// Deleting a poll option
await this.page1.waitForSelector(ple.deletePollOption, ELEMENT_WAIT_TIME);
await this.page1.clickNItem(ple.deletePollOption, true, customs[1]);
await this.page1.waitForSelector(e.deletePollOption);
await this.page1.clickNItem(e.deletePollOption, customs[1]);
break;
case 2:
// Editing a poll option
await this.page1.waitForSelector(ple.responseChoices, ELEMENT_WAIT_TIME);
await this.page1.clickNItem(ple.pollOptionItem, true, 2);
await this.page1.waitForSelector(e.responseChoices);
await this.page1.clickNItem(e.pollOptionItem, 2);
await this.page1.hold('Control');
await this.page1.press('KeyA');
await this.page1.release('Control');
@ -137,30 +133,106 @@ class MultiUsers {
case 3:
// Do nothing to let Users write their single response answer
await this.page1.waitForSelector(ple.responseChoices, ELEMENT_WAIT_TIME);
await sleep(2000);
await this.page1.waitForSelector(e.responseChoices);
break;
}
const condition = chosenRandomNb === 0 || chosenRandomNb === 1 || chosenRandomNb === 2;
await this.page1.waitForSelector(ple.startPoll, ELEMENT_WAIT_TIME);
await this.page1.click(ple.startPoll, true);
await this.page2.waitForSelector(ple.pollingContainer, ELEMENT_WAIT_TIME);
await this.page1.waitAndClick(e.startPoll);
await this.page2.waitForSelector(e.pollingContainer);
switch (condition) {
case true:
await this.page2.clickNItem(ple.pollAnswerOptionBtn, true, 2);
await this.page2.clickNItem(e.pollAnswerOptionBtn, 2);
break;
case false:
await this.page2.page.focus(ple.pollAnswerOptionInput);
await this.page2.page.focus(e.pollAnswerOptionInput);
await this.page2.page.keyboard.type(customs[3]);
await this.page2.waitForSelector(ple.pollSubmitAnswer, ELEMENT_WAIT_TIME);
await this.page2.click(ple.pollSubmitAnswer, true);
await this.page2.waitAndClick(e.pollSubmitAnswer);
break;
}
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(checkElementLengthDifferentTo, ple.receivedAnswer, 0);
return receivedAnswerFound;
const receivedAnswerFound = await this.page1.hasElement(e.receivedAnswer, true);
await this.page1.waitAndClick(e.publishLabel, ELEMENT_WAIT_TIME, true);
await this.page1.waitForSelector(e.restartPoll);
const isPollResultsPublished = await this.page1.hasElement(e.pollResults, true);
return receivedAnswerFound && isPollResultsPublished;
} catch (err) {
await this.page1.logger(err);
return false;
}
}
async askModeratorGuestPolicy(testName) {
try {
await this.initMod1(undefined, testName);
await this.page1.screenshot(`${testName}`, `01-before-closing-audio-modal-[${this.page1.meetingId}]`);
await this.page1.closeAudioModal();
await this.page1.screenshot(`${testName}`, `02-after-closing-audio-modal-[${this.page1.meetingId}]`);
await this.page1.waitAndClick(e.manageUsers);
await this.page1.screenshot(`${testName}`, `03-opened-users-managing-[${this.page1.meetingId}]`);
await this.page1.waitAndClick(e.guestPolicyLabel);
await this.page1.screenshot(`${testName}`, `04-opened-guest-policy-[${this.page1.meetingId}]`);
await this.page1.waitAndClick(e.askModerator);
await this.page1.screenshot(`${testName}`, `05-clicked-askModerator-[${this.page1.meetingId}]`);
await this.initUserPage(testName);
await this.page1.bringToFront();
const responseLoggedIn = await this.page1.hasElement(e.waitingUsersBtn);
await this.page1.screenshot(`${testName}`, `06-after-viewer-acceptance-[${this.page1.meetingId}]`);
return responseLoggedIn;
} catch (err) {
await this.page1.logger(err);
return false;
}
}
async alwaysAcceptGuestPolicy(testName) {
try {
await this.initMod1(undefined, testName);
await this.page1.screenshot(`${testName}`, `01-before-closing-audio-modal-[${this.page1.meetingId}]`);
await this.page1.closeAudioModal();
await this.page1.screenshot(`${testName}`, `02-after-closing-audio-modal-[${this.page1.meetingId}]`);
await this.page1.waitAndClick(e.manageUsers);
await this.page1.screenshot(`${testName}`, `03-opened-users-managing-[${this.page1.meetingId}]`);
await this.page1.waitAndClick(e.guestPolicyLabel);
await this.page1.screenshot(`${testName}`, `04-opened-guest-policy-[${this.page1.meetingId}]`);
await this.page1.waitAndClick(e.alwaysAccept);
await this.page1.screenshot(`${testName}`, `05-clicked-alwaysAccept-[${this.page1.meetingId}]`);
await this.initUserPage(testName);
const responseLoggedIn = await this.userPage.hasElement(e.whiteboard);
await this.userPage.screenshot(`${testName}`, `06-after-viewer-connection-[${this.page1.meetingId}]`);
return responseLoggedIn;
} catch (err) {
await this.page1.logger(err);
return false;
}
}
async alwaysDenyGuestPolicy(testName) {
try {
await this.initMod1(undefined, testName);
await this.page1.screenshot(`${testName}`, `01-before-closing-audio-modal-[${this.page1.meetingId}]`);
await this.page1.closeAudioModal();
await this.page1.screenshot(`${testName}`, `02-after-closing-audio-modal-[${this.page1.meetingId}]`);
await this.page1.waitAndClick(e.manageUsers);
await this.page1.screenshot(`${testName}`, `03-opened-users-managing-[${this.page1.meetingId}]`);
await this.page1.waitAndClick(e.guestPolicyLabel);
await this.page1.screenshot(`${testName}`, `04-opened-guest-policy-[${this.page1.meetingId}]`);
await this.page1.waitAndClick(e.alwaysDeny);
await this.page1.screenshot(`${testName}`, `05-clicked-alwaysAccept-[${this.page1.meetingId}]`);
await this.initUserPage(testName);
const responseLoggedIn = await this.userPage.hasElement(e.joinMeetingDemoPage);
await this.userPage.screenshot(`${testName}`, `06-after-viewer-gets-denied-[${this.page1.meetingId}]`);
return responseLoggedIn;
} catch (err) {
await this.page1.logger(err);
return false;
@ -171,14 +243,13 @@ class MultiUsers {
try {
await this.page1.closeAudioModal();
await this.page2.closeAudioModal();
await this.page3.closeAudioModal();
await this.page1.waitForSelector(we.whiteboard, ELEMENT_WAIT_TIME);
await this.page1.clickNItem(we.userListItem, true, 1);
await this.page1.clickNItem(we.changeWhiteboardAccess, true, 1);
await sleep(2000);
await this.page1.waitForSelector(e.whiteboard);
await this.page1.waitAndClick(e.userListItem);
await this.page1.waitAndClick(e.changeWhiteboardAccess);
await this.page1.waitForSelector(e.multiWhiteboardTool);
const resp = await this.page1.page.evaluate((multiWhiteboardTool) => {
return document.querySelector(multiWhiteboardTool).children[0].innerText === '1';
}, ue.multiWhiteboardTool);
}, e.multiWhiteboardTool);
return resp === true;
} catch (err) {
await this.page1.logger(err);
@ -191,10 +262,9 @@ class MultiUsers {
try {
await this.page1.closeAudioModal();
await this.page2.closeAudioModal();
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(checkElementLengthDifferentTo, we.lowerHandLabel, 0);
await this.page2.waitAndClick(e.raiseHandLabel);
const resp = await this.page2.hasElement(e.lowerHandLabel, true);
return resp === true;
} catch (err) {
await this.page1.logger(err);
@ -205,10 +275,10 @@ class MultiUsers {
// Lower Hand
async lowerHandTest() {
try {
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(checkElementLengthDifferentTo, we.raiseHandLabel, 0);
await this.page2.waitAndClick(e.lowerHandLabel);
await this.page2.waitAndClick(e.lowerHandLabel, ELEMENT_WAIT_TIME, true);
const resp = await this.page2.hasElement(e.raiseHandLabel, true);
return resp === true;
} catch (err) {
await this.page2.logger(err);
@ -219,8 +289,8 @@ class MultiUsers {
// Get Avatars Colors from Userlist and Notification toast
async getAvatarColorAndCompareWithUserListItem() {
try {
const avatarInToastElementColor = await this.page1.page.$eval(we.avatarsWrapperAvatar, (elem) => getComputedStyle(elem).backgroundColor);
const avatarInUserListColor = await this.page1.page.$eval(`${ue.userListItem} > div ${ue.statusIcon}`, (elem) => getComputedStyle(elem).backgroundColor);
const avatarInToastElementColor = await this.page1.page.$eval(e.avatarsWrapperAvatar, (elem) => getComputedStyle(elem).backgroundColor);
const avatarInUserListColor = await this.page1.page.$eval(`${e.userListItem} > div ${e.userAvatar}`, (elem) => getComputedStyle(elem).backgroundColor);
return avatarInToastElementColor === avatarInUserListColor;
} catch (err) {
await this.page1.logger(err);
@ -234,14 +304,12 @@ class MultiUsers {
await this.page2.closeAudioModal();
await this.page2.page.evaluate(() => window.dispatchEvent(new CustomEvent('socketstats', { detail: { rtt: 2000 } })));
await this.page2.page.setOfflineMode(true);
await sleep(3000);
await this.page2.close();
await sleep(5000);
await utilUser.connectionStatus(this.page1);
await sleep(5000);
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;
const connectionStatusItemEmpty = await this.page1.wasRemoved(e.connectionStatusItemEmpty);
const connectionStatusOfflineUser = await this.page1.hasElement(e.connectionStatusOfflineUser, true);
return connectionStatusItemEmpty && connectionStatusOfflineUser;
} catch (err) {
await this.page1.logger(err);
return false;
@ -252,8 +320,8 @@ class MultiUsers {
try {
await this.page1.closeAudioModal();
await this.page2.closeAudioModal();
const userlistPanel = await this.page1.page.evaluate(checkElementLengthEqualTo, ue.chatButton, 0);
const chatPanel = await this.page2.page.evaluate(checkElementLengthEqualTo, ue.chatButton, 0);
const userlistPanel = await this.page1.page.evaluate(checkElementLengthEqualTo, e.chatButtonKey, 0);
const chatPanel = await this.page2.page.evaluate(checkElementLengthEqualTo, e.chatButtonKey, 0);
return userlistPanel && chatPanel;
} catch (err) {
await this.page1.logger(err);
@ -265,12 +333,12 @@ class MultiUsers {
try {
await this.page1.closeAudioModal();
await this.page2.closeAudioModal();
await this.page1.click(ue.userListButton, true);
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(checkElementLengthEqualTo, cu.hidePresentation, 0);
await sleep(2000);
await this.page1.waitAndClick(e.userListButton);
await this.page2.waitAndClick(e.userListButton);
await this.page2.waitAndClick(e.chatButtonKey);
const onUserListPanel = await this.page1.isNotVisible(e.hidePresentation);
const onChatPanel = await this.page2.isNotVisible(e.hidePresentation);
return onUserListPanel && onChatPanel;
} catch (err) {
await this.page1.logger(err);
@ -282,11 +350,11 @@ class MultiUsers {
try {
await this.page1.closeAudioModal();
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(checkElementLengthEqualTo, ue.chatButton, 0);
const onChatPanel = await this.page2.isNotVisible(ue.chatButton, ELEMENT_WAIT_TIME) === true;
await sleep(2000);
await this.page2.waitAndClick(e.userListButton);
await this.page2.waitAndClick(e.chatButtonKey);
const whiteboard = await this.page1.page.evaluate(checkElementLengthEqualTo, e.chatButtonKey, 0);
const onChatPanel = await this.page2.isNotVisible(e.chatButtonKey);
return whiteboard && onChatPanel;
} catch (err) {
await this.page1.logger(err);

View File

@ -1,15 +1,15 @@
const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const Page = require('../core/page');
const e = require('./elements');
const e = require('../core/elements');
const util = require('./util');
const utilWebcam = require('../webcam/util');
const utilScreenshare = require('../screenshare/util');
const { sleep } = require('../core/helper');
const { clickElement, checkElementLengthEqualTo, checkElementLengthDifferentTo } = require('../core/util');
const { checkElementLengthEqualTo, checkElementLengthDifferentTo } = require('../core/util');
class Status extends Page {
constructor() {
super('user-status');
super();
}
async test() {
@ -19,9 +19,8 @@ class Status extends Page {
await util.setStatus(this, e.away);
const resp2 = await this.page.evaluate(checkElementLengthDifferentTo, e.awayIcon, 0);
await this.click(e.firstUser, true);
await this.waitForSelector(e.clearStatus, ELEMENT_WAIT_TIME);
await this.click(e.clearStatus, true);
await this.waitAndClick(e.firstUser);
await this.waitAndClick(e.clearStatus);
return resp1 === resp2;
} catch (err) {
await this.logger(err);
@ -31,9 +30,8 @@ class Status extends Page {
async mobileTagName() {
try {
await this.page.waitForSelector(e.userList, ELEMENT_WAIT_TIME);
await this.page.click(e.userList, true);
await this.page.waitForSelector(e.firstUser, ELEMENT_WAIT_TIME);
await this.waitAndClick(e.userList);
await this.waitForSelector(e.firstUser);
const response = await this.page.evaluate(checkElementLengthDifferentTo, e.mobileUser, 0);
return response === true;
@ -45,7 +43,7 @@ class Status extends Page {
async findConnectionStatusModal() {
try {
await util.connectionStatus(this.page);
await util.connectionStatus(this);
const resp = await this.page.evaluate(checkElementLengthDifferentTo, e.connectionStatusModal, 0);
return resp === true;
} catch (err) {
@ -59,10 +57,8 @@ class Status extends Page {
await this.closeAudioModal();
await utilWebcam.enableWebcam(this, ELEMENT_WAIT_LONGER_TIME);
await util.connectionStatus(this);
await this.waitForSelector(e.dataSavingWebcams, ELEMENT_WAIT_TIME);
await this.page.evaluate(clickElement, e.dataSavingWebcams);
await this.waitForSelector(e.closeConnectionStatusModal, ELEMENT_WAIT_TIME);
await this.page.evaluate(clickElement, e.closeConnectionStatusModal);
await this.waitAndClickElement(e.dataSavingWebcams);
await this.waitAndClickElement(e.closeConnectionStatusModal);
await sleep(2000);
const webcamsIsDisabledInDataSaving = await this.page.evaluate(checkElementLengthDifferentTo, e.webcamsIsDisabledInDataSaving, 0);
return webcamsIsDisabledInDataSaving === true;
@ -78,10 +74,8 @@ class Status extends Page {
await utilScreenshare.startScreenshare(this);
await utilScreenshare.waitForScreenshareContainer(this);
await util.connectionStatus(this);
await this.waitForSelector(e.dataSavingScreenshare, ELEMENT_WAIT_TIME);
await this.page.evaluate(clickElement, e.dataSavingScreenshare);
await this.waitForSelector(e.closeConnectionStatusModal, ELEMENT_WAIT_TIME);
await this.page.evaluate(clickElement, e.closeConnectionStatusModal);
await this.waitAndClickElement(e.dataSavingScreenshare);
await this.waitAndClickElement(e.closeConnectionStatusModal);
await sleep(2000);
const webcamsIsDisabledInDataSaving = await this.page.evaluate(checkElementLengthEqualTo, e.screenshareLocked, 0);
return webcamsIsDisabledInDataSaving === true;

View File

@ -1,18 +1,14 @@
const { ELEMENT_WAIT_TIME } = require('../core/constants');
const e = require('./elements');
const e = require('../core/elements');
async function setStatus(test, status) {
await test.waitForSelector(e.firstUser, ELEMENT_WAIT_TIME);
await test.click(e.firstUser, true);
await test.waitForSelector(e.setStatus, ELEMENT_WAIT_TIME);
await test.click(e.setStatus, true);
await test.waitForSelector(status, ELEMENT_WAIT_TIME);
await test.click(status, true);
await test.waitAndClick(e.firstUser);
await test.waitAndClick(e.setStatus);
await test.waitAndClick(status);
}
async function connectionStatus(test) {
await test.click(e.connectionStatusBtn, true);
await test.waitForSelector(e.connectionStatusModal, ELEMENT_WAIT_TIME);
await test.waitAndClick(e.connectionStatusBtn);
await test.waitForSelector(e.connectionStatusModal);
}
exports.setStatus = setStatus;

View File

@ -1,7 +1,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 { USER_LIST_VLIST_BOTS_LISTENING } = require('../core/constants');
const e = require('../core/elements');
const { getElementLength } = require('../core/util')
class VirtualizeList {
@ -15,7 +15,7 @@ class VirtualizeList {
try {
await this.page1.init(Page.getArgs(), meetingId, { ...params, fullName: 'BroadCaster1' }, undefined, testName);
await this.page1.closeAudioModal();
await this.page1.waitForSelector(ue.anyUser, ELEMENT_WAIT_TIME);
await this.page1.waitForSelector(e.anyUser);
for (let i = 1; i <= parseInt(USER_LIST_VLIST_BOTS_LISTENING); i++) {
const viewerPage = new Page();
await viewerPage.init(Page.getArgs(), this.page1.meetingId, { ...params, fullName: `Viewer${i}`, moderatorPW: '' }, undefined, testName);
@ -32,7 +32,7 @@ class VirtualizeList {
async test() {
try {
const USER_LIST_VLIST_VISIBLE_USERS = await this.page1.page.evaluate(getElementLength, ue.anyUser);
const USER_LIST_VLIST_VISIBLE_USERS = await this.page1.page.evaluate(getElementLength, e.anyUser);
const totalNumberOfUsersMongo = await this.page1.page.evaluate(() => {
const collection = require('/imports/api/users/index.js');
const users = collection.default._collection.find().count();

View File

@ -3,7 +3,7 @@ const util = require('./util');
class Check extends Share {
constructor() {
super('webcam-check-content-test');
super();
}
async compare() {

View File

@ -1,10 +0,0 @@
exports.joinVideo = 'button[data-test="joinVideo"]';
exports.leaveVideo = 'button[data-test="leaveVideo"]';
exports.videoPreview = 'video[data-test="videoPreview"]';
exports.startSharingWebcam = 'button[data-test="startSharingWebcam"]';
exports.stopSharingWebcam = 'button[aria-label="Stop sharing webcam"]';
exports.videoContainer = 'div[class^="videoListItem"]';
exports.webcamConnecting = 'div[data-test="webcamConnecting"]';
exports.presentationFullscreenButton = 'button[data-test="presentationFullscreenButton"]';
exports.webcamItemTalkingUser = 'div[data-test="webcamItemTalkingUser"]';
exports.webcamVideo = 'video[data-test="videoContainer"]';

View File

@ -1,13 +1,12 @@
const Page = require('../core/page');
const util = require('./util');
const wle = require('./elements');
const e = require('../core/elements');
const { checkElementLengthDifferentTo } = require('../core/util');
const { VIDEO_LOADING_WAIT_TIME } = require('../core/constants'); // core constants (Timeouts vars imported)
const e = require('../core/elements');
class Share extends Page {
constructor() {
super('webcam-share-test');
super();
}
async test() {
@ -35,10 +34,10 @@ class Share extends Page {
async webcamLayoutTest(testName) {
try {
await this.waitForSelector(wle.webcamVideo, VIDEO_LOADING_WAIT_TIME);
await this.waitForSelector(wle.stopSharingWebcam, VIDEO_LOADING_WAIT_TIME);
await this.waitForSelector(e.webcamVideo, VIDEO_LOADING_WAIT_TIME);
await this.waitForSelector(e.leaveVideo, VIDEO_LOADING_WAIT_TIME);
await this.waitForSelector(e.isTalking);
const foundTestElement = await this.page.evaluate(checkElementLengthDifferentTo, wle.webcamItemTalkingUser, 0);
const foundTestElement = await this.page.evaluate(checkElementLengthDifferentTo, e.webcamItemTalkingUser, 0);
if (foundTestElement === true) {
await this.screenshot(`${testName}`, `success-${testName}`);
this.logger(testName, ' passed');

View File

@ -1,29 +1,26 @@
const we = require('./elements');
const e = require('../core/elements');
const { sleep } = require('../core/helper');
const { checkElement, clickElement , checkElementLengthDifferentTo } = require('../core/util');
const { checkElement, checkElementLengthDifferentTo } = require('../core/util');
const {
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(clickElement, we.joinVideo);
await test.waitForSelector(we.videoPreview, videoPreviewTimeout);
await test.waitForSelector(we.startSharingWebcam, ELEMENT_WAIT_TIME);
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);
return test.page.evaluate(checkElementLengthDifferentTo, we.webcamVideo, 0);
await test.waitAndClick(e.joinVideo);
await test.waitForSelector(e.videoPreview, videoPreviewTimeout);
await test.waitAndClick(e.startSharingWebcam);
await test.waitForSelector(e.webcamConnecting);
await test.waitForSelector(e.webcamVideo, VIDEO_LOADING_WAIT_TIME);
await test.waitForSelector(e.leaveVideo, VIDEO_LOADING_WAIT_TIME);
return test.page.evaluate(checkElementLengthDifferentTo, e.webcamVideo, 0);
}
async function evaluateCheck(test) {
await test.waitForSelector(we.videoContainer, ELEMENT_WAIT_TIME);
return test.page.evaluate(checkElement, we.presentationFullscreenButton, 1);
await test.waitForSelector(e.videoContainer);
return test.page.evaluate(checkElement, e.presentationFullscreenButton, 1);
}
async function startAndCheckForWebcams(test) {
@ -33,8 +30,8 @@ async function startAndCheckForWebcams(test) {
}
async function webcamContentCheck(test) {
await test.waitForSelector(we.videoContainer, ELEMENT_WAIT_TIME);
await test.waitForElementHandleToBeRemoved(we.webcamConnecting, ELEMENT_WAIT_LONGER_TIME);
await test.waitForSelector(e.videoContainer);
await test.waitForElementHandleToBeRemoved(e.webcamConnecting, ELEMENT_WAIT_LONGER_TIME);
const repeats = 5;
let check;
for (let i = repeats; i >= 1; i--) {

View File

@ -47,7 +47,6 @@ const whiteboardTest = () => {
const testName = 'giveWhiteboardAdditionalAccess';
await test.page1.logger('begin of ', testName);
await test.init(undefined, testName);
await test.initUser3(testName);
await test.page1.startRecording(testName);
await test.page2.startRecording(testName);
await test.page1.logger('Test Name: ', testName);
@ -60,7 +59,6 @@ const whiteboardTest = () => {
await test.page1.logger(err);
} finally {
await test.close(test.page1, test.page2);
await test.closePage(test.page3);
}
expect(response).toBe(true);
await Page.checkRegression(0.9, screenshot);

View File

@ -1,22 +1,19 @@
const { ELEMENT_WAIT_TIME } = require('../core/constants');
const Page = require('../core/page');
const e = require('./elements');
const e = require('../core/elements');
class Draw extends Page {
constructor() {
super('whiteboard-draw');
super();
}
async test() {
try {
await this.waitForSelector(e.tools, ELEMENT_WAIT_TIME);
await this.click(e.tools, true);
await this.waitForSelector(e.rectangle, ELEMENT_WAIT_TIME);
await this.click(e.rectangle, true);
await this.waitForSelector(e.whiteboard, ELEMENT_WAIT_TIME);
await this.waitForSelector(e.whiteboard);
await this.waitAndClick(e.tools);
await this.waitAndClick(e.rectangle);
const shapes0 = await this.getTestElements();
shapes0 === '<g></g>';
const shapes1 = await this.getTestElements();
const test1 = shapes1 === '<g></g>';
const wb = await this.page.$(e.whiteboard);
const wbBox = await wb.boundingBox();
@ -25,11 +22,11 @@ class Draw extends Page {
await this.page.mouse.move(wbBox.x + 0.7 * wbBox.width, wbBox.y + 0.7 * wbBox.height);
await this.page.mouse.up();
await this.waitForSelector(e.drawnRectangle, ELEMENT_WAIT_TIME);
const shapes1 = await this.getTestElements();
shapes1 !== '<g></g>';
await this.waitForSelector(e.drawnRectangle);
const shapes2 = await this.getTestElements();
const test2 = shapes2 !== '<g></g>';
return shapes0 && shapes1;
return test1 && test2;
} catch (err) {
await this.logger(err);
return false;
@ -38,9 +35,8 @@ class Draw extends Page {
async getTestElements() {
try {
await this.waitForSelector('g[clip-path="url(#viewBox)"]', ELEMENT_WAIT_TIME);
const shapes = await this.page.evaluate(() => document.querySelector('svg g[clip-path]').children[1].outerHTML);
return shapes;
await this.waitForSelector(e.whiteboardViewBox);
return this.page.evaluate((selector) => document.querySelector(selector).children[1].outerHTML, e.whiteboardViewBox);
} catch (err) {
await this.logger(err);
}

View File

@ -1,12 +0,0 @@
exports.whiteboard = 'svg[data-test="whiteboard"]';
exports.tools = 'button[aria-label="Tools"]';
exports.pencil = 'button[aria-label="Pencil"]';
exports.rectangle = 'button[aria-label="Rectangle"]';
exports.drawnRectangle = 'rect[data-test="drawnRectangle"]';
exports.userListItem = 'div[data-test="userListItem"]';
exports.changeWhiteboardAccess = 'li[data-test="changeWhiteboardAccess"]';
exports.raiseHandLabel = 'button[data-test="raiseHandLabel"]';
exports.lowerHandLabel = 'button[data-test="lowerHandLabel"]';
exports.avatarsWrapperAvatar = 'div[data-test="avatarsWrapperAvatar"]';
exports.firstUserAvatar = '[data-test="userListItemCurrent"] > div [data-test="userAvatar"]';
exports.secondUserAvatar = '[data-test="userListItem"] > div [data-test="userAvatar"]';