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,10 @@
/* exported MockContactsButtons */
'use strict';
var MockContactsButtons = {
init: function() {},
renderPhones: function() {},
renderEmails: function() {},
reMark: function() {}
};

View file

@ -0,0 +1,86 @@
'use strict';
/* exported MockCall */
function MockCall(aNumber, aState, aServiceId) {
this._eventListeners = {
'connected': [],
'disconnected': [],
'statechange': []
};
this.id = { number: aNumber };
this.serviceId = (aServiceId === undefined) ? 1 : aServiceId;
this.state = aState;
this.switchable = true; // The call can be put on hold by default
this.mergeable = true; // The call can be merged by default
this.answer = function() {
this._connect();
};
this.hangUp = function() {
this._disconnect();
};
this.hold = function() {};
this.resume = function() {};
this.mEmergencyNumbers = ['112', '911'];
this.emergency = this.mEmergencyNumbers.indexOf(aNumber) >= 0;
this.mVoicemailNumbers = ['123'];
this.voicemail = this.mVoicemailNumbers.indexOf(aNumber) >= 0;
this.addEventListener = (function(type, handler) {
if (this._eventListeners[type]) {
this._eventListeners[type].push(handler);
}
}).bind(this);
this.removeEventListener = (function(type, handler) {
if (this._eventListeners[type]) {
var idx = this._eventListeners[type].indexOf(handler);
this._eventListeners[type].splice(idx, 1);
}
}).bind(this);
this.triggerEvent = function(type) {
this._mTriggerEventListeners(type);
},
// Mocking the events
this.mChangeState = (function(state) {
this.state = state;
this._mTriggerEventListeners('statechange');
}).bind(this);
this._connect = this.mChangeState.bind(this, 'connected');
this._disconnect = (function() {
this.mChangeState('disconnected');
this._mTriggerEventListeners('disconnected');
}).bind(this);
this._hold = (function() {
this.mChangeState('held');
}).bind(this);
this._resume = (function() {
this.mChangeState('connected');
}).bind(this);
this._mTriggerEventListeners = function(type) {
if (!this._eventListeners[type]) {
return;
}
var self = this;
this._eventListeners[type].forEach(function(callback) {
if (typeof callback === 'function') {
callback({call: self});
} else if (typeof callback == 'object' &&
typeof callback.handleEvent === 'function') {
callback.handleEvent({call: self});
}
});
};
}

View file

@ -0,0 +1,44 @@
'use strict';
/* exported MockCallsHandler */
var MockCallsHandler = {
mActiveCall: null,
mActiveCallForContactImage: null,
mIsFirstCallOnCdmaNetwork: false,
get activeCall() {
return this.mActiveCall;
},
get activeCallForContactImage() {
return this.mActiveCallForContactImage;
},
isFirstCallOnCdmaNetwork: function() {
return this.mIsFirstCallOnCdmaNetwork;
},
toggleCalls: function() {},
toggleMute: function() {},
unmute: function() {},
toggleSpeaker: function() {},
switchToSpeaker: function() {},
switchToDefaultOut: function() {},
switchToReceiver: function() {},
checkCalls: function() {},
end: function() {},
answer: function() {},
updateAllPhoneNumberDisplays: function() {},
updatePlaceNewCall: function() {},
mergeCalls: function() {},
holdOrResumeSingleCall: function() {},
updateMergeAndOnHoldStatus: function() {},
updateMuteAndSpeakerStatus: function() {},
setup: function () {},
mTeardown: function() {
this.mActiveCall = null;
this.mActiveCallForContactImage = null;
this.mIsFirstCallOnCdmaNetwork = false;
}
};

View file

@ -0,0 +1,60 @@
'use strict';
/* exported MockContacts */
var MockContacts = {
// We need to test calls without contact information
// so we'll return that info depending on the
// calling number
// '111': No contacts
// '222': More than 1 contact for that number
// Any other: 1 contact
findByNumber: function findByNumber(number, callback) {
this.mCalledWith = number;
this.mPhoto = 'test';
this.mName = 'test name';
var tel = {
value: this.mCalledWith,
carrier: this.mCarrier,
type: this.mType
};
var contact = {
id: this.mId,
name: [this.mName],
tel: [tel],
photo: [this.mPhoto]
};
var contactsWithSameNumber = 0;
switch (number) {
case '111':
this.mPhoto = null;
this.mName = null;
contact = null;
tel = null;
break;
case '222':
contactsWithSameNumber = 2;
break;
default:
}
callback(contact, tel, contactsWithSameNumber);
},
findListByNumber: function cm_getContactData(number, maxitems, callback) {
callback(this.mResult);
},
getRevision: function cm_getRevision(callback) { callback(0); },
mId: 'id',
mPhoto: null,
mName: null,
mCalledWith: null,
mCarrier: 'carrier',
mType: 'type',
mResult: null,
mTearDown: function tearDown() {
this._calledWith = null;
this.mCarrier = 'carrier';
this.mType = 'type';
this.mResult = [];
}
};

View file

@ -0,0 +1,18 @@
/* exported MockFontSizeManager */
'use strict';
var MockFontSizeManager = {
/**
* Possible scenarios as declared by FontSizeManager.
*/
DIAL_PAD: 0,
SINGLE_CALL: 1,
CALL_WAITING: 2,
STATUS_BAR: 3,
SECOND_INCOMING_CALL: 4,
adaptToSpace: function() {},
ensureFixedBaseline: function() {},
resetFixedBaseline: function() {}
};

View file

@ -0,0 +1,94 @@
/* globals HandledCall, MockNavigatorMozTelephony */
/* exported telephonyAddCall, telephonyAddCdmaCall */
'use strict';
function MockHandledCall(call) {
this.call = call;
this.node = document.createElement('section'); // fake dom
}
MockHandledCall.prototype.handleEvent = function hc_handle(evt) {
};
MockHandledCall.prototype.startTimer = function hc_startTimer() {
};
MockHandledCall.prototype.updateCallNumber = function hc_updateCallNumber() {
};
MockHandledCall.prototype.replaceAdditionalContactInfo =
function hc_replaceAdditionalContactInfo(additionalContactInfo) {
};
MockHandledCall.prototype.restoreAdditionalContactInfo =
function hc_restoreAdditionalContactInfo(additionalContactInfo) {
};
MockHandledCall.prototype.formatPhoneNumber =
function hc_formatPhoneNumber(ellipsisSide, maxFontSize) {
};
MockHandledCall.prototype.renderPhoneNumber =
function hc_renderPhoneNumber(phoneNumber, ellipsisSide) {
};
MockHandledCall.prototype.replacePhoneNumber =
function hc_replacePhoneNumber(phoneNumber, ellipsisSide) {
};
MockHandledCall.prototype.restorePhoneNumber =
function hc_restorePhoneNumber() {
};
MockHandledCall.prototype.updateDirection = function hc_updateDirection() {
};
MockHandledCall.prototype.remove = function hc_remove() {
};
MockHandledCall.prototype.connected = function hc_connected() {
};
MockHandledCall.prototype.busy = function hc_busy() {
};
MockHandledCall.prototype.disconnected = function hc_disconnected() {
};
MockHandledCall.prototype.show = function hc_show() {
};
MockHandledCall.prototype.hide = function hc_hide() {
};
// Should be called in the context of a suite
function telephonyAddCall(mockCall, opt) {
MockNavigatorMozTelephony.calls.push(mockCall);
var handledCall = new MockHandledCall(mockCall);
// not already stubed
if (!('restore' in HandledCall)) {
/* jshint validthis: true */
this.sinon.stub(window, 'HandledCall');
}
HandledCall.withArgs(mockCall).returns(handledCall);
if (opt && opt.trigger) {
MockNavigatorMozTelephony.mTriggerCallsChanged();
}
return handledCall;
}
/* Should be called in the context of a suite after one call has already been
* added via telephonyAddCall(). */
function telephonyAddCdmaCall(number, opt) {
MockNavigatorMozTelephony.calls[0].secondId = { number: number };
MockNavigatorMozTelephony.calls[0].state = 'connected';
if (opt && opt.trigger) {
MockNavigatorMozTelephony.mTriggerCallsChanged();
}
}

View file

@ -0,0 +1,29 @@
'use strict';
/* exported MockKeypadManager */
var MockKeypadManager = {
_phoneNumber: '',
mOnMakeCall: null,
lastCalled: '15555555555',
init: function() {},
updatePhoneNumber: function khm_updatePhoneNumber(number) {
this._phoneNumber = number;
},
makeCall: function makeCall() {
if (this.mOnMakeCall) {
if (this._phoneNumber) {
this.lastCalled = this._phoneNumber;
}
this.mOnMakeCall(this._phoneNumber);
}
},
phoneNumber: function phoneNumber() {
return this._phoneNumber;
},
fetchLastCalled: function() {
this._phoneNumber = this.lastCalled;
},
render: function() {},
restorePhoneNumber: function() {},
restoreAdditionalContactInfo: function() {}
};

View file

@ -0,0 +1,20 @@
'use strict';
/* exported MockTelephonyHelper */
var MockTelephonyHelper = {
mInUseSim: null,
mCallPromise: null,
call: function() {
if (!this.mCallPromise) {
this.mCallPromise = new Promise(() => {});
}
return this.mCallPromise;
},
getInUseSim: function() { return this.mInUseSim; },
mTeardown: function() {
this.mInUseSim = null;
this.mCallPromise = null;
}
};

View file

@ -0,0 +1,14 @@
'use strict';
/* exported MockTelephonyMessages */
var MockTelephonyMessages = {
REGULAR_CALL: 0,
NO_NETWORK: 1,
EMERGENCY_ONLY: 2,
displayMessage: function() {},
handleDisconnect: function() {},
handleError: function() {},
notifyBusyLine: function() {}
};

View file

@ -0,0 +1,10 @@
/* exported MockTonePlayer */
'use strict';
var MockTonePlayer = {
init: function() {},
playSequence: function() {},
start: function(frequencies, shortPress) {},
stop: function() {}
};

View file

@ -0,0 +1,72 @@
'use strict';
/* exported MockUtils */
var MockUtils = {
mCalledPrettyDate: false,
mCalledSetHeaderDate: false,
mCalledGetDayDate: false,
mCalledGetPhoneNumberPrimaryInfo: false,
mCalledGetPhoneNumberAdditionalInfo: false,
prettyDate: function ut_prettyDate(time) {
this.mCalledPrettyDate = true;
},
setHeaderDate: function ut_headerDate(elem, time) {
this.mCalledSetHeaderDate = true;
elem.textContent = time;
},
getDayDate: function re_getDayDate(timestamp) {
this.mCalledGetDayDate = true;
var date = new Date(timestamp);
var startDate = new Date(date.getFullYear(),
date.getMonth(), date.getDate());
return startDate.getTime();
},
getPhoneNumberAdditionalInfo:
function getPhoneNumberAdditionalInfo(matchingTel) {
return {
id: matchingTel.type,
args: {
carrier: matchingTel.carrier
}
};
},
addEllipsis: function ut_addEllipsis() {},
getNextFontSize: function ut_getNextFontSize(view, fakeView, maxFontSize,
minFontSize, fontStep) {
return maxFontSize;
},
mTearDown: function tearDown() {
this.mCalledPrettyDate = false;
this.mCalledHeaderDate = false;
this.mCalledGetDayDate = false;
this.mCalledGetPhoneNumberPrimaryInfo = false;
this.mCalledGetPhoneNumberAdditionalInfo = false;
},
getPhoneNumberPrimaryInfo: function ut_getPhoneNumberPrimaryInfo(matchingTel,
contact) {
this.mCalledGetPhoneNumberPrimaryInfo = true;
if (contact) {
if (contact.name && String(contact.name) !== '') {
return contact.name;
} else if (contact.org && String(contact.org) !== '') {
return contact.org;
}
}
if (matchingTel) {
return matchingTel.value;
}
return null;
},
prettyDuration: function(node, duration, l10nPrefix) {},
isPhoneType: function(type) {}
};

View file

@ -0,0 +1,77 @@
'use strict';
/**
* Helper for applying methods from a mock to an element in the DOM. This is
* needed when mocking web components. For instance, we may have to test that
* some code properly calls into a web component like so:
*
* ```html
* <!-- mock html -->
* <gaia-web-component id="myWC"></gaia-web-component>
* ```
*
* ```js
* // code to test
* var wc = document.getElementById('myWC');
* wc.foo();
* ```
*
* ```js
* // test
* var wc = document.getElementById('myWC');
* this.sinon.stub(wc, 'foo');
* // call method that will call foo()
* sinon.assert.calledOnce(wc.foo);
* ```
*
* This won't work because we aren't importing the actual gaia-web-component
* component. The solution here is to copy the methods from a mock to the
* gaia-web-component, like this:
*
* ```html
* <!-- mock html -->
* <gaia-web-component id="myWC"></gaia-web-component>
* ```
*
* ```js
* // code to test
* var wc = document.getElementById('myWC');
* wc.foo();
* ```
*
* ```js
* // mock
* var MockGaiaWebComponent = {
* foo: function() {}
* };
* ```
*
* ```js
* // test
*
* // use MocksHelper to set GaiaWebComponent = MockGaiaWebComponent
*
* var customElementsHelperForMyTest =
* new CustomElementsHelper(['GaiaWebComponent']);
* customElementsHelperForMyTest.resolve();
*
* // now stub and call it as before
* ```
*/
var CustomElementsHelper = function(mocks) {
this.mocks = mocks.sort();
};
CustomElementsHelper.prototype = {
resolve: function emh_resolve() {
this.mocks.forEach(function(objName) {
var eltName = objName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
var matchingElts = document.querySelectorAll(eltName);
for (var key in window[objName]) {
for (var i = 0; i < matchingElts.length; i++) {
matchingElts[i][key] = window[objName][key];
}
}
});
}
};

View file

@ -0,0 +1,8 @@
/* exported MockGaiaMenu */
'use strict';
var MockGaiaMenu = {
show: function() {},
hide: function() {}
};

View file

@ -0,0 +1,7 @@
/* exported MockGaiaSimPicker */
'use strict';
var MockGaiaSimPicker = {
getOrPick: function() { }
};

View file

@ -0,0 +1,12 @@
'use strict';
var Zlib = {};
Zlib.Gzip = function(data) {
this.data = data;
};
Zlib.Gzip.prototype.compress = function(payload) {
throw 'Gzip.compress error';
};

View file

@ -0,0 +1,27 @@
/* global Zlib */
'use strict';
importScripts('mock_gzip.min.js');
self.onmessage = function(message) {
var cmd = message.data.cmd;
if (cmd === 'gzip') {
// gzip function requires Uint8Array
var textEncoder = new TextEncoder('utf8');
var payload = message.data.payload;
var uint8Data = textEncoder.encode(payload);
try {
var gzip = new Zlib.Gzip(uint8Data);
var compressed = gzip.compress();
postMessage({returnResult: true, gzipData: compressed});
}
catch(e) {
postMessage({returnResult: false, error: e});
}
} else {
console.warn('GzipWorker, unsupported cmd:', cmd);
}
};

View file

@ -0,0 +1,7 @@
'use strict';
/* exported MockAccessibilityHelper */
var MockAccessibilityHelper = {
setAriaSelected: function(selectedTab, tabs) {}
};

View file

@ -0,0 +1,31 @@
/*
Copyright 2015, Mozilla Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
/* exported MockAdvancedTelemetryHelper */
function MockAdvancedTelemetryHelper(type, name) {
this.type = type;
this.name = name;
}
MockAdvancedTelemetryHelper.HISTOGRAM_COUNT = 4;
MockAdvancedTelemetryHelper.HISTOGRAM_EXP = 0;
MockAdvancedTelemetryHelper.HISTOGRAM_LINEAR = 1;
MockAdvancedTelemetryHelper.prototype.add = function(number) {};

View file

@ -0,0 +1,11 @@
/*exported MockasyncStorage */
'use strict';
var MockasyncStorage = {
getItem: function(key, callback) {
callback();
},
setItem: function(key, value) {},
removeItem: function() {}
};

View file

@ -0,0 +1,87 @@
'use strict';
function MockAudio(src) {
MockAudio.instances.push(this);
this.src = src;
this.readyState = 1;
this.paused = true;
}
MockAudio.instances = [];
MockAudio.mSetup = function() {
MockAudio.instances = [];
};
MockAudio.mTeardown = function() {
MockAudio.instances = [];
};
MockAudio.prototype.HAVE_NOTHING = 0;
MockAudio.prototype.load = function() {
};
MockAudio.prototype.play = function() {
// FIXME can we replace playing with paused?
this.playing = true;
this.paused = false;
};
MockAudio.prototype.pause = function() {
this.playing = false;
this.paused = true;
};
MockAudio.prototype.removeAttribute = function() {
};
MockAudio.prototype.cloneNode = function() {
return this;
};
function MockAudioContext(channel) {
MockAudioContext.instances.push(this);
this.mozAudioChannelType = channel;
this.currentTime = 0;
this.sampleRate = 0;
this.destination = {};
}
MockAudioContext.instances = [];
MockAudioContext.mSetup = function() {
MockAudioContext.instances = [];
};
MockAudioContext.mTeardown = function() {
MockAudioContext.instances = [];
};
MockAudioContext.prototype.createBuffer = function() { return {}; };
MockAudioContext.prototype.createBufferSource = function() {
return {
connect: function() {},
start: function() {},
stop: function() {}
};
};
MockAudioContext.prototype.createGain = function() {
return {
connect() {},
gain: {
setValueAtTime() {},
setValueCurveAtTime() {}
}
};
};
MockAudioContext.prototype.createOscillator = function() {
return {
frequency: { value: 0 },
connect: function() {},
start: function() {},
stop: function() {}
};
};
MockAudioContext.prototype.addEventListener = function() {};
MockAudioContext.prototype.removeEventListener = function() {};

