text: /*!
   * Copyright (c) 2015-2019 Cisco Systems, Inc. See LICENSE file.
   */
  
  import {assert} from '@webex/test-helper-chai';
  import sinon from '@webex/test-helper-sinon';
  import Meeting from '@webex/plugin-meetings/src/meeting';
  import Meetings from '@webex/plugin-meetings';
  import Members from '@webex/plugin-meetings/src/members';
  import Roap from '@webex/plugin-meetings/src/roap';
  import StateMachine from 'javascript-state-machine';
  import MeetingRequest from '@webex/plugin-meetings/src/meeting/request';
  import LocusInfo from '@webex/plugin-meetings/src/locus-info';
  import MediaProperties from '@webex/plugin-meetings/src/media/properties';
  import WebRTCStats from '@webex/plugin-meetings/src/stats';
  import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
  import Media from '@webex/plugin-meetings/src/media/index';
  import PeerConnectionManager from '@webex/plugin-meetings/src/peer-connection-manager';
  import ReconnectionManager from '@webex/plugin-meetings/src/reconnection-manager';
  import MediaUtil from '@webex/plugin-meetings/src/media/util';
  import MockSpark from '@webex/test-helper-mock-webex';
  import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
  import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
  import TriggerProxy from '@webex/plugin-meetings/src/common/events/trigger-proxy';
  import uuid from 'uuid';
  
  describe('plugin-meetings', () => {
    const logger = {
      log: () => {},
      error: () => {},
      warn: () => {},
      trace: () => {}
    };
  
    beforeEach(() => {
      LoggerConfig.set({verboseEvents: true, enable: false});
      LoggerProxy.set(logger);
      TriggerProxy.trigger = sinon.stub().returns(true);
      MediaUtil.createPeerConnection = sinon.stub().returns({
      });
    });
    describe('meeting index', () => {
      let meeting;
      let uuid1;
      let uuid2;
      let uuid3;
      let uuid4;
      let url1;
      let url2;
      let test1;
      let test2;
      let test3;
      let test4;
      const spark = new MockSpark({
        children: {
          meetings: Meetings
        }
      });
  
      beforeEach(() => {
        uuid1 = uuid.v4();
        uuid2 = uuid.v4();
        uuid3 = uuid.v4();
        uuid4 = uuid.v4();
        url1 = `https://example.com/${uuid.v4()}`;
        url2 = `https://example2.com/${uuid.v4()}`;
        test1 = `test-${uuid.v4()}`;
        test2 = `test2-${uuid.v4()}`;
        test3 = `test3-${uuid.v4()}`;
        test4 = `test4-${uuid.v4()}`;
        meeting = new Meeting(
          {
            userId: uuid1,
            resource: uuid2,
            deviceUrl: uuid3,
            locus: {url: url1}
          },
          {
            parent: spark
          }
        );
      });
      describe('Public Api Contract', () => {
        describe('#constructor', () => {
          it('should have created a meeting object with public properties', () => {
            assert.exists(meeting);
            assert.exists(meeting.spark);
            assert.exists(meeting.options);
            assert.exists(meeting.attrs);
            assert.exists(meeting.id);
            assert.equal(meeting.userId, uuid1);
            assert.equal(meeting.resource, uuid2);
            assert.equal(meeting.deviceUrl, uuid3);
            assert.equal(meeting.roapSeq, -1);
            assert.deepEqual(meeting.meetingInfo, {});
            assert.instanceOf(meeting.members, Members);
            assert.instanceOf(meeting.roap, Roap);
            assert.instanceOf(meeting.reconnectionManager, ReconnectionManager);
            assert.isNull(meeting.audio);
            assert.isNull(meeting.video);
            assert.instanceOf(meeting.meetingFSM, StateMachine);
            assert.isNull(meeting.stats);
            assert.isNull(meeting.convoId);
            assert.equal(meeting.locusUrl, url1);
            assert.isNull(meeting.sipUri);
            assert.isNull(meeting.partner);
            assert.isNull(meeting.type);
            assert.isNull(meeting.owner);
            assert.isNull(meeting.hostId);
            assert.isNull(meeting.policy);
            assert.instanceOf(meeting.meetingRequest, MeetingRequest);
            assert.instanceOf(meeting.locusInfo, LocusInfo);
            assert.instanceOf(meeting.mediaProperties, MediaProperties);
          });
        });
        describe('#invite', () => {
          it('should have #invite', () => {
            assert.exists(meeting.invite);
          });
          beforeEach(() => {
            meeting.members.addMember = sinon.stub().returns(Promise.resolve(test1));
          });
          it('should proxy members #addMember and return a promise', async () => {
            const invite = meeting.invite(uuid1, false);
  
            assert.exists(invite.then);
            await invite;
            assert.calledOnce(meeting.members.addMember);
            assert.calledWith(meeting.members.addMember, uuid1, false);
          });
        });
        describe('#admit', () => {
          it('should have #admit', () => {
            assert.exists(meeting.admit);
          });
          beforeEach(() => {
            meeting.members.admitMembers = sinon.stub().returns(Promise.resolve(test1));
          });
          it('should proxy members #admitMembers and return a promise', async () => {
            const admit = meeting.members.admitMembers([uuid1]);
  
            assert.exists(admit.then);
            await admit;
            assert.calledOnce(meeting.members.admitMembers);
            assert.calledWith(meeting.members.admitMembers, [uuid1]);
          });
        });
        describe('#getMembers', () => {
          it('should have #getMembers', () => {
            assert.exists(meeting.getMembers);
          });
          it('should get the members object as an instance and return Members', async () => {
            const members = meeting.getMembers();
  
            assert.instanceOf(members, Members);
          });
        });
        describe('#getStats', () => {
          it('should have #getStats', () => {
            assert.exists(meeting.getStats);
          });
          it('should create stats if not exists and return WebRTCStats', () => {
            assert.notOk(meeting.stats);
            meeting.createStats = sinon.stub().returns(new WebRTCStats({}, {parent: spark}));
            const stats = meeting.getStats();
  
            assert.calledOnce(meeting.createStats);
            assert.instanceOf(stats, WebRTCStats);
          });
        });
        describe('#isAudioMuted', () => {
          it('should have #isAudioMuted', () => {
            assert.exists(meeting.invite);
          });
          it('should get the audio muted status and return as a boolean', () => {
            const muted = meeting.isAudioMuted();
  
            assert.isNotOk(muted);
          });
        });
        describe('#isAudioSelf', () => {
          it('should have #isAudioSelf', () => {
            assert.exists(meeting.invite);
          });
          it('should get the audio self status and return as a boolean', () => {
            const self = meeting.isAudioSelf();
  
            assert.isNotOk(self);
          });
        });
        describe('#isVideoMuted', () => {
          it('should have #isVideoMuted', () => {
            assert.exists(meeting.isVideoMuted);
          });
          it('should get the video muted status and return as a boolean', () => {
            const muted = meeting.isVideoMuted();
  
            assert.isNotOk(muted);
          });
        });
        describe('#isVideoSelf', () => {
          it('should have #isVideoSelf', () => {
            assert.exists(meeting.invite);
          });
          it('should get the video self status and return as a boolean', () => {
            const self = meeting.isVideoSelf();
  
            assert.isNotOk(self);
          });
        });
        describe('#muteAudio', () => {
          it('should have #muteAudio', () => {
            assert.exists(meeting.muteAudio);
          });
          describe('before audio is defined', () => {
            it('should reject and return a promise', async () => {
              await meeting.muteAudio().catch((err) => {
                assert.instanceOf(err, Error);
              });
            });
          });
          describe('after audio is defined', () => {
            it('should return a promise resolution', async () => {
              const toggle = sinon.stub().returns(Promise.resolve(true));
  
              meeting.audio = {toggle};
              const audio = meeting.muteAudio();
  
              assert.exists(audio.then);
              await audio;
              assert.calledOnce(toggle);
              assert.calledWith(toggle, {mute: true, self: true});
            });
          });
        });
        describe('#unmuteAudio', () => {
          it('should have #unmuteAudio', () => {
            assert.exists(meeting.unmuteAudio);
          });
          describe('before audio is defined', () => {
            it('should reject and return a promise', async () => {
              await meeting.unmuteAudio().catch((err) => {
                assert.instanceOf(err, Error);
              });
            });
          });
          describe('after audio is defined', () => {
            it('should return a promise resolution', async () => {
              const toggle = sinon.stub().returns(Promise.resolve(true));
  
              meeting.audio = {toggle};
              const audio = meeting.unmuteAudio();
  
              assert.exists(audio.then);
              await audio;
              assert.calledOnce(toggle);
              assert.calledWith(toggle, {mute: false, self: true});
            });
          });
        });
        describe('#muteVideo', () => {
          it('should have #muteVideo', () => {
            assert.exists(meeting.muteVideo);
          });
          describe('before video is defined', () => {
            it('should reject and return a promise', async () => {
              await meeting.muteVideo().catch((err) => {
                assert.instanceOf(err, Error);
              });
            });
          });
          describe('after video is defined', () => {
            it('should return a promise resolution', async () => {
              const toggle = sinon.stub().returns(Promise.resolve(true));
  
              meeting.video = {toggle};
              const video = meeting.muteVideo();
  
              assert.exists(video.then);
              await video;
              assert.calledOnce(toggle);
              assert.calledWith(toggle, {mute: true, self: true});
            });
          });
        });
        describe('#unmuteVideo', () => {
          it('should have #unmuteVideo', () => {
            assert.exists(meeting.unmuteVideo);
          });
          describe('before video is defined', () => {
            it('should reject and return a promise', async () => {
              await meeting.unmuteVideo().catch((err) => {
                assert.instanceOf(err, Error);
              });
            });
          });
          describe('after video is defined', () => {
            it('should return a promise resolution', async () => {
              const toggle = sinon.stub().returns(Promise.resolve(true));
  
              meeting.video = {toggle};
              const video = meeting.unmuteVideo();
  
              assert.exists(video.then);
              await video;
              assert.calledOnce(toggle);
              assert.calledWith(toggle, {mute: false, self: true});
            });
          });
        });
        describe('#joinWithMedia', () => {
          it('should have #joinWithMedia', () => {
            assert.exists(meeting.joinWithMedia);
          });
          describe('resolution', () => {
            it('should success and return a promise', async () => {
              meeting.join = sinon.stub().returns(Promise.resolve(test1));
              meeting.getMediaStreams = sinon.stub().returns(Promise.resolve([test2, test3]));
              meeting.addMedia = sinon.stub().returns(Promise.resolve(test4));
              await meeting.joinWithMedia();
              assert.calledOnce(meeting.join);
              assert.calledOnce(meeting.getMediaStreams);
            });
          });
          describe('rejection', () => {
            it('should error out and return a promise', async () => {
              meeting.join = sinon.stub().returns(Promise.reject());
              meeting.getMediaStreams = sinon.stub().returns(true);
              await meeting.joinWithMedia();
              assert.calledOnce(meeting.join);
              assert.notCalled(meeting.getMediaStreams);
            });
          });
        });
        describe('#getMediaStreams', () => {
          it('should have #getMediaStreams', () => {
            assert.exists(meeting.getMediaStreams);
          });
          it('should proxy Media getUserMedia, and return a promise', async () => {
            Media.getUserMedia = sinon.stub().returns(Promise.resolve(['stream1', 'stream2']));
            await meeting.getMediaStreams();
            assert.calledOnce(Media.getUserMedia);
          });
        });
        describe('#join', () => {
          it('should have #join', () => {
            assert.exists(meeting.join);
          });
          beforeEach(() => {
            meeting.setCorrelationId = sinon.stub().returns(true);
            MeetingUtil.cleanOptions = sinon.stub().returns(true);
            meeting.setLocus = sinon.stub().returns(true);
          });
          describe('successful', () => {
            beforeEach(() => {
              MeetingUtil.joinMeeting = sinon.stub().returns(Promise.resolve());
            });
            it('should join the meeting and return promise', async () => {
              const join = meeting.join();
  
              assert.exists(join.then);
              await join;
              assert.calledOnce(meeting.setCorrelationId);
              assert.calledOnce(MeetingUtil.cleanOptions);
              assert.calledOnce(MeetingUtil.joinMeeting);
              assert.calledOnce(meeting.setLocus);
            });
          });
          describe('failure', () => {
            beforeEach(() => {
              MeetingUtil.joinMeeting = sinon.stub().returns(Promise.reject());
              meeting.logger.log = sinon.stub().returns(true);
            });
            describe('guest join', () => {
              beforeEach(() => {
                MeetingUtil.isPinOrGuest = sinon.stub().returns(true);
                MeetingUtil.hasOwner = sinon.stub().returns(false);
              });
              it('should try to join the meeting and return intent failure promise', async () => {
                await meeting.join().catch(() => {
                  assert.calledOnce(meeting.setCorrelationId);
                  assert.calledOnce(MeetingUtil.cleanOptions);
                  assert.calledOnce(MeetingUtil.joinMeeting);
                });
              });
            });
            describe('total failure', () => {
              beforeEach(() => {
                MeetingUtil.isPinOrGuest = sinon.stub().returns(false);
              });
            });
            it('should try to join the meeting and return promise reject', async () => {
              await meeting.join().catch(() => {
                assert.calledOnce(meeting.setCorrelationId);
                assert.calledOnce(MeetingUtil.cleanOptions);
                assert.calledOnce(MeetingUtil.joinMeeting);
              });
            });
          });
        });
        describe('#addMedia', () => {
          it('should have #addMedia', () => {
            assert.exists(meeting.addMedia);
          });
          beforeEach(() => {
            meeting.mediaProperties.setMediaDirection = sinon.stub().returns(true);
            meeting.audio = true;
            meeting.video = true;
            Media.attachMedia = sinon.stub().returns(Promise.resolve([test1, test2]));
            meeting.setPeerConnections = sinon.stub().returns(true);
            meeting.setRemoteStream = sinon.stub().returns(true);
            meeting.roap.sendRoapMediaRequest = sinon.stub().returns(Promise.resolve());
            PeerConnectionManager.setContentSlides = sinon.stub().returns(true);
          });
          it('should attach the media and return promise', async () => {
            const media = meeting.addMedia();
  
            assert.exists(media);
            await media;
            assert.calledOnce(meeting.mediaProperties.setMediaDirection);
            assert.calledOnce(Media.attachMedia);
            assert.calledOnce(meeting.setRemoteStream);
            assert.calledOnce(meeting.roap.sendRoapMediaRequest);
          });
        });
        describe('#acknowledge', () => {
          it('should have #acknowledge', () => {
            assert.exists(meeting.acknowledge);
          });
          beforeEach(() => {
            meeting.meetingRequest.acknowledgeMeeting = sinon.stub().returns(Promise.resolve());
          });
          it('should acknowledge incoming and return a promise', async () => {
            const ack = meeting.acknowledge('INCOMING', false);
  
            assert.exists(ack.then);
            await ack;
            assert.calledOnce(meeting.meetingRequest.acknowledgeMeeting);
          });
          it('should acknowledge a non incoming and return a promise', async () => {
            const ack = meeting.acknowledge(test1, false);
  
            assert.exists(ack.then);
            await ack;
            assert.notCalled(meeting.meetingRequest.acknowledgeMeeting);
          });
        });
        describe('#decline', () => {
          it('should have #decline', () => {
            assert.exists(meeting.decline);
          });
          beforeEach(() => {
            meeting.meetingRequest.declineMeeting = sinon.stub().returns(Promise.resolve());
            meeting.meetingFSM.ring();
          });
          it('should decline the meeting and trigger meeting destroy for 1:1', async () => {
            await meeting.decline();
            assert.calledOnce(meeting.meetingRequest.declineMeeting);
          });
        });
        describe('#leave', () => {
          it('should have #leave', () => {
            assert.exists(meeting.leave);
          });
          beforeEach(() => {
            meeting.meetingFSM.ring();
            meeting.meetingFSM.join();
            meeting.meetingRequest.leaveMeeting = sinon.stub().returns(Promise.resolve({body: 'test'}));
            meeting.locusInfo.onFullLocus = sinon.stub().returns(true);
            meeting.closeLocalStream = sinon.stub().returns(true);
            meeting.closeLocalShare = sinon.stub().returns(true);
            meeting.closePeerConnections = sinon.stub().returns(true);
            meeting.unsetLocalVideoTrack = sinon.stub().returns(true);
            meeting.unsetLocalShareTrack = sinon.stub().returns(true);
            meeting.unsetRemoteStream = sinon.stub().returns(true);
            meeting.unsetPeerConnections = sinon.stub().returns(true);
            meeting.roap.stop = sinon.stub().returns(Promise.resolve());
            meeting.logger.error = sinon.stub().returns(true);
          });
          it('should leave the meeting and return promise', async () => {
            const leave = meeting.leave();
  
            assert.exists(leave.then);
            await leave;
            assert.calledOnce(meeting.meetingRequest.leaveMeeting);
            assert.calledOnce(meeting.closeLocalStream);
            assert.calledOnce(meeting.closeLocalShare);
            assert.calledOnce(meeting.closePeerConnections);
            assert.calledOnce(meeting.unsetLocalVideoTrack);
            assert.calledOnce(meeting.unsetLocalShareTrack);
            assert.calledOnce(meeting.unsetRemoteStream);
            assert.calledOnce(meeting.unsetPeerConnections);
            assert.calledOnce(meeting.roap.stop);
          });
        });
        describe('#share', () => {
          it('should have #share', () => {
            assert.exists(meeting.invite);
          });
          beforeEach(() => {
            meeting.locusInfo.mediaShares = [{name: 'content', url: url1}];
            meeting.locusInfo.self = {url: url1};
            meeting.meetingRequest.changeMeetingFloor = sinon.stub().returns(Promise.resolve());
          });
          it('should send the share', async () => {
            const share = meeting.share();
  
            assert.exists(share.then);
            await share;
            assert.calledOnce(meeting.meetingRequest.changeMeetingFloor);
          });
        });
        describe('#stopShare', () => {
          it('should have #stopShare', () => {
            assert.exists(meeting.stopShare);
          });
          beforeEach(() => {
            meeting.locusInfo.mediaShares = [{name: 'content', url: url1}];
            meeting.locusInfo.self = {url: url2};
            meeting.meetingRequest.changeMeetingFloor = sinon.stub().returns(Promise.resolve());
          });
          it('should send the share', async () => {
            const share = meeting.share();
  
            assert.exists(share.then);
            await share;
            assert.calledOnce(meeting.meetingRequest.changeMeetingFloor);
          });
        });
      });
      describe('Public Event Triggers', () => {
        describe('#reconnect', () => {
          it('should have #reconnect', () => {
            assert.exists(meeting.reconnect);
          });
          describe('successful reconnect', () => {
            it('should reconnect and trigger reconnection and return a promise', async () => {
              meeting.reconnectionManager = new ReconnectionManager({config: {reconnection: {retry: {backOff: 1}}}});
              meeting.reconnectionManager.reconnect = sinon.stub().returns(Promise.resolve(test1));
              meeting.reconnectionManager.reset = sinon.stub().returns(true);
              const reconnect = meeting.reconnect();
  
              assert.exists(reconnect.then);
              await reconnect;
              assert.calledOnce(TriggerProxy.trigger);
              assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meeting), {file: 'meeting/index', function: 'reconnect'}, 'meeting:reconnectionSuccess', {reconnect: test1});
              assert.calledOnce(meeting.reconnectionManager.reset);
            });
          });
          describe('unsuccessful reconnect', () => {
            it('should trigger an unsuccessful reconnection and return a promise', async () => {
              meeting.reconnectionManager = new ReconnectionManager({config: {reconnection: {retry: {backOff: 1}}}});
              meeting.reconnectionManager.reconnect = sinon.stub().returns(Promise.reject());
              meeting.reconnectionManager.reset = sinon.stub().returns(true);
              await meeting.reconnect().catch(() => {
                assert.calledOnce(TriggerProxy.trigger);
                assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meeting), {file: 'meeting/index', function: 'reconnect'}, 'meeting:reconnectionFailure', {error: sinon.match.any});
                assert.calledOnce(meeting.reconnectionManager.reset);
              });
            });
          });
        });
        describe('#closeRemoteStream', () => {
          it('should stop the stream, and trigger a media:stopped event when the remote stream stops', async () => {
            Media.stopStream = sinon.stub().returns(Promise.resolve());
            await meeting.closeRemoteStream();
            assert.calledOnce(TriggerProxy.trigger);
            assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meeting), {file: 'meeting/index', function: 'closeRemoteStream'}, 'media:stopped');
            assert.notOk(meeting.mediaProperties.shareStream);
          });
        });
        describe('#closeLocalShare', () => {
          it('should stop the stream, and trigger a media:stopped event when the local share stream stops', async () => {
            Media.stopStream = sinon.stub().returns(Promise.resolve());
            await meeting.closeLocalShare();
            assert.calledOnce(TriggerProxy.trigger);
            assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meeting), {file: 'meeting/index', function: 'closeLocalShare'}, 'media:stopped', {type: 'localShare'});
          });
        });
        describe('#closeLocalStream', () => {
          it('should stop the stream, and trigger a media:stopped event when the local stream stops', async () => {
            Media.stopStream = sinon.stub().returns(Promise.resolve());
            await meeting.closeLocalStream();
            assert.calledOnce(TriggerProxy.trigger);
            assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meeting), {file: 'meeting/index', function: 'closeLocalStream'}, 'media:stopped', {type: 'local'});
          });
        });
        describe('#setLocalShareTrack', () => {
          it('should trigger a media:ready event with local share stream', () => {
            const track = {};
            const getVideoTracks = sinon.stub().returns([track]);
  
            meeting.stopShare = sinon.stub().returns(Promise.resolve());
            meeting.mediaProperties.setLocalShareTrack = sinon.stub().returns(true);
            meeting.mediaProperties.shareTrack = {getVideoTracks};
            meeting.stopShare = sinon.stub().returns(true);
            meeting.setLocalShareTrack(test1);
            assert.calledOnce(TriggerProxy.trigger);
            assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meeting), {file: 'meeting/index', function: 'setLocalShareTrack'}, 'media:ready');
            assert.calledOnce(meeting.mediaProperties.setLocalShareTrack);
            assert.equal(meeting.mediaProperties.localStream, undefined);
            meeting.mediaProperties.shareTrack.onended();
            assert.calledOnce(meeting.stopShare);
          });
        });
        describe('#setShareStream', () => {
          it('should trigger a media:ready event when share stream track ontrack is fired', () => {
            const pc = {};
  
            meeting.setShareStream(pc);
            pc.ontrack({streams: [test1]});
            assert.calledOnce(TriggerProxy.trigger);
            assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meeting), {file: 'meeting/index', function: 'setShareStream:pc.ontrack'}, 'media:ready', {type: 'remoteShare', stream: test1});
            assert.equal(meeting.mediaProperties.remoteShare, test1);
          });
        });
        describe('#setRemoteStream', () => {
          beforeEach(() => {
            MediaUtil.createMediaStream = sinon.stub().returns(true);
          });
          it('should trigger a media:ready event when remote stream track ontrack is fired', () => {
            const getAudioTracks = sinon.stub().returns(['audio']);
            const getVideoTracks = sinon.stub().returns(['media', 'share']);
            const streams = {
              getAudioTracks,
              getVideoTracks
            };
  
            const pc = {};
  
            meeting.setRemoteStream(pc);
            pc.ontrack({streams: [streams]});
            assert.calledThrice(TriggerProxy.trigger);
          });
        });
        describe('#setUpLocusInfoSelfListener', () => {
          it('listens to the self unadmitted guest event', (done) => {
            meeting.locusInfo.emit({function: 'test', file: 'test'}, 'SELF_UNADMITTED_GUEST', test1);
            assert.calledOnce(TriggerProxy.trigger);
            assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meeting), {file: 'meeting/index', function: 'setUpLocusInfoSelfListener'}, 'meeting:self:lobbyWaiting', {payload: test1});
            done();
          });
          it('listens to the self admitted guest event', (done) => {
            meeting.locusInfo.emit({function: 'test', file: 'test'}, 'SELF_ADMITTED_GUEST', test1);
            assert.calledOnce(TriggerProxy.trigger);
            assert.calledWith(TriggerProxy.trigger, sinon.match.instanceOf(Meeting), {file: 'meeting/index', function: 'setUpLocusInfoSelfListener'}, 'meeting:self:guestAdmitted', {payload: test1});
            done();
          });
        });
      });
      describe('Private Detailed API and Helpers', () => {
        describe('#setSipUri', () => {
          it('should set the sip Uri and return null', () => {
            assert.notOk(meeting.sipUri);
            meeting.setSipUri(test1);
            assert.equal(meeting.sipUri, test1);
          });
        });
        describe('#unsetRemoteStream', () => {
          it('should unset the remote stream and return null', () => {
            meeting.mediaProperties.unsetRemoteStream = sinon.stub().returns(true);
            meeting.unsetRemoteStream();
            assert.calledOnce(meeting.mediaProperties.unsetRemoteStream);
          });
        });
        describe('#unsetLocalVideoTrack', () => {
          it('should unset the local stream and return null', () => {
            meeting.mediaProperties.unsetLocalVideoTrack = sinon.stub().returns(true);
            meeting.unsetLocalVideoTrack();
            assert.calledOnce(meeting.mediaProperties.unsetLocalVideoTrack);
          });
        });
        describe('#unsetLocalShareTrack', () => {
          it('should unset the local share stream and return null', () => {
            meeting.mediaProperties.unsetLocalShareTrack = sinon.stub().returns(true);
            meeting.unsetLocalShareTrack();
            assert.calledOnce(meeting.mediaProperties.unsetLocalShareTrack);
          });
        });
        // TODO: remove
        describe('#setPeerConnections', () => {
          it('should set the peer connections', () => {
            PeerConnectionManager.detectFailures = sinon.stub().returns(true);
            meeting.reconnect = sinon.stub().returns(true);
            meeting.spark.internal.mercury.on = sinon.stub().returns(true);
            meeting.setPeerConnections(test1, test2);
            assert.instanceOf(meeting.reconnectionManager, ReconnectionManager);
          });
        });
        describe('#closePeerConnections', () => {
          it('should close the peer connections, and return a promise', async () => {
            PeerConnectionManager.close = sinon.stub().returns(Promise.resolve());
            const pcs = meeting.closePeerConnections();
  
            assert.exists(pcs.then);
            await pcs;
            assert.calledOnce(PeerConnectionManager.close);
          });
        });
        describe('#unsetPeerConnections', () => {
          it('should unset the peer connections', () => {
            meeting.mediaProperties.unsetPeerConnection = sinon.stub().returns(true);
            meeting.spark.internal.mercury.off = sinon.stub().returns(true);
            meeting.unsetPeerConnections();
            assert.calledOnce(meeting.mediaProperties.unsetPeerConnection);
          });
        });
        describe('#createStats', () => {
          it('should create stats for the meeting object', () => {
            const stats = meeting.createStats();
  
            assert.instanceOf(stats, WebRTCStats);
            assert.instanceOf(meeting.getStats(), WebRTCStats);
          });
        });
        describe('#parseMeetingInfo', () => {
          it('should parse meeting info, set values, and return null', () => {
            meeting.parseMeetingInfo({
              body: {
                convoId: uuid1,
                locusUrl: url1,
                sipMeetingUri: test1,
                owner: test2
              }
            });
            assert.equal(meeting.convoId, uuid1);
            assert.equal(meeting.locusUrl, url1);
            assert.equal(meeting.sipUri, test1);
            assert.equal(meeting.owner, test2);
          });
        });
        describe('#parseLocus', () => {
          describe('when CALL and participants', () => {
            beforeEach(() => {
              meeting.setLocus = sinon.stub().returns(true);
              MeetingUtil.getLocusPartner = sinon.stub().returns({person: {sipUrl: uuid3}});
            });
            it('should parse the locus object and set meeting properties and return null', () => {
              meeting.type = 'CALL';
              meeting.parseLocus({url: url1, participants: [{id: uuid1}], self: {id: uuid2}});
              assert.calledOnce(meeting.setLocus);
              assert.calledWith(meeting.setLocus, {url: url1, participants: [{id: uuid1}], self: {id: uuid2}});
              assert.calledOnce(MeetingUtil.getLocusPartner);
              assert.calledWith(MeetingUtil.getLocusPartner, [{id: uuid1}], {id: uuid2});
              assert.deepEqual(meeting.partner, {person: {sipUrl: uuid3}});
              assert.equal(meeting.sipUri, uuid3);
            });
          });
        });
        describe('#setRoapSeq', () => {
          it('should set the roap seq and return null', () => {
            assert.equal(-1, meeting.roapSeq);
            meeting.setRoapSeq(1);
            assert.equal(meeting.roapSeq, 1);
          });
        });
        describe('#setCorrelationId', () => {
          it('should set the correlationId and return undefined', () => {
            assert.ok(meeting.correlationId);
            meeting.setCorrelationId(uuid1);
            assert.equal(meeting.correlationId, uuid1);
          });
        });
        describe('#setLocus', () => {
          beforeEach(() => {
            meeting.locusInfo.initialSetup = sinon.stub().returns(true);
          });
          it('should read the locus object, set on the meeting and return null', () => {
            meeting.parseLocus({
              mediaConnections: [test1],
              locusUrl: url1,
              locusId: uuid1,
              selfId: uuid2,
              mediaId: uuid3,
              host: {id: uuid4}
            });
            assert.calledOnce(meeting.locusInfo.initialSetup);
            assert.calledWith(meeting.locusInfo.initialSetup, {
              mediaConnections: [test1],
              locusUrl: url1,
              locusId: uuid1,
              selfId: uuid2,
              mediaId: uuid3,
              host: {id: uuid4}
            });
            assert.equal(meeting.mediaConnections, test1);
            assert.equal(meeting.locusUrl, url1);
            assert.equal(meeting.locusId, uuid1);
            assert.equal(meeting.selfId, uuid2);
            assert.equal(meeting.mediaId, uuid3);
            assert.equal(meeting.hostId, uuid4);
          });
        });
      });
    });
  });
  