VulpesOS/gaia/apps/callscreen/test/unit/handled_call_test.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

1115 lines
37 KiB
JavaScript
Executable file

/* globals ConferenceGroupHandler, FontSizeManager,
HandledCall, l10nAssert, MockCall, MockCallScreen, MockCallsHandler,
MockContactPhotoHelper, MockContacts, MockFontSizeUtils, MockL10n,
MockNavigatorMozIccManager, MockNavigatorSettings, MocksHelper,
MockTonePlayer, MockUtils, MockVoicemail */
'use strict';
require('/shared/test/unit/mocks/mock_navigator_moz_settings.js');
require('/shared/test/unit/mocks/mock_audio.js');
require('/shared/test/unit/mocks/mock_contact_photo_helper.js');
require('/shared/test/unit/mocks/mock_font_size_utils.js');
require('/shared/test/unit/mocks/mock_l10n.js');
require('/shared/test/unit/mocks/mock_navigator_moz_icc_manager.js');
require('/shared/test/unit/mocks/dialer/mock_contacts.js');
require('/shared/test/unit/mocks/dialer/mock_keypad.js');
require('/shared/test/unit/mocks/dialer/mock_utils.js');
require('/shared/test/unit/mocks/dialer/mock_call.js');
require('/shared/test/unit/mocks/dialer/mock_calls_handler.js');
require('/shared/test/unit/mocks/dialer/mock_tone_player.js');
require('/shared/test/unit/mocks/dialer/mock_font_size_manager.js');
require('/shared/test/unit/mocks/mock_voicemail.js');
require('/test/unit/mock_call_screen.js');
require('/test/unit/mock_conference_group_handler.js');
require('/js/handled_call.js');
var mocksHelperForHandledCall = new MocksHelper([
'Audio',
'AudioContext',
'Contacts',
'CallScreen',
'ConferenceGroupHandler',
'CallsHandler',
'FontSizeUtils',
'KeypadManager',
'Utils',
'ContactPhotoHelper',
'TonePlayer',
'FontSizeManager',
'Voicemail'
]).init();
suite('dialer/handled_call', function() {
var realMozL10n;
var realNavigatorSettings;
var realMozIccManager;
const VOICEMAIL_NUMBER = '123';
var subject;
var mockCall;
var templates;
var phoneNumber;
var photoFullResolution;
var photoThumbnail;
mocksHelperForHandledCall.attachTestHelpers();
suiteSetup(function() {
realMozL10n = navigator.l10n;
navigator.mozL10n = MockL10n;
realNavigatorSettings = navigator.mozSettings;
navigator.mozSettings = MockNavigatorSettings;
realMozIccManager = navigator.mozIccManager;
navigator.mozIccManager = MockNavigatorMozIccManager;
phoneNumber = Math.floor(Math.random() * 10000);
templates = document.createElement('div');
templates.innerHTML = `<section id="handled-call-template" role="dialog"
hidden>
<div class="hangup-button" role="button"
data-l10n-id="hangup-a11y-button"></div>
<div class="numberWrapper
direction-status-bar">
<div class="number font-light">
<bdi></bdi>
</div>
<span role="button" id="switch-calls-button">
</span>
</div>
<div class="additionalContactInfo font-light">
<span class="tel" dir="ltr"></span>
<span class="separator"></span>
<span class="tel-type" dir="auto"></span>
</div>
<div class="duration">
<span class="font-light"></span>
<div class="total-duration"></div>
<div class="direction"></div>
</div>
<div class="sim">
<span class="via-sim"></span>
<span class="sim-number"></span>
</div>
<button class="merge-button"
data-l10n-id="merge">Merge</button>
</section>`;
document.body.appendChild(templates);
});
suiteTeardown(function() {
templates.parentNode.removeChild(templates);
navigator.mozSettings = realNavigatorSettings;
navigator.mozIccManager = realMozIccManager;
navigator.mozL10n = realMozL10n;
});
setup(function() {
photoFullResolution = new Blob();
photoThumbnail = new Blob();
this.sinon.stub(MockContactPhotoHelper,
'getFullResolution').returns(photoFullResolution);
this.sinon.stub(MockContactPhotoHelper,
'getThumbnail').returns(photoThumbnail);
this.sinon.stub(MockFontSizeUtils, 'getMaxFontSizeInfo').returns({
fontSize: 1.0
});
this.sinon.useFakeTimers(Date.now());
mockCall = new MockCall(String(phoneNumber), 'dialing');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
document.body.appendChild(subject.node);
});
teardown(function() {
MockNavigatorMozIccManager.mTeardown();
var node = subject.node;
if (node && node.parentNode) {
node.parentNode.removeChild(node);
}
});
suite('initialization', function() {
setup(function() {
this.sinon.spy(MockCallsHandler, 'updatePlaceNewCall');
});
test('full resolution photo', function() {
assert.equal(subject.photo, photoFullResolution);
});
test('should set caller image by contact photo', function() {
assert.isTrue(MockCallScreen.mSetCallerContactImageCalled);
});
test('call', function() {
assert.equal(subject.call, mockCall);
});
test('call event listener', function() {
assert.equal(mockCall._eventListeners.statechange.length, 1);
});
test('CallsHandler.updatePlaceNewCall added as call state listener',
function() {
subject.call.mChangeState();
sinon.assert.calledOnce(MockCallsHandler.updatePlaceNewCall);
});
suite('node', function() {
test('should not have an id', function() {
assert.equal(subject.node.id, '');
});
test('should have the handled-call class', function() {
assert.isTrue(subject.node.classList.contains('handled-call'));
});
test('should not be hidden', function() {
assert.isFalse(subject.node.hidden);
});
test('should have a numberNode in a numberWrapper', function() {
var numberNode =
subject.node.querySelector('.numberWrapper .number bdi');
assert.equal(subject.numberNode, numberNode);
});
test('should have an outerNode in a numberWrapper', function() {
var outerNode = subject.node.querySelector('.numberWrapper .number');
assert.equal(subject.outerNode, outerNode);
});
test('should have an additionalContactTel node', function() {
var additionalTelNode =
subject.node.querySelector('.additionalContactInfo .tel');
assert.equal(subject.additionalTelNode, additionalTelNode);
});
test('should have an additionalContactTelType node', function() {
var additionalTelTypeNode =
subject.node.querySelector('.additionalContactInfo .tel-type');
assert.equal(subject.additionalTelTypeNode, additionalTelTypeNode);
});
test('should have a duration node', function() {
var durationNode = subject.node.querySelector('.duration');
assert.equal(subject.durationNode, durationNode);
});
test('should have a duration child node', function() {
var durationChildNode = subject.node.querySelector('.duration span');
assert.equal(subject.durationChildNode, durationChildNode);
assert.isTrue(durationChildNode.classList.contains('font-light'));
});
});
test('duration outgoing', function() {
assert.ok(subject.durationChildNode);
l10nAssert(subject.durationChildNode, 'connecting');
});
test('duration incoming', function() {
mockCall = new MockCall('888', 'incoming');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
assert.ok(subject.durationChildNode);
l10nAssert(subject.durationChildNode, 'incoming');
});
test('number', function() {
assert.ok(subject.numberNode);
assert.equal(MockContacts.mCalledWith, mockCall.id.number);
});
test('initial state', function() {
assert.equal(subject._initialState, 'dialing');
});
test('support for calls already connected at init', function() {
mockCall = new MockCall(String(phoneNumber), 'connected');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
assert.isFalse(subject.node.hidden);
assert.isTrue(subject.node.classList.contains('ongoing'));
});
suite('stk call', function() {
var reqStub, settingsSetSpy;
var contactLookupSpy, tel, contact;
setup(function() {
reqStub = {
onsuccess: null,
result: {
'icc.callmessage': 'stk second alpha identifier'
}
};
settingsSetSpy = this.sinon.spy();
var newCreateLock = function() {
return {
get: function() {
return reqStub;
},
set: settingsSetSpy
};
};
this.sinon.stub(navigator.mozSettings, 'createLock', newCreateLock);
tel = {
value: '666666666',
carrier: 'carrier',
type: 'type'
};
contact = {
id: 666,
name: ['from contact lookup'],
tel: [tel]
};
contactLookupSpy = this.sinon.spy(MockContacts, 'findByNumber');
mockCall = new MockCall(String(phoneNumber), 'dialing');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
});
test('should display the icc call message', function() {
contactLookupSpy.yield(contact, tel, false);
reqStub.onsuccess();
assert.equal(subject.numberNode.textContent,
'stk second alpha identifier');
});
test('should clear the icc call message setting', function() {
reqStub.onsuccess();
assert.isTrue(settingsSetSpy.calledOnce);
assert.isTrue(settingsSetSpy.calledWith({'icc.callmessage': null}));
});
test('should not let the contact lookup override the number', function() {
reqStub.onsuccess();
contactLookupSpy.yield(contact, tel, false);
assert.equal(subject.numberNode.textContent,
'stk second alpha identifier');
});
});
});
suite('on connect', function() {
setup(function() {
this.sinon.spy(MockCallsHandler, 'updatePlaceNewCall');
this.sinon.spy(MockCallsHandler, 'updateMergeAndOnHoldStatus');
this.sinon.spy(MockCallsHandler, 'updateMuteAndSpeakerStatus');
mockCall._connect();
});
test('show the node', function() {
assert.isFalse(subject.node.hidden);
});
test('ensure the callscreen in connected mode', function() {
assert.equal(MockCallScreen.mLastRenderMode, 'connected');
});
test('start the timer', function() {
assert.isTrue(MockCallScreen.mCalledCreateTicker);
});
test('sync speaker', function() {
assert.isTrue(MockCallScreen.mSyncSpeakerCalled);
});
test('photo displaying', function() {
assert.isTrue(MockCallScreen.mSetCallerContactImageCalled);
});
test('should set contact picture', function() {
this.sinon.stub(MockCallScreen, 'setCallerContactImage');
mockCall._connect();
sinon.assert.calledOnce(MockCallScreen.setCallerContactImage);
});
suite('in a group', function() {
setup(function() {
MockCallScreen.mSetCallerContactImageCalled = false;
mockCall.group = {};
mockCall._connect();
});
test('contact image updated', function() {
assert.isTrue(MockCallScreen.mSetCallerContactImageCalled);
});
});
test('primary contact info', function() {
assert.isTrue(MockUtils.mCalledGetPhoneNumberPrimaryInfo);
});
test('mute initially off', function() {
assert.isFalse(MockCallScreen.mMuteOn);
});
test('speaker initially off', function() {
assert.isFalse(MockCallScreen.mSpeakerOn);
});
test('the place new call button status is updated', function() {
sinon.assert.calledOnce(MockCallsHandler.updatePlaceNewCall);
});
test('the merge and on hold buttons status is updated', function() {
sinon.assert.calledOnce(MockCallsHandler.updateMergeAndOnHoldStatus);
});
test('the mute and speaker buttons\' status is updated', function() {
sinon.assert.calledOnce(MockCallsHandler.updateMuteAndSpeakerStatus);
});
});
suite('on disconnect', function() {
var node;
setup(function() {
node = subject.node;
});
suite('from a regular call', function() {
setup(function() {
mockCall._connect();
MockCallScreen.mute();
MockCallScreen.switchToSpeaker();
});
test('should show call ended', function() {
mockCall._disconnect();
l10nAssert(subject.node.querySelector('.duration span'), 'callEnded');
});
test('should not show the total call duration', function() {
subject.node.querySelector('.duration span').textContent = 'Incoming';
mockCall._disconnect();
assert.equal(subject.node.querySelector('.total-duration').textContent,
'');
});
test('should show the total call duration', function() {
var totalCallDuration = '12:34';
subject.node.querySelector('.duration span').textContent =
totalCallDuration;
mockCall._disconnect();
assert.equal(subject.node.querySelector('.total-duration').textContent,
totalCallDuration);
});
test('should remove listener on the call', function() {
this.sinon.spy(mockCall, 'removeEventListener');
mockCall._disconnect();
sinon.assert.calledWith(
mockCall.removeEventListener, 'statechange', subject);
mockCall.removeEventListener.restore();
});
test('should keep the call', function() {
mockCall._disconnect();
assert.ok(subject.call);
});
test('should nullify the photo', function() {
mockCall._disconnect();
assert.isNull(subject.photo);
});
test('should clear the ticker', function() {
mockCall._disconnect();
assert.isTrue(MockCallScreen.mCalledStopTicker);
});
test('should remove the node from the dom', function() {
assert.isFalse(MockCallScreen.mRemoveCallCalled);
mockCall._disconnect();
//check that the node is not immediately removed from DOM.
assert.isFalse(MockCallScreen.mRemoveCallCalled);
this.sinon.clock.tick(MockCallScreen.callEndPromptTime);
assert.isTrue(MockCallScreen.mRemoveCallCalled);
});
test('should nullify the node', function() {
mockCall._disconnect();
assert.isNotNull(subject.node);
this.sinon.clock.tick(MockCallScreen.callEndPromptTime);
assert.isNull(subject.node);
});
test('it does not show the banner', function() {
assert.isFalse(MockCallScreen.mShowStatusMessageCalled);
});
test('end call tone should be played', function() {
var playSpy = this.sinon.spy(MockTonePlayer, 'playSequence');
mockCall._disconnect();
assert.isTrue(playSpy.calledWith([[480, 620, 250]]));
});
test('the place new call button status is updated', function() {
this.sinon.spy(MockCallsHandler, 'updatePlaceNewCall');
mockCall._disconnect();
sinon.assert.calledOnce(MockCallsHandler.updatePlaceNewCall);
});
test('the merge and on hold buttons status is updated', function() {
this.sinon.spy(MockCallsHandler, 'updateMergeAndOnHoldStatus');
mockCall._disconnect();
sinon.assert.calledOnce(MockCallsHandler.updateMergeAndOnHoldStatus);
});
test('the mute and speaker buttons\' status is updated', function() {
this.sinon.spy(MockCallsHandler, 'updateMuteAndSpeakerStatus');
mockCall._disconnect();
sinon.assert.calledOnce(MockCallsHandler.updateMuteAndSpeakerStatus);
});
});
suite('from a group', function() {
setup(function() {
this.sinon.spy(MockCallScreen, 'showStatusMessage');
mockCall._connect();
MockCallScreen.mute();
MockCallScreen.switchToSpeaker();
mockCall.group = null;
mockCall.mChangeState('disconnecting');
mockCall.ongroupchange(mockCall);
mockCall._disconnect();
});
test('show the banner', function() {
sinon.assert.calledWithMatch(
MockCallScreen.showStatusMessage, {
id: 'caller-left-call',
args: { caller: ['test name'] }
}
);
});
});
suite('the call was not connected', function() {
test('end call tone is not played', function() {
var playSpy = this.sinon.spy(MockTonePlayer, 'playSequence');
mockCall._disconnect();
assert.isFalse(playSpy.called);
});
});
});
suite('on hold', function() {
setup(function() {
this.sinon.spy(MockCallsHandler, 'updatePlaceNewCall');
this.sinon.spy(MockCallsHandler, 'updateMergeAndOnHoldStatus');
this.sinon.spy(MockCallsHandler, 'updateMuteAndSpeakerStatus');
mockCall._hold();
});
test('show the node', function() {
assert.isFalse(subject.node.hidden);
});
test('put the callscreen in connected-hold mode', function() {
assert.equal(MockCallScreen.mLastRenderMode, 'connected-hold');
});
test('mute is off', function() {
assert.isFalse(MockCallScreen.mMuteOn);
});
test('speaker is off', function() {
assert.isFalse(MockCallScreen.mSpeakerOn);
});
test('the place new call button status is updated', function() {
sinon.assert.calledOnce(MockCallsHandler.updatePlaceNewCall);
});
test('the merge and on hold buttons status is updated', function() {
sinon.assert.calledOnce(MockCallsHandler.updateMergeAndOnHoldStatus);
});
test('the mute and speaker buttons\' status is updated', function() {
sinon.assert.calledOnce(MockCallsHandler.updateMuteAndSpeakerStatus);
});
});
suite('call direction', function() {
suite('outgoing call', function() {
setup(function() {
mockCall = new MockCall('888', 'outgoing');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
});
test('before and after connexion', function() {
assert.isTrue(subject.node.classList.contains('outgoing'));
assert.isFalse(subject.node.classList.contains('ongoing'));
mockCall._connect();
assert.isTrue(subject.node.classList.contains('ongoing'));
assert.isTrue(subject.node.classList.contains('outgoing'));
assert.isTrue(subject.node.hasAttribute('data-l10n-id'));
l10nAssert(subject.node, 'outgoing_screen_reader');
});
});
suite('incoming call', function() {
setup(function() {
mockCall = new MockCall('888', 'incoming');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
});
test('before and after connexion', function() {
assert.isTrue(subject.node.classList.contains('incoming'));
assert.isFalse(subject.node.classList.contains('ongoing'));
mockCall._connect();
assert.isTrue(subject.node.classList.contains('ongoing'));
assert.isTrue(subject.node.classList.contains('incoming'));
assert.isTrue(subject.node.hasAttribute('data-l10n-id'));
l10nAssert(subject.node, 'incoming_screen_reader');
});
});
});
test('should display contact name', function() {
mockCall = new MockCall('888', 'incoming');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
assert.equal(subject.numberNode.textContent, 'test name');
});
test('should display withheld-number l10n key', function() {
mockCall = new MockCall('', 'incoming');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
l10nAssert(subject.numberNode, 'withheld-number');
});
test('should display switch-calls l10n key', function() {
mockCall = new MockCall('888', 'connected');
subject = new HandledCall(mockCall);
mockCall.secondId = { number: '999' };
MockVoicemail.mResolvePromise(false);
subject.updateCallNumber();
l10nAssert(subject.numberNode, 'switch-calls');
});
suite('Emergency Call layout', function() {
setup(function() {
MockCallScreen.mSetEmergencyWallpaperCalled = false;
});
test('should set the emergency class', function() {
mockCall = new MockCall('112', 'dialing');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
assert.isTrue(subject.node.classList.contains('emergency'));
});
test('should display emergency number label', function() {
mockCall = new MockCall('112', 'dialing');
mockCall.emergency = true;
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
l10nAssert(subject.additionalTelNode, 'emergencyNumber');
});
});
test('should display voicemail label', function() {
mockCall = new MockCall(VOICEMAIL_NUMBER, 'dialing');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(true);
l10nAssert(subject.numberNode, 'voiceMail');
});
suite('additional information', function() {
test('check additional info updated', function() {
this.sinon.stub(MockUtils, 'getPhoneNumberAdditionalInfo')
.returns({
id: 'phone_type_custom_and_carrier',
args: { type: 'type', carrier: 'carrier' }
});
mockCall = new MockCall('888', 'incoming');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
assert.equal(subject.additionalTelNode.textContent, '888');
l10nAssert(
subject.additionalTelTypeNode, {
id: 'phone_type_custom_and_carrier',
args: { type: 'type', carrier: 'carrier' }
}
);
});
test('check switch-calls mode', function() {
mockCall = new MockCall('888', 'connected');
subject = new HandledCall(mockCall);
mockCall.secondId = { number: '999' };
MockVoicemail.mResolvePromise(false);
subject.updateCallNumber();
assert.equal('', subject.additionalTelNode.textContent);
assert.equal('', subject.additionalTelTypeNode.textContent);
subject.restoreAdditionalContactInfo();
assert.equal('', subject.additionalTelNode.textContent);
assert.equal('', subject.additionalTelTypeNode.textContent);
});
suite('additional contact info', function() {
setup(function() {
mockCall = new MockCall('888', 'incoming');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
});
suite('when there are additional infos to display', function() {
setup(function() {
subject.replaceAdditionalContactInfo(
{ raw: 'test additional tel' }, {
id: 'phone_type_mobile_and_carrier',
args: { carrier: 'carrier' }
}
);
});
test('should update the text content', function() {
assert.equal(subject.additionalTelNode.textContent,
'test additional tel');
l10nAssert(
subject.additionalTelTypeNode, {
id: 'phone_type_mobile_and_carrier',
args: { carrier: 'carrier' }
}
);
});
test('should add the proper css class', function() {
assert.isTrue(subject.node.classList.contains('additionalInfo'));
});
});
suite('when there aren\'t additional infos to display', function() {
setup(function() {
subject.replaceAdditionalContactInfo('', '');
});
test('should empty the text content', function() {
assert.equal(subject.additionalTelNode.textContent, '');
assert.equal(subject.additionalTelTypeNode.textContent, '');
});
test('should remove the css class', function() {
assert.isFalse(subject.node.classList.contains('additionalInfo'));
});
});
});
});
suite('phone number', function() {
test('formatPhoneNumber should call the font size manager if call is not' +
' in a conference', function() {
this.sinon.spy(FontSizeManager, 'adaptToSpace');
subject.formatPhoneNumber('end');
sinon.assert.calledWith(
FontSizeManager.adaptToSpace, MockCallScreen.mScenario,
subject.outerNode, false, 'end');
});
test('formatPhoneNumber should not call the font size manager if call is' +
' in a conference', function() {
subject.call.group = {};
this.sinon.spy(FontSizeManager, 'adaptToSpace');
subject.formatPhoneNumber('end');
assert.equal(FontSizeManager.adaptToSpace.callCount, 0);
delete subject.call.group;
});
test('should ensureFixedBaseline with a contact', function() {
mockCall = new MockCall('888', 'dialing');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
this.sinon.spy(FontSizeManager, 'ensureFixedBaseline');
subject.formatPhoneNumber('end');
sinon.assert.calledWith(
FontSizeManager.ensureFixedBaseline,
MockCallScreen.mScenario,
subject.numberNode
);
});
test('should call resetFixedBaseline without a contact', function() {
mockCall = new MockCall('111', 'dialing');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
this.sinon.spy(FontSizeManager, 'resetFixedBaseline');
subject.formatPhoneNumber('end');
sinon.assert.calledWith(
FontSizeManager.resetFixedBaseline, subject.numberNode);
});
test('check render number with regular number', function() {
mockCall = new MockCall('888', 'incoming');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
subject.renderPhoneNumber({ raw: '12345678' });
l10nAssert(subject.numberNode, { raw: '12345678' });
});
test('check render number with l10n id', function() {
mockCall = new MockCall('', 'incoming');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
subject.renderPhoneNumber('withheld-number');
l10nAssert(subject.numberNode, 'withheld-number');
});
test('check restore number', function() {
mockCall = new MockCall('888', 'incoming');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
subject.replacePhoneNumber({ raw: '12345678' });
subject.renderPhoneNumber('123');
subject.restorePhoneNumber();
l10nAssert(subject.numberNode, { raw: '12345678' });
});
test('check restore withheld-number', function() {
mockCall = new MockCall('', 'incoming');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
subject.replacePhoneNumber('withheld-number');
subject.renderPhoneNumber('123');
subject.restorePhoneNumber();
l10nAssert(subject.numberNode, 'withheld-number');
});
test('check restore voicemail number', function() {
mockCall = new MockCall(VOICEMAIL_NUMBER, 'incoming');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(true);
subject.renderPhoneNumber('123');
subject.restorePhoneNumber();
l10nAssert(subject.numberNode, 'voiceMail');
});
test('check restore emergency number', function() {
mockCall = new MockCall('112', 'incoming');
mockCall.emergency = true;
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
subject.renderPhoneNumber('123');
subject.restorePhoneNumber();
assert.equal(subject.numberNode.textContent, '112');
});
});
suite('caller photo', function() {
setup(function() {
MockCallScreen.mSetCallerContactImageCalled = false;
});
test('should reset photo when receiving a new handled call', function() {
mockCall = new MockCall('111', 'incoming');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
assert.isTrue(MockCallScreen.mSetCallerContactImageCalled);
});
});
suite('explicit visibility', function() {
test('calling show should show the node', function() {
subject.node.hidden = true;
subject.show();
assert.isFalse(subject.node.hidden);
});
test('calling show should update singleLine status', function() {
subject.show();
assert.isTrue(MockCallScreen.mUpdateSingleLineCalled);
});
test('calling hide should hide the node', function() {
subject.node.hidden = false;
subject.hide();
assert.isTrue(subject.node.hidden);
});
test('calling hide should update singleLine status', function() {
subject.show();
assert.isTrue(MockCallScreen.mUpdateSingleLineCalled);
});
suite('when the node got nullified', function() {
setup(function() {
subject.node = null;
});
test('show() should handle it', function() {
subject.show();
assert.isTrue(true); // We'll get a JS error otherwise
});
test('hide() should handle it', function() {
subject.hide();
assert.isTrue(true); // We'll get a JS error otherwise
});
});
});
suite('ongroupchange', function() {
var addToGroupDetailsSpy;
setup(function() {
mockCall = new MockCall(String(phoneNumber), 'connected');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
addToGroupDetailsSpy = this.sinon.spy(
ConferenceGroupHandler, 'addToGroupDetails');
this.sinon.spy(MockCallScreen, 'insertCall');
});
test('When entering a group, it should ask ' +
'the CallScreen to move into the group details', function() {
mockCall.group = this.sinon.stub();
mockCall.ongroupchange(mockCall);
assert.isTrue(addToGroupDetailsSpy.calledWith(subject.node));
assert.isFalse(MockCallScreen.mShowStatusMessageCalled);
});
suite('when leaving a group but still connected', function() {
setup(function() {
mockCall.group = null;
});
test('it should clone the call node if the participant list overlay is ' +
'shown', function() {
this.sinon.stub(
ConferenceGroupHandler, 'isGroupDetailsShown').returns(true);
var parent = document.createElement('div');
this.sinon.spy(parent, 'insertBefore');
parent.appendChild(subject.node);
mockCall.ongroupchange(mockCall);
sinon.assert.calledOnce(parent.insertBefore);
document.body.appendChild(subject.node);
});
test('it should move the call node back to the CallScreen', function() {
mockCall.ongroupchange(mockCall);
sinon.assert.calledWith(MockCallScreen.insertCall, subject.node);
});
test('it should not show any status message on disconnect', function() {
mockCall.ongroupchange(mockCall);
mockCall._disconnect();
assert.isFalse(MockCallScreen.mShowStatusMessageCalled);
});
});
suite('when leaving a group by hanging up', function() {
setup(function() {
mockCall.group = null;
mockCall.state = 'disconnecting';
mockCall.ongroupchange(mockCall);
});
test('it shouldn\'t move back to the CallScreen', function() {
sinon.assert.notCalled(MockCallScreen.insertCall);
assert.isFalse(MockCallScreen.mShowStatusMessageCalled);
});
test('it should show a status message.', function() {
mockCall._disconnect();
assert.isTrue(MockCallScreen.mShowStatusMessageCalled);
});
});
suite('when leaving a group by hanging up the whole group calls',
function() {
setup(function() {
mockCall.group = null;
mockCall.state = 'disconnecting';
subject.node.dataset.groupHangup = 'groupHangup';
mockCall.ongroupchange(mockCall);
});
test('it shouldn\'t move back',
function() {
sinon.assert.notCalled(MockCallScreen.insertCall);
});
test('it shouldn\'t show any status message',
function() {
mockCall._disconnect();
assert.isFalse(MockCallScreen.mShowStatusMessageCalled);
});
});
});
suite('Controls displayed when in a group', function() {
test('hangup button', function() {
mockCall = new MockCall(String(phoneNumber), 'connected');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
var hangUpSpy = this.sinon.spy(mockCall, 'hangUp');
subject.hangupButton.onclick();
assert.isTrue(hangUpSpy.calledOnce);
});
});
suite('DSDS SIM display >', function() {
setup(function() {
MockNavigatorMozIccManager.addIcc('12345', {'cardState': 'ready'});
});
suite('One SIM >', function() {
test('should hide the sim nodes', function() {
mockCall = new MockCall('888', 'outgoing');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
assert.isTrue(subject.viaSimNode.hidden);
assert.isTrue(subject.simNumberNode.hidden);
});
});
suite('Multiple SIMs >', function() {
setup(function() {
MockNavigatorMozIccManager.addIcc('424242', {'cardState': 'ready'});
});
test('should show which sim is in use', function() {
mockCall = new MockCall('888', 'outgoing');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
assert.isFalse(subject.viaSimNode.hidden);
assert.isFalse(subject.simNumberNode.hidden);
l10nAssert(subject.viaSimNode, { id: 'via-sim', args: { n: 2 } });
l10nAssert(subject.simNumberNode, { id: 'sim-number', args: { n: 2 } });
});
});
});
suite('STK Call Control changes Number', function() {
test('should resolve to changed contact', function() {
mockCall = new MockCall('111', 'dialing');
subject = new HandledCall(mockCall);
assert.equal(subject.numberNode.textContent, '');
//simulate the STK change to a different number
mockCall.id.number = '555';
mockCall._connect();
MockVoicemail.mResolvePromise(false);
assert.equal(subject.numberNode.textContent, 'test name');
});
test('should resolve to number if no contact', function() {
mockCall = new MockCall('555', 'dialing');
subject = new HandledCall(mockCall);
assert.equal(subject.numberNode.textContent, '');
//simulate the STK change to a different number
mockCall.id.number = '111';
mockCall._connect();
MockVoicemail.mResolvePromise(false);
assert.equal(subject.numberNode.textContent, '111');
});
test('should resolve to voicemail', function() {
//simulate the STK change to a different number
mockCall = new MockCall('111', 'dialing');
subject = new HandledCall(mockCall);
mockCall.id.number = '123';
mockCall._connect();
MockVoicemail.mResolvePromise(true);
l10nAssert(subject.numberNode, 'voiceMail');
});
test('should correctly identify emergency', function() {
mockCall = new MockCall('555', 'dialing');
subject = new HandledCall(mockCall);
MockVoicemail.mResolvePromise(false);
mockCall.id.number = '112';
mockCall.emergency = true;
mockCall._connect();
l10nAssert(subject.additionalTelNode, 'emergencyNumber');
assert.isTrue(subject.node.classList.contains('emergency'));
assert.isTrue(subject.node.textContent.includes('112'));
});
});
suite('Resizing the call ended string', function() {
var durationChildNode;
setup(function() {
durationChildNode = subject.node.querySelector('.duration span');
durationChildNode.textContent = 'Call ended';
this.sinon.spy(subject.mutationObserver, 'disconnect');
this.sinon.spy(subject.mutationObserver, 'observe');
this.sinon.spy(subject, 'computeCallEndedFontSizeRules');
});
test('Does not resize the string if no l10n attribute is present',
function() {
subject.observeMutation();
sinon.assert.notCalled(subject.mutationObserver.disconnect);
sinon.assert.notCalled(subject.mutationObserver.observe);
sinon.assert.notCalled(subject.computeCallEndedFontSizeRules);
});
test('Disconnects and reconnects the observer before adjusting the string',
function() {
durationChildNode.setAttribute('data-l10n-id', 'callEnded');
subject.observeMutation();
assert.isTrue(
subject.mutationObserver.disconnect.calledBefore(
subject.computeCallEndedFontSizeRules
)
);
assert.isTrue(
subject.mutationObserver.observe.calledAfter(
subject.computeCallEndedFontSizeRules
)
);
});
});
});