View file

@ -0,0 +1,25 @@
/* global Promise */
/* exported MockBasket */
'use strict';
var MockBasket = {
_err: null,
_data: {
'status': 'ok'
},
_dataStore: null,
send: function(data, callback) {
if (callback) {
callback(this._err, this._data);
}
},
getDataStore: function() {
var self = this;
return new Promise(function (resolve, reject) {
resolve(self._dataStore);
});
}
};

View file

@ -0,0 +1,33 @@
/* exported MockBluetoothHelper, MockBluetoothHelperInstance */
'use strict';
var MockBluetoothHelperInstance = {
profiles: {
'HFP': 0x111E,
'A2DP': 0x110D
},
answerWaitingCall: function() {},
ignoreWaitingCall: function() {},
toggleCalls: function() {},
getConnectedDevicesByProfile: function() {},
connectSco: function() {},
disconnectSco: function() {},
getPairedDevices: function() {},
getAddress: function() {},
setPairingConfirmation: function() {},
setPinCode: function() {},
setPasskey: function() {},
isScoConnected: function() {},
sendMediaMetaData: function() {},
sendMediaPlayStatus: function() {},
onhfpstatuschanged: null,
onscostatuschanged: null,
ona2dpstatuschanged: null,
onpairedstatuschanged: null,
onrequestmediaplaystatus: null
};
var MockBluetoothHelper = function() {
return MockBluetoothHelperInstance;
};

View file

@ -0,0 +1,32 @@
'use strict';
(function(exports) {
exports.MockBookmarksDatabase = {
get: function() {},
_callbacks: {},
getAll: function() {},
getRevisionId: function() {},
addEventListener: function(type, cb) {
this._callbacks[type] = cb;
},
removeEventListener: function(type) {
this._callbacks[type] = null;
},
add: function(data) {
if (this._callbacks.added) {
this._callbacks.added(data);
}
},
put: function(data) {
if (this._callbacks.added) {
this._callbacks.added(data);
}
},
remove: function(id) {
if (this._callbacks.removed) {
this._callbacks.removed(id);
}
},
clear: function() {}
};
}(window));

View file

@ -0,0 +1,16 @@
'use strict';
(function(exports) {
var MockCanvas = function() {
this.width = null;
this.height = null;
return this;
};
MockCanvas.prototype = {
getContext: function mc_getContext() {
}
};
exports.MockCanvas = MockCanvas;
})(window);

View file

@ -0,0 +1,18 @@
'use strict';
(function(exports) {
var MockCanvasRenderingContext2D = function() {
this.width = null;
this.height = null;
return this;
};
MockCanvasRenderingContext2D.prototype = {
drawImage: function mcrc2_drawImage() {
},
getImageData: function mcrc2_getImageData() {
},
};
exports.MockCanvasRenderingContext2D = MockCanvasRenderingContext2D;
})(window);

View file

@ -0,0 +1,35 @@
(function(exports) {
'use strict';
var MockCardStore = {
_dataInStore: {},
mPrepareData: function(id, data) {
this._dataInStore[id] = data;
},
mClearData: function() {
this._dataInStore = {};
},
getData: function(id) {
var that = this;
return new Promise(function(resolve, reject) {
if (that._dataInStore[id]) {
resolve(that._dataInStore[id]);
} else {
resolve(undefined);
}
});
},
saveData: function(id, data) {
var that = this;
return new Promise(function(resolve, reject) {
that._dataInStore[id] = data;
resolve();
});
}
};
exports.MockCardStore = MockCardStore;
}(window));

View file

@ -0,0 +1,22 @@
'use strict';
/* exported MockConfirmDialog */
var MockConfirmDialog = {
showing: false,
title: null,
text: null,
button: null,
show: function(title, text, button) {
this.showing = true;
this.title = title;
this.text = text;
this.button = button;
},
hide: function() {
this.showing = false;
this.title = null;
this.text = null;
this.button = null;
}
};

View file

@ -0,0 +1,98 @@
'use strict';
/* exported MockContactAllFields */
function MockContactAllFields(withoutPhoto) {
var photo;
if (!withoutPhoto) {
photo = getPhotoBlob();
}
return {
'id': '1',
'updated': new Date(),
'additionalName': ['Green'],
'adr': [
{
'type': ['home'],
'pref': true,
'countryName': 'Germany',
'locality': 'Chemnitz',
'region': 'Chemnitz',
'postalCode': '09034',
'streetAddress': 'Gotthardstrasse 22'
}
],
'bday': new Date(Date.UTC(1970, 0, 1)),
'email': [
{
'type': ['personal'],
'value': 'test@test.com'
},
{
'type': ['work'],
'value': 'test@work.com',
'pref': true
}
],
'honorificPrefix': ['Mr.'],
'familyName': ['Grillo'],
'givenName': ['Pepito'],
'nickname': ['PG'],
'jobTitle': ['Sr. Software Architect'],
'name': ['Pepito Grillo'],
'org': ['Test ORG'],
'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'],
'note': ['Note 1'],
'photo': [photo]
};
}
function getPhotoBlob() {
var b64 = 'R0lGODlhEAAQAMQfAKxoR8VkLxFw1feVPITSWv+eQv7Qo0Cc6OyIN/v7+3PLTSCZ' +
'EFy17Wa6XuT1x2bGQ3nNUU6vRXPAa9mLXMTkwJZEHJt7LL5aJ/z8/O2KONx3L/ubP/r6+rtV' +
'I////////yH5BAEAAB8ALAAAAAAQABAAAAWD4CeOZDlimOitnvlhXefFiyCs3NkZMe9QDMGi' +
'k3t1BgZDIcZgHCCxHAyxKRQmnYOkoYgaNYMNr3JoEB6dDBGmyWxihwNBgVZz2Js3YB+JWNpr' +
'HW15YgA2FxkaRB8JgoQxHQEbdiKNg4R5iYuVgpcZmkUjHDEapYqbJRyjkKouoqqhIyEAOw==';
return b64toBlob(b64, 'image/gif');
}
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 1024;
function charCodeFromCharacter(c) {
return c.charCodeAt(0);
}
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = Array.prototype.map.call(slice, charCodeFromCharacter);
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
return new Blob(byteArrays, {type: contentType});
}

View file

@ -0,0 +1,21 @@
'use strict';
/* exported MockContactPhotoHelper */
var MockContactPhotoHelper = {
getThumbnail: function(contact) {
if (!contact || !contact.photo || !contact.photo.length) {
return null;
}
return contact.photo[0];
},
getFullResolution: function(contact) {
if (!contact || !contact.photo || !contact.photo.length) {
return null;
}
return contact.photo[0];
}
};

View file

@ -0,0 +1,41 @@
'use strict';
/*jshint maxlen:false*/
/*exported MockCropResizeRotate*/
var MockCropResizeRotate =
function(blob, cropRegion, outputSize, outputType, metadata, callback) {
// The 2nd, 3rd, 4th and 5th arguments are optional, so fix things up if we're
// called with fewer than 6 args. The last argument is always the callback.
switch (arguments.length) {
case 2:
callback = cropRegion;
cropRegion = outputSize = outputType = metadata = null;
break;
case 3:
callback = outputSize;
outputSize = outputType = metadata = null;
break;
case 4:
callback = outputType;
outputType = metadata = null;
break;
case 5:
callback = metadata;
metadata = null;
break;
case 6:
// everything fine. do nothing here
break;
default:
throw new Error('wrong number of arguments: ' + arguments.length);
}
if (typeof callback === 'function') {
callback(null, blob);
}
};

View file

@ -0,0 +1,38 @@
/* exported MockCustomDialog */
'use strict';
var MockCustomDialog = {
show: function(title, msg, cancel, confirm, element) {
this.mShown = true;
this.mShowedTitle = title;
this.mShowedMsg = msg;
this.mShowedCancel = cancel;
this.mShowedConfirm = confirm;
this.mShowedElement = element;
this.mShowedScreen = document.createElement('form');
return this.mShowedScreen;
},
hide: function() {
this.mShown = false;
},
mShown: false,
mShowedTitle: null,
mShowedMsg: null,
mShowedCancel: null,
mShowedConfirm: null,
mShowedElement: null,
mShowedScreen: null,
mTeardown: function teardown() {
this.mShown = false;
this.mShowedTitle = null;
this.mShowedMsg = null;
this.mShowedCancel = null;
this.mShowedConfirm = null;
this.mShowedElement = null;
this.mShowedScreen = null;
}
};

View file

@ -0,0 +1,26 @@
'use strict';
(function(exports) {
var MockCustomEvent = function(type, eventInitDict) {
this.type = type;
if (typeof eventInitDict === 'object') {
this.bubbles = eventInitDict.bubbles;
this.cancelable = eventInitDict.cancelable;
this.detail = eventInitDict.detail;
}
return this;
};
MockCustomEvent.prototype = {
initCustomEvent:
function mce_initCustomEvent(type, canBubble, cancelable, detail) {
this.type = type;
this.bubbles = canBubble;
this.cancelable = cancelable;
this.detail = detail;
}
};
exports.MockCustomEvent = MockCustomEvent;
}(window));

View file

@ -0,0 +1,30 @@
'use strict';
window.MockDefaultActivityHelper = {
getDefaultConfig: function(name, type) {
if (name === 'testactivity' && type === 'testtype') {
return {
name: 'testactivity',
type: ['testtype']
};
} else {
return undefined;
}
},
getDefaultAction: function(name, type) {
if (name === 'testactivity' && type === 'testtype') {
return {
'aa': 'kk'
};
} else {
return undefined;
}
},
setDefaultAction: function(name, type, choice) {
}
};

View file

@ -0,0 +1,85 @@
'use strict';
function MockDeviceStorage() {
MockDeviceStorage.instances.push(this);
this.entries = [
{name: 'mock1'},
{name: 'mock2'},
{name: 'mock3'},
{name: 'mock4'}
];
this.cursors = [];
}
MockDeviceStorage.mSetup = function() {
this.realGetDeviceStorage = navigator.getDeviceStorage;
navigator.getDeviceStorage = function() {
return new MockDeviceStorage();
};
MockDeviceStorage.instances = [];
};
MockDeviceStorage.mTeardown = function() {
navigator.getDeviceStorage = this.realGetDeviceStorage;
MockDeviceStorage.instances = [];
};
MockDeviceStorage.prototype.enumerate = function() {
var storage = this;
var req = {
onsuccess: null,
onerror: null
};
var cursor = {
index: -1,
done: false,
continue: function() {
this.index += 1;
if (this.index < storage.entries.length) {
this.result = storage.entries[this.index];
} else {
this.result = null;
this.done = true;
}
setTimeout(function() {
if (req.onsuccess) {
req.onsuccess.call(cursor);
}
});
},
result: null
};
this.cursors.push(cursor);
cursor.continue();
return req;
};
MockDeviceStorage.prototype.delete = function(name) {
for (var i = 0; i < this.entries.length; i++) {
if (this.entries[i] && this.entries[i].name === name) {
this.entries.splice(i, 1);
break;
}
}
if (i > this.entries.length) {
return;
}
for (var j = 0; j < this.cursors.length; j++) {
if (this.cursors[j].index >= i) {
this.cursors[j].index -= 1;
}
}
};

View file

@ -0,0 +1,149 @@
'use strict';
/* global MockEventTarget */
(function(exports) {
/**
* This is an reimplementation of DOMRequest in JavaScript,
* usable as a mock for tests.
*
* See https://developer.mozilla.org/en-US/docs/Web/API/DOMRequest
* and http://dxr.mozilla.org/mozilla-central/source/dom/base/DOMRequest.h
* for the simulated real APIs.
*
* There are two additional methods (fireSuccess() and fireError()) for
* explicitly invoking success/error in test script.
*
* @class MockDOMRequest
* @requires MockEventTarget
*
*/
var MockDOMRequest = function MockDOMRequest() {
this._promise = null;
};
MockDOMRequest.prototype = new MockEventTarget();
/**
* The operation's result.
* @memberof MockDOMRequest.prototype
* @type {Mixed}
*/
MockDOMRequest.prototype.result = undefined;
/**
* Error information, if any.
* @type {Mixed}
*/
MockDOMRequest.prototype.error = undefined;
/**
* A callback handler called when the operation represented by the
* DOMRequest is completed.
* @memberof MockDOMRequest.prototype
* @type {Function}
*/
MockDOMRequest.prototype.onsuccess = null;
/**
* A callback handler that gets called when an error occurs while processing
* the operation.
* @memberof MockDOMRequest.prototype
* @type {Function}
*/
MockDOMRequest.prototype.onerror = null;
/**
* A string indicating whether or not the operation is finished running.
* Its value is either "done" or "pending".
* @memberof MockDOMRequest.prototype
* @type {String}
*/
MockDOMRequest.prototype.readyState = 'pending';
/**
* Fire success event with result given.
* @memberof MockDOMRequest.prototype
* @param {Mixed} result The result.
*/
MockDOMRequest.prototype.fireSuccess = function(result) {
if (this.readyState === 'done') {
throw 'The DOMRequest instance has already fired.';
}
this.readyState = 'done';
this.result = result;
// Fake event that only implements two properties.
// I am not interested in writing MockDOMEvent :-/
var evt = {
type: 'success'
};
this.dispatchEvent(evt);
// Remove callbacks since we will never file them again.
this._captureCallbacks = [];
this._bubbleCallbacks = [];
this._getInternalPromise().resolve(result);
};
/**
* Fire error event with error given.
* @memberof MockDOMRequest.prototype
* @param {Mixed} error The error.
*/
MockDOMRequest.prototype.fireError = function(error) {
if (this.readyState === 'done') {
throw 'The DOMRequest instance has already fired.';
}
this.readyState = 'done';
this.error = error;
// Fake event that only implements two properties.
// I am not interested in writing MockDOMEvent :-/
var evt = {
type: 'error'
};
this.dispatchEvent(evt);
// Remove callbacks since we will never file them again.
this._captureCallbacks = [];
this._bubbleCallbacks = [];
this._getInternalPromise().reject(error);
};
/**
* The then-able interface of DOMRequest. See bug 839838 for real impl.
* @returns {Mixed} A Promise instance returned by the then() method.
*/
MockDOMRequest.prototype.then = function(fulfillCallback, rejectCallback) {
return this._getInternalPromise().then(fulfillCallback, rejectCallback);
};
/**
* Get the internal promise instance. Internal only.
* Create the instance when being required for the first time.
* @returns {Mixed} A Promise instance.
*/
MockDOMRequest.prototype._getInternalPromise = function() {
if (this._promise) {
return this._promise;
}
var oResolve, oReject;
var p = this._promise = new Promise(function(resolve, reject) {
oResolve = resolve;
oReject = reject;
});
p.resolve = oResolve;
p.reject = oReject;
return p;
};
exports.MockDOMRequest = MockDOMRequest;
}(window));

View file

@ -0,0 +1,56 @@
'use strict';
var DEFAULT_PARAMS = {
id: '0',
totalBytes: 1800,
currentBytes: 100,
url: 'http://firefoxos.com/archivo.mp3',
path: '//SDCARD/Downloads/archivo.mp3',
state: 'downloading',
contentType: 'audio/mpeg',
startTime: new Date(),
error: null
};
function MockDownload(params) {
params = params || {};
this.id = params.id || '0';
this.totalBytes = params.totalBytes || DEFAULT_PARAMS.totalBytes;
this.currentBytes = params.currentBytes || DEFAULT_PARAMS.currentBytes;
this.url = params.url || DEFAULT_PARAMS.url;
this.path = params.path || DEFAULT_PARAMS.path;
this.state = params.state || DEFAULT_PARAMS.state;
this.contentType = params.contentType || DEFAULT_PARAMS.contentType;
this.startTime = params.startTime || DEFAULT_PARAMS.startTime;
this.error = params.error || DEFAULT_PARAMS.error;
this.listeners = [];
}
MockDownload.prototype = {
addEventListener: function(type, listener) {
if(this.listeners.indexOf(listener) == -1) {
this.listeners.push(listener);
}
},
removeEventListener: function(type, listener) {
var index = this.listeners.indexOf(listener);
if (index > -1) {
this.listeners.splice(index, 1);
}
},
pause: function() {
return {
then: function(success, error) { setTimeout(success, 0); }
};
},
resume: function() {
return {
then: function(success, error) { setTimeout(success, 0); }
};
}
};

