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.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,259 @@
/*global MocksHelper, Contacts, MockMozContactsObj,
MockasyncStorage, Mockfb
*/
'use strict';
require('/shared/test/unit/mocks/mock_mozContacts.js');
require('/shared/test/unit/mocks/mock_contact_all_fields.js');
require('/shared/test/unit/mocks/mock_lazy_loader.js');
require('/shared/test/unit/mocks/mock_async_storage.js');
require('/shared//test/unit/mocks/mock_simple_phone_matcher.js');
require('/apps/communications/contacts/test/unit/mock_fb.js');
var mocksHelperForContacts = new MocksHelper([
'asyncStorage',
'LazyLoader',
'SimplePhoneMatcher',
'fb'
]);
mocksHelperForContacts.init();
require('/shared/js/dialer/contacts.js');
suite('dialer/contacts', function() {
var realMozContacts;
var searchNumber = '3334445555';
var mozContactNum = '638883';
var aMozTestContact = {
id: 'abcdef',
givenName: ['Carlos'],
familyName: ['Fernández'],
tel: [
{
type: ['home'],
value: mozContactNum
}
]
};
var aFacebookContact = {
id:'567',
updated: 'date',
additionalName:['Green'],
adr:[{type:['home'],locality:'Palencia', region:'Castilla y León',
countryName:'España'},{type:['current'], locality:'Greater London',
region:'London', countryName:'United Kingdom'}],
bday:'Thu, 01 Jan 1970 00:00:00 GMT',
email:[{type:['personal'],value:'test@test.com'},
{type:['work'],value:'test@work.com',pref:true}],
honorificPrefix:['Mr.'],familyName:['Taylor'],givenName:['Bret'],
nickname:['PG'],jobTitle:['Sr. Software Architect'],name:['Bret Taylor'],
org:['FB'],tel:[{value:'+346578888888',type:['mobile'],carrier:'TEF',
pref:true},{value:'+3120777777',type:['Home'],carrier:'KPN'}],
url:[{type:['fb_profile_photo'],value:'https://abcd1.jpg'}],
category:['favorite','facebook','not_linked',220439],note:['Note 1'],
photo:[{}]
};
aFacebookContact.bday = new Date(0);
mocksHelperForContacts.attachTestHelpers();
function checkContacts (test, expected) {
for (var key in expected) {
if (key !== 'photo') {
assert.deepEqual(test[key], expected[key], 'Contact.' + key);
}
}
}
suiteSetup(function() {
realMozContacts = navigator.mozContacts;
navigator.mozContacts = new MockMozContactsObj([aMozTestContact]);
});
suiteTeardown(function() {
navigator.mozContacts = realMozContacts;
});
suite('> Contacts Revision', function() {
test('> Should return revision', function(done) {
Contacts.getRevision(function(status) {
done(function() {
assert.deepEqual(status, 'fakeRevision');
});
});
});
});
suite('> FindByNumber', function() {
var expectedMatchingTel = {type: ['home'], value: mozContactNum };
var expectedMatchingContact = {id: 'abcdef', givenName: ['Carlos'],
familyName: ['Fernández'],
tel: [expectedMatchingTel]};
setup(function() {
this.sinon.spy(navigator.mozContacts, 'find');
this.sinon.spy(Mockfb, 'getContactByNumber');
this.sinon.spy(Mockfb, 'getData');
});
test('should find the exact number for < 7 digits', function() {
var options = {
filterBy: ['tel'],
filterOp: 'equals',
filterValue: mozContactNum
};
Contacts.findByNumber(mozContactNum, function(contact, matchingTel) {
sinon.assert.calledWith(navigator.mozContacts.find, options);
assert.deepEqual(matchingTel, expectedMatchingTel);
assert.deepEqual(contact, expectedMatchingContact);
});
});
test('should find numbers matching for >= 7 digits', function() {
var options = {
filterBy: ['tel'],
filterOp: 'match',
filterValue: '6388830123'
};
Contacts.findByNumber('6388830123', function(contact, matchingTel) {
sinon.assert.calledWith(navigator.mozContacts.find, options);
assert.deepEqual(matchingTel, expectedMatchingTel);
assert.deepEqual(contact, expectedMatchingContact);
});
});
test('should search FB if no MozContact found', function() {
navigator.mozContacts.setContacts([]);
Contacts.findByNumber('6388830123', function(contact, matchingTel) {
sinon.assert.calledWith(Mockfb.getContactByNumber, '6388830123');
});
});
test('should NOT search FB if MozContact found', function() {
navigator.mozContacts.setContacts([aMozTestContact]);
Contacts.findByNumber(mozContactNum, function(contact, matchingTel) {
sinon.assert.notCalled(Mockfb.getContactByNumber);
assert.deepEqual(matchingTel, expectedMatchingTel);
assert.deepEqual(contact, expectedMatchingContact);
});
});
test('should return null if no FB or MozContact found', function() {
navigator.mozContacts.setContacts([]);
Mockfb.setEmptyContacts();
Contacts.findByNumber(searchNumber, function(contact, matchingTel) {
assert.isNull(contact);
});
});
test('should merge w/FB if contact is facebook linked', function() {
navigator.mozContacts.setContacts([aMozTestContact]);
Mockfb.setIsFbLinked(true);
Contacts.findByNumber(mozContactNum, function(contact, matchingTel) {
sinon.assert.calledOnce(Mockfb.getData);
assert.deepEqual(matchingTel, expectedMatchingTel);
//Check that the facebook data was added. Fake out the date (but
//validate it's a date format first) to avoid having the test fail
//due to date being mismatched.
assert.ok(contact.updated instanceof Date &&
!isNaN(contact.updated.valueOf()));
contact.updated = 'date';
checkContacts(contact, aFacebookContact);
});
});
test('should NOT merge w/FB if not linked', function() {
navigator.mozContacts.setContacts([aMozTestContact]);
Mockfb.setIsFbLinked(false);
Contacts.findByNumber(searchNumber, function(contact, matchingTel) {
sinon.assert.notCalled(Mockfb.getData);
assert.notEqual(contact.id, '567');
assert.isUndefined(contact.jobTitle);
});
});
});
suite('> FindListByNumber ', function() {
var limit = 20;
setup(function() {
this.sinon.spy(navigator.mozContacts, 'find');
this.sinon.spy(Mockfb, 'isFbContact');
this.sinon.spy(Mockfb, 'getData');
this.sinon.stub(MockasyncStorage, 'getItem');
});
teardown(function() {
MockasyncStorage.getItem.restore();
});
test('should call find with correct filter option', function() {
//From contacts.js
var options = {
filterBy: ['tel'],
filterOp: 'contains',
filterValue: searchNumber,
sortBy: 'familyName',
sortOrder: 'ascending',
filterLimit: limit
};
Contacts.findListByNumber(searchNumber, limit, function() {
sinon.assert.calledWith(navigator.mozContacts.find, options);
});
});
test('should merge w/FB contacts if mozContacts are also FB contacts',
function() {
Mockfb.setIsFbContact(true);
navigator.mozContacts.setContacts([aMozTestContact]);
MockasyncStorage.getItem.yields(false);
Contacts.findListByNumber(limit, searchNumber, function(contacts) {
sinon.assert.called(Mockfb.isFbContact);
sinon.assert.called(Mockfb.getData);
//Check that the facebook data was added. Fake out the date (but
//validate it's a date format first) to avoid having the test fail
//due to date being mismatched.
assert.ok(contacts[0].updated instanceof Date &&
!isNaN(contacts[0].updated.valueOf()));
contacts[0].updated = 'date';
// Phone numbers haven't been merged
aFacebookContact.tel = aMozTestContact.tel;
checkContacts(contacts[0], aFacebookContact);
});
});
test('should not merge w/FB contacts if mozContacts is not FB contacts',
function() {
Mockfb.setIsFbContact(false);
navigator.mozContacts.setContacts([aMozTestContact]);
MockasyncStorage.getItem.yields(true);
Contacts.findListByNumber(limit, searchNumber, function(contacts) {
sinon.assert.called(Mockfb.isFbContact);
//Check that facebook data was not added
assert.isUndefined(contacts[0].honorificPrefix);
assert.isUndefined(contacts[0].jobTitle);
assert.isUndefined(contacts[0].org);
assert.isUndefined(contacts[0].note);
//Check that existing MozContact data is unchanged
assert.deepEqual(contacts[0], aMozTestContact);
});
});
test('should NOT get FB contacts if no MozContacts found', function() {
navigator.mozContacts.setContacts([]);
Contacts.findListByNumber(searchNumber, limit, function(contacts) {
sinon.assert.notCalled(Mockfb.isFbContact);
assert.isNull(contacts);
});
});
});
});

