Skip to content

Commit 0f705db

Browse files
authored
3way-calling-3-ConferenceCall module (#899)
* implement ConferenceCall module * add ConferenceCall module integration tests * use cached profileImageUrl
1 parent aaa7263 commit 0f705db

File tree

15 files changed

+1395
-4
lines changed

15 files changed

+1395
-4
lines changed

packages/ringcentral-integration/integration-test/commons/Phone/index.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import ActivityMatcher from '../../../modules/ActivityMatcher';
5050
// import CallLog from '../CallLog';
5151
// import AutoLogger from '../AutoLogger';
5252
// import DataMatcher from '../DataMatcher';
53+
import ConferenceCall from '../../../modules/ConferenceCall';
5354

5455

5556
export default class Phone extends RcModule {
@@ -375,7 +376,9 @@ export default class Phone extends RcModule {
375376
}));
376377
this.contactSearch.addSearchSource({
377378
sourceName: 'test',
378-
searchFn: ({ searchString }) => [{
379+
searchFn: ({
380+
searchString
381+
}) => [{
379382
entityType: 'account',
380383
name: searchString,
381384
phoneNumber: '+1234567890',
@@ -444,6 +447,20 @@ export default class Phone extends RcModule {
444447
// getState: () => this.state.adapter,
445448
// }));
446449

450+
this.addModule('conferenceCall', new ConferenceCall({
451+
...options,
452+
auth: this.auth,
453+
storage: this.storage,
454+
client: this.client,
455+
tabManager: this.tabManager,
456+
alert: this.alert,
457+
call: this.call,
458+
callingSettings: this.callingSettings,
459+
rolesAndPermissions: this.rolesAndPermissions,
460+
pulling: false,
461+
getState: () => this.state.conferenceCall,
462+
}));
463+
447464
this._reducer = combineReducers({
448465
app: (state = {
449466
name: appName,
@@ -488,6 +505,7 @@ export default class Phone extends RcModule {
488505
messageStore: this.messageStore.reducer,
489506
conversations: this.conversations.reducer,
490507
// adapter: this.adapter.reducer,
508+
conferenceCall: this.conferenceCall.reducer,
491509
});
492510
}
493511

packages/ringcentral-integration/integration-test/commons/specs/commons.spec.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import runDialingPlanTests from '../../spec-modules/dialingPlan';
2525
import runRolesAndPermissionsTests from '../../spec-modules/rolesAndPermissions';
2626
import runExtensionPhoneNumberTests from '../../spec-modules/extensionPhoneNumber';
2727
import runPresenceTests from '../../spec-modules/presence';
28+
import runConferenceCallTests from '../../spec-modules/conferenceCall';
2829

2930
let phone = getTestPhone();
3031
runNumValidInCallTests(phone.auth, phone.alert, phone.client, phone.regionSettings, phone.call,
@@ -150,3 +151,12 @@ runPresenceTests(
150151
phone.presence,
151152
defaultAccount,
152153
);
154+
155+
phone = getTestPhone();
156+
runConferenceCallTests(
157+
phone.auth,
158+
phone.client,
159+
phone.conferenceCall,
160+
phone.alert,
161+
defaultAccount,
162+
);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"session": {
3+
"creationTime": "2018-05-29T14:40:44Z",
4+
"id": "Y3MxNzI2MjI1NTQzODI0MzUzM0AxMC43NC4yLjIxOA",
5+
"origin": {
6+
"type": "Conference"
7+
},
8+
"parties": [],
9+
"voiceCallToken": "conf_59334d784e7a49324d6a49314e54517a4f4449304d7a557a4d3041784d4334334e4334794c6a49784f414031302e37342e322e3231383a35303730"
10+
}
11+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"uri": "http://api-xmnup.lab.nordigy.ru/restapi/v1.0/number-parser/parse?nationalAsPriority=false&homeCountry=US",
3+
"homeCountry": {
4+
"uri": "http://api-xmnup.lab.nordigy.ru/restapi/v1.0/dictionary/country/1",
5+
"id": "1",
6+
"name": "United States",
7+
"isoCode": "US",
8+
"callingCode": "1"
9+
},
10+
"phoneNumbers": [{
11+
"originalString": "+12092313293",
12+
"country": {
13+
"uri": "http://api-xmnup.lab.nordigy.ru/restapi/v1.0/dictionary/country/1",
14+
"id": "1",
15+
"name": "United States",
16+
"isoCode": "US",
17+
"callingCode": "1"
18+
},
19+
"areaCode": "209",
20+
"subscriberNumber": "2313293",
21+
"formattedNational": "(209) 231-3293",
22+
"formattedInternational": "+1 (209) 2313293",
23+
"dialable": "2092313293",
24+
"e164": "+12092313293",
25+
"special": false,
26+
"normalized": "12092313293",
27+
"tollFree": false
28+
}]
29+
}

packages/ringcentral-integration/integration-test/mock/index.js

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const conferencingBody = require('./data/conferencing.json');
2828
const activeCallsBody = require('./data/activeCalls.json');
2929
const meetingBody = require('./data/meeting');
3030
const serviceInfoBody = require('./data/serviceInfo');
31+
const conferenceCallBody = require('./data/conferenceCall');
32+
const numberParseBody = require('./data/numberParse');
3133

3234
const mockServer = 'http://whatever';
3335
export function createSDK(options = {}) {
@@ -61,7 +63,9 @@ export function mockApi({
6163
let responseHeaders;
6264
const isJson = typeof body !== 'string';
6365
if (isJson && !headers) {
64-
responseHeaders = { 'Content-Type': 'application/json' };
66+
responseHeaders = {
67+
'Content-Type': 'application/json'
68+
};
6569
} else {
6670
responseHeaders = headers;
6771
}
@@ -412,6 +416,31 @@ export function conferencing(mockResponse = {}) {
412416
});
413417
}
414418

419+
export function numberParse(mockResponse = {}, homeCountry) {
420+
mockApi({
421+
method: 'POST',
422+
path: `/restapi/v1.0/number-parser/parse?homeCountry=${homeCountry}`,
423+
body: {
424+
...numberParseBody,
425+
...mockResponse,
426+
},
427+
isOnce: false
428+
});
429+
}
430+
431+
export function conferenceCall(mockResponse = {}) {
432+
conferenceCallBody.session.on = () => {};
433+
mockApi({
434+
method: 'POST',
435+
path: '/restapi/v1.0/account/~/telephony/conference',
436+
body: {
437+
...conferenceCallBody,
438+
...mockResponse,
439+
},
440+
isOnce: false
441+
});
442+
}
443+
415444
export function activeCalls(mockResponse = {}) {
416445
mockApi({
417446
method: 'GET',
@@ -539,5 +568,3 @@ export function mockForLogin({
539568
}
540569
numberParser();
541570
}
542-
543-
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import {
2+
ensureLogin,
3+
containsErrorMessage
4+
} from '../utils/HelpUtil';
5+
import {
6+
waitInSeconds
7+
} from '../utils/WaitUtil';
8+
import * as mock from '../mock';
9+
import ClientHistoryRequest from '../utils/ClientHistoryRequest';
10+
import conferenceCallErrors from '../../modules/ConferenceCall/conferenceCallErrors';
11+
import conferenceCallStatus from '../../modules/ConferenceCall/conferenceCallStatus';
12+
import callingOptions from '../../modules/CallingSettings/callingOptions';
13+
import callDirection from '../../enums/callDirections';
14+
import sinon from 'sinon';
15+
16+
export default (auth, client, conferenceCall, alert, account) => {
17+
describe('ConferenceCall:', function () {
18+
this.timeout(20000);
19+
mock.mockClient(client);
20+
const clientHistoryRequest = new ClientHistoryRequest(new Map(), client);
21+
let isLoginSuccess;
22+
23+
describe('Should Init Successfully with Default Setting', () => {
24+
it('Should Have Empty Records of Conferences By Default', () => {
25+
expect(conferenceCall.state.conferences).to.be.an('object').that.is.empty;
26+
});
27+
it('Should Be Idle By Default', () => {
28+
expect(conferenceCall.state.conferenceCallStatus).to.equal(conferenceCallStatus.idle);
29+
});
30+
});
31+
32+
describe('Should Update Conference Successfully', function () {
33+
after(async function () {
34+
await auth.logout();
35+
await waitInSeconds(1);
36+
});
37+
38+
before(async function () {
39+
mock.restore();
40+
mock.mockForLogin({
41+
mockAuthzProfile: false
42+
});
43+
isLoginSuccess = await ensureLogin(auth, account);
44+
45+
if (!isLoginSuccess) {
46+
console.error('Skip test case as failed to login with credential ', account);
47+
this.skip();
48+
}
49+
mock.conferenceCall();
50+
mock.numberParse({}, 'US');
51+
});
52+
53+
it('Should Update Records of Conferences When Request One', async () => {
54+
let sessionData;
55+
sessionData = await conferenceCall._makeConference();
56+
const rawRequest =
57+
clientHistoryRequest.getRawResponse(ClientHistoryRequest.endPoints.conferenceCall);
58+
expect(JSON.stringify(sessionData)).to.equal(JSON.stringify(rawRequest.session));
59+
// FIXME: because we are unable to mock sip.js instance, so skip the session assertation below:
60+
// expect(conferenceCall.conferences).to.have.key(rawRequest.session.id);
61+
});
62+
63+
it('Should Not Have Failure Alert', () => {
64+
Object.values(conferenceCallErrors).forEach(err => {
65+
expect(containsErrorMessage(
66+
alert.state.messages,
67+
err
68+
)).to.equal(undefined);
69+
});
70+
});
71+
});
72+
73+
describe('Should Failed to Update Conference', async () => {
74+
after(async function () {
75+
await auth.logout();
76+
await waitInSeconds(1);
77+
});
78+
79+
before(async function () {
80+
conferenceCall._reset();
81+
mock.restore();
82+
mock.mockForLogin({
83+
mockAuthzProfile: false
84+
});
85+
isLoginSuccess = await ensureLogin(auth, account);
86+
87+
if (!isLoginSuccess) {
88+
console.error('Skip test case as failed to login with credential ', account);
89+
this.skip();
90+
}
91+
mock.mockForbidden({
92+
method: 'POST',
93+
path: ClientHistoryRequest.endPoints.conferenceCall
94+
});
95+
mock.numberParse({}, 'US');
96+
});
97+
98+
it('Should Have No Records of Conference', async () => {
99+
await conferenceCall._makeConference(false);
100+
expect(conferenceCall.conferences).to.be.an('object').that.is.empty;
101+
});
102+
103+
it('Should Have A Failure Alert', () => {
104+
expect(containsErrorMessage(
105+
alert.state.messages,
106+
conferenceCallErrors.makeConferenceFailed
107+
)).to.not.equal(undefined);
108+
});
109+
110+
it('Should Not Bring Session into Non-existent Conference', async () => {
111+
try {
112+
await conferenceCall.bringInToConference(Math.random(), {
113+
direction: callDirection.outbound
114+
});
115+
} catch (e) {
116+
// skip the error that were throwed intentinally
117+
}
118+
expect(containsErrorMessage(
119+
alert.state.messages,
120+
conferenceCallErrors.makeConferenceFailed
121+
)).to.not.equal(undefined);
122+
});
123+
});
124+
});
125+
};

packages/ringcentral-integration/integration-test/utils/ClientHistoryRequest.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export default class ClientHistoryRequest {
66
token: '/restapi/oauth/token',
77
companyPager: '/restapi/v1.0/account/~/extension/~/company-pager',
88
sms: '/restapi/v1.0/account/~/extension/~/sms',
9+
conferenceCall: '/restapi/v1.0/account/~/telephony/conference',
910
}
1011

1112
constructor(requestContainer, client) {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import Enum from '../../lib/Enum';
2+
import moduleActionTypes from '../../enums/moduleActionTypes';
3+
4+
export default new Enum([
5+
...Object.keys(moduleActionTypes),
6+
'mergeStart',
7+
'mergeSucceeded',
8+
'mergeFailed',
9+
// make conference call
10+
'makeConference',
11+
'makeConferenceSucceeded',
12+
'makeConferenceFailed',
13+
// terminate
14+
'terminateConference',
15+
'terminateConferenceSucceeded',
16+
'terminateConferenceFailed',
17+
// update
18+
'updateConference',
19+
'updateConferenceSucceeded',
20+
'updateConferenceFailed',
21+
// get party
22+
'getParty',
23+
'getPartySucceeded',
24+
'getPartyFailed',
25+
// bring-in
26+
'bringInConference',
27+
'bringInConferenceSucceeded',
28+
'bringInConferenceFailed',
29+
// remove
30+
'removeFromConference',
31+
'removeFromConferenceSucceeded',
32+
'removeFromConferenceFailed',
33+
// update merge pairs
34+
'updateFromSession',
35+
'updateToSession',
36+
], 'conferenceCall');
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Enum from '../../lib/Enum';
2+
3+
export default new Enum([
4+
'internalServerError',
5+
'conferenceForbidden',
6+
'conferenceBadRequest',
7+
'conferenceNotFound',
8+
'conferenceConflict',
9+
'modeError',
10+
'makeConferenceFailed',
11+
'bringInFailed',
12+
], 'conferenceCall');
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Enum from '../../lib/Enum';
2+
3+
export default new Enum([
4+
'idle',
5+
'requesting',
6+
], 'conferenceCall');

0 commit comments

Comments
 (0)