View file

@ -0,0 +1,26 @@
'use strict';
/* exported MockDownloadFormatter */
var MockDownloadFormatter = {
getFormattedSize: function(bytes) {
return Promise.resolve('45 MB');
},
getPercentage: function(download) {
return 10;
},
getFileName: function(download) {
return 'file.mp3';
},
getTotalSize: function(download) {
return Promise.resolve('12 MB');
},
getDownloadedSize: function(download) {
return Promise.resolve('2 MB');
},
getDate: function(download, callback) {
callback && callback('Just now');
},
getUUID: function(download) {
return download.id;
}
};

View file

@ -0,0 +1,25 @@
'use strict';
/* exported MockDownloadHelper */
var MockDownloadHelper = {
open: function() {
return {
set onsuccess(s) { setTimeout(function() {
s();
}, 100); },
set onerror(e) {}
};
},
remove: function() {
return {
set onsuccess(s) { s(); },
set onerror(e) {}
};
},
handlerError: function(error, download, cb) {
},
showRemoveFileUI: function(download, cb) {
}
};

View file

@ -0,0 +1,34 @@
'use strict';
var MockDump = (function() {
var dump_off = function() {};
var dump_on = function(msg, optionalObject) {
var output = msg;
if (optionalObject) {
output += JSON.stringify(optionalObject);
}
console.log('[MockDUMP] ' + output);
};
return {
enable: function() {
return dump_on;
},
disable: function() {
return dump_off;
}
};
}());
MockDump.disable();
var realDUMP = null;
MockDump.mSuiteSetup = function() {
realDUMP = window.DUMP;
window.DUMP = MockDump.disable();
};
MockDump.mSuiteTeardown = function() {
window.DUMP = realDUMP;
};

View file

@ -0,0 +1,15 @@
'use strict';
var MockEnumerateAll = function(storages, dir, options) {
return {
result: {
name: MockEnumerateAll.certificateName
},
set onsuccess(callback) {
callback();
},
continue: function() {}
};
};
MockEnumerateAll.certificateName = 'filename';

View file

@ -0,0 +1,120 @@
'use strict';
(function(exports) {
/**
* This is an reimplementation of EventTarget in JavaScript,
* usable as a mock for tests, and creating interfaces that inherits
* from MockEventTarget.
*
* @class MockEventTarget
*/
var MockEventTarget = function MockEventTarget() {
};
/**
* Adding an event listener for the success/error event.
* @memberof MockEventTarget.prototype
* @param {String} type Event type, success or error.
* @param {Function|Object} handler Event handler.
* @param {Boolean} capture True if use capture mode.
*/
MockEventTarget.prototype.addEventListener =
function(type, handler, capture) {
if (typeof handler !== 'function' && handler &&
typeof handler.handleEvent !== 'function') {
return;
}
var eventCallbacks;
if (capture) {
eventCallbacks = this._captureCallbacks = this._captureCallbacks || {};
} else {
eventCallbacks = this._bubbleCallbacks = this._bubbleCallbacks || {};
}
eventCallbacks[type] = eventCallbacks[type] || [];
// the same handler should not be added twice.
if (eventCallbacks[type].indexOf(handler) !== -1) {
return;
}
eventCallbacks[type].push(handler);
};
/**
* Remove an event listener for the success/error event.
* @memberof MockEventTarget.prototype
* @param {String} type Event type, success or error.
* @param {Function|Object} handler Event handler.
* @param {Boolean} capture True if use capture mode.
*/
MockEventTarget.prototype.removeEventListener = function(type, handler,
capture) {
if (typeof handler !== 'function' && handler &&
typeof handler.handleEvent !== 'function') {
return;
}
var eventCallbacks;
if (capture) {
eventCallbacks = this._captureCallbacks = this._captureCallbacks || {};
} else {
eventCallbacks = this._bubbleCallbacks = this._bubbleCallbacks || {};
}
var callbacks = eventCallbacks[type] || [];
var index = callbacks.indexOf(handler);
if (index === -1) {
return;
}
callbacks.splice(index, 1);
};
/**
* Dispatch event.
* @memberof MockEventTarget.prototype
* @param {object} event Mocked event to dispatch (`type` is required).
*/
MockEventTarget.prototype.dispatchEvent = function(evt) {
var type = evt.type;
this._captureCallbacks = this._captureCallbacks || {};
this._bubbleCallbacks = this._bubbleCallbacks || {};
var captureCallbacks = this._captureCallbacks[type] || [];
var bubbleCallbacks = this._bubbleCallbacks[type] || [];
// Don't overwrite evt.target if it is assigned already.
// Sometimes we want to simulate event bubbling/capturing in the DOM tree
// even though this is not how this mock behaves.
if (!evt.target) {
evt.target = this;
}
evt.currentTarget = this;
captureCallbacks.forEach(function fireCaptureEvents(handler) {
if (typeof handler === 'function') {
handler.call(this, evt);
} else {
handler.handleEvent(evt);
}
}, this);
if (('on' + evt.type) in this &&
typeof this['on' + evt.type] === 'function') {
this['on' + evt.type](evt);
}
bubbleCallbacks.forEach(function fireCaptureEvents(handler) {
if (typeof handler === 'function') {
handler.call(this, evt);
} else {
handler.handleEvent(evt);
}
}, this);
};
exports.MockEventTarget = MockEventTarget;
}(window));

View file

@ -0,0 +1,52 @@
'use strict';
/* exported MockFbContacts */
var MockFbContactsObj = function(result, inError) {
this.mResult = result;
this.inError = inError;
};
MockFbContactsObj.prototype = {
_getRequest: function() {
if (this.inError === true) {
return {
error: {
name: 'UnknownError'
},
set onerror(cb) {
window.setTimeout(function() {
cb({
target: this
});
});
}
};
}
return {
result: this.mResult,
set onsuccess(cb) {
cb();
}
};
},
search: function(by, number) {
return this._getRequest();
},
get: function(uid) {
return this._getRequest();
},
getByPhone: function(number) {
return this._getRequest();
},
mTeardown: function() {
this.mResult = [];
}
};
var MockFbContacts = new MockFbContactsObj();

View file

@ -0,0 +1,20 @@
'use strict';
/* exported MockFbReaderUtilsObj */
var MockFbReaderUtilsObj = function() {
this.getContactByNumber = function(number, cb, errorCb) {
if (this.inError) {
errorCb({
name: 'Data in error'
});
return;
}
if (number !== this.targetFbNumber) {
cb(null);
return;
}
cb({ name: [this.fbContactName], isFbContact: true });
};
};

View file

@ -0,0 +1,8 @@
/* exported MockFontSizeUtils */
'use strict';
var MockFontSizeUtils = {
getMaxFontSizeInfo: function() {},
getOverflowCount: function() {}
};

View file

@ -0,0 +1,68 @@
/* exported MockGeolocation */
'use strict';
var MockGeolocation = {
mSetup: function() {
this.fakeCoords = {
latitude: 37.388590,
longitude: -122.061704,
accuracy: 5.0
};
this.fakePosition = {
timestamp: 1404756850457,
coords: this.fakeCoords
};
this.activeWatches = [];
this.realGetCurrentPosition = navigator.geolocation.getCurrentPosition;
navigator.geolocation.getCurrentPosition = (function(onsuccess, onerror) {
if (onsuccess) {
onsuccess(this.createFakePosition());
}
}).bind(this);
this.realWatchPosition = navigator.geolocation.watchPosition;
navigator.geolocation.watchPosition = (function(onsuccess, onerror) {
var watch = setInterval(function() {
if (onsuccess) {
onsuccess(this.createFakePosition());
}
}.bind(this), 4);
this.activeWatches.push(watch);
return watch;
}).bind(this);
this.realClearWatch = navigator.geolocation.clearWatch;
navigator.geolocation.clearWatch = (function(watch) {
var idx = this.activeWatches.indexOf(watch);
if (idx >= 0) {
this.activeWatches.splice(idx, 1);
clearInterval(watch);
}
}).bind(this);
this.createFakePosition = function() {
this.fakePosition = {
timestamp: Date.now(),
coords: this.fakeCoords
};
return this.fakePosition;
};
},
mTeardown: function() {
for (var i = 0; i < this.activeWatches.length; i++) {
clearInterval(this.activeWatches[i]);
}
this.activeWatches = [];
navigator.geolocation.getCurrentPosition = this.realGetCurrentPosition;
navigator.geolocation.watchPosition = this.realWatchPosition;
navigator.geolocation.clearWatch = this.realClearWatch;
}
};

View file

@ -0,0 +1,9 @@
'use strict';
var MockGestureDetector = function() {};
MockGestureDetector.prototype = {
startDetecting: function() {},
stopDetecting: function() {}
};

View file

@ -0,0 +1,80 @@
'use strict';
/* exported MockIccHelper */
var MockIccHelper = {
mProps: {'cardState': null, 'iccInfo': {}, 'retryCount': 0},
mEventListeners: {'cardstatechange': [], 'iccinfochange': []},
mSetup: function icch_suite_setup() {
this.mProps = {
'cardState': null,
'iccInfo': {},
'retryCount': 0
};
this.mEventListeners = {'cardstatechange': [], 'iccinfochange': []};
},
mTeardown: function icch_teardown() {
this.mProps = {};
this.mEventListeners = {};
},
mTriggerEventListeners: function icch_triggerEventListeners(type, evt) {
if (!this.mEventListeners[type]) {
return;
}
this.mEventListeners[type].forEach(function(callback) {
if (typeof callback === 'function') {
callback(evt);
} else if (typeof callback == 'object' &&
typeof callback.handleEvent === 'function') {
callback.handleEvent(evt);
}
});
if (typeof this['on' + type] === 'function') {
this['on' + type](evt);
}
},
get cardState() {
return this.mProps.cardState;
},
get iccInfo() {
return this.mProps.iccInfo;
},
getCardLockRetryCount: function(lockType, onresult) {
onresult(this.mProps.retryCount);
},
setProperty: function _setProperty(property, newState) {
this.mProps[property] = newState;
},
addEventListener: function icch_addEventListener(type, callback) {
if (this.mEventListeners[type]) {
this.mEventListeners[type][this.mEventListeners[type].length] = callback;
}
},
removeEventListener: function icch_removeEventListener(type, callback) {
if (this.mEventListeners[type]) {
var idx = this.mEventListeners[type].indexOf(callback);
this.mEventListeners[type].splice(idx, 1);
}
},
unlockCardLock: function() {
var settingsRequest = {
result: {},
set onsuccess(callback) {
callback.call(this);
},
set onerror(callback) {}
};
return settingsRequest;
}
};

View file

@ -0,0 +1,8 @@
/* exported MockIccManager */
'use strict';
var MockIccManager = {
iccIds: [],
getIccById: function() {},
addEventListener: function() {}
};

View file

@ -0,0 +1,73 @@
'use strict';
var MockIccManager = function() {
this.iccIds = [];
this.adnContacts = [];
this.sdnContacts = [];
this.isAdnOnError = false;
this.isSdnOnError = false;
this.async = false;
};
MockIccManager.prototype.getIccById = function(id) {
var self = this;
return {
'iccInfo': {
'iccid': id
},
'readContacts': function(type) {
if (type === 'adn') {
return new MockReadContactsRequest(self.isAdnOnError, self.adnContacts,
self.async);
}
if (type === 'sdn') {
return new MockReadContactsRequest(self.isSdnOnError, self.sdnContacts,
self.async);
}
}
};
};
function MockReadContactsRequest(willFail, result, async) {
this._result = result;
this._willFail = willFail;
this._async = async;
}
MockReadContactsRequest.prototype = {
set onsuccess(successCb) {
var self = this;
if (!this._willFail) {
this.result = this._result;
if (typeof successCb === 'function') {
if (this._async) {
setTimeout(function() {
successCb({ target: self });
});
} else {
successCb({ target: this });
}
}
}
},
set onerror(errorCb) {
var self = this;
if (this._willFail) {
this.error = { name: 'error' };
if (typeof errorCb === 'function') {
if (this._async) {
setTimeout(function() {
errorCb(self.error);
});
} else {
errorCb(this.error);
}
}
}
}
};

View file

@ -0,0 +1,14 @@
/* globals Promise */
/* exported MockICEStore */
'use strict';
var MockICEStore = {
setContacts: function mis_setContacts(ids) {
MockICEStore.ids = ids;
return Promise.resolve(ids);
},
getContacts: function mis_getContacts() {
return Promise.resolve(MockICEStore.ids);
},
onChange: function() {}
};

View file

@ -0,0 +1,38 @@
'use strict';
/* exported MockIconsHelper */
var _defaultIconSize = 0;
var MockIconsHelper = {
set _defaultIconSize(size) {
_defaultIconSize = size;
},
getIcon: function(url, placeObject, siteObject) {
return new Promise(resolve => {
resolve();
});
},
getIconBlob: function(uri, iconTargetSize, placeObj = {}, siteObj = {}) {
return Promise.resolve({
blob: 'abc',
originalUrl: 'http://example.com/icons/16.png',
timestamp: Date.now()
});
},
setElementIcon: Promise.resolve.bind(Promise),
getBestIconFromWebManifest: function() {},
getBestIconFromMetaTags: function() {},
fetchIcon: function() {},
fetchIconBlob: function() {},
get defaultIconSize() {
return _defaultIconSize;
},
clear: function() {}
};

View file

@ -0,0 +1,34 @@
'use strict';
/* exported MockImage */
var MockImage = function() {
this.complete = false;
this.onload = null;
this.onabort = null;
this.onerror = null;
MockImage.instances.push(this);
};
MockImage.instances = [];
MockImage.triggerEvent = function(name) {
MockImage.instances.forEach(function(aInstance) {
aInstance.triggerEvent(name);
});
};
MockImage.teardown = function() {
MockImage.instances = [];
};
MockImage.prototype.triggerEvent = function(name) {
var callback = this[name];
if (name === 'onload') {
this.complete = true;
}
callback && callback();
};

View file

@ -0,0 +1,244 @@
'use strict';
/* global sinon */
/* exported MockIndexedDB */
function MockIndexedDB() {
var dbs = [];
var deletedDbs = [];
this.options = {};
this.storedDataDbs = {};
var self = this;
var nextId = 1;
Object.defineProperty(this, 'dbs', {
get: function() {
return dbs;
}
});
Object.defineProperty(this, 'deletedDbs', {
get: function() {
return deletedDbs;
}
});
var FakeDB = function(name, storedData) {
var dummyFunction = function(obj) {
return obj;
};
this.receivedData = [];
this.receivedDataHash = {};
this.deletedData = [];
this.storedData = storedData || {};
this.options = {};
var objectStore = {
createIndex: dummyFunction
};
this.objectStoreNames = ['fakeObjStore'];
this.createObjectStore = dummyFunction.bind(undefined,
objectStore);
this.deleteObjectStore = dummyFunction;
this.transaction = sinon.stub();
this.objectStore = sinon.stub();
this.get = dummyFunction;
this.put = dummyFunction;
this.delete = dummyFunction;
this.openCursor = dummyFunction;
this.close = dummyFunction;
this.clear = dummyFunction;
this.index = dummyFunction;
this.transaction.returns(this);
this.objectStore.returns(this);
var self = this;
sinon.stub(this, 'index', function(indexName) {
var data = self.storedData;
if (self._indexedData && self._indexedData.by) {
data = self._indexedData.by[indexName] || self.storedData;
}
return new FakeIndex(indexName, data, self.options);
});
sinon.stub(this, 'close', function() {
self.isClosed = true;
});
sinon.stub(this, 'put', function(data) {
data.id = data.id || nextId++;
self.receivedDataHash[data.id] = data;
self.receivedData.push(data);
return _getRequest();
});
sinon.stub(this, 'get', function(key) {
return _getRequest(self.storedData[key] || self.receivedDataHash[key]);
});
sinon.stub(this, 'openCursor', function() {
if (self.options.cursorOpenInError === true) {
return _getRequest(null, {
isInError: true
});
}
if (Object.keys(self.storedData).length === 0) {
return _getRequest(null);
}
var cursor = new FakeCursor(self.storedData);
var req = _getRequest(cursor);
cursor.request = req;
return req;
});
sinon.stub(this, 'delete', function(id) {
if (Array.isArray(self.options.deleteInError) &&
self.options.deleteInError.indexOf(id) !== -1) {
return _getRequest(null, {
isInError: true
});
}
delete self.storedData[id];
delete self.receivedDataHash[id];
var idx = self.receivedData.findIndex(function(elem) {
return elem.id && elem.id === id;
});
if (idx !== -1) {
self.receivedData.splice(idx, 1);
}
self.deletedData.push(id);
return _getRequest(true);
});
sinon.stub(this, 'clear', function() {
self.storedData = {};
self.receivedDataHash = {};
self.receivedData = [];
return _getRequest();
});
};
function FakeIndex(indexName, data, options) {
this.openCursor = function() {
if (options.cursorOpenInError === true) {
return _getRequest(null, {
isInError: true
});
}
if (Object.keys(data).length === 0) {
return _getRequest(null);
}
var cursor = new FakeCursor(data);
var req = _getRequest(cursor);
cursor.request = req;
return req;
};
}
var FakeCursor = function(data) {
var _pointer = 0;
var keys = Object.keys(data);
Object.defineProperty(this, 'value', {
get: function() {
return data[keys[_pointer]];
}
});
this.continue = function() {
_pointer++;
if (_pointer < keys.length) {
this.request.done(this);
}
else {
this.request.done(null);
}
};
};
var openStub = sinon.stub(window.indexedDB, 'open', function(name) {
if (Array.isArray(self.options.inErrorDbs) &&
self.options.inErrorDbs.indexOf(name) !== -1) {
return _getRequest(null, {
isInError: true
});
}
var db = new FakeDB(name, self.storedDataDbs[name]);
dbs.push(db);
var outReq = _getRequest(db, {
upgradeNeeded: (Array.isArray(self.options.upgradeNeededDbs) &&
self.options.upgradeNeededDbs.indexOf(name) !== -1)
});
return outReq;
});
var deleteDatabaseStub = sinon.stub(window.indexedDB, 'deleteDatabase',
function(name) {
deletedDbs.push(name);
return _getRequest(null);
});
function _getRequest(result, opts) {
var options = opts || {};
return {
result: result,
error: null,
set onerror(cb) {
if (options.isInError) {
this.error = {
name: 'DB In Error'
};
cb({
target: this
});
}
},
set onsuccess(cb) {
this._doneCb = cb;
if (!options.isInError) {
cb({
target: this
});
}
},
set onupgradeneeded(cb) {
if (options.upgradeNeeded) {
cb({
target: this
});
}
},
done: function(result) {
this.result = result;
if (typeof this._doneCb === 'function') {
this._doneCb({
target: this
});
}
}
};
}
this.mTearDown = () => {
openStub.restore();
deleteDatabaseStub.restore();
};
}