View file

@ -0,0 +1,327 @@
/* globals FontSizeManager, FontSizeUtils, MocksHelper, MockL10n */
'use strict';
require('/shared/test/unit/mocks/mock_font_size_utils.js');
require('/shared/test/unit/mocks/mock_l10n.js');
require('/shared/js/dialer/font_size_manager.js');
var mocksHelperForCallScreen = new MocksHelper([
'FontSizeUtils'
]).init();
suite('font size manager', function() {
var ROOT_FONT_SIZE = 10;
var realMozL10n;
var view;
var bdiNode;
var innerEl;
mocksHelperForCallScreen.attachTestHelpers();
suiteSetup(function() {
realMozL10n = navigator.mozL10n;
navigator.mozL10n = MockL10n;
});
suiteTeardown(function() {
navigator.mozL10n = realMozL10n;
});
suite('adaptToSpace', function() {
setup(function() {
this.sinon.stub(FontSizeUtils, 'getMaxFontSizeInfo');
});
var scenarios = [0, // FontSizeManager.DIAL_PAD
1, // FontSizeManager.SINGLE_CALL
2, // FontSizeManager.CALL_WAITING
3, // FontSizeManager.STATUS_BAR
4]; // FontSizeManager.SECOND_INCOMING_CALL
scenarios.forEach(function(scenario) {
test('does nothing for empty inputs, scenario ' + scenario, function() {
view = document.createElement('input');
document.body.appendChild(view);
FontSizeManager.adaptToSpace(scenario, view);
assert.equal(view.style.fontSize, '');
});
test('does nothing for empty elements, scenario ' + scenario, function() {
view.textContent = '';
FontSizeManager.adaptToSpace(scenario, view);
assert.equal(view.style.fontSize, '');
});
});
var viewElements = [
{
element: 'div',
textField: 'textContent'
},
{
element: 'input',
textField: 'value'
},
{
element: 'div',
childElement: 'bdi',
textField: 'textContent'
}
];
viewElements.forEach(function(viewElement) {
suite('on ' + viewElement.element, function() {
var getExpectedEllipsizedText = function(side, direction) {
// MockL10n does not invert text when in RTL mode, but FSM will
// treat the left side as the end for the purpose of ellipses.
return side === 'end' ? 'fo\u2026' : '\u2026ar';
};
setup(function() {
document.documentElement.style.fontSize = ROOT_FONT_SIZE + 'px';
view = document.createElement(viewElement.element);
if(viewElement.childElement) {
innerEl = document.createElement(viewElement.childElement);
view.appendChild(innerEl);
} else {
innerEl = view;
}
innerEl[viewElement.textField] = 'foobar';
document.body.appendChild(view);
});
teardown(function() {
document.body.innerHTML = '';
});
test('calls FSU with the proper arguments', function() {
FontSizeUtils.getMaxFontSizeInfo.returns({
fontSize: 10,
overflow: false
});
view.style.fontFamily = 'Arial';
view.style.width = '200px';
FontSizeManager.adaptToSpace(FontSizeManager.DIAL_PAD, view);
sinon.assert.calledWith(FontSizeUtils.getMaxFontSizeInfo,
view[viewElement.textField],
[26, 30, 34, 38, 41],
view.style.fontFamily,
view.getBoundingClientRect().width);
});
test('changes the font size', function() {
FontSizeUtils.getMaxFontSizeInfo.returns({
fontSize: 42,
overflow: false
});
FontSizeManager.adaptToSpace(FontSizeManager.DIAL_PAD, view);
assert.equal(view.style.fontSize, '42px');
});
test('forces maxfontsize', function() {
FontSizeUtils.getMaxFontSizeInfo.returns({
fontSize: 10,
overflow: false
});
FontSizeManager.adaptToSpace(FontSizeManager.DIAL_PAD, view, true);
sinon.assert.calledWith(FontSizeUtils.getMaxFontSizeInfo,
view[viewElement.textField],
[41]);
});
suite('ellipses in LTR/RTL modes', function() {
var l10nLanguageDirection;
suiteSetup(function() {
l10nLanguageDirection = MockL10n.language.direction;
});
suiteTeardown(function() {
MockL10n.language.direction = l10nLanguageDirection;
});
['ltr', 'rtl'].forEach(function(direction) {
test('adds ellipsis', function() {
MockL10n.language.direction = direction;
FontSizeUtils.getMaxFontSizeInfo.returns({
fontSize: 10,
overflow: true
});
this.sinon.stub(FontSizeUtils, 'getOverflowCount').returns(2);
FontSizeManager.adaptToSpace(FontSizeManager.DIAL_PAD, view,
true);
assert.equal(view[viewElement.textField],
getExpectedEllipsizedText('begin', direction));
});
test('adds ellipsis to the correct side', function() {
MockL10n.language.direction = direction;
FontSizeUtils.getMaxFontSizeInfo.returns({
fontSize: 10,
overflow: true
});
this.sinon.stub(FontSizeUtils, 'getOverflowCount').returns(2);
FontSizeManager.adaptToSpace(FontSizeManager.DIAL_PAD, view, true,
'end');
assert.equal(view[viewElement.textField],
getExpectedEllipsizedText('end', direction));
});
});
});
});
});
suite('special view cases', function() {
var originalFontSize;
setup(function() {
document.documentElement.style.fontSize = ROOT_FONT_SIZE + 'px';
FontSizeUtils.getMaxFontSizeInfo.returns({
fontSize: 42,
overflow: false
});
});
teardown(function() {
document.body.innerHTML = '';
});
suite('on <input> with no value', function() {
setup(function() {
view = document.createElement('input');
document.body.appendChild(view);
});
test('no adaptation is made', function() {
FontSizeManager.adaptToSpace(FontSizeManager.DIAL_PAD, view);
assert.notEqual(view.style.fontSize, '42px');
});
});
suite('on child <bdi>', function() {
setup(function() {
originalFontSize = document.documentElement.style.fontSize;
document.documentElement.style.fontSize = ROOT_FONT_SIZE + 'px';
bdiNode = document.createElement('bdi');
bdiNode.textContent = 'testing';
view = document.createElement('div');
view.appendChild(bdiNode);
document.body.appendChild(view);
});
teardown(function() {
document.body.innerHTML = '';
document.documentElement.style.fontSize = originalFontSize;
});
test('bdi Node is preserved', function() {
FontSizeUtils.getMaxFontSizeInfo.returns({
fontSize: 42,
overflow: true
});
FontSizeManager.adaptToSpace(FontSizeManager.SINGLE_CALL, view);
var el = view.querySelector('bdi');
assert.isNotNull(el);
});
});
suite('on <div> with no text content', function() {
setup(function() {
view = document.createElement('div');
document.body.appendChild(view);
});
test('no adaptation is made', function() {
FontSizeManager.adaptToSpace(FontSizeManager.DIAL_PAD, view);
assert.notEqual(view.style.fontSize, '42px');
});
});
// Bug 1082139 - JavascriptException: JavascriptException: TypeError:
// window.getComputedStyle(...) is null at://
// app://callscreen.gaiamobile.org/gaia_build_defer_index.js line: 146
suite('if window.getComputedStyle(view) is null', function() {
setup(function() {
view = document.createElement('input');
view.value = 'foobar';
document.body.appendChild(view);
this.sinon.stub(window, 'getComputedStyle').returns(null);
});
test('no adaptation is made', function() {
FontSizeManager.adaptToSpace(FontSizeManager.DIAL_PAD, view);
assert.notEqual(view.style.fontSize, '42px');
});
});
});
});
suite('ensureFixedBaseline', function() {
setup(function() {
document.documentElement.style.fontSize = ROOT_FONT_SIZE + 'px';
view = document.createElement('div');
view.textContent = 'foobar';
document.body.appendChild(view);
});
teardown(function() {
document.body.innerHTML = '';
});
test('sets correct line heights', function() {
FontSizeManager.ensureFixedBaseline(FontSizeManager.SINGLE_CALL, view);
assert.equal(view.style.lineHeight, '46px');
view.style.fontSize = '100px';
FontSizeManager.ensureFixedBaseline(FontSizeManager.SINGLE_CALL, view);
assert.equal(view.style.lineHeight, '1px');
});
});
suite('resetFixedBaseline', function() {
setup(function() {
view = document.createElement('div');
view.textContent = 'foobar';
view.style.lineHeight = '12px';
document.body.appendChild(view);
});
teardown(function() {
document.body.innerHTML = '';
});
test('resets line heights', function() {
FontSizeManager.resetFixedBaseline(view);
assert.equal(view.style.lineHeight, '');
});
});
});

