@webex/plugin-meetings 2.14.2 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/common/errors/parameter.js +1 -1
- package/dist/common/errors/parameter.js.map +1 -1
- package/dist/constants.js +8 -4
- package/dist/constants.js.map +1 -1
- package/dist/locus-info/index.js +7 -0
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js +4 -2
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/selfUtils.js +14 -0
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +3 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +164 -118
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +4 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/metrics/constants.js +5 -1
- package/dist/metrics/constants.js.map +1 -1
- package/package.json +6 -6
- package/src/common/errors/parameter.js +1 -1
- package/src/constants.js +3 -0
- package/src/locus-info/index.js +10 -0
- package/src/locus-info/infoUtils.js +11 -3
- package/src/locus-info/selfUtils.js +12 -0
- package/src/meeting/in-meeting-actions.js +2 -0
- package/src/meeting/index.js +106 -52
- package/src/meeting/util.js +2 -0
- package/src/metrics/constants.js +5 -1
- package/test/unit/spec/fixture/locus.js +404 -0
- package/test/unit/spec/locus-info/index.js +27 -0
- package/test/unit/spec/locus-info/infoUtils.js +17 -10
- package/test/unit/spec/locus-info/selfConstant.js +1 -0
- package/test/unit/spec/meeting/in-meeting-actions.js +2 -0
- package/test/unit/spec/meeting/index.js +230 -0
- package/test/unit/spec/meeting/utils.js +7 -0
|
@@ -33,22 +33,29 @@ describe('plugin-meetings', () => {
|
|
|
33
33
|
it('only gives includes display hints when user has the correct role', () => {
|
|
34
34
|
assert.deepEqual(InfoUtils.parse(info, ['MODERATOR']), {
|
|
35
35
|
policy: {HINT_3: true},
|
|
36
|
-
moderator: {HINT_1: true, HINT_2: true},
|
|
37
|
-
coHost: {HINT_4: true},
|
|
38
|
-
userDisplayHints: ['HINT_3', 'HINT_1', 'HINT_2']
|
|
36
|
+
moderator: {HINT_1: true, HINT_2: true, LOWER_SOMEONE_ELSES_HAND: true},
|
|
37
|
+
coHost: {HINT_4: true, LOWER_SOMEONE_ELSES_HAND: true},
|
|
38
|
+
userDisplayHints: ['HINT_3', 'HINT_1', 'HINT_2', 'LOWER_SOMEONE_ELSES_HAND']
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
assert.deepEqual(InfoUtils.parse(info, ['MODERATOR', 'COHOST']), {
|
|
42
|
+
policy: {HINT_3: true},
|
|
43
|
+
moderator: {HINT_1: true, HINT_2: true, LOWER_SOMEONE_ELSES_HAND: true},
|
|
44
|
+
coHost: {HINT_4: true, LOWER_SOMEONE_ELSES_HAND: true},
|
|
45
|
+
userDisplayHints: ['HINT_3', 'HINT_4', 'LOWER_SOMEONE_ELSES_HAND', 'HINT_1', 'HINT_2']
|
|
39
46
|
});
|
|
40
47
|
|
|
41
48
|
assert.deepEqual(InfoUtils.parse(info, ['COHOST']), {
|
|
42
49
|
policy: {HINT_3: true},
|
|
43
|
-
moderator: {HINT_1: true, HINT_2: true},
|
|
44
|
-
coHost: {HINT_4: true},
|
|
45
|
-
userDisplayHints: ['HINT_3', 'HINT_4']
|
|
50
|
+
moderator: {HINT_1: true, HINT_2: true, LOWER_SOMEONE_ELSES_HAND: true},
|
|
51
|
+
coHost: {HINT_4: true, LOWER_SOMEONE_ELSES_HAND: true},
|
|
52
|
+
userDisplayHints: ['HINT_3', 'HINT_4', 'LOWER_SOMEONE_ELSES_HAND']
|
|
46
53
|
});
|
|
47
54
|
|
|
48
55
|
assert.deepEqual(InfoUtils.parse(info, []), {
|
|
49
56
|
policy: {HINT_3: true},
|
|
50
|
-
moderator: {HINT_1: true, HINT_2: true},
|
|
51
|
-
coHost: {HINT_4: true},
|
|
57
|
+
moderator: {HINT_1: true, HINT_2: true, LOWER_SOMEONE_ELSES_HAND: true},
|
|
58
|
+
coHost: {HINT_4: true, LOWER_SOMEONE_ELSES_HAND: true},
|
|
52
59
|
userDisplayHints: ['HINT_3']
|
|
53
60
|
});
|
|
54
61
|
});
|
|
@@ -99,7 +106,7 @@ describe('plugin-meetings', () => {
|
|
|
99
106
|
|
|
100
107
|
assert.calledWith(parseDisplayHintSectionSpy, info, 'moderator');
|
|
101
108
|
|
|
102
|
-
assert.deepEqual(result, parseDisplayHintSectionSpy.firstCall.returnValue);
|
|
109
|
+
assert.deepEqual(result, {...parseDisplayHintSectionSpy.firstCall.returnValue, LOWER_SOMEONE_ELSES_HAND: true});
|
|
103
110
|
});
|
|
104
111
|
|
|
105
112
|
it('parsePolicy calls parseDisplayHintSection correctly and returns the result', () => {
|
|
@@ -115,7 +122,7 @@ describe('plugin-meetings', () => {
|
|
|
115
122
|
|
|
116
123
|
assert.calledWith(parseDisplayHintSectionSpy, info, 'coHost');
|
|
117
124
|
|
|
118
|
-
assert.deepEqual(result, parseDisplayHintSectionSpy.firstCall.returnValue);
|
|
125
|
+
assert.deepEqual(result, {...parseDisplayHintSectionSpy.firstCall.returnValue, LOWER_SOMEONE_ELSES_HAND: true});
|
|
119
126
|
});
|
|
120
127
|
});
|
|
121
128
|
});
|
|
@@ -16,6 +16,7 @@ describe('plugin-meetings', () => {
|
|
|
16
16
|
canStopRecording: null,
|
|
17
17
|
canRaiseHand: null,
|
|
18
18
|
canLowerAllHands: null,
|
|
19
|
+
canLowerSomeoneElsesHand: null,
|
|
19
20
|
...expected
|
|
20
21
|
};
|
|
21
22
|
|
|
@@ -38,6 +39,7 @@ describe('plugin-meetings', () => {
|
|
|
38
39
|
'canStopRecording',
|
|
39
40
|
'canRaiseHand',
|
|
40
41
|
'canLowerAllHands',
|
|
42
|
+
'canLowerSomeoneElsesHand',
|
|
41
43
|
].forEach((key) => {
|
|
42
44
|
it(`get and set for ${key} work as expected`, () => {
|
|
43
45
|
const inMeetingActions = new InMeetingActions();
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
} from '@webex/plugin-meetings/src/constants';
|
|
43
43
|
import BEHAVIORAL_METRICS from '@webex/plugin-meetings/src/metrics/constants';
|
|
44
44
|
|
|
45
|
+
import locus from '../fixture/locus';
|
|
45
46
|
import {
|
|
46
47
|
UserNotJoinedError,
|
|
47
48
|
MeetingNotActiveError,
|
|
@@ -785,6 +786,7 @@ describe('plugin-meetings', () => {
|
|
|
785
786
|
beforeEach(() => {
|
|
786
787
|
meeting.setCorrelationId = sinon.stub().returns(true);
|
|
787
788
|
meeting.setLocus = sinon.stub().returns(true);
|
|
789
|
+
webex.meetings.registered = true;
|
|
788
790
|
});
|
|
789
791
|
describe('successful', () => {
|
|
790
792
|
beforeEach(() => {
|
|
@@ -853,6 +855,14 @@ describe('plugin-meetings', () => {
|
|
|
853
855
|
assert.calledWith(MeetingUtil.joinMeeting, meeting, {moderator: false, pin: '1234'});
|
|
854
856
|
});
|
|
855
857
|
});
|
|
858
|
+
|
|
859
|
+
it('should throw error if device is not registered', async () => {
|
|
860
|
+
webex.meetings.registered = false;
|
|
861
|
+
await meeting.join().catch((error) => {
|
|
862
|
+
assert.equal(error.message, 'Meeting:index#join --> Device not registered');
|
|
863
|
+
});
|
|
864
|
+
});
|
|
865
|
+
|
|
856
866
|
it('should post error event if failed', async () => {
|
|
857
867
|
await meeting.join().catch(() => {
|
|
858
868
|
assert.calledWithMatch(Metrics.postEvent, {event: eventType.LOCUS_JOIN_RESPONSE});
|
|
@@ -2561,6 +2571,7 @@ describe('plugin-meetings', () => {
|
|
|
2561
2571
|
assert.equal(result.failureReason, MEETING_INFO_FAILURE_REASON.WRONG_CAPTCHA);
|
|
2562
2572
|
});
|
|
2563
2573
|
});
|
|
2574
|
+
|
|
2564
2575
|
describe('#mediaNegotiatedEvent', () => {
|
|
2565
2576
|
it('should have #mediaNegotiatedEvent', () => {
|
|
2566
2577
|
assert.exists(meeting.mediaNegotiatedEvent);
|
|
@@ -2638,6 +2649,222 @@ describe('plugin-meetings', () => {
|
|
|
2638
2649
|
assert.calledOnce(meeting?.roap?.stop);
|
|
2639
2650
|
});
|
|
2640
2651
|
});
|
|
2652
|
+
|
|
2653
|
+
describe('#moveTo', () => {
|
|
2654
|
+
let sandbox;
|
|
2655
|
+
|
|
2656
|
+
beforeEach(() => {
|
|
2657
|
+
sandbox = sinon.createSandbox();
|
|
2658
|
+
sandbox.stub(meeting, 'closeLocalStream');
|
|
2659
|
+
sandbox.stub(meeting, 'closeLocalShare');
|
|
2660
|
+
|
|
2661
|
+
sandbox.stub(meeting.mediaProperties, 'setMediaDirection');
|
|
2662
|
+
sandbox.stub(meeting.mediaProperties, 'unsetMediaTracks');
|
|
2663
|
+
|
|
2664
|
+
sandbox.stub(meeting.reconnectionManager, 'reconnectMedia').returns(Promise.resolve());
|
|
2665
|
+
sandbox.stub(MeetingUtil, 'joinMeeting').returns(Promise.resolve(MeetingUtil.parseLocusJoin({body: {locus, mediaConnections: []}})));
|
|
2666
|
+
});
|
|
2667
|
+
|
|
2668
|
+
afterEach(() => {
|
|
2669
|
+
sandbox.restore();
|
|
2670
|
+
sandbox = null;
|
|
2671
|
+
});
|
|
2672
|
+
|
|
2673
|
+
it('should throw an error if resourceId not passed', async () => {
|
|
2674
|
+
try {
|
|
2675
|
+
await meeting.moveTo();
|
|
2676
|
+
}
|
|
2677
|
+
catch (err) {
|
|
2678
|
+
assert.instanceOf(err, ParameterError);
|
|
2679
|
+
assert.equal(err.sdkMessage, 'Cannot move call without a resourceId.');
|
|
2680
|
+
}
|
|
2681
|
+
});
|
|
2682
|
+
|
|
2683
|
+
it('should postEvent on moveTo ', async () => {
|
|
2684
|
+
await meeting.moveTo('resourceId');
|
|
2685
|
+
assert.calledWithMatch(Metrics.postEvent, {
|
|
2686
|
+
event: eventType.MEDIA_CAPABILITIES,
|
|
2687
|
+
data: {
|
|
2688
|
+
mediaCapabilities: {
|
|
2689
|
+
rx: {
|
|
2690
|
+
audio: false,
|
|
2691
|
+
share: true,
|
|
2692
|
+
share_audio: false,
|
|
2693
|
+
video: false,
|
|
2694
|
+
whiteboard: false
|
|
2695
|
+
},
|
|
2696
|
+
tx: {
|
|
2697
|
+
audio: false,
|
|
2698
|
+
share: false,
|
|
2699
|
+
share_audio: false,
|
|
2700
|
+
video: false,
|
|
2701
|
+
whiteboard: false
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
});
|
|
2706
|
+
assert.calledWithMatch(Metrics.postEvent, {event: eventType.MOVE_MEDIA});
|
|
2707
|
+
});
|
|
2708
|
+
|
|
2709
|
+
it('should call `MeetingUtil.joinMeetingOptions` with resourceId', async () => {
|
|
2710
|
+
sinon.spy(MeetingUtil, 'joinMeetingOptions');
|
|
2711
|
+
await meeting.moveTo('resourceId');
|
|
2712
|
+
|
|
2713
|
+
assert.calledWith(MeetingUtil.joinMeetingOptions, meeting, {resourceId: 'resourceId', moveToResource: true});
|
|
2714
|
+
});
|
|
2715
|
+
|
|
2716
|
+
it('should reconnectMedia after DX joins after moveTo', async () => {
|
|
2717
|
+
await meeting.moveTo('resourceId');
|
|
2718
|
+
|
|
2719
|
+
|
|
2720
|
+
await meeting.locusInfo.emitScoped(
|
|
2721
|
+
{
|
|
2722
|
+
file: 'locus-info',
|
|
2723
|
+
function: 'updateSelf'
|
|
2724
|
+
},
|
|
2725
|
+
'SELF_OBSERVING'
|
|
2726
|
+
);
|
|
2727
|
+
|
|
2728
|
+
// beacuse we are calling callback so we need to wait
|
|
2729
|
+
|
|
2730
|
+
assert.called(meeting.closeLocalStream);
|
|
2731
|
+
assert.called(meeting.closeLocalShare);
|
|
2732
|
+
|
|
2733
|
+
// give queued Promise callbacks a chance to run
|
|
2734
|
+
await Promise.resolve();
|
|
2735
|
+
|
|
2736
|
+
assert.called(meeting.mediaProperties.setMediaDirection);
|
|
2737
|
+
assert.called(meeting.mediaProperties.unsetMediaTracks);
|
|
2738
|
+
|
|
2739
|
+
assert.calledWith(meeting.reconnectionManager.reconnectMedia,
|
|
2740
|
+
{
|
|
2741
|
+
mediaDirection: {
|
|
2742
|
+
sendVideo: false,
|
|
2743
|
+
receiveVideo: false,
|
|
2744
|
+
sendAudio: false,
|
|
2745
|
+
receiveAudio: false,
|
|
2746
|
+
sendShare: false,
|
|
2747
|
+
receiveShare: true
|
|
2748
|
+
}
|
|
2749
|
+
});
|
|
2750
|
+
});
|
|
2751
|
+
|
|
2752
|
+
it('should throw an error if moveTo call fails', async () => {
|
|
2753
|
+
MeetingUtil.joinMeeting = sinon.stub().returns(Promise.reject());
|
|
2754
|
+
try {
|
|
2755
|
+
await meeting.moveTo('resourceId');
|
|
2756
|
+
}
|
|
2757
|
+
catch {
|
|
2758
|
+
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
2759
|
+
assert.calledWith(
|
|
2760
|
+
Metrics.sendBehavioralMetric,
|
|
2761
|
+
BEHAVIORAL_METRICS.MOVE_TO_FAILURE,
|
|
2762
|
+
{
|
|
2763
|
+
correlation_id: meeting.correlationId,
|
|
2764
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
2765
|
+
reason: sinon.match.any,
|
|
2766
|
+
stack: sinon.match.any
|
|
2767
|
+
}
|
|
2768
|
+
);
|
|
2769
|
+
}
|
|
2770
|
+
Metrics.sendBehavioralMetric.reset();
|
|
2771
|
+
meeting.reconnectionManager.reconnectMedia = sinon.stub().returns(Promise.reject());
|
|
2772
|
+
try {
|
|
2773
|
+
await meeting.moveTo('resourceId');
|
|
2774
|
+
|
|
2775
|
+
await meeting.locusInfo.emitScoped(
|
|
2776
|
+
{
|
|
2777
|
+
file: 'locus-info',
|
|
2778
|
+
function: 'updateSelf'
|
|
2779
|
+
},
|
|
2780
|
+
'SELF_OBSERVING'
|
|
2781
|
+
);
|
|
2782
|
+
}
|
|
2783
|
+
catch {
|
|
2784
|
+
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
2785
|
+
assert.calledWith(
|
|
2786
|
+
Metrics.sendBehavioralMetric,
|
|
2787
|
+
BEHAVIORAL_METRICS.MOVE_TO_FAILURE,
|
|
2788
|
+
{
|
|
2789
|
+
correlation_id: meeting.correlationId,
|
|
2790
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
2791
|
+
reason: sinon.match.any,
|
|
2792
|
+
stack: sinon.match.any
|
|
2793
|
+
}
|
|
2794
|
+
);
|
|
2795
|
+
}
|
|
2796
|
+
});
|
|
2797
|
+
});
|
|
2798
|
+
|
|
2799
|
+
describe('#moveFrom', () => {
|
|
2800
|
+
let sandbox;
|
|
2801
|
+
|
|
2802
|
+
beforeEach(() => {
|
|
2803
|
+
sandbox = sinon.createSandbox();
|
|
2804
|
+
sandbox.stub(MeetingUtil, 'joinMeeting').returns(Promise.resolve(MeetingUtil.parseLocusJoin({body: {locus, mediaConnections: []}})));
|
|
2805
|
+
sandbox.stub(MeetingUtil, 'leaveMeeting').returns(Promise.resolve());
|
|
2806
|
+
});
|
|
2807
|
+
|
|
2808
|
+
afterEach(() => {
|
|
2809
|
+
sandbox.restore();
|
|
2810
|
+
sandbox = null;
|
|
2811
|
+
});
|
|
2812
|
+
|
|
2813
|
+
it('should throw an error if resourceId not passed', async () => {
|
|
2814
|
+
try {
|
|
2815
|
+
await meeting.moveFrom();
|
|
2816
|
+
}
|
|
2817
|
+
catch (err) {
|
|
2818
|
+
assert.instanceOf(err, ParameterError);
|
|
2819
|
+
|
|
2820
|
+
assert.equal(err.sdkMessage, 'Cannot move call without a resourceId.');
|
|
2821
|
+
}
|
|
2822
|
+
});
|
|
2823
|
+
|
|
2824
|
+
it('should postEvent on moveFrom ', async () => {
|
|
2825
|
+
await meeting.moveFrom('resourceId');
|
|
2826
|
+
|
|
2827
|
+
assert.calledWithMatch(Metrics.postEvent, {event: eventType.MOVE_MEDIA});
|
|
2828
|
+
});
|
|
2829
|
+
|
|
2830
|
+
it('should call `MeetingUtil.joinMeetingOptions` with resourceId', async () => {
|
|
2831
|
+
sinon.spy(MeetingUtil, 'joinMeetingOptions');
|
|
2832
|
+
await meeting.moveFrom('resourceId');
|
|
2833
|
+
|
|
2834
|
+
assert.calledWith(MeetingUtil.joinMeetingOptions, meeting);
|
|
2835
|
+
assert.calledWith(MeetingUtil.leaveMeeting, meeting, {
|
|
2836
|
+
resourceId: 'resourceId',
|
|
2837
|
+
correlationId: meeting.correlationId,
|
|
2838
|
+
moveMeeting: true
|
|
2839
|
+
});
|
|
2840
|
+
|
|
2841
|
+
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
2842
|
+
assert.calledWith(
|
|
2843
|
+
Metrics.sendBehavioralMetric,
|
|
2844
|
+
BEHAVIORAL_METRICS.MOVE_FROM_SUCCESS,
|
|
2845
|
+
);
|
|
2846
|
+
});
|
|
2847
|
+
|
|
2848
|
+
it('should throw an error if moveFrom call fails', async () => {
|
|
2849
|
+
MeetingUtil.joinMeeting = sinon.stub().returns(Promise.reject());
|
|
2850
|
+
try {
|
|
2851
|
+
await meeting.moveFrom('resourceId');
|
|
2852
|
+
}
|
|
2853
|
+
catch {
|
|
2854
|
+
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
2855
|
+
assert.calledWith(
|
|
2856
|
+
Metrics.sendBehavioralMetric,
|
|
2857
|
+
BEHAVIORAL_METRICS.MOVE_FROM_FAILURE,
|
|
2858
|
+
{
|
|
2859
|
+
correlation_id: meeting.correlationId,
|
|
2860
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
2861
|
+
reason: sinon.match.any,
|
|
2862
|
+
stack: sinon.match.any
|
|
2863
|
+
}
|
|
2864
|
+
);
|
|
2865
|
+
}
|
|
2866
|
+
});
|
|
2867
|
+
});
|
|
2641
2868
|
});
|
|
2642
2869
|
|
|
2643
2870
|
describe('Public Event Triggers', () => {
|
|
@@ -3316,6 +3543,7 @@ describe('plugin-meetings', () => {
|
|
|
3316
3543
|
let canUserResumeSpy;
|
|
3317
3544
|
let canUserRaiseHandSpy;
|
|
3318
3545
|
let canUserLowerAllHandsSpy;
|
|
3546
|
+
let canUserLowerSomeoneElsesHandSpy;
|
|
3319
3547
|
|
|
3320
3548
|
|
|
3321
3549
|
beforeEach(() => {
|
|
@@ -3329,6 +3557,7 @@ describe('plugin-meetings', () => {
|
|
|
3329
3557
|
inMeetingActionsSetSpy = sinon.spy(meeting.inMeetingActions, 'set');
|
|
3330
3558
|
canUserRaiseHandSpy = sinon.spy(MeetingUtil, 'canUserRaiseHand');
|
|
3331
3559
|
canUserLowerAllHandsSpy = sinon.spy(MeetingUtil, 'canUserLowerAllHands');
|
|
3560
|
+
canUserLowerSomeoneElsesHandSpy = sinon.spy(MeetingUtil, 'canUserLowerSomeoneElsesHand');
|
|
3332
3561
|
});
|
|
3333
3562
|
|
|
3334
3563
|
afterEach(() => {
|
|
@@ -3363,6 +3592,7 @@ describe('plugin-meetings', () => {
|
|
|
3363
3592
|
assert.calledWith(canUserResumeSpy, payload.info.userDisplayHints);
|
|
3364
3593
|
assert.calledWith(canUserRaiseHandSpy, payload.info.userDisplayHints);
|
|
3365
3594
|
assert.calledWith(canUserLowerAllHandsSpy, payload.info.userDisplayHints);
|
|
3595
|
+
assert.calledWith(canUserLowerSomeoneElsesHandSpy, payload.info.userDisplayHints);
|
|
3366
3596
|
|
|
3367
3597
|
assert.calledWith(
|
|
3368
3598
|
TriggerProxy.trigger,
|
|
@@ -228,6 +228,13 @@ describe('plugin-meetings', () => {
|
|
|
228
228
|
});
|
|
229
229
|
});
|
|
230
230
|
|
|
231
|
+
describe('canUserLowerSomeoneElsesHand', () => {
|
|
232
|
+
it('works as expected', () => {
|
|
233
|
+
assert.deepEqual(MeetingUtil.canUserLowerSomeoneElsesHand(['LOWER_SOMEONE_ELSES_HAND']), true);
|
|
234
|
+
assert.deepEqual(MeetingUtil.canUserLowerSomeoneElsesHand([]), false);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
231
238
|
describe('canUserLock', () => {
|
|
232
239
|
it('works as expected', () => {
|
|
233
240
|
assert.deepEqual(MeetingUtil.canUserLock(['LOCK_CONTROL_LOCK', 'LOCK_STATUS_UNLOCKED']), true);
|