View file

@ -0,0 +1,31 @@
(function(global) {
'use strict';
/* global mozIntl */
const helperCache = new Map();
global.MockIntlHelper = {
define: function(name, type, options) {
helperCache.set(name, {options, type});
},
get: function(name) {
if (!helperCache.has(name)) {
throw new Error('Intl Object with name "' + name + '" is not defined');
}
var formatter = helperCache.get(name);
switch (formatter.type) {
case 'number':
return Intl.NumberFormat(navigator.languages, formatter.options);
case 'datetime':
return Intl.DateTimeFormat(navigator.languages, formatter.options);
case 'mozdatetime':
return mozIntl.DateTimeFormat(navigator.languages, formatter.options);
case 'mozduration':
return mozIntl.DurationFormat(navigator.languages, formatter.options);
}
},
observe: function() {},
unobserve: function() {},
};
}(this));

View file

@ -0,0 +1,142 @@
'use strict';
var MockKeyboardHelper = {
fallbackLayouts: {},
mKeyboards: [
{
manifestURL: 'app://keyboard.gaiamobile.org/manifest.webapp',
manifest: {
name: 'app1',
description: 'app1',
permissions: {
'settings': { 'access': 'readwrite' },
'keyboard': {}
},
role: 'input',
launch_path: '/settings.html',
inputs: {
'en': {
'name': 'layout1',
'launch_path': '/index.html#layout1',
'description': 'layout1',
'types': ['url', 'text'],
enabled: true,
'default': true
},
'number': {
'name': 'layout2',
'launch_path': '/index.html#layout2',
'description': 'layout2',
'types': ['number']
}
}
}
},
{
manifestURL: 'app://app2.gaiamobile.org/manifest.webapp',
manifest: {
name: 'app2',
description: 'app2',
permissions: {
'settings': { 'access': 'readwrite' },
'input': {}
},
role: 'input',
launch_path: '/settings.html',
inputs: {
'layout1': {
'name': 'layout1',
'launch_path': '/index.html#layout1',
'description': 'layout1',
'types': ['url']
}
}
}
},
{
manifestURL: 'app://app3.gaiamobile.org/manifest.webapp',
manifest: {
name: 'app3',
description: 'app3',
permissions: {
'settings': { 'access': 'readwrite' },
'keyboard': {}
},
role: 'input',
launch_path: '/settings.html',
inputs: {
'layout1': {
'name': 'layout1',
'launch_path': '/index.html#layout1',
'description': 'layout1',
'types': ['number'],
enabled: true,
'default': true
}
}
}
}
],
mSetup: function() {
this.watchCallback = null;
// dirty clone
this.keyboards = JSON.parse(JSON.stringify(this.mKeyboards));
this.layouts = this.keyboards.reduce(function(carry, keyboard) {
var inputIds = Object.keys(keyboard.manifest.inputs);
var layouts = inputIds.map(function(layoutId) {
var inputManifest = keyboard.manifest.inputs[layoutId];
return {
app: keyboard,
manifest: keyboard.manifest,
inputManifest: inputManifest,
layoutId: layoutId,
enabled: inputManifest.enabled,
'default': inputManifest['default']
};
});
return carry.concat(layouts);
}, []);
},
stopWatching: function() {
this.watchCallback = null;
},
getLayouts: function(options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
callback(this.layouts);
},
watchLayouts: function(options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
this.watchCallback = callback;
callback(this.layouts, { apps: true, settings: true });
},
checkDefaults: function() {},
setLayoutEnabled: function(manifestURL, layoutId, enabled) {
this.layouts.some(function eachLayout(layout) {
if (layout.app.manifestURL === manifestURL &&
layout.layoutId === layoutId) {
layout.enabled = enabled;
return true;
}
});
},
saveToSettings: function() {
if (this.watchCallback) {
this.watchCallback(this.layouts, { settings: true });
}
},
isKeyboardType: function() {
return true;
},
changeDefaultLayouts: function() {}
};
MockKeyboardHelper.mSuiteSetup = MockKeyboardHelper.mSetup;

View file

@ -0,0 +1,139 @@
/* globals assert */
(function(exports) {
'use strict';
exports.MockL10n = {
readyState: 'complete',
get: stringify,
_stringify: stringify,
formatValue: function(id, args) {
return Promise.resolve(stringify(id, args || ''));
},
translateFragment: function() {},
// XXX Remove in https://bugzil.la/1020137
localize: function(element, id, args) {
if (id) {
element.setAttribute('data-l10n-id', id);
} else {
element.removeAttribute('data-l10n-id');
element.removeAttribute('data-l10n-args');
element.textContent = '';
}
if (args) {
element.setAttribute('data-l10n-args', JSON.stringify(args));
} else {
element.removeAttribute('data-l10n-args');
}
element.textContent = id + (args ? JSON.stringify(args) : '');
},
setAttributes: function(element, id, args) {
element.setAttribute('data-l10n-id', id);
if (args) {
element.setAttribute('data-l10n-args', JSON.stringify(args));
}
},
getAttributes: function(element) {
return {
id: element.getAttribute('data-l10n-id'),
args: JSON.parse(element.getAttribute('data-l10n-args'))
};
},
ready: function(handler) {
setTimeout(handler);
},
once: function(handler) {
setTimeout(handler);
},
language: {
code: 'en-US',
direction: 'ltr'
},
qps: {
'fr-x-psaccent': {
id: 'fr-x-psaccent',
name: 'Pseudo English',
translate: stringify
}
},
DateTimeFormat: function() {
// Support navigator.mozL10n.DateTimeFormat() without new the object.
if (!this.localeFormat) {
var localeFormat = function mockLocaleFormat(time, strFormat) {
return '' + time;
};
return {
localeFormat: localeFormat
};
}
}
};
// Defining methods on the prototype allows to spy on them in tests
exports.MockL10n.DateTimeFormat.prototype = {
localeFormat: stringify,
fromNow: stringify,
relativeParts: stringify
};
/**
* Helper used to check that an element has been properly localized. This
* supports all the patterns described on MDN for localization best
* practices:
* - If 'expectedL10n' is a string it will check that the node's
* 'data-l10n-id' attribute is set and matches that id.
* - If 'expectedL10n' is an object then if it as an id and an args field it
* will check if the node's 'data-l10n-id' and 'data-l10n-args' fields
* match them.
* - If 'expectedL10n' is an object with a 'raw' field it will check that the
* node doesn't have a 'data-l10n-id' attribute and its 'textContent' field
* matches the'raw' field.
* - If 'expectedL10n' is an object with am 'html' field it will check that
* the node doesn't have a 'data-l10n-id' attribute and its 'innerHTML'
* field matches the'html' field.
*/
exports.l10nAssert = function(node, expectedL10n) {
if (typeof expectedL10n === 'string') {
assert.isTrue(node.hasAttribute('data-l10n-id'));
assert.equal(node.getAttribute('data-l10n-id'), expectedL10n);
} else if (expectedL10n.raw) {
assert.isFalse(node.hasAttribute('data-l10n-id'));
assert.equal(node.textContent, expectedL10n.raw);
} else if (expectedL10n.html) {
assert.isFalse(node.hasAttribute('data-l10n-id'));
assert.equal(node.innerHTML, expectedL10n.html);
} else if (expectedL10n.id) {
assert.isTrue(node.hasAttribute('data-l10n-id'));
assert.equal(node.getAttribute('data-l10n-id'), expectedL10n.id);
if (expectedL10n.args) {
assert.isTrue(node.hasAttribute('data-l10n-args'));
assert.deepEqual(
JSON.parse(node.getAttribute('data-l10n-args')),
expectedL10n.args
);
}
}
};
function stringify() {
return Array.prototype.reduce.call(arguments, function(prev, cur) {
if (typeof cur === 'object') {
cur = JSON.stringify(cur);
}
return prev + cur;
}, '');
}
}(this));

View file

@ -0,0 +1,91 @@
/* globals assert */
(function(exports) {
'use strict';
exports.MockL10n = {
_stringify: stringify,
formatValue: function(id, args) {
return Promise.resolve(
args ? stringify(id, args) : stringify(id));
},
formatValues: function(...keys) {
return Promise.resolve(
keys.map(key => stringify(key)));
},
translateFragment: function() {
return Promise.resolve();
},
setAttributes: function(element, id, args) {
element.setAttribute('data-l10n-id', id);
if (args) {
element.setAttribute('data-l10n-args', JSON.stringify(args));
}
},
getAttributes: function(element) {
return {
id: element.getAttribute('data-l10n-id'),
args: JSON.parse(element.getAttribute('data-l10n-args'))
};
},
ready: Promise.resolve(),
requestLanguages: function() {
return Promise.resolve();
},
};
/**
* Helper used to check that an element has been properly localized. This
* supports all the patterns described on MDN for localization best
* practices:
* - If 'expectedL10n' is a string it will check that the node's
* 'data-l10n-id' attribute is set and matches that id.
* - If 'expectedL10n' is an object then if it as an id and an args field it
* will check if the node's 'data-l10n-id' and 'data-l10n-args' fields
* match them.
* - If 'expectedL10n' is an object with a 'raw' field it will check that the
* node doesn't have a 'data-l10n-id' attribute and its 'textContent' field
* matches the'raw' field.
* - If 'expectedL10n' is an object with am 'html' field it will check that
* the node doesn't have a 'data-l10n-id' attribute and its 'innerHTML'
* field matches the'html' field.
*/
exports.l10nAssert = function(node, expectedL10n) {
if (typeof expectedL10n === 'string') {
assert.isTrue(node.hasAttribute('data-l10n-id'));
assert.equal(node.getAttribute('data-l10n-id'), expectedL10n);
} else if (expectedL10n.raw) {
assert.isFalse(node.hasAttribute('data-l10n-id'));
assert.equal(node.textContent, expectedL10n.raw);
} else if (expectedL10n.html) {
assert.isFalse(node.hasAttribute('data-l10n-id'));
assert.equal(node.innerHTML, expectedL10n.html);
} else if (expectedL10n.id) {
assert.isTrue(node.hasAttribute('data-l10n-id'));
assert.equal(node.getAttribute('data-l10n-id'), expectedL10n.id);
if (expectedL10n.args) {
assert.isTrue(node.hasAttribute('data-l10n-args'));
assert.deepEqual(
JSON.parse(node.getAttribute('data-l10n-args')),
expectedL10n.args
);
}
}
};
function stringify(...args) {
return args.reduce(
(prev, cur) =>
prev + (typeof cur === 'object' ? JSON.stringify(cur) : cur), '');
}
}(this));

View file

@ -0,0 +1,22 @@
(function(exports) {
'use strict';
var langs = {
'en-US': 'English (US)'
};
exports.MockLanguageList = {
_languages: {
then: function(callback) {
callback(langs);
}
},
get: function(callback) {
callback(langs, 'en-US');
},
wrapBidi: function(lang, name) {
return name;
}
};
}(this));

View file

@ -0,0 +1,16 @@
'use strict';
/* exported MockLazyLoader */
var MockLazyLoader = {
load: function(fileArray, callback) {
if (callback) {
callback();
} else {
return Promise.resolve();
}
},
getJSON: function(file) {
return Promise.resolve({});
}
};

View file

@ -0,0 +1,14 @@
'use strict';
/* exported MockManifestHelper */
function MockManifestHelper(manifest) {
for (var prop in manifest) {
this[prop] = manifest[prop];
}
}
Object.defineProperty(MockManifestHelper.prototype, 'displayName', {
get: function displayName() {
return this.short_name || this.name;
}
});

View file

@ -0,0 +1,29 @@
'use strict';
/* exported MockMediaDB */
var MockMediaDB = (function() {
function MockMediaDB(blob) {
this.blob = blob;
this.OPENING = 'opening'; // this is initializing itself
this.UPGRADING = 'upgrading'; // this is upgrading database
this.READY = 'ready'; // this is available and ready for use
this.NOCARD = 'nocard'; // Unavailable because there is no sd card
this.UNMOUNTED = 'unmounted'; // Unavailable because card unmounted
this.CLOSED = 'closed'; // Unavailable because closed() was called
}
MockMediaDB.prototype = {
getFile: function getFile(filename, callback) {
callback(this.blob);
},
updateMetadata: sinon.spy()
};
sinon.spy(MockMediaDB.prototype, 'getFile');
return MockMediaDB;
}());

View file

@ -0,0 +1,20 @@
'use strict';
/* exported MockMobileOperator */
var MockMobileOperator = {
userFacingInfo: function mmo_userFacingInfo(mobileConnection) {
return {
'operator': this.mOperator,
'carrier': this.mCarrier,
'region': this.mRegion
};
},
mOperator: '',
mCarrier: '',
mRegion: '',
mTeardown: function() {
this.mOperator = this.mCarrier = this.mRegion = '';
}
};

View file

@ -0,0 +1,157 @@
'use strict';
var MockMozContacts;
function MockMozContactsObj(contacts) {
this.contacts = contacts;
}
var listeners = {};
MockMozContactsObj.prototype = {
limit: 20,
addEventListener: function(evt, handler) {
listeners[evt] = handler;
},
removeEventListener: function(evt, handler) {
delete listeners[evt];
},
dispatchEvent: function(evt) {
listeners[evt.type] && listeners[evt.type](evt);
},
_getRequest: function(options) {
var that = this;
function Req(options) {
var self = this;
Object.defineProperty(self, 'onsuccess', { set: function(cb) {
if (options.type === 'find') {
if (options.data.filterBy &&
options.data.filterBy.indexOf('id') !== -1) {
for (var i = 0; i < that.contacts.length; i++) {
if (options.data.filterValue === that.contacts[i].id) {
self.result = [that.contacts[i]];
}
}
} else {
self.result = that.contacts;
}
} else {
self.result = options.data;
}
cb.call(self, { target: self });
}});
}
return new Req(options);
},
find: function find(filter) {
return this._getRequest({
type: 'find',
data: filter
});
},
total: 0,
set number(n) {
this.total = n;
},
getCount: function() {
return this._getRequest({
type: 'count',
data: MockMozContacts.total
});
},
getAll: function getAll() {
return {
set onsuccess(callback) {
var count = 0;
this.continue = function() {
count++;
var evt = {
target: {}
};
if (count <= MockMozContacts.limit) {
evt.target.result = {
id: count,
givenName: ['givenName ' + count],
lastName: ['lastName ' + count]
};
}
callback.call(this, evt);
};
var evt = {
target: {
result: {
id: count,
givenName: ['givenName ' + count],
lastName: ['lastName ' + count]
}
}
};
callback.call(this, evt);
},
set onerror(callback) {
}
};
},
save: function save(ct) {
ct.id = this.contacts.length;
this.contacts.push(ct);
return {
set onsuccess(callback) {
var self = this;
setTimeout(function() {
callback.call(self);
}, 10);
},
set onerror(callback) {
}
};
},
getRevision: function() {
var req = {
result: 'fakeRevision',
set onsuccess(callback) {
setTimeout(() => {
callback.call(this, { target: req });
});
},
set onerror(callback) {
}
};
return req;
},
setContacts: function(contacts) {
this.contacts = contacts;
},
remove: function remove(ct) {
var contactsIndex = this.contacts.indexOf(ct);
if (contactsIndex > -1) {
this.contacts.splice(contactsIndex, 1);
}
return {
set onsuccess(callback) {
var self = this;
setTimeout(function() {
callback.call(self);
}, 0);
},
set onerror(callback) {
}
};
},
clear: function clear() {
this.contacts.splice(0, this.contacts.length);
}
};
MockMozContacts = new MockMozContactsObj([]);