View file

@ -0,0 +1,253 @@
'use strict';
/* globals MocksHelper, TelephonyMessages, MockConfirmDialog, LazyLoader */
require('/shared/test/unit/mocks/mock_lazy_loader.js');
require('/shared/test/unit/mocks/mock_confirm_dialog.js');
require('/shared/test/unit/mocks/dialer/mock_tone_player.js');
require('/shared/test/unit/mocks/dialer/mock_telephony_messages.js');
require('/shared/js/dialer/telephony_messages.js');
var mocksHelperForTelephonyMessages = new MocksHelper([
'LazyLoader',
'TonePlayer',
'ConfirmDialog'
]);
suite('Telephony messages', function() {
var subject;
mocksHelperForTelephonyMessages.attachTestHelpers();
suiteSetup(function() {
subject = TelephonyMessages;
});
setup(function() {
// This doesn't really matter. We do this to prevent the output from
// appearing during testing.
this.sinon.stub(console, 'error');
});
suite('Display messages', function() {
var expectedMessages = [
{
message: 'BadNumber',
title: 'invalidNumberToDialTitle',
body: 'invalidNumberToDialMessage'
},
{
message: 'FlightMode',
title: 'callAirplaneModeTitle',
body: 'callAirplaneModeMessage'
},
{
message: 'NoNetwork',
title: 'emergencyDialogTitle',
body: 'emergencyDialogBodyBadNumber'
},
{
message: 'DeviceNotAccepted',
title: 'emergencyDialogTitle',
body: 'emergencyDialogBodyDeviceNotAccepted'
},
{
message: 'UnableToCall',
title: 'unableToCallTitle',
body: 'unableToCallMessage'
},
{
message: 'NumberIsBusy',
title: 'numberIsBusyTitle',
body: 'numberIsBusyMessage'
},
{
message: 'FixedDialingNumbers',
title: 'fdnIsActiveTitle',
body: 'fdnIsActiveMessage'
},
{
message: 'OtherConnectionInUse',
title: 'otherConnectionInUseTitle',
body: 'otherConnectionInUseMessage'
},
{
message: 'EmergencyCallOnly',
title: 'emergency-call-only',
body: 'emergency-call-error'
},
{
message: 'OperatorDeterminedBarring',
title: 'unableToCallTitle',
body: 'callBarredByTheOperatorMessage'
}
];
setup(function() {
this.sinon.spy(MockConfirmDialog, 'show');
});
suite('Lazyloading', function() {
setup(function() {
this.sinon.spy(LazyLoader, 'load');
});
test('Loads #confirmation-message element', function() {
var confirmationMessage = document.createElement('span');
confirmationMessage.id = 'confirmation-message';
document.body.appendChild(confirmationMessage);
subject.displayMessage('BadNumber');
assert.notEqual(
LazyLoader.load.args[0][0].indexOf(confirmationMessage), -1);
document.body.removeChild(confirmationMessage);
});
test('Loads ConfirmDialog', function() {
subject.displayMessage('BadNumber');
assert.notEqual(
LazyLoader.load.args[0][0].indexOf('/shared/style/confirm.css'), -1);
assert.notEqual(
LazyLoader.load.args[0][0].indexOf('/shared/js/confirm.js'), -1);
});
});
expectedMessages.forEach(function(messageTuple) {
test(messageTuple.message + ' displays message ' + messageTuple.title,
function() {
subject.displayMessage(messageTuple.message, '123');
sinon.assert.calledWith(MockConfirmDialog.show, messageTuple.title,
{id: messageTuple.body, args: {number: '123'}});
});
});
test('Invalid input message doesn\'t display anything', function() {
subject.displayMessage('asdfghjkl');
sinon.assert.notCalled(MockConfirmDialog.show);
});
suite('ConfirmDialog', function() {
test('Calls ConfirmDialog.show() with correct args', function() {
subject.displayMessage('BadNumber', '123');
assert.equal(MockConfirmDialog.show.args[0][2].title,
'emergencyDialogBtnOk');
assert.equal(typeof MockConfirmDialog.show.args[0][2].callback,
'function');
});
test('Clicking a button closes the ConfirmDialog', function() {
this.sinon.spy(MockConfirmDialog, 'hide');
subject.displayMessage('BadNumber', '123');
MockConfirmDialog.show.args[0][2].callback();
sinon.assert.calledOnce(MockConfirmDialog.hide);
});
});
});
suite('Disconnection handling', function() {
setup(function() {
this.sinon.spy(subject, 'handleError');
});
test('normal call clearing', function() {
subject.handleDisconnect(
'NormalCallClearing', '123', subject.REGULAR_CALL
);
sinon.assert.notCalled(subject.handleError);
});
test('abnormal call disconnection', function() {
var reason = 'Busy';
subject.handleDisconnect(reason, '123', subject.REGULAR_CALL);
sinon.assert.calledWith(
subject.handleError, reason + 'Error', '123', subject.REGULAR_CALL
);
});
});
suite('Error handling', function() {
var expectedErrors = [
{
error: 'BadNumberError',
message: 'BadNumber'
},
{
error: 'DeviceNotAcceptedError',
message: 'DeviceNotAccepted',
},
{
error: 'RadioNotAvailable',
message: 'FlightMode'
},
{
error: 'BusyError',
message: 'NumberIsBusy'
},
{
error: 'OtherConnectionInUse',
message: 'OtherConnectionInUse'
},
{
error: 'OperatorDeterminedBarringError',
message: 'OperatorDeterminedBarring'
},
{
// This is not an actual type. It is the catch-all for unhandled errors.
error: 'Unknown/unhandled error',
message: 'UnableToCall'
}
];
setup(function() {
this.sinon.spy(subject, 'displayMessage');
});
expectedErrors.forEach(function(errorTuple) {
test(errorTuple.error + ' displays ' + errorTuple.message + ' error',
function() {
subject.handleError(errorTuple.error, '123', subject.REGULAR_CALL);
sinon.assert.calledWith(subject.displayMessage, errorTuple.message);
});
});
test('FDNBlockedError displays FixedDialingNumbers error', function() {
subject.handleError('FDNBlockedError', '123', subject.REGULAR_CALL);
sinon.assert.calledWith(
subject.displayMessage, 'FixedDialingNumbers', '123');
});
test('FdnCheckFailure displays FixedDialingNumbers error', function() {
subject.handleError('FdnCheckFailure', '123', subject.REGULAR_CALL);
sinon.assert.calledWith(
subject.displayMessage, 'FixedDialingNumbers', '123');
});
test('BusyError displays NumberIsBusy error', function() {
subject.handleError('BusyError');
sinon.assert.calledWith(subject.displayMessage, 'NumberIsBusy');
});
test('BadNumberError displays NoNetwork error (no network)', function() {
subject.handleError('BadNumberError', '123', subject.NO_NETWORK);
sinon.assert.calledWith(subject.displayMessage, 'NoNetwork');
});
test('BadNumberError displays EmergencyCallOnly error (emergency only)',
function() {
subject.handleError('BadNumberError', '123', subject.EMERGENCY_ONLY);
sinon.assert.calledWith(subject.displayMessage, 'EmergencyCallOnly');
});
test('ModifiedDialError not displayed', function() {
subject.handleError('ModifiedDialError');
sinon.assert.notCalled(subject.displayMessage);
});
});
});

