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:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
38
gaia/apps/network-alerts/attention.html
Executable file
38
gaia/apps/network-alerts/attention.html
Executable file
|
|
@ -0,0 +1,38 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<title>CMAS message</title>
|
||||
<link media="(min-height: 4.5rem)" rel="stylesheet" href="/shared/style/confirm.css">
|
||||
<link media="(min-height: 4.5rem)" rel="stylesheet" href="style/attention.css">
|
||||
<link media="(max-height: 4.5rem)" rel="stylesheet" href="style/attention-small.css">
|
||||
|
||||
<script defer src="shared/js/l10n.js"></script>
|
||||
<script defer src="shared/js/notification_helper.js"></script>
|
||||
<script defer src="js/utils.js"></script>
|
||||
<script defer src="js/attention/notify.js"></script>
|
||||
<script defer src="js/attention/attention.js"></script>
|
||||
<script defer src="js/attention/startup.js"></script>
|
||||
|
||||
<!-- Date/Time Localization -->
|
||||
<meta name="defaultLanguage" content="en-US">
|
||||
<meta name="availableLanguages" content="en-US">
|
||||
<link rel="localization" href="/shared/locales/date/date.{locale}.properties">
|
||||
<link rel="localization" href="locales/network-alerts.{locale}.properties">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form role="dialog" data-type="confirm">
|
||||
<section>
|
||||
<h1></h1>
|
||||
<p></p>
|
||||
</section>
|
||||
<menu>
|
||||
<button class="full recommend" data-l10n-id="btn-ok">OK</button>
|
||||
</menu>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
10
gaia/apps/network-alerts/index.html
Executable file
10
gaia/apps/network-alerts/index.html
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset='UTF-8'>
|
||||
<script defer src='js/index.js'></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
98
gaia/apps/network-alerts/js/attention/attention.js
Executable file
98
gaia/apps/network-alerts/js/attention/attention.js
Executable file
|
|
@ -0,0 +1,98 @@
|
|||
/* global NotificationHelper,
|
||||
Notify,
|
||||
Promise,
|
||||
Utils
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
|
||||
var form;
|
||||
|
||||
function init() {
|
||||
form = document.querySelector('form');
|
||||
form.addEventListener('submit', onFormSubmit);
|
||||
|
||||
navigator.mozL10n.once(function () {
|
||||
sendNotification().catch((err) => {
|
||||
console.error('Error while sending a notification', err);
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('visibilitychange', onVisibilityChange);
|
||||
}
|
||||
|
||||
function sendNotification() {
|
||||
var params = Utils.parseParams();
|
||||
var fromNotification = params.notification;
|
||||
if (fromNotification) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
var titleL10n = params.title;
|
||||
var body = params.body;
|
||||
var req = navigator.mozApps.getSelf();
|
||||
|
||||
req.onsuccess = function onsuccess(event) {
|
||||
var app = event.target.result;
|
||||
|
||||
NotificationHelper.send(titleL10n, {
|
||||
body: body,
|
||||
tag: '' + Date.now(), // needs to be unique
|
||||
icon: NotificationHelper.getIconURI(app),
|
||||
data: { title: titleL10n },
|
||||
closeOnClick: false
|
||||
}).then(function(notification){
|
||||
notification.onerror = function onerror() {
|
||||
reject(new Error('CMAS: notification API error'));
|
||||
};
|
||||
|
||||
notification.onshow = resolve;
|
||||
});
|
||||
};
|
||||
|
||||
req.onerror = function onerror() {
|
||||
reject(new Error('CMAS: App getSelf request error'));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function closeApp() {
|
||||
// make sure we close both parent and child window
|
||||
window.opener ? window.opener.close() : window.close();
|
||||
}
|
||||
|
||||
function onFormSubmit(e) {
|
||||
e.preventDefault();
|
||||
// Close parent(if exist) and child attention window after user click ok
|
||||
closeApp();
|
||||
}
|
||||
|
||||
function onVisibilityChange() {
|
||||
// Close app when app resized as top banner and moved to background
|
||||
if (document.hidden && !document.querySelector('h1').clientHeight) {
|
||||
closeApp();
|
||||
}
|
||||
}
|
||||
|
||||
function render() {
|
||||
var params = Utils.parseParams();
|
||||
renderForm(params);
|
||||
var fromNotification = params.notification;
|
||||
if (!fromNotification) {
|
||||
Notify.notify();
|
||||
}
|
||||
}
|
||||
|
||||
function renderForm(params) {
|
||||
var title = params.title;
|
||||
var body = params.body;
|
||||
|
||||
form.querySelector('h1').setAttribute('data-l10n-id', title);
|
||||
form.querySelector('p').textContent = body;
|
||||
}
|
||||
|
||||
exports.Attention = { init, render };
|
||||
|
||||
})(window);
|
||||
120
gaia/apps/network-alerts/js/attention/notify.js
Executable file
120
gaia/apps/network-alerts/js/attention/notify.js
Executable file
|
|
@ -0,0 +1,120 @@
|
|||
/* global
|
||||
AudioContext
|
||||
*/
|
||||
|
||||
(function(exports) {
|
||||
'use strict';
|
||||
|
||||
const SETTINGS = {
|
||||
notificationVolume: 'audio.volume.notification',
|
||||
vibration: 'vibration.enabled'
|
||||
};
|
||||
|
||||
const ATTENTION_PATTERN = [4, 1, 2, 1, 2, 1];
|
||||
ATTENTION_PATTERN.push(...ATTENTION_PATTERN);
|
||||
|
||||
const ATTENTION_SOUND_VOLUME = 0.3;
|
||||
|
||||
function getSetting(key) {
|
||||
if (!navigator.mozSettings) {
|
||||
return Promise.reject(new Error('The mozSettings API is not available.'));
|
||||
}
|
||||
|
||||
return navigator.mozSettings.createLock().get(key).then(
|
||||
(result) => result[key]
|
||||
);
|
||||
}
|
||||
|
||||
function getSettings(settings) {
|
||||
return Promise.all(
|
||||
settings.map(getSetting)
|
||||
).catch((e) => {
|
||||
// catch and log errors
|
||||
console.error('Error while retrieving settings', e.message, e);
|
||||
return settings.map(() => null);
|
||||
}).then((results) => {
|
||||
return settings.reduce((result, setting, i) => {
|
||||
result[setting] = results[i];
|
||||
return result;
|
||||
}, {});
|
||||
});
|
||||
}
|
||||
|
||||
// Converts from the ATTENTION_PATTERN (suitable for the Vibration API) to a
|
||||
// Float32Array suitable for the Audio API.
|
||||
//
|
||||
// The Float32Array will be interpolated so we just need to have the changes.
|
||||
// Each value will last a "unit" of time.
|
||||
function getAttentionCurveWave() {
|
||||
var result = [];
|
||||
var currentValue = ATTENTION_SOUND_VOLUME;
|
||||
|
||||
ATTENTION_PATTERN.forEach(duration => {
|
||||
for (var i = 0; i < duration; i++) {
|
||||
result.push(currentValue);
|
||||
}
|
||||
|
||||
currentValue = ATTENTION_SOUND_VOLUME - currentValue;
|
||||
});
|
||||
|
||||
return new Float32Array(result);
|
||||
}
|
||||
|
||||
function ringtone() {
|
||||
var audioChannel = 'notification';
|
||||
var audioCtx = new AudioContext(audioChannel);
|
||||
|
||||
var o1 = audioCtx.createOscillator();
|
||||
var o2 = audioCtx.createOscillator();
|
||||
var gain = audioCtx.createGain();
|
||||
|
||||
var time = audioCtx.currentTime;
|
||||
o1.type = o2.type = 'sine';
|
||||
o1.frequency.value = 853;
|
||||
o2.frequency.value = 960;
|
||||
|
||||
o1.start();
|
||||
o2.start();
|
||||
// Eventually stop the oscillator to allow garbage collecting.
|
||||
o1.stop(time + 11);
|
||||
o2.stop(time + 11);
|
||||
|
||||
var wave = getAttentionCurveWave();
|
||||
gain.gain.setValueCurveAtTime(wave, time, 11);
|
||||
|
||||
o1.connect(gain);
|
||||
o2.connect(gain);
|
||||
gain.connect(audioCtx.destination);
|
||||
}
|
||||
|
||||
function vibrate() {
|
||||
var pattern = ATTENTION_PATTERN.map((value) => value * 500);
|
||||
// vibration only works when App is in the foreground
|
||||
if (document.hidden) {
|
||||
window.addEventListener('visibilitychange', function waitOn() {
|
||||
window.removeEventListener('visibilitychange', waitOn);
|
||||
navigator.vibrate(pattern);
|
||||
});
|
||||
} else {
|
||||
navigator.vibrate(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
var Notify = {
|
||||
notify: function notification_ringtone() {
|
||||
return getSettings(
|
||||
[SETTINGS.notificationVolume, SETTINGS.vibration]
|
||||
).then((settings) => {
|
||||
if (settings[SETTINGS.notificationVolume]) {
|
||||
ringtone();
|
||||
}
|
||||
|
||||
if (settings[SETTINGS.vibration]) {
|
||||
vibrate();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.Notify = Notify;
|
||||
}(this));
|
||||
8
gaia/apps/network-alerts/js/attention/startup.js
Executable file
8
gaia/apps/network-alerts/js/attention/startup.js
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
/* global Attention */
|
||||
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
Attention.init();
|
||||
Attention.render();
|
||||
})();
|
||||
110
gaia/apps/network-alerts/js/index.js
Executable file
110
gaia/apps/network-alerts/js/index.js
Executable file
|
|
@ -0,0 +1,110 @@
|
|||
'use strict';
|
||||
|
||||
// See reference TS in following document for GSM and CDMA:
|
||||
// [1] GSM:
|
||||
// http://www.etsi.org/deliver/etsi_ts/123000_123099/123041/11.06.00_60/ts_123041v110600p.pdf
|
||||
//
|
||||
// [2] CDMA:
|
||||
// http://www.3gpp2.org/public_html/specs/C.R1001-G_v1.0_Param_Administration.pdf
|
||||
|
||||
(function() {
|
||||
const CMAS_ID = 'emergency-alert-title',
|
||||
CMAS_ENABLED_KEY = 'cmas.enabled';
|
||||
|
||||
// See GSM[1] section 9.4.1.2.2 Message Identifier and
|
||||
// CDMA[2] section 9.3.3 Commercial Mobile for thet presidential alerts
|
||||
const GSM_PRESIDENTIAL_ALERTS = [4370, 4383];
|
||||
const CDMA_PRESIDENTIAL_ALERT = 0x1000;
|
||||
|
||||
window.navigator.mozSetMessageHandler(
|
||||
'cellbroadcast-received',
|
||||
onCellbroadcast
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if the id of the message in in CMAS specific range. Please ref link
|
||||
* above for GSM[1] and CDMA[2]
|
||||
*
|
||||
* @param {number} Message
|
||||
*/
|
||||
function isEmergencyAlert(message) {
|
||||
var messageId = message.messageId;
|
||||
var cdmaServiceCategory = message.cdmaServiceCategory;
|
||||
var isGSM = cdmaServiceCategory === null;
|
||||
|
||||
if (isGSM) {
|
||||
return (messageId >= 4370 && messageId < 4400);
|
||||
} else {
|
||||
return (cdmaServiceCategory >= 0x1000 && cdmaServiceCategory <= 0x10FF);
|
||||
}
|
||||
}
|
||||
|
||||
function isCmasEnabledForServiceId(serviceId) {
|
||||
var getPromise = navigator.mozSettings.createLock().get(CMAS_ENABLED_KEY);
|
||||
|
||||
return getPromise.then(
|
||||
result => !!(result[CMAS_ENABLED_KEY][serviceId])
|
||||
);
|
||||
}
|
||||
|
||||
function isPresidentialAlert(message) {
|
||||
var messageId = message.messageId;
|
||||
var cdmaServiceCategory = message.cdmaServiceCategory;
|
||||
var isGSM = cdmaServiceCategory === null;
|
||||
|
||||
if (isGSM) {
|
||||
return GSM_PRESIDENTIAL_ALERTS.indexOf(messageId) !== -1;
|
||||
} else {
|
||||
return CDMA_PRESIDENTIAL_ALERT === cdmaServiceCategory;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handling the cellbroadcast system message.
|
||||
* @param {Object} Cellbroadcast message object which contains necessary
|
||||
* information like Identifier and body for displaying attention screen.
|
||||
*/
|
||||
function onCellbroadcast(message) {
|
||||
if (!isEmergencyAlert(message)) {
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
|
||||
var shouldSendAlertPromise =
|
||||
isPresidentialAlert(message) ?
|
||||
Promise.resolve(true) :
|
||||
isCmasEnabledForServiceId(message.serviceId).catch((e) => {
|
||||
console.error('CMAS: Unable to query settings database', e);
|
||||
return false;
|
||||
});
|
||||
|
||||
return shouldSendAlertPromise.then((yes) => {
|
||||
if (yes) {
|
||||
sendAlert({
|
||||
title: CMAS_ID,
|
||||
body: message.body
|
||||
});
|
||||
// Do not close window here because it will close attention screen
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open CMAS alert attention screen with given message body content and
|
||||
* title.
|
||||
* @param {Object} Options object that contains the title l10n id and message
|
||||
* body.
|
||||
*/
|
||||
function sendAlert(opts) {
|
||||
var url = [
|
||||
'attention.html?title=',
|
||||
encodeURIComponent(opts.title),
|
||||
'&body=',
|
||||
encodeURIComponent(opts.body)
|
||||
].join('');
|
||||
|
||||
window.open(url, '_blank', 'attention');
|
||||
}
|
||||
})();
|
||||
36
gaia/apps/network-alerts/js/notification/notification.js
Executable file
36
gaia/apps/network-alerts/js/notification/notification.js
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
|
||||
function init() {
|
||||
window.navigator.mozSetMessageHandler('notification', onNotification);
|
||||
}
|
||||
|
||||
function closeWindow() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
function onNotification(message) {
|
||||
if (!message.clicked) {
|
||||
closeWindow();
|
||||
return;
|
||||
}
|
||||
|
||||
var title = message.data.title;
|
||||
|
||||
var url = [
|
||||
'attention.html?title=',
|
||||
encodeURIComponent(title),
|
||||
'&body=',
|
||||
encodeURIComponent(message.body),
|
||||
'¬ification=1'
|
||||
].join('');
|
||||
|
||||
window.open(url, '_blank', 'attention');
|
||||
}
|
||||
|
||||
exports.NotificationHandler = {
|
||||
init: init
|
||||
};
|
||||
|
||||
})(window);
|
||||
7
gaia/apps/network-alerts/js/notification/startup.js
Executable file
7
gaia/apps/network-alerts/js/notification/startup.js
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
/* global NotificationHandler */
|
||||
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
NotificationHandler.init();
|
||||
})();
|
||||
18
gaia/apps/network-alerts/js/utils.js
Executable file
18
gaia/apps/network-alerts/js/utils.js
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
var rparams = /([^?=&]+)(?:=([^&]*))?/g;
|
||||
|
||||
function parseParams(input) {
|
||||
input = input || window.location.href;
|
||||
var parsed = {};
|
||||
input.replace(rparams, function($0, $1, $2) {
|
||||
parsed[decodeURIComponent($1)] = $2 ? decodeURIComponent($2) : $2;
|
||||
});
|
||||
return parsed;
|
||||
}
|
||||
|
||||
exports.Utils = {
|
||||
parseParams: parseParams
|
||||
};
|
||||
})(window);
|
||||
18
gaia/apps/network-alerts/jsdoc.json
Executable file
18
gaia/apps/network-alerts/jsdoc.json
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "network-alerts",
|
||||
"tags": {
|
||||
"dictionaries": ["jsdoc"]
|
||||
},
|
||||
"source": {
|
||||
"include": ["apps/network-alerts/js/**/*.js"]
|
||||
},
|
||||
"plugins": [
|
||||
"plugins/markdown",
|
||||
"plugins/summarize"
|
||||
],
|
||||
"opts": {
|
||||
"private": true,
|
||||
"recurse": true,
|
||||
"destination": "docs/network-alerts"
|
||||
}
|
||||
}
|
||||
3
gaia/apps/network-alerts/locales/network-alerts.en-US.properties
Executable file
3
gaia/apps/network-alerts/locales/network-alerts.en-US.properties
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
# attenstion screen dialog
|
||||
btn-ok=OK
|
||||
emergency-alert-title=Emergency Alert
|
||||
35
gaia/apps/network-alerts/manifest.webapp
Executable file
35
gaia/apps/network-alerts/manifest.webapp
Executable file
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "Network Alerts",
|
||||
"description": "Handling network alerts (like CMAS)",
|
||||
"type": "certified",
|
||||
"launch_path": "/index.html",
|
||||
"role": "system",
|
||||
"developer": {
|
||||
"name": "The Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
},
|
||||
"icons": {
|
||||
"30": "/style/icons/icon-30.png",
|
||||
"45": "/style/icons/icon-45.png",
|
||||
"60": "/style/icons/icon-60.png",
|
||||
"68": "/style/icons/icon-68.png"
|
||||
},
|
||||
"permissions": {
|
||||
"themeable":{},
|
||||
"attention":{},
|
||||
"desktop-notification":{},
|
||||
"cellbroadcast":{},
|
||||
"settings":{ "access": "readonly" },
|
||||
"audio-channel-notification":{},
|
||||
"moz-extremely-unstable-and-will-change-webcomponents":{}
|
||||
},
|
||||
"locales": {
|
||||
"en-US": {}
|
||||
},
|
||||
"default_locale": "en-US",
|
||||
"orientation": "default",
|
||||
"messages": [
|
||||
{ "notification": "/notification.html" },
|
||||
{ "cellbroadcast-received": "/index.html"}
|
||||
]
|
||||
}
|
||||
11
gaia/apps/network-alerts/notification.html
Executable file
11
gaia/apps/network-alerts/notification.html
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<script src="js/utils.js"></script>
|
||||
<script src="js/notification/notification.js"></script>
|
||||
<script src="js/notification/startup.js"></script>
|
||||
</head>
|
||||
</html>
|
||||
10
gaia/apps/network-alerts/package.json
Executable file
10
gaia/apps/network-alerts/package.json
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"webide": {
|
||||
"prepackage": {
|
||||
"command": "make",
|
||||
"env": ["APP=network-alerts"],
|
||||
"cwd": "../.."
|
||||
},
|
||||
"packageDir": "../../build_stage/network-alerts/"
|
||||
}
|
||||
}
|
||||
14
gaia/apps/network-alerts/style/attention-small.css
Executable file
14
gaia/apps/network-alerts/style/attention-small.css
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
body {
|
||||
background: #2D2D2D;
|
||||
color: white;
|
||||
}
|
||||
|
||||
h1 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
p {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
4
gaia/apps/network-alerts/style/attention.css
Executable file
4
gaia/apps/network-alerts/style/attention.css
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
body, html {
|
||||
/* Can be increased if we want a bigger font in the alert */
|
||||
font-size: 10px;
|
||||
}
|
||||
BIN
gaia/apps/network-alerts/style/icons/icon-30.png
Executable file
BIN
gaia/apps/network-alerts/style/icons/icon-30.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
gaia/apps/network-alerts/style/icons/icon-45.png
Executable file
BIN
gaia/apps/network-alerts/style/icons/icon-45.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
BIN
gaia/apps/network-alerts/style/icons/icon-60.png
Executable file
BIN
gaia/apps/network-alerts/style/icons/icon-60.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
gaia/apps/network-alerts/style/icons/icon-68.png
Executable file
BIN
gaia/apps/network-alerts/style/icons/icon-68.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 2 KiB |
27
gaia/apps/network-alerts/test/build/integration/network-alerts_test.js
Executable file
27
gaia/apps/network-alerts/test/build/integration/network-alerts_test.js
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
'use strict';
|
||||
|
||||
/* jshint node: true, mocha: true */
|
||||
/* global suiteSetup */
|
||||
|
||||
var helper = require('helper');
|
||||
|
||||
suite('Network-alerts tests', function() {
|
||||
suiteSetup(helper.cleanupWorkspace);
|
||||
teardown(helper.cleanupWorkspace);
|
||||
|
||||
test('APP=network-alerts make', function(done) {
|
||||
helper.exec('APP=network-alerts make', function(error, stdout, stderr) {
|
||||
helper.checkError(error, stdout, stderr);
|
||||
|
||||
var zipPath = process.cwd() +
|
||||
'/profile/webapps/network-alerts.gaiamobile.org/application.zip';
|
||||
var checkList = ['manifest.webapp'];
|
||||
|
||||
checkList.forEach(function(filePath) {
|
||||
helper.checkFilePathInZip(zipPath, filePath);
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
17
gaia/apps/network-alerts/test/unit/.jshintrc
Executable file
17
gaia/apps/network-alerts/test/unit/.jshintrc
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../../.jshintrc",
|
||||
"predef": [
|
||||
"assert",
|
||||
"suite",
|
||||
"test",
|
||||
"setup",
|
||||
"teardown",
|
||||
"suiteSetup",
|
||||
"suiteTeardown",
|
||||
"require",
|
||||
"requireApp",
|
||||
"sinon",
|
||||
"mocha",
|
||||
"loadBodyHTML"
|
||||
]
|
||||
}
|
||||
204
gaia/apps/network-alerts/test/unit/attention/attention_test.js
Executable file
204
gaia/apps/network-alerts/test/unit/attention/attention_test.js
Executable file
|
|
@ -0,0 +1,204 @@
|
|||
/* global Attention,
|
||||
MockL10n,
|
||||
MockNavigatormozApps,
|
||||
MockNotification,
|
||||
MockNotifications,
|
||||
NotificationHelper,
|
||||
MocksHelper,
|
||||
Notify,
|
||||
Utils
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
require('/shared/test/unit/mocks/mock_navigator_moz_apps.js');
|
||||
require('/shared/test/unit/mocks/mock_notification.js');
|
||||
require('/shared/test/unit/mocks/mock_notification_helper.js');
|
||||
require('/shared/test/unit/mocks/mock_l10n.js');
|
||||
require('/test/unit/mock_utils.js');
|
||||
require('/test/unit/mock_notify.js');
|
||||
|
||||
require('/js/attention/attention.js');
|
||||
|
||||
var mocksHelperForAttention = new MocksHelper([
|
||||
'Notify',
|
||||
'Notification',
|
||||
'NotificationHelper',
|
||||
'Utils'
|
||||
]);
|
||||
|
||||
suite('Network Alerts - Attention Screen', function() {
|
||||
var title,
|
||||
body;
|
||||
|
||||
var realL10n = navigator.mozL10n;
|
||||
var realMozApps = navigator.mozApps;
|
||||
var realOpener;
|
||||
|
||||
mocksHelperForAttention.attachTestHelpers();
|
||||
|
||||
suiteSetup(function() {
|
||||
realOpener = Object.getOwnPropertyDescriptor(window, 'opener');
|
||||
|
||||
Object.defineProperty(window, 'opener', {
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
value: {
|
||||
close: function() {}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
suiteTeardown(function() {
|
||||
Object.defineProperty(window, 'opener', realOpener);
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
loadBodyHTML('/attention.html');
|
||||
|
||||
title = 'title-id';
|
||||
body = 'some body';
|
||||
|
||||
this.sinon.stub(Utils, 'parseParams');
|
||||
this.sinon.stub(window.opener, 'close');
|
||||
this.sinon.stub(Notify, 'notify');
|
||||
|
||||
navigator.mozL10n = MockL10n;
|
||||
this.sinon.stub(navigator.mozL10n, 'once').yields();
|
||||
|
||||
navigator.mozApps = MockNavigatormozApps;
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
navigator.mozL10n = realL10n;
|
||||
MockNavigatormozApps.mTeardown();
|
||||
navigator.mozApps = realMozApps;
|
||||
});
|
||||
|
||||
suite('display from received message', function() {
|
||||
setup(function() {
|
||||
Utils.parseParams.returns({
|
||||
title: title,
|
||||
body: body
|
||||
});
|
||||
|
||||
Attention.init();
|
||||
Attention.render();
|
||||
});
|
||||
|
||||
test('form is properly displayed', function() {
|
||||
assert.equal(
|
||||
document.querySelector('h1').getAttribute('data-l10n-id'),
|
||||
title,
|
||||
'The title is properly displayed'
|
||||
);
|
||||
assert.equal(
|
||||
document.querySelector('p').textContent, body,
|
||||
'The body is properly displayed'
|
||||
);
|
||||
});
|
||||
|
||||
test('Notification should be displayed and alert is played', function() {
|
||||
this.sinon.stub(NotificationHelper, 'send').returns(Promise.resolve({}));
|
||||
MockNavigatormozApps.mTriggerLastRequestSuccess();
|
||||
|
||||
sinon.assert.calledOnce(NotificationHelper.send);
|
||||
sinon.assert.calledWithMatch(NotificationHelper.send, title, {
|
||||
body: body,
|
||||
icon: 'sms',
|
||||
data: { title }
|
||||
});
|
||||
|
||||
sinon.assert.called(Notify.notify);
|
||||
});
|
||||
|
||||
test('Notification should not be displayed if mozApp got error',
|
||||
function() {
|
||||
MockNavigatormozApps.mLastRequest.onerror();
|
||||
|
||||
assert.equal(MockNotifications.length, 0);
|
||||
});
|
||||
|
||||
test('click button: closes window', function() {
|
||||
document.querySelector('button').click();
|
||||
|
||||
sinon.assert.called(window.opener.close);
|
||||
});
|
||||
|
||||
suite('on visibility change', function() {
|
||||
var realVisibility,
|
||||
isDocumentHidden;
|
||||
|
||||
suiteSetup(function() {
|
||||
realVisibility = Object.getOwnPropertyDescriptor(document, 'hidden');
|
||||
|
||||
Object.defineProperty(document, 'hidden', {
|
||||
configurable: true,
|
||||
get: function() {
|
||||
return isDocumentHidden;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
suiteTeardown(function() {
|
||||
Object.defineProperty(document, 'hidden', {
|
||||
configurable: true,
|
||||
get: function() {
|
||||
return realVisibility;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
document.querySelector('h1').style.height = '10px';
|
||||
});
|
||||
|
||||
test('do nothing while app visible',function() {
|
||||
isDocumentHidden = false;
|
||||
document.dispatchEvent(new CustomEvent('visibilitychange'));
|
||||
|
||||
sinon.assert.notCalled(window.opener.close);
|
||||
});
|
||||
|
||||
test('do nothing while app hidden but not resized',function() {
|
||||
isDocumentHidden = true;
|
||||
document.dispatchEvent(new CustomEvent('visibilitychange'));
|
||||
|
||||
sinon.assert.notCalled(window.opener.close);
|
||||
});
|
||||
|
||||
test('close window while app hidden and resized',function() {
|
||||
isDocumentHidden = true;
|
||||
document.querySelector('h1').style.height = '';
|
||||
document.dispatchEvent(new CustomEvent('visibilitychange'));
|
||||
|
||||
sinon.assert.called(window.opener.close);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('display from notification,', function() {
|
||||
setup(function() {
|
||||
Utils.parseParams.returns({
|
||||
title: title,
|
||||
body: body,
|
||||
notification: 1
|
||||
});
|
||||
|
||||
MockNotification.mTeardown();
|
||||
Attention.init();
|
||||
Attention.render();
|
||||
});
|
||||
|
||||
test('Notification should not be displayed, and no alert should be played',
|
||||
function() {
|
||||
assert.isUndefined(
|
||||
MockNotifications[0],
|
||||
'should not send a new notification'
|
||||
);
|
||||
|
||||
sinon.assert.notCalled(Notify.notify);
|
||||
});
|
||||
});
|
||||
});
|
||||
226
gaia/apps/network-alerts/test/unit/attention/notify_test.js
Executable file
226
gaia/apps/network-alerts/test/unit/attention/notify_test.js
Executable file
|
|
@ -0,0 +1,226 @@
|
|||
/*global
|
||||
AudioContext,
|
||||
MockAudioContext,
|
||||
MockNavigatorSettings,
|
||||
MocksHelper,
|
||||
Notify
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
require('/shared/test/unit/mocks/mock_navigator_moz_settings.js');
|
||||
require('/shared/test/unit/mocks/mock_audio.js');
|
||||
require('/js/attention/notify.js');
|
||||
|
||||
var mocksHelperNotifications = new MocksHelper([
|
||||
'AudioContext'
|
||||
]).init();
|
||||
|
||||
suite('check the ringtone and vibrate function', function() {
|
||||
var realMozSettings;
|
||||
var getStub, setStub;
|
||||
var isDocumentHidden = true;
|
||||
|
||||
mocksHelperNotifications.attachTestHelpers();
|
||||
|
||||
setup(function() {
|
||||
realMozSettings = navigator.mozSettings;
|
||||
navigator.mozSettings = MockNavigatorSettings;
|
||||
|
||||
this.sinon.stub(navigator, 'vibrate');
|
||||
this.sinon.spy(window, 'AudioContext');
|
||||
|
||||
this.sinon.stub(
|
||||
MockAudioContext.prototype, 'createOscillator',
|
||||
() => sinon.stub({
|
||||
frequency: { value: 0 },
|
||||
type: '',
|
||||
connect() {},
|
||||
start() {},
|
||||
stop() {}
|
||||
})
|
||||
);
|
||||
|
||||
this.sinon.stub(
|
||||
MockAudioContext.prototype, 'createGain',
|
||||
() => sinon.stub({
|
||||
gain: sinon.stub({ setValueCurveAtTime() {} }),
|
||||
connect() {}
|
||||
})
|
||||
);
|
||||
|
||||
getStub = sinon.stub();
|
||||
setStub = sinon.stub();
|
||||
|
||||
this.sinon.stub(MockNavigatorSettings, 'createLock').returns({
|
||||
get: getStub,
|
||||
set: setStub
|
||||
});
|
||||
|
||||
Object.defineProperty(document, 'hidden', {
|
||||
configurable: true,
|
||||
get: () => isDocumentHidden
|
||||
});
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
navigator.mozSettings = realMozSettings;
|
||||
delete document.hidden;
|
||||
});
|
||||
|
||||
function sendVisibilityEvent() {
|
||||
var visibilityEvent = new CustomEvent(
|
||||
'visibilitychange',
|
||||
{ bubbles: true }
|
||||
);
|
||||
|
||||
window.dispatchEvent(visibilityEvent);
|
||||
}
|
||||
|
||||
function assertVibrate() {
|
||||
sinon.assert.calledWith(
|
||||
navigator.vibrate,
|
||||
[2000, 500, 1000, 500, 1000, 500, 2000, 500, 1000, 500, 1000, 500]
|
||||
);
|
||||
}
|
||||
|
||||
function assertAudio() {
|
||||
sinon.assert.calledWith(AudioContext, 'notification');
|
||||
sinon.assert.calledTwice(AudioContext.prototype.createOscillator);
|
||||
sinon.assert.calledOnce(AudioContext.prototype.createGain);
|
||||
|
||||
var audioCtx = AudioContext.firstCall.returnValue;
|
||||
var gainNode = AudioContext.prototype.createGain.firstCall.returnValue;
|
||||
var o1 = AudioContext.prototype.createOscillator.firstCall.returnValue;
|
||||
var o2 = AudioContext.prototype.createOscillator.secondCall.returnValue;
|
||||
|
||||
assert.equal(o1.type, 'sine');
|
||||
assert.equal(o2.type, 'sine');
|
||||
|
||||
// either one case or the other
|
||||
try {
|
||||
assert.equal(o1.frequency.value, 853);
|
||||
assert.equal(o2.frequency.value, 960);
|
||||
} catch(e) {
|
||||
assert.equal(o2.frequency.value, 853);
|
||||
assert.equal(o1.frequency.value, 960);
|
||||
}
|
||||
|
||||
sinon.assert.called(o1.connect);
|
||||
sinon.assert.called(o2.connect);
|
||||
sinon.assert.calledWith(o1.connect, gainNode);
|
||||
sinon.assert.calledWith(o2.connect, gainNode);
|
||||
sinon.assert.calledWith(gainNode.connect, audioCtx.destination);
|
||||
|
||||
sinon.assert.called(o1.start);
|
||||
sinon.assert.called(o2.start);
|
||||
sinon.assert.called(o1.stop);
|
||||
sinon.assert.called(o2.stop);
|
||||
sinon.assert.calledWith(o1.stop, 11);
|
||||
sinon.assert.calledWith(o2.stop, 11);
|
||||
|
||||
sinon.assert.called(gainNode.gain.setValueCurveAtTime);
|
||||
sinon.assert.calledWith(
|
||||
gainNode.gain.setValueCurveAtTime,
|
||||
sinon.match.instanceOf(Float32Array), 0, 11
|
||||
);
|
||||
}
|
||||
|
||||
function setSettings(settings) {
|
||||
for (var key in settings) {
|
||||
getStub.withArgs(key).returns(Promise.resolve({
|
||||
[key]: settings[key]
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
suite('mozSettings is unavailable', function() {
|
||||
test('We do nothing but we do not stop', function(done) {
|
||||
delete navigator.mozSettings;
|
||||
|
||||
Notify.notify().then(() => {
|
||||
sinon.assert.notCalled(AudioContext);
|
||||
sinon.assert.notCalled(navigator.vibrate);
|
||||
}).then(done, done);
|
||||
});
|
||||
});
|
||||
|
||||
suite('volume is 1 and vibration is enabled', function() {
|
||||
test('play ringtone and vibrate', function(done) {
|
||||
setSettings({
|
||||
'audio.volume.notification': 1,
|
||||
'vibration.enabled': true
|
||||
});
|
||||
|
||||
Notify.notify().then(() => {
|
||||
// let's be sure we vibrate after the visibility event only
|
||||
sinon.assert.notCalled(navigator.vibrate);
|
||||
// As document is not shown in the test, we launch the
|
||||
// event of visibility
|
||||
sendVisibilityEvent();
|
||||
assertAudio();
|
||||
assertVibrate();
|
||||
}).then(done, done);
|
||||
});
|
||||
});
|
||||
|
||||
suite('volume is 1 and vibration is disabled', function() {
|
||||
test('play ringtone and do not vibrate', function(done) {
|
||||
setSettings({
|
||||
'audio.volume.notification': 1,
|
||||
'vibration.enabled': false
|
||||
});
|
||||
|
||||
Notify.notify().then(() => {
|
||||
sinon.assert.notCalled(navigator.vibrate);
|
||||
assertAudio();
|
||||
}).then(done, done);
|
||||
});
|
||||
});
|
||||
|
||||
suite('volume is 0 and vibration is enabled', function() {
|
||||
test('do not play ringtone and vibrate', function(done) {
|
||||
setSettings({
|
||||
'audio.volume.notification': 0,
|
||||
'vibration.enabled': true
|
||||
});
|
||||
|
||||
Notify.notify().then(() => {
|
||||
sinon.assert.notCalled(navigator.vibrate);
|
||||
// As document is not shown in the test, we launch the
|
||||
// event of visibility
|
||||
sendVisibilityEvent();
|
||||
|
||||
sinon.assert.notCalled(AudioContext);
|
||||
|
||||
assertVibrate();
|
||||
}).then(done, done);
|
||||
});
|
||||
|
||||
test('vibrate asap if the app is displayed', function(done) {
|
||||
setSettings({
|
||||
'audio.volume.notification': 0,
|
||||
'vibration.enabled': true
|
||||
});
|
||||
isDocumentHidden = false;
|
||||
|
||||
Notify.notify().then(() => {
|
||||
assertVibrate();
|
||||
}).then(done, done);
|
||||
});
|
||||
});
|
||||
|
||||
suite('volume is 0 and vibration is disabled', function() {
|
||||
test('do not play ringtone and do not vibrate', function(done) {
|
||||
setSettings({
|
||||
'audio.volume.notification': 0,
|
||||
'vibration.enabled': false
|
||||
});
|
||||
|
||||
Notify.notify().then(() => {
|
||||
sinon.assert.notCalled(navigator.vibrate);
|
||||
sinon.assert.notCalled(AudioContext);
|
||||
}).then(done, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
223
gaia/apps/network-alerts/test/unit/index_test.js
Executable file
223
gaia/apps/network-alerts/test/unit/index_test.js
Executable file
|
|
@ -0,0 +1,223 @@
|
|||
/* global MockNavigatorSettings
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
require('/shared/test/unit/mocks/mock_navigator_moz_settings.js');
|
||||
|
||||
suite('Network Alerts - cellbroadcast system message handling', function() {
|
||||
var handlerStub;
|
||||
var realSettings = navigator.mozSettings;
|
||||
var CMAS_KEY = 'cmas.enabled';
|
||||
var getStub, setStub;
|
||||
|
||||
function mockMessage(opt = {}) {
|
||||
var message = {
|
||||
serviceId: 0,
|
||||
cdmaServiceCategory: null,
|
||||
body: 'Some body'
|
||||
};
|
||||
|
||||
for (var key in opt) {
|
||||
message[key] = opt[key];
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
suiteSetup(function(done) {
|
||||
if (!window.navigator.mozSetMessageHandler) {
|
||||
window.navigator.mozSetMessageHandler = function() {};
|
||||
}
|
||||
sinon.stub(window.navigator, 'mozSetMessageHandler');
|
||||
handlerStub = window.navigator.mozSetMessageHandler;
|
||||
|
||||
require('/js/index.js', done);
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
this.sinon.stub(window, 'close');
|
||||
this.sinon.stub(window, 'open');
|
||||
|
||||
getStub = sinon.stub().returns(Promise.resolve());
|
||||
setStub = sinon.stub().returns(Promise.resolve());
|
||||
|
||||
this.sinon.stub(MockNavigatorSettings, 'createLock').returns({
|
||||
get: getStub,
|
||||
set: setStub
|
||||
});
|
||||
|
||||
navigator.mozSettings = MockNavigatorSettings;
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
navigator.mozSettings = realSettings;
|
||||
MockNavigatorSettings.mTeardown();
|
||||
});
|
||||
|
||||
test('do not open attention screen if error returns from settings DB',
|
||||
function(done) {
|
||||
|
||||
var message = mockMessage({ messageId: 4371 });
|
||||
|
||||
getStub.returns(Promise.reject(new Error('error')));
|
||||
|
||||
var handler = handlerStub.withArgs('cellbroadcast-received').args[0][1];
|
||||
var finished = handler(message);
|
||||
|
||||
finished.then(() => {
|
||||
sinon.assert.notCalled(window.open);
|
||||
sinon.assert.called(window.close);
|
||||
}).then(done, done);
|
||||
});
|
||||
|
||||
suite('if CMAS in settings DB is off', function() {
|
||||
setup(function() {
|
||||
getStub.returns(Promise.resolve({
|
||||
[CMAS_KEY]: {
|
||||
0: false,
|
||||
1: false
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
test('do not open attention screen', function(done) {
|
||||
|
||||
var message = mockMessage({ messageId: 4371 });
|
||||
|
||||
var handler = handlerStub.withArgs('cellbroadcast-received').args[0][1];
|
||||
var finished = handler(message);
|
||||
|
||||
finished.then(() => {
|
||||
sinon.assert.notCalled(window.open);
|
||||
sinon.assert.called(window.close);
|
||||
}).then(done, done);
|
||||
});
|
||||
|
||||
[4370, 4383].forEach((presidentialId) => {
|
||||
test('opens an attention screen if GSM message is a presidential alert ' +
|
||||
presidentialId,
|
||||
function(done) {
|
||||
|
||||
var message = mockMessage({ messageId: presidentialId });
|
||||
var handler = handlerStub.withArgs('cellbroadcast-received').args[0][1];
|
||||
var finished = handler(message);
|
||||
|
||||
var expectedUrl = [
|
||||
'attention.html?',
|
||||
'title=emergency-alert-title&',
|
||||
'body=Some%20body'
|
||||
].join('');
|
||||
|
||||
finished.then(() => {
|
||||
sinon.assert.calledWith(
|
||||
window.open,
|
||||
expectedUrl, '_blank', 'attention'
|
||||
);
|
||||
sinon.assert.notCalled(window.close);
|
||||
}).then(done, done);
|
||||
});
|
||||
});
|
||||
|
||||
test('opens an attention screen if CDMA message is a presidential alert ',
|
||||
function(done) {
|
||||
|
||||
var message = mockMessage({ cdmaServiceCategory: 4096 });
|
||||
var handler = handlerStub.withArgs('cellbroadcast-received').args[0][1];
|
||||
var finished = handler(message);
|
||||
|
||||
var expectedUrl = [
|
||||
'attention.html?',
|
||||
'title=emergency-alert-title&',
|
||||
'body=Some%20body'
|
||||
].join('');
|
||||
|
||||
finished.then(() => {
|
||||
sinon.assert.calledWith(
|
||||
window.open,
|
||||
expectedUrl, '_blank', 'attention'
|
||||
);
|
||||
sinon.assert.notCalled(window.close);
|
||||
}).then(done, done);
|
||||
});
|
||||
});
|
||||
|
||||
test('opens an attention screen if GSM message is CMAS', function(done) {
|
||||
var message = mockMessage({ messageId: 4371 });
|
||||
|
||||
getStub.returns(Promise.resolve({
|
||||
[CMAS_KEY]: {
|
||||
0: true,
|
||||
1: false
|
||||
}
|
||||
}));
|
||||
|
||||
var handler = handlerStub.withArgs('cellbroadcast-received').args[0][1];
|
||||
var finished = handler(message);
|
||||
|
||||
var expectedUrl = [
|
||||
'attention.html?',
|
||||
'title=emergency-alert-title&',
|
||||
'body=Some%20body'
|
||||
].join('');
|
||||
|
||||
finished.then(() => {
|
||||
sinon.assert.calledWith(
|
||||
window.open,
|
||||
expectedUrl, '_blank', 'attention'
|
||||
);
|
||||
sinon.assert.notCalled(window.close);
|
||||
}).then(done, done);
|
||||
});
|
||||
|
||||
test('do not open attention screen if GSM message is other cellbroadcast',
|
||||
function() {
|
||||
|
||||
var message = mockMessage({ messageId: 4401 });
|
||||
|
||||
handlerStub.withArgs('cellbroadcast-received').yield(message);
|
||||
|
||||
sinon.assert.notCalled(window.open);
|
||||
sinon.assert.called(window.close);
|
||||
});
|
||||
|
||||
|
||||
test('opens an attention screen if CDMA message is CMAS', function(done) {
|
||||
var message = mockMessage({ cdmaServiceCategory: 4096 });
|
||||
|
||||
getStub.returns(Promise.resolve({
|
||||
[CMAS_KEY]: {
|
||||
0: true,
|
||||
1: false
|
||||
}
|
||||
}));
|
||||
|
||||
var handler = handlerStub.withArgs('cellbroadcast-received').args[0][1];
|
||||
var finished = handler(message);
|
||||
|
||||
var expectedUrl = [
|
||||
'attention.html?',
|
||||
'title=emergency-alert-title&',
|
||||
'body=Some%20body'
|
||||
].join('');
|
||||
|
||||
finished.then(() => {
|
||||
sinon.assert.calledWith(
|
||||
window.open,
|
||||
expectedUrl, '_blank', 'attention'
|
||||
);
|
||||
sinon.assert.notCalled(window.close);
|
||||
}).then(done, done);
|
||||
});
|
||||
|
||||
test('do not open attention screen if CDMA message is other cellbroadcast',
|
||||
function() {
|
||||
|
||||
var message = mockMessage({ cdmaServiceCategory: 4095 });
|
||||
|
||||
handlerStub.withArgs('cellbroadcast-received').yield(message);
|
||||
|
||||
sinon.assert.notCalled(window.open);
|
||||
sinon.assert.called(window.close);
|
||||
});
|
||||
});
|
||||
|
||||
6
gaia/apps/network-alerts/test/unit/mock_notify.js
Executable file
6
gaia/apps/network-alerts/test/unit/mock_notify.js
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
/* exported MockNotify */
|
||||
'use strict';
|
||||
|
||||
var MockNotify = {
|
||||
notify() {}
|
||||
};
|
||||
11
gaia/apps/network-alerts/test/unit/mock_utils.js
Executable file
11
gaia/apps/network-alerts/test/unit/mock_utils.js
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
|
||||
exports.MockUtils = {
|
||||
parseParams: function() {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
})(window);
|
||||
60
gaia/apps/network-alerts/test/unit/notification/notification_test.js
Executable file
60
gaia/apps/network-alerts/test/unit/notification/notification_test.js
Executable file
|
|
@ -0,0 +1,60 @@
|
|||
/* global NotificationHandler
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
require('/js/notification/notification.js');
|
||||
|
||||
suite('Network Alerts - Notification handling', function() {
|
||||
|
||||
setup(function() {
|
||||
this.sinon.stub(window, 'close');
|
||||
this.sinon.stub(window, 'open');
|
||||
// We only need titleID after parsing, so mock parseParams that simply
|
||||
// return fake titleID for testing.
|
||||
|
||||
if (!window.navigator.mozSetMessageHandler) {
|
||||
window.navigator.mozSetMessageHandler = function() {};
|
||||
}
|
||||
this.sinon.stub(window.navigator, 'mozSetMessageHandler');
|
||||
NotificationHandler.init();
|
||||
});
|
||||
|
||||
test('opens an attention screen if user clicks the notification', function() {
|
||||
var message = {
|
||||
title: 'Some title',
|
||||
body: 'Some body',
|
||||
clicked: true,
|
||||
data: { title: 'Some title' }
|
||||
};
|
||||
|
||||
var handlerStub = window.navigator.mozSetMessageHandler;
|
||||
handlerStub.withArgs('notification').yield(message);
|
||||
|
||||
var expectedUrl = [
|
||||
'attention.html?',
|
||||
'title=Some%20title&',
|
||||
'body=Some%20body&',
|
||||
'notification=1'
|
||||
].join('');
|
||||
|
||||
sinon.assert.calledWith(
|
||||
window.open,
|
||||
expectedUrl, '_blank', 'attention'
|
||||
);
|
||||
sinon.assert.notCalled(window.close);
|
||||
});
|
||||
|
||||
test('only closes window if user dismisses the notification', function() {
|
||||
var message = {
|
||||
title: 'Some title',
|
||||
body: 'Some body'
|
||||
};
|
||||
|
||||
var handlerStub = window.navigator.mozSetMessageHandler;
|
||||
handlerStub.withArgs('notification').yield(message);
|
||||
|
||||
sinon.assert.notCalled(window.open);
|
||||
sinon.assert.called(window.close);
|
||||
});
|
||||
});
|
||||
|
||||
4
gaia/apps/network-alerts/test/unit/setup.js
Executable file
4
gaia/apps/network-alerts/test/unit/setup.js
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
'use strict';
|
||||
|
||||
require('/shared/test/unit/load_body_html_helper.js');
|
||||
require('/shared/test/unit/mocks/mocks_helper.js');
|
||||
42
gaia/apps/network-alerts/test/unit/utils_test.js
Executable file
42
gaia/apps/network-alerts/test/unit/utils_test.js
Executable file
|
|
@ -0,0 +1,42 @@
|
|||
/* global Utils */
|
||||
|
||||
'use strict';
|
||||
|
||||
require('/js/utils.js');
|
||||
|
||||
suite('Network Alerts - Utils', function() {
|
||||
var parameters = [
|
||||
'attention.html?',
|
||||
'subject=hello%20world&',
|
||||
'body=how%20are%20you&',
|
||||
'novalue&',
|
||||
'emptyvalue='
|
||||
];
|
||||
|
||||
var expected = {
|
||||
subject: 'hello world',
|
||||
body: 'how are you',
|
||||
novalue: undefined,
|
||||
emptyvalue: ''
|
||||
};
|
||||
|
||||
test('parseParams decodes search parameters', function() {
|
||||
var subject = [ 'attention.html?' ].concat(parameters).join('');
|
||||
|
||||
var result = Utils.parseParams(subject);
|
||||
for (var key in result) {
|
||||
assert.strictEqual(result[key], expected[key]);
|
||||
}
|
||||
});
|
||||
|
||||
test('parseParams decodes hash parameters', function() {
|
||||
var subject = [ 'attention.html#' ].concat(parameters).join('');
|
||||
|
||||
var result = Utils.parseParams(subject);
|
||||
for (var key in result) {
|
||||
assert.strictEqual(result[key], expected[key]);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Loading…
Reference in a new issue