View file

@ -0,0 +1,49 @@
'use strict';
/* exported MockMozActivity */
var MockMozActivity = function(info) {
MockMozActivity.calls.push(info);
MockMozActivity.instances.push(this);
if (!info) {
return;
}
var name = info.name;
var data = info.data;
return {
set onsuccess(cb) {
MockMozActivity.timeouts.push(setTimeout(cb, 50));
},
set onerror(cb) {
MockMozActivity.errorCallback = cb;
},
name: name,
data: data,
get result() {
return MockMozActivity.successResult;
}
};
};
// create an array to hold any calls to this function to test them
MockMozActivity.mSetup = function() {
MockMozActivity.calls = [];
MockMozActivity.instances = [];
MockMozActivity.successResult = null;
MockMozActivity.timeouts = [];
};
MockMozActivity.mTriggerOnError = function() {
MockMozActivity.errorCallback();
};
// destroy the array so it resets every time
MockMozActivity.mTeardown = function() {
delete MockMozActivity.calls;
delete MockMozActivity.instances;
MockMozActivity.timeouts.forEach(clearTimeout);
MockMozActivity.timeouts = [];
};

View file

@ -0,0 +1,96 @@
// modified from the clock app's mock_moz_alarm.js for bug 1034570
(function(exports) {
'use strict';
var mozAlarmsId = 0;
function MockOSAlarm(date, respectTimezone, data, callback) {
this.date = date || new Date();
this.data = data || {};
this.callback = callback;
this.id = mozAlarmsId++;
this.respectTimezone = respectTimezone;
this.timeout = setTimeout(function() {
if ((typeof this.callback) === 'function') {
this.callback({
id: this.id,
respectTimezone: this.respectTimezone,
date: this.date,
data: this.data
});
}
}.bind(this), this.date.getTime() - Date.now());
}
function MockMozAlarmRequest(config) {
this.init(config || {});
}
MockMozAlarmRequest.prototype = {
init: function mar_init(config) {
setTimeout(function() {
this.fire(config.error, config.result);
}.bind(this), 0);
},
fire: function mar_call(error, result) {
if (!error) {
this.result = result;
this.onsuccess && this.onsuccess(this);
} else {
this.error = error;
this.onerror && this.onerror(this);
}
}
};
var messageHandlers = [];
navigator.mozSetMessageHandler = function(type, callback) {
if (type === 'alarm') {
messageHandlers.push(callback);
}
};
exports.MockMozAlarms = {
alarms: [],
getAll: function() {
return new MockMozAlarmRequest({
result: this.alarms
});
},
add: function(date, timezone, data) {
if (!(timezone === 'ignoreTimezone' ||
timezone === 'honorTimezone')) {
throw new Error('invalid timezone argument');
}
var alarm = new MockOSAlarm(date, timezone, data, function(x) {
messageHandlers.forEach(function(callback) {
callback(x);
});
this.remove(x.id);
}.bind(this));
this.alarms.push(alarm);
return new MockMozAlarmRequest({
result: alarm.id
});
},
remove: function(id) {
for (var i = 0; i < this.alarms.length; i++) {
var alarm = this.alarms[i];
if (alarm && (alarm.id === id)) {
clearTimeout(alarm.timeout);
this.alarms.splice(i, 1);
return true;
}
}
return false;
}
};
}(this));

View file

@ -0,0 +1,13 @@
/* exported MockmozContact */
'use strict';
var MockmozContact = function(obj) {
if (!obj) {
return;
}
var self = this;
Object.keys(obj).forEach(function(k) {
self[k] = obj[k];
});
};

View file

@ -0,0 +1,61 @@
(function(global) {
'use strict';
global.MockMozIntl = {
formatList: function(list) {
return Promise.resolve(list.join(', '));
},
DateTimeFormat: function(locales, options) {
var formatter = Intl.DateTimeFormat(locales, options);
return {
// we need this because mozIntl options extend Intl options
resolvedOptions() { return options; },
format: formatter.format.bind(formatter)
};
},
calendarInfo: function(token) {
return Promise.resolve(0);
},
DurationFormat: function(locales, options) {
return Promise.resolve({
format: function(input) {
return JSON.stringify({ value: input, options: options });
}
});
},
RelativeTimeFormat: function(locales, options) {
return {
format: function(value) {
return Promise.resolve();
}
};
},
UnitFormat: function(locales, options) {
return {
format: function(value) {
return Promise.resolve();
}
};
},
_gaia: {
relativePart: function(ms) {
return {
unit: 'minutes',
value: Math.abs(parseInt(ms / 1000 / 60))
};
},
RelativeDate: function(locales, options) {
return {
format: function(value) {
return Promise.resolve('pretty date');
},
formatElement: function(element, time, maxDiff) {}
};
},
getFormattedUnit(type, style, v) {
return Promise.resolve();
},
}
};
}(this));

View file

@ -0,0 +1,13 @@
'use strict';
var MockMozNDEFRecord = function(dict) {
this.tnf = dict ? dict.tnf : 'empty';
this.type = dict && dict.type;
this.id = dict && dict.id;
this.payload = dict && dict.payload;
};
MockMozNDEFRecord.tnf = 'empty';
MockMozNDEFRecord.type = null;
MockMozNDEFRecord.id = null;
MockMozNDEFRecord.payload = null;

View file

@ -0,0 +1,20 @@
/* exported MockMozNfc */
/* global MockPromise */
'use strict';
(function(exports) {
require('/shared/test/unit/mocks/mock_promise.js');
var MockMozNfc = {
onpeerready: null,
notifySendFileStatus: function() {
},
MockNFCPeer: {
isLost: false,
sendNDEF: function(records) {
return new MockPromise();
}
}
};
exports.MockMozNfc = MockMozNfc;
})(window);

View file

@ -0,0 +1,9 @@
'use strict';
/* global SimplePhoneMatcher */
/* exported MockPhoneNumberService */
var MockPhoneNumberService = {
normalize: function(number) {
return SimplePhoneMatcher.sanitizedNumber(number);
}
};

View file

@ -0,0 +1,15 @@
'use strict';
/* globals Promise */
var MockMultiContact = {
_data: Object.create(null),
getData: function(entry) {
return new Promise(function(resolve, reject) {
var id = entry.entryData[0].uid;
resolve(MockMultiContact._data[id]);
});
}
};

View file

@ -0,0 +1,22 @@
/* exported MockMultiSimActionButton */
'use strict';
var MockMultiSimActionButtonSingleton = {
mIsInitialized: false,
performAction: function() {
},
_phoneNumberGetter: null,
_click: function() {}
};
var MockMultiSimActionButton =
function(button, callCallback, settings, phoneNumberGetter) {
MockMultiSimActionButtonSingleton.mIsInitialized = true;
MockMultiSimActionButtonSingleton._phoneNumberGetter = phoneNumberGetter;
button.addEventListener('click', MockMultiSimActionButtonSingleton._click);
return MockMultiSimActionButtonSingleton;
};

View file

@ -0,0 +1,27 @@
'use strict';
(function(exports) {
var id = 0;
var MockMutationObserver = function MockMutationObserver(callback) {
var o = {
id: id++,
type: 'MockMutationObserver',
observe: function(element, config) {},
disconnect: function() {},
mTriggerCallback: function(mutations) {
callback(mutations);
}
};
MockMutationObserver.mLastObserver = o;
return o;
};
MockMutationObserver.mTeardown = function() {
this.mLastObserver = null;
};
exports.MockMutationObserver = MockMutationObserver;
})(window);

View file

@ -0,0 +1,221 @@
'use strict';
/* exports MockDatastore, MockDatastoreObj */
function MockDatastoreObj(name, owner, records) {
this.name = name || 'Mock_Datastore';
this.owner = owner;
this._records = records || Object.create(null);
}
MockDatastoreObj.prototype = {
readOnly: false,
revisionId: '123456',
_nextId: 1,
_inError: false,
_raceCondition: null,
_cb: null,
_clone: function(obj) {
var out = null;
if (obj) {
out = JSON.parse(JSON.stringify(obj));
}
return out;
},
_reject: function(errorName, errorMessage) {
return new window.Promise(function(resolve, reject) {
reject({
name: errorName || 'UnknownError',
message: errorMessage
});
});
},
get: function() {
if (this._inError === true) {
return this._reject();
}
var self = this;
var funcArgs = arguments;
return new window.Promise(function(resolve, reject) {
var dsIds;
var args = [];
for (var j = 0; j < funcArgs.length; j++) {
args.push(funcArgs[j]);
}
if (args.length === 1) {
dsIds = Array.isArray(args[0]) ? args[0] : [args[0]];
} else {
dsIds = args;
}
var results = [];
dsIds.forEach(function(aId) {
var record = self._clone(self._records[aId]);
results.push(record);
});
var out = args.length > 1 ? results : results[0];
resolve(out);
});
},
put: function(obj, dsId, revisionId) {
if (this._inError === true) {
return this._reject();
}
if (revisionId && this._raceCondition) {
return this._reject('ConstraintError', 'RevisionId is not up-to-date');
}
if (dsId === this._nextId) {
this._nextId++;
}
this._records[dsId] = this._clone(obj);
var self = this;
return new window.Promise(function(resolve, reject) {
resolve();
self._cb && self._cb({
operation: 'updated',
id: dsId
});
});
},
add: function(obj, dsId, revisionId) {
if (this._inError === true) {
return this._reject();
}
if (revisionId && this._raceCondition) {
return this._reject('ConstraintError', 'RevisionId is not up-to-date');
}
var newId = dsId || this._nextId;
this._nextId++;
if (typeof this._records[newId] !== 'undefined') {
return this._reject('ConstraintError');
}
this._records[newId] = this._clone(obj);
var self = this;
return new window.Promise(function(resolve, reject) {
resolve(newId);
self._cb && self._cb({
operation: 'added',
id: newId
});
});
},
remove: function(dsId, revisionId) {
if (this._inError === true) {
return this._reject();
}
if (revisionId && this._raceCondition) {
return this._reject('ConstraintError', 'RevisionId is not up-to-date');
}
delete this._records[dsId];
return new window.Promise(function(resolve, reject) {
resolve(true);
});
},
sync: function(revisionId) {
return {
next: () => {
if (!this._tasks[this._taskCounter]) {
this._taskCounter = 0;
}
return Promise.resolve(this._tasks[this._taskCounter++]);
}
};
},
_taskCounter: 0,
// Please make sure there is always a 'done' task at the end.
_tasks: [
{
operation: 'update',
id: 0,
data: {}
},
{
operation: 'done',
id: 0,
data: null
}
],
getLength: function() {
if (this._inError === true) {
return this._reject();
}
var total = Object.keys(this._records).length;
return new window.Promise(function(resolve, reject) {
resolve(total);
});
},
clear: function(revisionId) {
if (this._inError === true) {
return this._reject();
}
if (revisionId && this._raceCondition) {
return this._reject('ConstraintError', 'RevisionId is not up-to-date');
}
this._records = {};
this._nextId = 1;
return new window.Promise(function(resolve, reject) {
resolve();
});
},
addEventListener: function(type, cb) {
if (type === 'change') {
this._cb = cb;
}
},
removeEventListener: function() {
this._cb = null;
}
};
var MockDatastore = new MockDatastoreObj();
var MockNavigatorDatastore = {
_datastores: null,
getDataStores: function() {
if (MockNavigatorDatastore._notFound === true) {
return new window.Promise(function(resolve, reject) {
resolve([]);
});
}
return new window.Promise(function(resolve, reject) {
if (!MockNavigatorDatastore._datastores) {
resolve([MockDatastore]);
} else {
resolve(MockNavigatorDatastore._datastores);
}
});
}
};

View file

@ -0,0 +1,9 @@
'use strict';
/* global Promise */
window.MockNavigatorGetFeature = function(key) {
return new Promise((resolve, reject) => {
resolve(window.MockNavigatorGetFeature._values[key]);
});
};
window.MockNavigatorGetFeature._values = {};

View file

@ -0,0 +1,59 @@
'use strict';
/* globals MockDOMRequest */
/* exported MockGetDeviceStorage */
var MockGetDeviceStorage = function() {
return {
get: function(filepath) {
return {
set onsuccess(cb) {
cb.call(this);
},
get result() {
var file = {
name: filepath,
size: 1
};
return file;
}
};
},
addNamed: function(contact, filename) {
var response = {
target: {
result: filename
}
};
return {
set onsuccess(cb) {
cb(response);
}
};
},
addEventListener: function() {
// Do nothing
},
available: function() {
return {
set onsuccess(cb) {
setTimeout(cb);
},
get result() {
return 'available';
}
};
},
// need include libraries to test following domrequest functions
// * /shared/test/unit/mocks/mock_event_target.js
// * /shared/test/unit/mocks/mock_dom_request.js
freeSpace: function freeSpace() {
return new MockDOMRequest();
},
usedSpace: function usedSpace() {
return new MockDOMRequest();
},
storageStatus: function storageStatus() {
return new MockDOMRequest();
}
};
};

View file

@ -0,0 +1,7 @@
'use strict';
/* global MockGetDeviceStorage */
/* exported MockGetDeviceStorages */
var MockGetDeviceStorages = function(storageName) {
return [MockGetDeviceStorage()];
};

View file

@ -0,0 +1,175 @@
'use strict';
/* global MockEventTarget, Promise */
(function(exports) {
/**
* MockInputMethod is a constructer function that will give you an mock
* instance of `navigator.mozInputMethod`. For the real implementation, see
* http://dxr.mozilla.org/mozilla-central/source/dom/inputmethod/MozKeyboard.js
*
* The only extra mothod in the mock is `setInputContext()`, for you to set
* the inputContext.
*
* @param {Object} inputContext MockInputContext instance.
*
* @class MockInputMethod
* @requires MockEventTarget
*/
var MockInputMethod = function MockInputMethod(inputContext) {
this.inputcontext = inputContext || null;
this.mgmt = new MockInputMethodManager();
};
MockInputMethod.prototype = new MockEventTarget();
MockInputMethod.prototype.oninputcontextchange = null;
MockInputMethod.prototype.inputcontext = null;
/**
* Set the mocked inputContext. Will send an inputcontextchange event if
* the context is different.
*
* @param {Object} inputContext MockInputContext instance.
* @memberof MockInputMethod.prototype
*/
MockInputMethod.prototype.setInputContext = function(inputContext) {
inputContext = inputContext || null;
if (inputContext === this.inputcontext) {
return;
}
if (inputContext) {
this.inputcontext = inputContext;
} else {
this.inputcontext = null;
}
var evt = {
type: 'inputcontextchange'
};
this.dispatchEvent(evt);
};
MockInputMethod.prototype.addInput = function(inputId, inputManifest) {
// Return a promise here.
};
MockInputMethod.prototype.removeInput = function(inputId) {
// Return a promise here.
};
/**
* This class allow you to create a mock inputContext instance.
* It does *not* manage it's own states and properties. Doing so inevitablely
* reimplements the API :'(.
*
* Many of it's method returns a Promise. You should install a
* sinon.spy on the method and retrive the Promise instance with
* 'spy.getCall(0).returnValue'.
*
* These Promise instances comes with their `resolve()` and `reject()`
* methods exposed, so you should call them accordingly after setting the
* properties.
*
* Two additional methods, `fireSurroundingTextChange()` and
* `fireSelectionChange()` allow you to dispatch simulated events.
*
* @class MockInputContext
* @requires MockEventTarget
*
*/
var MockInputContext = function MockInputContext() {
};
MockInputContext.prototype = new MockEventTarget();
MockInputContext.prototype.type = 'text';
MockInputContext.prototype.inputType = 'text';
MockInputContext.prototype.inputMode = '';
MockInputContext.prototype.lang = '';
MockInputContext.prototype.selectionStart = 0;
MockInputContext.prototype.selectionEnd = 0;
MockInputContext.prototype.textBeforeCursor = '';
MockInputContext.prototype.textAfterCursor = '';
MockInputContext.prototype.onsurroundingtextchange = null;
MockInputContext.prototype.onselectionchange = null;
MockInputContext.prototype.fireSurroundingTextChange = function() {
var evt = {
type: 'surroundingtextchange',
detail: {
beforeString: this.textBeforeCursor,
afterString: this.textAfterCursor
}
};
this.dispatchEvent(evt);
};
MockInputContext.prototype.fireSelectionChange = function() {
var evt = {
type: 'selectionchange',
detail: {
selectionStart: this.selectionStart,
selectionEnd: this.selectionEnd
}
};
this.dispatchEvent(evt);
};
MockInputContext.prototype.getText =
MockInputContext.prototype.setSelectionRange =
MockInputContext.prototype.replaceSurroundingText =
MockInputContext.prototype.deleteSurroundingText =
MockInputContext.prototype.sendKey =
MockInputContext.prototype.setComposition =
MockInputContext.prototype.endComposition = function sendPromise() {
var oResolve, oReject;
// We are using the native Promise here but expose
// the reject method and a resolve method.
// See http://mdn.io/promise
var p = new Promise(function(resolve, reject) {
oResolve = resolve;
oReject = reject;
});
p.resolve = oResolve;
p.reject = oReject;
return p;
};
/**
* A MockInputMethodManager instance when the
* MockInputMethod instance is created.
*
* Noop method are in place to install spies.
*
* @class MockInputMethodManager
*
*/
var MockInputMethodManager = function MozInputMethodManager() {
};
MockInputMethodManager.prototype.showAll = function() {
};
MockInputMethodManager.prototype.next = function() {
};
MockInputMethodManager.prototype.hide = function() {
};
MockInputMethodManager.prototype.supportsSwitching = function() {
};
exports.MockInputMethodManager = MockInputMethodManager;
exports.MockInputMethod = MockInputMethod;
exports.MockInputContext = MockInputContext;
}(window));