View file

@ -0,0 +1,230 @@
/* global MockL10n, Utils, l10nAssert */
'use strict';
require('/shared/test/unit/mocks/dialer/mock_contacts.js');
require('/shared/test/unit/mocks/mock_l10n.js');
require('/shared/js/dialer/utils.js');
suite('dialer/utils', function() {
var realL10n;
var subject;
suiteSetup(function() {
realL10n = navigator.mozL10n;
navigator.mozL10n = MockL10n;
subject = Utils;
});
suiteTeardown(function() {
navigator.mozL10n = realL10n;
});
suite('Utility library', function() {
test('#headerDate should identify yesterday as a time range', function() {
var timestamp = Math.round(new Date().getTime() / 1000);
var tsYesterday = (timestamp - (25 * 3600)) * 1000;
var elem = document.createElement('span');
subject.setHeaderDate(elem, tsYesterday);
l10nAssert(elem, 'yesterday');
});
test('#headerDate should identify today as a time range', function() {
var tsToday = Math.round(new Date().getTime());
var elem = document.createElement('span');
subject.setHeaderDate(elem, tsToday);
l10nAssert(elem, 'today');
});
test('#headerDate should format 3 days ago as a weekday name', function() {
var ts = Math.round(new Date().getTime() / 1000);
var ts3DaysAgo = (ts - (73 * 3600)) * 1000;
var threeDaysAgo = new
Date(ts3DaysAgo).toLocaleString(navigator.languages, {
weekday: 'long'
});
var elem = document.createElement('span');
subject.setHeaderDate(elem, ts3DaysAgo);
assert.equal(elem.textContent, threeDaysAgo);
});
test('#headerDate should format a week ago as a date', function() {
var ts = Math.round(new Date().getTime() / 1000);
var tsWeekAgo = (ts - (193 * 3600)) * 1000;
var weekAgo = new
Date(tsWeekAgo).toLocaleString(navigator.languages, {
year: '2-digit',
month: '2-digit',
day: '2-digit'
});
var elem = document.createElement('span');
subject.setHeaderDate(elem, tsWeekAgo);
assert.equal(elem.textContent, weekAgo);
});
test('#headerDate should identify incorrect date', function() {
var elem = document.createElement('span');
subject.setHeaderDate(elem, 'not-a-date');
l10nAssert(elem, 'incorrectDate');
});
test('#prettyDate should identify 12 hour time', function() {
var tsToday = Math.round(new Date().getTime());
window.navigator.mozHour12 = true;
var hourString = new
Date(tsToday).toLocaleString(navigator.languages, {
hour12: navigator.mozHour12,
hour: 'numeric',
minute: 'numeric'
});
assert.equal(subject.prettyDate(tsToday), hourString);
});
test('#prettyDate should identify 24 hour time', function() {
var tsToday = Math.round(new Date().getTime());
window.navigator.mozHour12 = false;
var hourString = new
Date(tsToday).toLocaleString(navigator.languages, {
hour12: navigator.mozHour12,
hour: 'numeric',
minute: 'numeric'
});
assert.equal(subject.prettyDate(tsToday), hourString);
});
});
suite('prettyDuration', function() {
var durationNode;
setup(function() {
durationNode = document.createElement('div');
this.sinon.spy(MockL10n, 'setAttributes');
});
test('formats as minutes if less than one hour', function() {
Utils.prettyDuration(durationNode, 60 * 60 * 1000 - 1);
sinon.assert.calledWith(MockL10n.setAttributes, durationNode,
'callDurationMinutes', { h: '00', m: '59', s: '59' });
});
test('formats with hours if more than one hour', function() {
Utils.prettyDuration(durationNode, 60 * 60 * 1000);
sinon.assert.calledWith(MockL10n.setAttributes, durationNode,
'callDurationHours', { h: '01', m: '00', s: '00' });
});
test('Single digits are padded', function() {
var hours = 2;
var minutes = 4;
var seconds = 7;
var duration = hours * 60 * 60 + minutes * 60 + seconds;
Utils.prettyDuration(durationNode, duration * 1000);
sinon.assert.calledWith(MockL10n.setAttributes, durationNode,
'callDurationHours', { h: '02', m: '04', s: '07' });
});
suite('When using text format', function() {
test('single digits are not padded', function() {
var hours = 1;
var minutes = 4;
var seconds = 2;
var duration = hours * 60 * 60 + minutes * 60 + seconds;
Utils.prettyDuration(durationNode, duration * 1000,
'callDurationTextFormat');
sinon.assert.calledWith(MockL10n.setAttributes, durationNode,
'callDurationTextFormatHours', { h: '1', m: '4', s: '2' });
});
test('formats as minutes if less than one hour', function() {
Utils.prettyDuration(durationNode, 60 * 60 * 1000 - 1,
'callDurationTextFormat');
sinon.assert.calledWith(MockL10n.setAttributes, durationNode,
'callDurationTextFormatMinutes', { h: '0', m: '59', s: '59' });
});
test('formats as seconds if less than one minute', function() {
Utils.prettyDuration(durationNode, 60 * 1000 - 1,
'callDurationTextFormat');
sinon.assert.calledWith(MockL10n.setAttributes, durationNode,
'callDurationTextFormatSeconds', { h: '0', m: '0', s: '59' });
});
});
suite('isPhoneType()', function() {
test('Identifies known phone types correctly', function() {
[
'mobile',
'home',
'work',
'personal',
'faxHome',
'faxOffice',
'faxOther',
'other'
].forEach(type => { assert.isTrue(Utils.isPhoneType(type)); });
});
test('Identifies unknown types correctly', function() {
assert.isFalse(Utils.isPhoneType('custom-phone-type'));
});
});
suite('getPhoneNumberAdditionalInfo()', function() {
var dummyCarrier = 'Dummy carrier';
var dummyCustomType = 'My custom type';
test('No type, no carrier', function() {
var result = Utils.getPhoneNumberAdditionalInfo({});
assert.deepEqual(result, {id: 'phone_type_mobile', args: null});
});
test('Specific type, no carrier', function() {
var result = Utils.getPhoneNumberAdditionalInfo({
type: 'work'
});
assert.deepEqual(result, {id: 'phone_type_work', args: null});
});
test('Custom type, no carrier', function() {
var result = Utils.getPhoneNumberAdditionalInfo({
type: dummyCustomType
});
assert.propertyVal(result, 'id', 'phone_type_custom');
assert.deepPropertyVal(result, 'args.type', dummyCustomType);
});
test('No type with carrier', function() {
var result = Utils.getPhoneNumberAdditionalInfo({
carrier: dummyCarrier
});
assert.propertyVal(result, 'id', 'phone_type_mobile_and_carrier');
assert.deepPropertyVal(result, 'args.carrier', dummyCarrier);
});
test('Specific type with carrier', function() {
var result = Utils.getPhoneNumberAdditionalInfo({
carrier: dummyCarrier,
type: 'work'
});
assert.propertyVal(result, 'id', 'phone_type_work_and_carrier');
assert.deepPropertyVal(result, 'args.carrier', dummyCarrier);
});
test('Custom type with carrier', function() {
var result = Utils.getPhoneNumberAdditionalInfo({
carrier: dummyCarrier,
type: dummyCustomType
});
assert.propertyVal(result, 'id', 'phone_type_custom_and_carrier');
assert.deepPropertyVal(result, 'args.carrier', dummyCarrier);
assert.deepPropertyVal(result, 'args.type', dummyCustomType);
});
});
});
});