View file

@ -0,0 +1,71 @@
'use strict';
/* exported MockNavigatormozApps */
var MockNavigatormozApps = {
mApps: [],
getSelf: function mnma_getSelf() {
var request = {};
this.mLastRequest = request;
return request;
},
mTriggerLastRequestSuccess: function(result) {
var request = this.mLastRequest;
var self = this;
request.result = result || {
name: 'sms',
launch: this._mLaunch.bind(this),
connect: function(keyword) {
self.mLastConnectionKeyword = keyword;
return {
then: function(cb) {
self.mLastConnectionCallback = cb;
}
};
}
};
if (request.onsuccess) {
var evt = {
target: request
};
return request.onsuccess(evt);
}
},
mTriggerOninstall: function mam_mTriggerOninstall(app) {
if (this.mgmt.oninstall) {
var evt = { application: app };
this.mgmt.oninstall(evt);
}
},
mgmt: {
getAll: function() {
return {
result: MockNavigatormozApps.mApps,
set onsuccess(cb) {
cb({target: this});
}
};
},
uninstall: function() {},
addEventListener: function() {}
},
mLastRequest: null,
mAppWasLaunched: false,
_mLaunch: function mnma_launch(entryPoint) {
this.mAppWasLaunched = true;
this.mAppWasLaunchedWithEntryPoint = entryPoint;
},
mTeardown: function mnma_mTeardown() {
this.mAppWasLaunched = false;
this.mAppWasLaunchedWithEntryPoint = null;
this.mLastRequest = null;
}
};

View file

@ -0,0 +1,77 @@
/* exported MockMozBluetooth, MockBTAdapter */
'use strict';
(function(window) {
var MockBTAdapter = {
answerWaitingCall: function mba_answerWaitingCall() {},
ignoreWaitingCall: function mba_ignoreWaitingCall() {},
toggleCalls: function mba_toggleCalls() {},
getConnectedDevices: function mba_getConnectedDevices() {},
getPairedDevices: function mba_getPairedDevices() {},
connect: function mba_connect() {},
connectSco: function mba_connectSco() {},
disconnectSco: function mba_disconnectSco() {},
setPairingConfirmation: function mba_setPairingConfirmation() {},
setPinCode: function mba_setPinCode() {},
setPasskey: function mba_setPasskey() {},
confirmReceivingFile: function mba_confirmReceivingFile() {},
sendFile: function mba_sendFile() {},
stopSendingFile: function mba_stopSendingFile() {},
pair: function mba_pair() {},
isScoConnected: function mba_isScoConnected() {},
sendMediaMetaData: function mba_sendMediaMetaData() {},
sendMediaPlayStatus: function mba_sendMediaPlayStatus() {},
onscostatuschanged: null,
onhfpstatuschanged: null,
ona2dpstatuschanged: null,
onrequestmediaplaystatus: null
};
var mEventListeners = [];
var mAdapterRequest = {
result: MockBTAdapter,
onsuccess: null,
onerror: null
};
function mmb_getDefaultAdapter() {
return mAdapterRequest;
}
function mmb_triggerOnGetAdapterSuccess() {
if (mAdapterRequest.onsuccess) {
mAdapterRequest.onsuccess();
}
}
function mmb_addEventListener(type, callback) {
mEventListeners.push({
type: type,
callback: callback
});
}
function mmb_triggerEventListeners(type) {
mEventListeners.forEach(function(eventListener) {
if (eventListener.type === type) {
eventListener.callback();
}
});
}
window.MockMozBluetooth = {
addEventListener: mmb_addEventListener,
triggerEventListeners: mmb_triggerEventListeners,
getDefaultAdapter: mmb_getDefaultAdapter,
triggerOnGetAdapterSuccess: mmb_triggerOnGetAdapterSuccess,
ondisabled: function mmb_ondisabled() {},
enabled: true
};
window.MockBTAdapter = MockBTAdapter;
})(window);

View file

@ -0,0 +1,95 @@
/* exported MockMozBluetooth, MockBTAdapter */
'use strict';
(function(window) {
var mAdapterEventListeners = [];
function mba_addEventListener(type, callback) {
mAdapterEventListeners.push({
type: type,
callback: callback
});
}
function mba_removeEventListener(type, callback) {
mAdapterEventListeners.forEach(function(item, idx) {
if (item.type === type && Object.is(item, callback)) {
mAdapterEventListeners.slice(idx, 1);
}
});
}
// refer to http://dxr.mozilla.org/mozilla-central/source/
// dom/webidl/BluetoothAdapter2.webidl
var MockBTAdapter = {
answerWaitingCall: function mba_answerWaitingCall() {},
ignoreWaitingCall: function mba_ignoreWaitingCall() {},
toggleCalls: function mba_toggleCalls() {},
getConnectedDevices: function mba_getConnectedDevices() {},
getPairedDevices: function mba_getPairedDevices() {},
connect: function mba_connect() {},
connectSco: function mba_connectSco() {},
disconnectSco: function mba_disconnectSco() {},
enable: function mba_enable() {},
disable: function mba_disable() {},
addEventListener: mba_addEventListener,
removeEventListener: mba_removeEventListener,
confirmReceivingFile: function mba_confirmReceivingFile() {},
sendFile: function mba_sendFile() {},
stopSendingFile: function mba_stopSendingFile() {},
pair: function mba_pair() {},
isScoConnected: function mba_isScoConnected() {},
sendMediaMetaData: function mba_sendMediaMetaData() {},
sendMediaPlayStatus: function mba_sendMediaPlayStatus() {},
onscostatuschanged: null,
onhfpstatuschanged: null,
ona2dpstatuschanged: null,
onrequestmediaplaystatus: null
};
var mManagerEventListeners = [];
function mmb_defaultAdapter() {
return MockBTAdapter;
}
function mmb_addEventListener(type, callback) {
mManagerEventListeners.push({
type: type,
callback: callback
});
}
function mmb_removeEventListener(type, callback) {
mManagerEventListeners.forEach(function(item, idx) {
if (item.type === type && Object.is(item, callback)) {
mManagerEventListeners.slice(idx, 1);
}
});
}
function mmb_triggerEventListeners(type, eventObj) {
mManagerEventListeners.forEach(function(eventListener) {
if (eventListener.type === type) {
eventListener.callback(eventObj);
}
});
}
// refer to http://dxr.mozilla.org/mozilla-central/source/
// dom/webidl/BluetoothManager2.webidl
window.MockMozBluetooth = {
defaultAdapter: mmb_defaultAdapter(),
addEventListener: mmb_addEventListener,
removeEventListener: mmb_removeEventListener,
triggerEventListeners: mmb_triggerEventListeners,
onattributechanged: function mmb_onattributechanged() {},
getAdapters: function mmb_getAdapters() {}
};
window.MockBTAdapter = MockBTAdapter;
})(window);

View file

@ -0,0 +1,57 @@
'use strict';
/* global MockDownload */
/* exported MockMozDownloads */
/*
* This mockup needs to import as well:
* /shared/unit/tests/mock/mock_download.js
*/
var MockMozDownloads = {
_getState: function(i) {
if (i === 0) {
return 'finalized';
} else if (i === 1) {
return 'stopped';
} else {
return 'downloading';
}
},
mockLength: 10,
getDownloads: function() {
return {
then: function(fulfill, reject) {
var mockDownloads = [];
for (var i = 0; i < this.mockLength; i++) {
var download = new MockDownload({
id: String(i),
url: 'http://firefoxos.com/archivo' + i + '.mp3',
startTime: new Date(i * 10000),
state: this._getState(i)
});
mockDownloads.push(download);
}
fulfill(mockDownloads);
}.bind(this)
};
},
set ondownloadstarted(handler) {
// Mock that a new download has been started
var newID = this.mockLength + 1;
var download = new MockDownload({
id: String(newID),
url: 'http://firefoxos.com/archivo' + newID + '.mp3'
});
setTimeout(function() {
handler(download);
});
},
remove: function(download) {
return {
then: function(success, error) {
success(download);
}
};
}
};

View file

@ -0,0 +1,298 @@
'use strict';
(function() {
// container for icc instances
var iccs = {};
var iccIds = [];
var timeouts = [];
var MockIccManager = {
_eventListeners: {},
get iccIds() {
return iccIds;
},
addEventListener: function(type, callback) {
if (!this._eventListeners[type]) {
this._eventListeners[type] = [];
}
var eventLength = this._eventListeners[type].length;
this._eventListeners[type][eventLength] = callback;
},
triggerEventListeners: function(type, evt) {
evt = evt || {};
evt.type = type;
if (!this._eventListeners[type]) {
return;
}
this._eventListeners[type].forEach(function(callback) {
if (typeof callback === 'function') {
callback(evt);
} else if (typeof callback == 'object' &&
typeof callback.handleEvent === 'function') {
callback.handleEvent(evt);
}
});
},
removeEventListener: function(type, callback) {
if (this._eventListeners[type]) {
var idx = this._eventListeners[type].indexOf(callback);
this._eventListeners[type].splice(idx, 1);
}
},
addIcc: function(id, object) {
object = object || {};
object.iccId = id;
// override by default
if (iccIds.indexOf(id) == -1) {
iccIds.push(id);
}
iccs[id] = this._wrapIcc(object);
},
removeIcc: function(id) {
var index = iccIds.indexOf(id);
if (index >= 0) {
iccIds.splice(index, 1);
}
if (iccs[id]) {
delete iccs[id];
}
},
getIccById: function(id) {
if (id in iccs) {
return iccs[id];
}
return;
},
// we will wrap icc to add some internal
// methods that will be called outside
_wrapIcc: function(object) {
object.setCardLock = function(options) {
var handlers = {
error: {
retryCount: object.retryCount
}
};
// We can manipulate object here
object._setCardLockOptions = options;
object._setCardLockCachedHandlers = handlers;
return handlers;
};
object.getCardLock = function(type) {
object._getCardLockType = type;
var req = {};
timeouts.push(setTimeout(function() {
req.result = { enabled: true };
if (req.onsuccess) {
req.onsuccess();
}
}));
return req;
};
object.getCardLockRetryCount = function(type) {
var req = {};
timeouts.push(setTimeout(function() {
if (req.onsuccess) {
req.result = { retryCount: 3 };
req.onsuccess && req.onsuccess();
}
}));
return req;
};
object.unlockCardLock = function(options) {
var pin;
if (typeof options.pin !== 'undefined') {
pin = options.pin;
} else if (typeof options.puk !== 'undefined') {
pin = options.puk;
}
// Fail sim unlock for 0000/00000000 pins/puks/xcks.
var req;
if (parseInt(pin, 10) !== 0) {
req = {
// fires success handler immediately
set onsuccess(handler) {
return handler();
},
get onsuccess() {
return function() {};
}
};
} else {
req = {
error: {
retryCount: object.retryCount
},
// fires onerror handler immediately
set onerror(handler) {
return handler();
},
get onerror() {
return function() {};
}
};
}
return req;
};
object.iccInfo = object.iccInfo || { msisdn: '0912345678' };
object._eventListeners = {};
object.addEventListener = function(type, callback) {
if (!this._eventListeners[type]) {
this._eventListeners[type] = [];
}
var eventLength = this._eventListeners[type].length;
this._eventListeners[type][eventLength] = callback;
};
object.removeEventListener = function(type, callback) {
if (this._eventListeners[type]) {
var idx = this._eventListeners[type].indexOf(callback);
this._eventListeners[type].splice(idx, 1);
}
};
object.triggerEventListeners = function(type, evt) {
if (!this._eventListeners[type]) {
return;
}
this._eventListeners[type].forEach(function(callback) {
if (typeof callback === 'function') {
callback(evt);
} else if (typeof callback == 'object' &&
typeof callback.handleEvent === 'function') {
callback.handleEvent(evt);
}
});
if (typeof object['on' + type] === 'function') {
object['on' + type](evt);
}
};
object.sendStkResponse = function() {};
object.sendStkMenuSelection = function() {};
object.sendStkEventDownload = function() {};
return object;
},
mTeardown: function iccm_teardown() {
iccIds = [];
iccs = {};
timeouts.forEach(clearTimeout);
timeouts = [];
},
// STK Constants
STK_MENU_TYPE_NOT_SPECIFIED: 0x00,
STK_MENU_TYPE_DATA_VALUES: 0x01,
STK_MENU_TYPE_NAVIGATION_OPTIONS: 0x03,
STK_BROWSER_MODE_LAUNCH_IF_NOT_ALREADY_LAUNCHED: 0x00,
STK_BROWSER_MODE_USING_EXISTING_BROWSER: 0x02,
STK_BROWSER_MODE_USING_NEW_BROWSER: 0x03,
STK_CMD_REFRESH: 0x01,
STK_CMD_POLL_INTERVAL: 0x03,
STK_CMD_POLL_OFF: 0x04,
STK_CMD_SET_UP_EVENT_LIST: 0x05,
STK_CMD_SET_UP_CALL: 0x10,
STK_CMD_SEND_SS: 0x11,
STK_CMD_SEND_USSD: 0x12,
STK_CMD_SEND_SMS: 0x13,
STK_CMD_SEND_DTMF: 0x14,
STK_CMD_LAUNCH_BROWSER: 0x15,
STK_CMD_PLAY_TONE: 0x20,
STK_CMD_DISPLAY_TEXT: 0x21,
STK_CMD_GET_INKEY: 0x22,
STK_CMD_GET_INPUT: 0x23,
STK_CMD_SELECT_ITEM: 0x24,
STK_CMD_SET_UP_MENU: 0x25,
STK_CMD_PROVIDE_LOCAL_INFO: 0x26,
STK_CMD_TIMER_MANAGEMENT: 0x27,
STK_CMD_SET_UP_IDLE_MODE_TEXT: 0x28,
STK_RESULT_OK: 0x00,
STK_RESULT_PRFRMD_WITH_PARTIAL_COMPREHENSION: 0x01,
STK_RESULT_PRFRMD_WITH_MISSING_INFO: 0x02,
STK_RESULT_PRFRMD_WITH_ADDITIONAL_EFS_READ: 0x03,
STK_RESULT_PRFRMD_LIMITED_SERVICE: 0x06,
STK_RESULT_UICC_SESSION_TERM_BY_USER: 0x10,
STK_RESULT_BACKWARD_MOVE_BY_USER: 0x11,
STK_RESULT_NO_RESPONSE_FROM_USER: 0x12,
STK_RESULT_HELP_INFO_REQUIRED: 0x13,
STK_RESULT_USSD_SS_SESSION_TERM_BY_USER: 0x14,
STK_RESULT_TERMINAL_CRNTLY_UNABLE_TO_PROCESS: 0x20,
STK_RESULT_NETWORK_CRNTLY_UNABLE_TO_PROCESS: 0x21,
STK_RESULT_USER_NOT_ACCEPT: 0x22,
STK_RESULT_USER_CLEAR_DOWN_CALL: 0x23,
STK_RESULT_LAUNCH_BROWSER_ERROR: 0x26,
STK_RESULT_BEYOND_TERMINAL_CAPABILITY: 0x30,
STK_RESULT_CMD_TYPE_NOT_UNDERSTOOD: 0x31,
STK_RESULT_CMD_DATA_NOT_UNDERSTOOD: 0x32,
STK_RESULT_CMD_NUM_NOT_KNOWN: 0x33,
STK_RESULT_SS_RETURN_ERROR: 0x34,
STK_RESULT_SMS_RP_ERROR: 0x35,
STK_RESULT_REQUIRED_VALUES_MISSING: 0x36,
STK_RESULT_USSD_RETURN_ERROR: 0x37,
STK_RESULT_MULTI_CARDS_CMD_ERROR: 0x38,
STK_RESULT_USIM_CALL_CONTROL_PERMANENT: 0x39,
STK_RESULT_BIP_ERROR: 0x3a,
STK_EVENT_TYPE_MT_CALL: 0x00,
STK_EVENT_TYPE_CALL_CONNECTED: 0x01,
STK_EVENT_TYPE_CALL_DISCONNECTED: 0x02,
STK_EVENT_TYPE_LOCATION_STATUS: 0x03,
STK_EVENT_TYPE_USER_ACTIVITY: 0x04,
STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE: 0x05,
STK_EVENT_TYPE_CARD_READER_STATUS: 0x06,
STK_EVENT_TYPE_LANGUAGE_SELECTION: 0x07,
STK_EVENT_TYPE_BROWSER_TERMINATION: 0x08,
STK_EVENT_TYPE_DATA_AVAILABLE: 0x09,
STK_EVENT_TYPE_CHANNEL_STATUS: 0x0a,
STK_EVENT_TYPE_SINGLE_ACCESS_TECHNOLOGY_CHANGED: 0x0b,
STK_EVENT_TYPE_DISPLAY_PARAMETER_CHANGED: 0x0c,
STK_EVENT_TYPE_LOCAL_CONNECTION: 0x0d,
STK_EVENT_TYPE_NETWORK_SEARCH_MODE_CHANGED: 0x0e,
STK_EVENT_TYPE_BROWSING_STATUS: 0x0f,
STK_EVENT_TYPE_FRAMES_INFORMATION_CHANGED: 0x10,
STK_SERVICE_STATE_NORMAL: 0x00,
STK_SERVICE_STATE_LIMITED: 0x01,
STK_SERVICE_STATE_UNAVAILABLE: 0x02,
STK_TONE_TYPE_DIAL_TONE: 0x01,
STK_TONE_TYPE_CALLED_SUBSCRIBER_BUSY: 0x02,
STK_TONE_TYPE_CONGESTION: 0x03,
STK_TONE_TYPE_RADIO_PATH_ACK: 0x04,
STK_TONE_TYPE_RADIO_PATH_NOT_AVAILABLE: 0x05,
STK_TONE_TYPE_ERROR: 0x06,
STK_TONE_TYPE_CALL_WAITING_TONE: 0x07,
STK_TONE_TYPE_RINGING_TONE: 0x08,
STK_TONE_TYPE_GENERAL_BEEP: 0x10,
STK_TONE_TYPE_POSITIVE_ACK_TONE: 0x11,
STK_TONE_TYPE_NEGATIVE_ACK_TONE: 0x12,
STK_TIME_UNIT_MINUTE: 0x00,
STK_TIME_UNIT_SECOND: 0x01,
STK_TIME_UNIT_TENTH_SECOND: 0x02,
STK_LOCAL_INFO_LOCATION_INFO: 0x00,
STK_LOCAL_INFO_IMEI: 0x01,
STK_LOCAL_INFO_DATE_TIME_ZONE: 0x03,
STK_LOCAL_INFO_LANGUAGE: 0x04,
STK_TIMER_START: 0x00,
STK_TIMER_DEACTIVATE: 0x01,
STK_TIMER_GET_CURRENT_VALUE: 0x02
};
// add default Icc instance at first
MockIccManager.addIcc('12345', {
'cardState': 'ready'
});
window.MockNavigatorMozIccManager = MockIccManager;
})();

View file

@ -0,0 +1,61 @@
'use strict';
(function() {
var props = ['voice', 'data'];
var eventListeners = null;
function mnmmc_init() {
props.forEach(function(prop) {
Mock[prop] = null;
});
eventListeners = { 'iccinfochange': [] };
}
function mnmmc_addEventListener(type, callback) {
if (eventListeners[type]) {
eventListeners[type][eventListeners[type].length] = callback;
}
}
function mnmmc_removeEventListener(type, callback) {
if (eventListeners[type]) {
var idx = eventListeners[type].indexOf(callback);
eventListeners[type].splice(idx, 1);
}
}
function mnmmc_triggerEventListeners(type, evt) {
if (!eventListeners[type]) {
return;
}
eventListeners[type].forEach(function(callback) {
if (typeof callback === 'function') {
callback(evt);
} else if (typeof callback == 'object' &&
typeof callback.handleEvent === 'function') {
callback.handleEvent(evt);
}
});
if (typeof Mock['on' + type] === 'function') {
Mock['on' + type](evt);
}
}
var Mock = {
addEventListener: mnmmc_addEventListener,
removeEventListener: mnmmc_removeEventListener,
triggerEventListeners: mnmmc_triggerEventListeners,
mTeardown: mnmmc_init,
get mEventListeners() {
return eventListeners;
},
supportedNetworkTypes: function() {},
setPreferredNetworkType: function() {}
};
mnmmc_init();
window.MockNavigatorMozMobileConnection = Mock;
})();

View file

@ -0,0 +1,177 @@
'use strict';
/**
* Will provide 1 Mobileconnection by default. call mAddMobileConnection and
* mRemoveMobileConnection to add/remove extra connections.
*/
(function() {
function MockMobileconnection() {
var props = ['voice', 'data', 'iccId', 'radioState', 'iccInfo'];
var eventListeners = null;
var radioEnabledReq = null;
var sendMMIReq = null;
var getCallBarringOptionReq = null;
var setCallBarringOptionReq = null;
var changeCallBarringPasscodeReq = null;
function mnmmc_init() {
props.forEach(function(prop) {
_mock[prop] = null;
});
eventListeners = {
'voicechange': [],
'iccinfochange': [],
'radiostatechange': [],
'datachange': [],
'cfstatechange': [],
'ussdreceived': []
};
radioEnabledReq = {};
sendMMIReq = {};
getCallBarringOptionReq = {};
setCallBarringOptionReq = {};
changeCallBarringPasscodeReq = {};
}
function mnmmc_addEventListener(type, callback) {
if (eventListeners[type]) {
eventListeners[type][eventListeners[type].length] = callback;
}
}
function mnmmc_removeEventListener(type, callback) {
if (eventListeners[type]) {
var idx = eventListeners[type].indexOf(callback);
eventListeners[type].splice(idx, 1);
}
}
function mnmmc_triggerEventListeners(type, evt) {
if (!eventListeners[type]) {
return;
}
eventListeners[type].forEach(function(callback) {
if (typeof callback === 'function') {
callback(evt);
} else if (typeof callback == 'object' &&
typeof callback.handleEvent === 'function') {
callback.handleEvent(evt);
}
});
if (typeof _mock['on' + type] === 'function') {
_mock['on' + type](evt);
}
}
function mnmmc_setRadioEnabled() {
return radioEnabledReq;
}
function mnmmc_sendMMI() {
return sendMMIReq;
}
function mnmmc_cancelMMI() {}
function mnmmc_getCallBarringOption(option) {
return getCallBarringOptionReq;
}
function mnmmc_setCallBarringOption(option) {
return setCallBarringOptionReq;
}
function mnmmc_changeCallBarringPassword(data) {
return changeCallBarringPasscodeReq;
}
var _mock = {
// Constants
ICC_SERVICE_CLASS_VOICE: (1 << 0),
ICC_SERVICE_CLASS_DATA: (1 << 1),
ICC_SERVICE_CLASS_FAX: (1 << 2),
ICC_SERVICE_CLASS_SMS: (1 << 3),
ICC_SERVICE_CLASS_DATA_SYNC: (1 << 4),
ICC_SERVICE_CLASS_DATA_ASYNC: (1 << 5),
ICC_SERVICE_CLASS_PACKET: (1 << 6),
ICC_SERVICE_CLASS_PAD: (1 << 7),
ICC_SERVICE_CLASS_MAX: (1 << 7),
// Methods
addEventListener: mnmmc_addEventListener,
removeEventListener: mnmmc_removeEventListener,
triggerEventListeners: mnmmc_triggerEventListeners,
setRadioEnabled: mnmmc_setRadioEnabled,
sendMMI: mnmmc_sendMMI,
cancelMMI: mnmmc_cancelMMI,
getCallBarringOption: mnmmc_getCallBarringOption,
setCallBarringOption: mnmmc_setCallBarringOption,
changeCallBarringPassword: mnmmc_changeCallBarringPassword,
mTeardown: mnmmc_init,
get mCachedRadioEnabledReq() {
return radioEnabledReq;
},
get mEventListeners() {
return eventListeners;
},
supportedNetworkTypes: function() {},
setPreferredNetworkType: function() {}
};
mnmmc_init();
return _mock;
}
function MockMobileConnections() {
var _mobileConnections = [];
function _mAddMobileConnection(newConn, index) {
if (newConn) {
_mobileConnections.splice(index, 0, newConn);
_mock[index] = newConn;
} else {
var conn = MockMobileconnection();
_mock[_mobileConnections.length] = conn;
_mobileConnections.push(conn);
}
}
function _mRemoveMobileConnection(index) {
if (!_mobileConnections.length) {
return;
}
if (index) {
_mobileConnections.splice(index, 1);
_mock[index] = null;
} else {
_mobileConnections.splice(_mobileConnections.length - 1, 1);
_mock[_mobileConnections.length - 1] = null;
}
}
function _mTeardown() {
_mobileConnections.every(function(conn, index) {
conn.mTeardown();
});
_mobileConnections = [];
_mAddMobileConnection();
}
var _mock = {
mTeardown: _mTeardown,
mAddMobileConnection: _mAddMobileConnection,
mRemoveMobileConnection: _mRemoveMobileConnection,
get length() {
return _mobileConnections.length;
}
};
_mAddMobileConnection();
return _mock;
}
window.MockMobileconnection = MockMobileconnection;
window.MockNavigatorMozMobileConnections = MockMobileConnections();
})();

View file

@ -0,0 +1,18 @@
'use strict';
/* exported MockMozPower */
var MockMozPower = {
addWakeLockListener: function() {},
cpuSleepAllowed: false,
screenBrightness: 0,
screenEnabled: false,
keyLightEnabled: false,
powerOff: function() {},
reboot: function() {},
factoryReset: function() {},
mTeardown: function teardown() {
this.cpuSleepAllowed = false;
this.screenBrightness = 0;
this.screenEnabled = false;
}
};

View file

@ -0,0 +1,35 @@
'use strict';
(function(window) {
var messageHandlers;
function mozSetMessageHandler(name, func) {
if (!mozSetMessageHandler.mLock[name]) {
messageHandlers[name] = func;
}
}
mozSetMessageHandler.mSetup = mozSetMessageHandler.mTeardown =
function msmh_setup() {
messageHandlers = Object.create(null);
mozSetMessageHandler.mLock = {};
};
mozSetMessageHandler.mTrigger = function msmh_trigger(name, message) {
if (typeof messageHandlers[name] === 'function') {
messageHandlers[name](message);
}
};
Object.defineProperty(mozSetMessageHandler, 'mMessageHandlers', {
get: function msmh_getMessageHandlers() { return messageHandlers; },
set: function msmh_setMessageHandlers(handlers) {
messageHandlers = handlers;
}
});
window.MockNavigatormozSetMessageHandler = mozSetMessageHandler;
})(window);

View file

@ -0,0 +1,276 @@
'use strict';
/*
* This is a mock for the API navigator.mozSettings. This is supposed to be used
* in unit tests to simulate the API and exercize all branches of your code. It
* should simulate it correctly for get/set operations, and for observers as
* well.
*
* To use it, you need to have the following code in your test:
*
* var realMozSettings;
* suiteSetup(funcction() {
* realMozSettings = navigator.mozSettings
* navigator.mozSettings = MockNavigatorSettings
* });
*
* suiteTeardown(function() {
* navigator.mozSettings = realMozSettings;
* });
*
* setup(function() {
* MockNavigatorSettings.mSetup();
* });
*
* teardown(function() {
* MockNavigatorSettings.mTeardown();
* });
*
* This mock is stateful until we reset it with mSetup or mTeardown. This means
* that any setting that has been set can also be retrieved.
* MockNavigatorSettings.mSettings gives a direct access to the stored settings.
* Then during a test, it's possible to check what setting(s) a code has set, or
* set settings before the test starts.
*
* In a normal operation, this mock uses setTimeout to properly simulate that
* mozSettings' get and set operations are asynchronous. Because setTimeout can
* have inconvenients (is slow, could produce races, intermittents, and sinon's
* fake timers do not play well), this mock also has a synchronous way for the
* get operation only:
*
* - you need to set the boolean MockNavigatorSettings.mSyncRepliesOnly to true
* after calling mSetup.
* - then you can call mReplyToRequests to answer any pending request in a
* synchronous way.
*
*/
(function(window) {
var observers, settings, removedObservers, requests, timeouts;
var _mSyncRepliesOnly, _onsettingchange;
function mns_mLockSet(obj) {
// Set values.
for (var key in obj) {
settings[key] = obj[key];
}
// Trigger observers to mimic real mozSettings implementation.
for (key in obj) {
mns_mTriggerObservers(
key,
{ settingName: key, settingValue: obj[key] }
);
}
var resolved;
var promise = new Promise((resolve, reject) => {
resolved = resolve;
});
var req = {
listeners: {},
addEventListener: function(name, cb) {
if (req.listeners[name]) {
req.listeners[name].push(cb);
} else {
req.listeners[name] = [cb];
}
},
then: function(cb, eb) {
// error-handler `eb` is never used, since the mock never fails.
return promise.then(cb);
}
};
if (!_mSyncRepliesOnly) {
timeouts.push(setTimeout(function() {
resolved(0);
if (req.onsuccess) {
req.onsuccess();
}
if ('success' in req.listeners) {
req.listeners.success.forEach(function (func) {
func();
});
}
}));
} else {
req.addEventListener('success', function () {
resolved(0);
});
requests.push(req);
}
return req;
}
function mns_clearRequests() {
requests = [];
if (timeouts) {
timeouts.forEach(clearTimeout);
}
timeouts = [];
}
function mns_mReplyToRequests() {
try {
var currentRequests = requests;
requests = [];
currentRequests.forEach(function(request) {
if (request.onsuccess) {
request.onsuccess({
target: request
});
}
if ('success' in request.listeners) {
request.listeners.success.forEach(function (func) {
func();
});
}
});
} catch(e) {
}
}
function mns_mLockGet(key) {
var resultObj = {};
if (key === '*') {
resultObj = settings;
} else {
resultObj[key] = settings[key];
}
var resolved;
var promise = new Promise((resolve, reject) => {
resolved = resolve;
});
var settingsRequest = {
listeners: {},
result: resultObj,
addEventListener: function(name, cb) {
if (settingsRequest.listeners[name]) {
settingsRequest.listeners[name].push(cb);
} else {
settingsRequest.listeners[name] = [cb];
}
},
then: function(cb, eb) {
// error-handler `eb` is never used, since the mock never fails.
return promise.then(cb);
}
};
if (!_mSyncRepliesOnly) {
timeouts.push(setTimeout(function() {
resolved(settingsRequest.result);
if (settingsRequest.onsuccess) {
settingsRequest.onsuccess();
}
if ('success' in settingsRequest.listeners) {
settingsRequest.listeners.success.forEach(function (func) {
func();
});
}
}));
} else {
settingsRequest.addEventListener('success', function () {
resolved(settingsRequest.result);
});
requests.push(settingsRequest);
}
return settingsRequest;
}
function mns_addObserver(name, cb) {
observers[name] = observers[name] || [];
observers[name].push(cb);
}
function mns_removeObserver(name, cb) {
if (!observers[name]) {
return;
}
removedObservers[name] = removedObservers[name] || [];
removedObservers[name].push(cb);
var index = observers[name].indexOf(cb);
if (index > -1) {
observers[name].splice(index, 1);
}
}
function mns_createLock() {
return {
set: mns_mLockSet,
get: mns_mLockGet
};
}
function mns_mTriggerObservers(name, args) {
var theseObservers = observers[name];
args.settingName = name;
if (theseObservers) {
theseObservers.forEach(function(func) {
func(args);
});
}
if (_onsettingchange) {
_onsettingchange(args);
}
}
function mns_reset() {
observers = {};
settings = {};
removedObservers = {};
mns_clearRequests();
_mSyncRepliesOnly = false;
_onsettingchange = null;
}
function mns_set(obj) {
for (var p in obj) {
settings[p] = obj[p];
}
}
mns_reset();
window.MockNavigatorSettings = {
addObserver: mns_addObserver,
removeObserver: mns_removeObserver,
createLock: mns_createLock,
mClearRequests: mns_clearRequests,
mReplyToRequests: mns_mReplyToRequests,
mTriggerObservers: mns_mTriggerObservers,
mSetup: mns_reset,
mTeardown: mns_reset,
mSet: mns_set,
get onsettingchange() {
return _onsettingchange;
},
set onsettingchange(value) {
_onsettingchange = value;
},
get mSyncRepliesOnly() {
return _mSyncRepliesOnly;
},
set mSyncRepliesOnly(value) {
_mSyncRepliesOnly = value;
},
get mObservers() {
return observers;
},
get mSettings() {
return settings;
},
get mRemovedObservers() {
return removedObservers;
},
get mRequests() {
return requests;
}
};
})(window);

View file

@ -0,0 +1,124 @@
'use strict';
(function() {
var listeners;
function mnmt_init() {
Mock.active = null;
Mock.calls = [];
Mock.conferenceGroup.state = null;
Mock.conferenceGroup.calls = [];
Mock.speakerEnabled = false;
listeners = {};
}
function mnmt_addEventListener(evtName, func) {
listeners[evtName] = listeners[evtName] || [];
listeners[evtName].push(func);
}
function mnmt_removeEventListener(evtName, func) {
if (listeners[evtName]) {
var listenerArray = listeners[evtName];
var index = listenerArray.indexOf(func);
if (index !== -1) {
listenerArray.splice(index, 1);
}
}
}
function mnmt_countEventListener(evtName, func) {
var count = 0;
var list = listeners[evtName];
if (!list) {
return count;
}
for (var i = 0; i < list.length; ++i) {
if (list[i] === func) {
count += 1;
}
}
return count;
}
function mnmt_mTriggerEvent(evt) {
var evtName = evt.type;
if (listeners[evtName]) {
listeners[evtName].forEach(function(listener) {
if (listener.handleEvent) {
listener.handleEvent(evt);
} else {
listener.call(Mock, evt);
}
});
}
}
function mnmt_mSuiteTeardown() {
Mock.oncallschanged = null;
Mock.conferenceGroup.oncallschanged = null;
Mock.conferenceGroup.onstatechange = null;
}
function mnmt_mTriggerCallsChanged() {
if (Mock.oncallschanged) {
Mock.oncallschanged();
}
mnmt_mTriggerEvent({ type: 'callschanged' });
}
function mnmt_mTriggerGroupCallsChanged() {
if (Mock.conferenceGroup.oncallschanged) {
Mock.conferenceGroup.oncallschanged();
mnmt_mTriggerEvent('callschanged');
}
}
function mnmt_mTriggerGroupStateChange() {
if (Mock.conferenceGroup.onstatechange) {
Mock.conferenceGroup.onstatechange();
mnmt_mTriggerEvent('statechange');
}
}
function mnmt_mTeardown() {
mnmt_init();
mnmt_mTriggerCallsChanged();
mnmt_mTriggerGroupCallsChanged();
}
var Mock = {
dial: function() { return {}; },
dialEmergency: function() {},
conferenceGroup: {
hangUp: function() { return {}; },
add: function() { return Promise.resolve(); },
hold: function() {},
resume: function() {},
addEventListener: function() {},
removeEventListener: function() {}
},
startTone: function(dtmfChar) {},
stopTone: function() {},
sendTones: function() {},
addEventListener: mnmt_addEventListener,
removeEventListener: mnmt_removeEventListener,
mCountEventListener: mnmt_countEventListener,
mTeardown: mnmt_mTeardown,
mSuiteTeardown: mnmt_mSuiteTeardown,
mTriggerEvent: mnmt_mTriggerEvent,
mTriggerCallsChanged: mnmt_mTriggerCallsChanged,
mTriggerGroupCallsChanged: mnmt_mTriggerGroupCallsChanged,
mTriggerGroupStateChange: mnmt_mTriggerGroupStateChange
};
mnmt_init();
window.MockNavigatorMozTelephony = Mock;
})();

View file

@ -0,0 +1,100 @@
/* exported MockNavigatorMozWifiManager */
'use strict';
var MockNavigatorMozWifiManager = {
enabled: true,
_certificateList: [],
_cb: {
onerror: []
},
setMacAddress: function(mac) {
this.macAddress = mac;
},
forget: function(network) {
return {
set onsuccess(callback) {
callback();
},
set onerror(callback) {
callback();
}
};
},
setNetworks: function(networks) {
this.networks = networks;
},
getKnownNetworks: function() {
var self = this;
return {
result: self.networks,
set onsuccess(callback) {
this.result = self.networks;
callback(this);
}
};
},
getNetworks: function() {
var self = this;
return {
result: self.networks,
set onsuccess(callback) {
this.result = self.networks;
callback(this);
}
};
},
connection: {
network: null
},
connectionInfoUpdate: null,
connectionInformation: {
ipAddress: '0.0.0.0',
linkSpeed: '10'
},
deleteCert: function(certName) {
return {
set onsuccess(callback) {
callback();
}
};
},
getImportedCerts: function() {
var self = this;
return {
result: {
ServerCert: self._certificateList
},
set onsuccess(callback) {
callback();
}
};
},
importCert: function() {
var self = this;
return {
set onsuccess(callback) {
callback();
},
set onerror(callback) {
self._cb.onerror.push(callback);
}
};
},
associate: function(network) {
return {
set onsuccess(callback) {
callback();
},
set onerror(callback) {
callback();
}
};
},
mSetup: function() {
this.enabled = true;
this._certificateList = [];
this._cb = {
onerror: []
};
}
};

View file

@ -0,0 +1,43 @@
'use strict';
(function() {
var lastWakeLock,
throwAtNextUnlock;
function mnwl_requestWakeLock(lock) {
lastWakeLock = {
released: false,
topic: lock,
mUnlockCount: 0,
unlock: function() {
if (throwAtNextUnlock) {
throwAtNextUnlock = false;
throw 'NS_ERROR_DOM_INVALID_STATE_ERR';
}
this.released = true;
this.mUnlockCount++;
}
};
return lastWakeLock;
}
function mnwl_teardown() {
lastWakeLock = undefined;
throwAtNextUnlock = undefined;
}
function mnwl_throwAtNextUnlock() {
throwAtNextUnlock = true;
}
window.MockNavigatorWakeLock = {
requestWakeLock: mnwl_requestWakeLock,
mTeardown: mnwl_teardown,
mThrowAtNextUnlock: mnwl_throwAtNextUnlock,
get mLastWakeLock() {
return lastWakeLock;
}
};
})();

View file

@ -0,0 +1,49 @@
'use strict';
var MockNotifications = [];
/**
* This mock partly implements a Web Notification contructor, see
* https://developer.mozilla.org/en-US/docs/Web/API/notification
*/
function MockNotification(title, options) {
this.id = options.id || 0;
this.title = title;
this.icon = options.icon;
this.body = options.body;
this.tag = options.tag;
this.data = options.data;
this.mEvents = {};
MockNotifications.push(this);
}
MockNotification.prototype.close = function() {
// nothing to do
};
MockNotification.prototype.onshow = function() {
// nothing to do
};
MockNotification.prototype.addEventListener =
function mockNotification_addEventListener(evt, callback) {
this.mEvents[evt] = callback;
};
MockNotification.prototype.removeEventListener =
function mockNotification_removeEventListener(evt, callback) {
delete this.mEvents[evt];
};
MockNotification.get = function mockNotification_get(options) {
return {
then: function() {}
};
};
MockNotification.mTeardown = function mn_mTeardown() {
MockNotifications = [];
};
MockNotification.requestPermission = function() {};

View file

@ -0,0 +1,42 @@
'use strict';
/* exported MockNotificationHelper */
var MockNotificationHelper = {
send: function(titleL10n, options) {
this.mOptions = options;
this.mTitleL10n = titleL10n;
var self = this;
var notification = {
addEventListener: function(type, cb) {
self.mEvents[type] = cb;
},
removeEventListener: function(type, cb) {
},
close: sinon.stub()
};
sinon.spy(notification, 'addEventListener');
return Promise.resolve(notification);
},
getIconURI: function nc_getIconURI(app, entryPoint) {
var result = '' + app.name;
if (entryPoint) {
result += '/' + entryPoint;
}
return result;
},
mEmit: function(type) {
this.mEvents[type]();
},
mEvents: {},
mTitleL10n: null,
mOptions: null,
mTeardown: function teardown() {
this.mTitleL10n = null;
this.mOptions = null;
this.mEvents = {};
}
};

View file

@ -0,0 +1,28 @@
/* global define */
define(function() {
'use strict';
var ctor = {
mUnlocked: false,
unlockBlob: function(secret, blob, callback) {
callback(this.mUnlocked);
},
mSetupUnlocked: function(value) {
this.mUnlocked = value;
},
get mimeSubtype() {
return this.mockMimeSubtype;
},
mSetupMimeSubtype: function(value) {
this.mockMimeSubtype = value;
},
getKey: function(callback) {
callback();
},
getOrCreateKey: function() {
}
};
return ctor;
});

View file

@ -0,0 +1,23 @@
'use strict';
function MockOptionMenu(options) {
MockOptionMenu.calls.push(options);
MockOptionMenu.instances.push(this);
}
MockOptionMenu.prototype = {
show: function() {
this.show.called = true;
}
};
// create an array to hold any calls to this function to test them
MockOptionMenu.mSetup = function() {
MockOptionMenu.calls = [];
MockOptionMenu.instances = [];
};
// destroy the array so it resets every time
MockOptionMenu.mTeardown = function() {
delete MockOptionMenu.calls;
delete MockOptionMenu.instances;
};

View file

@ -0,0 +1,26 @@
/* exported MockPermissionSettings */
'use strict';
var MockPermissionSettings = {
permissions: {},
mSetup: function() {
this.permissions = {};
},
set: function(permission, value, manifest, origin, browserFlag) {
this.permissions[permission] = value;
},
mTeardown: function() {
this.permissions = {};
},
get: function(permission, manifest, origin, browserFlag) {
return this.permissions[permission];
},
isExplicit: function(permission, manifest, origin, browserFlag) {
return !!this.permissions[permission];
}
};

View file

@ -0,0 +1,10 @@
(function(exports) {
'use strict';
var MockPipedPromise = {
_getPipedPromise: function (key, executor) {
return new Promise(executor);
}
};
exports.MockPipedPromise = MockPipedPromise;
}(window));

View file

@ -0,0 +1,84 @@
/* globals MockPresentationSession */
(function(exports) {
'use strict';
// Mock API from http://bit.ly/15wfAtX
var MockPresentation = {
_mEventHandlers: {
'available': [],
'sessionready': []
},
startSession: function(url, sessionId) {
var session = MockPresentationSession._mCreateSession();
session._state = true;
return Promise.resolve(session);
},
joinSession: function(url, sessionId) {
},
session: undefined,
_onsessionready: undefined,
set onsessionready (handler) {
if (typeof handler === 'function') {
this._onsessionready = handler;
}
},
_onavailable: undefined,
set onavailable (handler) {
if (typeof handler === 'function') {
this._onavailable = handler;
}
},
available: false,
addEventListener: function(eventName, handler) {
if (this._mEventHandlers[eventName] && typeof handler === 'function') {
this._mEventHandlers[eventName].push(handler);
}
},
removeEventListener: function(eventName, handler) {
if (this._mEventHandlers[eventName]) {
var index = this._mEventHandlers[eventName].indexOf(handler);
if (index >= 0) {
this._mEventHandlers[eventName].splice(index, 1);
}
}
},
_mFireEvent: function(eventName, eventObject) {
if (typeof this['_on' + eventName] === 'function') {
this['_on' + eventName](eventObject);
}
if (this._mEventHandlers[eventName]) {
this._mEventHandlers[eventName].forEach(function(handler) {
handler(eventObject);
});
}
},
_mInjectSession: function(session) {
this.session = session;
this._mFireEvent('sessionready', undefined);
},
_mReset: function() {
for (var eventHandlers in this._mEventHandlers) {
eventHandlers = [];
}
this._onavailable = undefined;
this._onsessionready = undefined;
this.session = undefined;
}
};
exports.MockPresentation = MockPresentation;
}(window));

View file

@ -0,0 +1,96 @@
(function(exports) {
'use strict';
// Mock API from http://bit.ly/1uAh0jd
var MockPresentationSession = {
_id: undefined,
get id () {
return this._id;
},
_mEventHandlers: {
'statechange': [],
'message': []
},
_onstatechange: undefined,
set onstatechange (handler) {
if (typeof handler === 'function') {
this._onstatechange = handler;
}
},
_onmessage: undefined,
set onmessage (handler) {
if (typeof handler === 'function') {
this._onmessage = handler;
}
},
get onmessage () {
return this._onmessage;
},
send: function(data) {
},
disconnect: function() {
this._state = false;
},
// two states: true and false
_state: false,
get state () {
return this._state;
},
addEventListener: function(eventName, handler) {
if (this._mEventHandlers[eventName] && typeof handler === 'function') {
this._mEventHandlers[eventName].push(handler);
}
},
removeEventListener: function(eventName, handler) {
if (this._mEventHandlers[eventName]) {
var index = this._mEventHandlers[eventName].indexOf(handler);
if (index >= 0) {
this._mEventHandlers[eventName].splice(index, 1);
}
}
},
_mFireEvent: function(eventName, eventObject) {
if (typeof this['_on' + eventName] === 'function') {
this['_on' + eventName](eventObject);
}
if (this._mEventHandlers[eventName]) {
this._mEventHandlers[eventName].forEach(function(handler) {
handler(eventObject);
});
}
},
_mCreateSession: function() {
this._mReset();
this._id = 'testsession';
return this;
},
_mReset: function() {
for (var eventHandlers in this._mEventHandlers) {
eventHandlers = [];
}
this._onstatechange = undefined;
this._onmessage = undefined;
this._state = false;
}
};
exports.MockPresentationSession = MockPresentationSession;
}(window));

View file

@ -0,0 +1,127 @@
'use strict';
/**
* MockPromise provides minimal logic to replace the original Promise interface.
* It does not call anything when called. You should spy the functions to get
* the passed callbacks and call them.
*
* This mock is only helpful if you are testing on a promise chain and you wish
* to assert the condition of the middle of the chain. It will not be really
* helpful if you are only interested in end-result of the chain from the
* returned promise. (you could just then() your assert function after the
* returned promise)
*
* Help methods are provided for calling the specified passed callback.
* These methods however only deal with the first then() or catch() calls.
*
* This mock will help you make the test script testing promise chain
* synchronize (without using any |done()| in mocha).
*
* For example, to test this chain:
*
* function foo() {
* (new Promise(callback1))
* .then(doSomething1)
* .then(doSomething2)
* .catch(somethingWrong1);
* }
*
* You can do:
*
* // Execute the chain
* foo();
*
* // Call callback1
* var p0 = window.Promise.firstCall.returnValue;
* p0.mExecuteCallback(function resolve(val) {
* ... assert val
* }, function reject() {
* ... assert
* });
*
* ... do something to cause the callback1 to call resolve or reject here.
*
* // Call doSomething1
* var returned1 = p0.mFulfillToValue(val);
*
* ... assert end result of doSomething1
*
* // Call doSomething2
* var p1 = p0.mGetNextPromise();
* var returned2 = p1.mFulfillToValue(returned1);
*
* ... assert end result of doSomething2
*
* In a separate test, do any of the following will invoke somethingWrong1:
*
* p0.mRejectToError(error);
* p1.mRejectToError(error);
*
*/
(function(exports) {
var id=0;
var MockPromise = function MockPromise(callback) {
var p = {
id: id++,
type: 'MockPromise',
then: sinon.spy(function SpyThen(onFulfilled, onRejected) {
return new MockPromise();
}),
catch: sinon.spy(function SpyCatch(onRejected) {
return new MockPromise();
}),
mExecuteCallback: function mExecCallback(resolve, reject) {
callback(resolve, reject);
},
mGetNextPromise: function mGetNextPromise() {
if (!this.then.called) {
throw new Error(
'MockPromise: cannot mGetNextPromise, then() not called.');
}
return this.then.firstCall.returnValue;
},
mFulfillToValue: function mFulfill(value) {
if (!this.then.called) {
throw new Error('MockPromise: cannot fulfill, then() not called.');
}
return this.then.firstCall.args[0].call(window, value);
},
mRejectToError: function mRejectToError(error) {
if (this.then.called) {
if (typeof this.then.firstCall.args[1] === 'function') {
return this.then.firstCall.args[1].call(window, error);
} else {
return this.then.firstCall.returnValue.mRejectToError(error);
}
} else if (this.catch.called) {
return this.catch.firstCall.args[0].call(window, error);
} else {
throw new Error(
'MockPromise: cannot reject, then() nor catch() not called.');
}
}
};
return p;
};
// Spy these in setup(), e.g.
// this.sinon.spy(MockPromise, 'all');
MockPromise.all = MockPromise;
MockPromise.reject = MockPromise;
MockPromise.resolve = MockPromise;
MockPromise.race = MockPromise;
// Spy this in setup(), e.g.
// window.Promise = this.sinon.spy(MockPromise);
exports.MockPromise = MockPromise;
})(window);

Some files were not shown because too many files have changed in this diff Show more