'use strict'; /* global AppUpdatable, asyncStorage, MocksHelper, MockApp, MockAppsMgmt, MockChromeEvent, MockCustomDialog, MockNavigatorBattery, MockNavigatorSettings, MockNotificationHelper, MockService, MockUpdateManager, MockUtilityTray, SystemUpdatable */ requireApp('system/js/updatable.js'); requireApp('system/test/unit/mock_app.js'); requireApp('system/test/unit/mock_asyncStorage.js'); requireApp('system/test/unit/mock_update_manager.js'); requireApp('system/test/unit/mock_app_window_manager.js'); requireApp('system/test/unit/mock_apps_mgmt.js'); requireApp('system/test/unit/mock_chrome_event.js'); requireApp('system/test/unit/mock_utility_tray.js'); requireApp('system/test/unit/mock_navigator_battery.js'); requireApp('system/shared/test/unit/mocks/mock_service.js'); requireApp('system/shared/test/unit/mocks/mock_custom_dialog.js'); requireApp('system/shared/test/unit/mocks/mock_manifest_helper.js'); requireApp('system/shared/test/unit/mocks/mock_navigator_moz_settings.js'); require('/shared/test/unit/mocks/mock_notification_helper.js'); require('/shared/test/unit/mocks/mock_notification.js'); var mocksHelperForUpdatable = new MocksHelper([ 'CustomDialog', 'UpdateManager', 'AppWindowManager', 'UtilityTray', 'ManifestHelper', 'Notification', 'NotificationHelper', 'asyncStorage', 'Service' ]).init(); suite('system/Updatable', function() { var subject; var mockApp; var realDispatchEvent; var realL10n; var realMozApps; var realMozSettings; var lastDispatchedEvent = null; var fakeDispatchEvent; var MID_CHARGE = 50; var BATTERY_THRESHOLD_PLUGGED = 'app.update.battery-threshold.plugged'; var BATTERY_THRESHOLD_UNPLUGGED = 'app.update.battery-threshold.unplugged'; var SYSTEM_LOW_BATTERY_L10N_KEY = 'systemUpdateLowBatteryThreshold'; mocksHelperForUpdatable.attachTestHelpers(); suiteSetup(function() { realMozSettings = window.navigator.mozSettings; navigator.mozSettings = MockNavigatorSettings; realL10n = navigator.mozL10n; navigator.mozL10n = { get: function get(key) { return key; } }; var getSpy = sinon.spy(navigator.mozL10n, 'get'); getSpy.withArgs(SYSTEM_LOW_BATTERY_L10N_KEY); // we used to set subject._mgmt in setup // but now, this seems to work and feels cleaner realMozApps = navigator.mozApps; navigator.mozApps = { mgmt: MockAppsMgmt }; }); suiteTeardown(function() { navigator.mozL10n = realL10n; navigator.mozApps = realMozApps; navigator.mozSettings = realMozSettings; }); setup(function() { this.sinon.stub(MockService, 'request', function(action) { if (action === 'showCustomDialog') { MockCustomDialog.show( arguments[1], arguments[2], arguments[3], arguments[4]); } else { MockCustomDialog.hide( arguments[1], arguments[2], arguments[3], arguments[4]); } }); mockApp = new MockApp(); subject = new AppUpdatable(mockApp); MockNavigatorSettings.mSettings[BATTERY_THRESHOLD_UNPLUGGED] = 25; MockNavigatorSettings.mSettings[BATTERY_THRESHOLD_PLUGGED] = 10; navigator.mozL10n.get.withArgs(SYSTEM_LOW_BATTERY_L10N_KEY).reset(); fakeDispatchEvent = function(type, value) { lastDispatchedEvent = { type: type, value: value }; }; subject._dispatchEvent = fakeDispatchEvent; var fakeScreen = document.createElement('div'); fakeScreen.id = 'screen'; document.body.appendChild(fakeScreen); }); teardown(function() { MockAppsMgmt.mTeardown(); subject._dispatchEvent = realDispatchEvent; lastDispatchedEvent = null; }); function downloadAvailableSuite(name, setupFunc) { suite(name, function() { setup(setupFunc); test('should add self to the available downloads', function() { assert.isNotNull(MockUpdateManager.mLastUpdatesAdd); assert.equal(MockUpdateManager.mLastUpdatesAdd.app.mId, mockApp.mId); }); suite('first progress', function() { setup(function() { mockApp.mTriggerDownloadProgress(42); }); test('should add self to active downloads', function() { assert.isNotNull(MockUpdateManager.mLastDownloadsAdd); assert.equal(MockUpdateManager.mLastDownloadsAdd.app.mId, mockApp.mId); }); test('should start with first progress value', function() { assert.equal(42, subject.progress); }); }); }); } suite('init', function() { test('should keep a reference to the app', function() { assert.equal(mockApp, subject.app); }); test('should handle fresh app with just an updateManifest', function() { var freshApp = new MockApp(); freshApp.manifest = undefined; subject = new AppUpdatable(freshApp); assert.equal(freshApp, subject.app); }); test('should add itself to updatable apps', function() { assert.equal(MockUpdateManager.mLastUpdatableAdd, subject); }); test('should remember about the update on startup', function() { asyncStorage.mItems[SystemUpdatable.KNOWN_UPDATE_FLAG] = true; var systemUpdatable = new SystemUpdatable(); // jshint ignore:line assert.equal(MockUpdateManager.mCheckForUpdatesCalledWith, true); }); downloadAvailableSuite('app has a download available', function() { mockApp.downloadAvailable = true; subject = new AppUpdatable(mockApp); }); suite('applyDownload', function() { setup(function() { mockApp.readyToApplyDownload = true; subject = new AppUpdatable(mockApp); }); test('should apply update if downloaded', function() { assert.equal(MockAppsMgmt.mLastAppApplied, mockApp); }); test('should kill the app if downloaded', function() { assert.isTrue(MockService.request.calledWith('kill', mockApp.origin)); }); }); }); suite('infos', function() { suite('name', function() { test('should give a name for app updates', function() { assert.equal('Mock app', subject.name); }); }); suite('size', function() { test('should give packaged app update size', function() { assert.equal(null, subject.size); }); test('should return null for hosted apps', function() { mockApp.updateManifest = null; subject = new AppUpdatable(mockApp); assert.isNull(subject.size); }); test('should update size on download available', function() { mockApp.updateManifest = null; subject = new AppUpdatable(mockApp); assert.isNull(subject.size); mockApp.mTriggerDownloadAvailable(45678); assert.equal(45678, subject.size); }); }); }); suite('actions', function() { suite('ask for download', function() { setup(function() { mockApp.mTriggerDownloadAvailable(); subject.download(); }); test('should call download on the app', function() { assert.isTrue(mockApp.mDownloadCalled); }); }); suite('download system update', function() { setup(function() { subject = new SystemUpdatable(42); subject._dispatchEvent = fakeDispatchEvent; subject.progress = 42; subject.download(); }); test('should send download message for system updates', function() { assert.equal('update-available-result', lastDispatchedEvent.type); assert.equal('download', lastDispatchedEvent.value); }); test('should add system updates to active downloads too', function() { assert.isNotNull(MockUpdateManager.mLastDownloadsAdd); assert.equal(subject, MockUpdateManager.mLastDownloadsAdd); }); test('should start system updates with progress 0 too', function() { assert.equal(subject.progress, 0); }); test('should do nothing if already downloading', function() { lastDispatchedEvent = null; subject.progress = 42; subject.download(); assert.equal(subject.progress, 42); assert.isNull(lastDispatchedEvent); }); }); suite('cancel app update download', function() { setup(function() { subject.cancelDownload(); }); test('should call cancelDownload on the app', function() { assert.isTrue(mockApp.mCancelCalled); }); }); suite('cancel system update download', function() { setup(function() { asyncStorage.setItem(SystemUpdatable.KNOWN_UPDATE_FLAG, true); subject = new SystemUpdatable(42); subject.download(); subject._dispatchEvent = fakeDispatchEvent; subject.cancelDownload(); }); test('should send cancel message', function() { assert.equal('update-download-cancel', lastDispatchedEvent.type); }); test('should remove the downloading flag', function() { assert.isFalse(subject.downloading); }); }); suite('signal system update ready', function() { var addEventListenerSpy, dispatchEventSpy; setup(function() { asyncStorage.setItem(SystemUpdatable.KNOWN_UPDATE_FLAG, true); dispatchEventSpy = this.sinon.spy(SystemUpdatable.prototype, '_dispatchEvent'); addEventListenerSpy = this.sinon.spy(window, 'addEventListener'); subject = new SystemUpdatable(42); }); test('should add event listener', function() { sinon.assert.calledOnce(addEventListenerSpy); sinon.assert.calledWith(addEventListenerSpy, 'mozChromeEvent'); }); test('should send ready message', function() { sinon.assert.calledOnce(dispatchEventSpy); sinon.assert.calledWith(dispatchEventSpy, 'update-prompt-ready'); }); test('should have proper ordering', function() { sinon.assert.callOrder(addEventListenerSpy, dispatchEventSpy); }); }); }); suite('events', function() { suite('apps events', function() { // This function checks that we release the callbacks properly // at the end of a download. Assumes subject.download() was called. function testCleanup() { test('should stop responding to progress', function() { mockApp.mTriggerDownloadProgress(42); assert.notEqual(subject.progress, 42); }); test('should stop responding to error', function() { MockUpdateManager.mErrorBannerRequested = false; mockApp.mTriggerDownloadError(); assert.isFalse(MockUpdateManager.mErrorBannerRequested); }); test('progress should be reset', function() { assert.isNull(subject.progress); }); } downloadAvailableSuite('ondownloadavailable', function() { mockApp.mTriggerDownloadAvailable(); }); suite('ondownloadavailable when not installed', function() { setup(function() { mockApp.installState = 'pending'; mockApp.mTriggerDownloadAvailable(); }); test('should not add self to the available downloads', function() { assert.isNull(MockUpdateManager.mLastUpdatesAdd); }); test('should not answer to progress', function() { mockApp.mTriggerDownloadSuccess(); assert.isNull(MockUpdateManager.mLastDownloadsRemoval); }); }); suite('downloadavailable at init when not installed', function() { setup(function() { mockApp.installState = 'pending'; subject = new AppUpdatable(mockApp); mockApp.mTriggerDownloadAvailable(); }); test('should not add self to the available downloads', function() { assert.isNull(MockUpdateManager.mLastUpdatesAdd); }); test('should not answer to progress', function() { mockApp.mTriggerDownloadSuccess(); assert.isNull(MockUpdateManager.mLastDownloadsRemoval); }); }); suite('ondownloadsuccess', function() { test('should remove self from active downloads', function() { mockApp.mTriggerDownloadAvailable(); mockApp.mTriggerDownloadProgress(42); mockApp.mTriggerDownloadSuccess(); assert.isNotNull(MockUpdateManager.mLastDownloadsRemoval); assert.equal(MockUpdateManager.mLastDownloadsRemoval.app.mId, mockApp.mId); }); test('should call downloaded of UpdateManager', function() { mockApp.mTriggerDownloadAvailable(); mockApp.mTriggerDownloadProgress(42); mockApp.mTriggerDownloadSuccess(); assert.isTrue(MockUpdateManager.mDownloadedCalled); }); test('should not remove self if not downloading', function() { mockApp.mTriggerDownloadSuccess(); assert.isNull(MockUpdateManager.mLastDownloadsRemoval); }); test('should remove self from available downloads', function() { mockApp.mTriggerDownloadAvailable(); mockApp.mTriggerDownloadProgress(42); mockApp.mTriggerDownloadSuccess(); assert.isNotNull(MockUpdateManager.mLastUpdatesRemoval); assert.equal(MockUpdateManager.mLastUpdatesRemoval.app.mId, mockApp.mId); }); suite('application of the download', function() { test('should apply if the app is not in foreground', function() { mockApp.mTriggerDownloadAvailable(); MockService.mockQueryWith('AppWindowManager.getActiveWindow', { origin: 'homescreen' }); mockApp.mTriggerDownloadSuccess(); assert.isNotNull(MockAppsMgmt.mLastAppApplied); assert.equal(MockAppsMgmt.mLastAppApplied.mId, mockApp.mId); }); test('should wait for appwillclose if it is', function() { var origin = 'http://testapp.gaiamobile.org'; mockApp.origin = origin; MockService.mockQueryWith('AppWindowManager.getActiveWindow', mockApp); mockApp.mTriggerDownloadAvailable(); mockApp.mTriggerDownloadSuccess(); assert.isNull(MockAppsMgmt.mLastAppApplied); var evt = document.createEvent('CustomEvent'); evt.initCustomEvent('appwillclose', true, false, { origin: origin }); window.dispatchEvent(evt); assert.isNotNull(MockAppsMgmt.mLastAppApplied); assert.equal(MockAppsMgmt.mLastAppApplied.mId, mockApp.mId); }); test('should kill the app before applying the update', function() { MockService.mockQueryWith('AppWindowManager.getActiveWindow', { origin: 'test' }); mockApp.mTriggerDownloadAvailable(); mockApp.mTriggerDownloadSuccess(); assert.isTrue(MockService.request.calledWith('kill', 'https://testapp.gaiamobile.org')); }); }); }); suite('ondownloaderror', function() { setup(function() { mockApp.mTriggerDownloadAvailable(); mockApp.mTriggerDownloadError(); }); test('should request error banner', function() { assert.isTrue(MockUpdateManager.mErrorBannerRequested); }); test('should remove self from active downloads', function() { assert.isNotNull(MockUpdateManager.mLastDownloadsRemoval); assert.equal(MockUpdateManager.mLastDownloadsRemoval.app.mId, mockApp.mId); }); test('progress should be reset', function() { assert.isNull(subject.progress); }); test('should still answer to progress events', function() { mockApp.mTriggerDownloadProgress(42); assert.equal(42, subject.progress); }); }); suite('ondownloaderror, downloadAvailable = false', function() { setup(function() { mockApp.mTriggerDownloadAvailable(); mockApp.downloadAvailable = false; mockApp.mTriggerDownloadError(); }); test('should remove self from available updates', function() { assert.equal(MockUpdateManager.mLastUpdatesRemoval, subject); }); }); suite('onprogress', function() { setup(function() { mockApp.mTriggerDownloadAvailable(); }); test('should send progress to update manager', function() { mockApp.mTriggerDownloadProgress(1234); assert.equal(1234, MockUpdateManager.mProgressCalledWith); }); test('should send progress delta to update manager', function() { mockApp.mTriggerDownloadProgress(1234); mockApp.mTriggerDownloadProgress(2234); assert.equal(1000, MockUpdateManager.mProgressCalledWith); }); }); suite('ondownloadapplied', function() { setup(function() { mockApp.mTriggerDownloadAvailable(); mockApp.mTriggerDownloadApplied(); }); testCleanup(); }); }); suite('system update events', function() { var errorObject = { appVersion: '99.0', buildID: '20151008155421', detailsURL: 'http://www.mozilla.com/test/sample-details.html', displayVersion: '99.0', errorCode: '80', isOSUpdate: true, platformVersion: null, previousAppVersion: '44.0a1', state: 'failed', statusText: 'Install Failed', size: 225860143, updateType: 'complete', type: 'update-error' }; function forceBatteryThresholdToMidCharge() { return { then: function(callback) { callback(MID_CHARGE); } }; } setup(function() { subject = new SystemUpdatable(42); sinon.stub(subject, 'getBatteryPercentageThreshold', forceBatteryThresholdToMidCharge); subject._dispatchEvent = fakeDispatchEvent; subject.download(); }); suite('update-downloaded', function() { setup(function() { asyncStorage.setItem(SystemUpdatable.KNOWN_UPDATE_FLAG, true); var event = new MockChromeEvent({ type: 'update-downloaded' }); subject.handleEvent(event); }); test('should reset the downloading flag', function() { assert.isFalse(subject.downloading); }); test('should signal the UpdateManager', function() { assert.isTrue(MockUpdateManager.mDownloadedCalled); }); test('should remove the system download from the queue', function() { assert.isNotNull(MockUpdateManager.mLastDownloadsRemoval); assert.equal(subject, MockUpdateManager.mLastDownloadsRemoval); assert.equal(MockUpdateManager.mDownloads.length, 0); }); test('should reset SystemUpdatable.KNOWN_UPDATE_FLAG', function() { assert.isUndefined( asyncStorage.mItems[SystemUpdatable.KNOWN_UPDATE_FLAG]); }); testSystemApplyPrompt(); }); suite('update-prompt-apply', function() { setup(function() { asyncStorage.setItem(SystemUpdatable.KNOWN_UPDATE_FLAG, true); MockUtilityTray.show(); var event = new MockChromeEvent({ type: 'update-prompt-apply' }); subject.handleEvent(event); }); test('should reset SystemUpdatable.KNOWN_UPDATE_FLAG', function() { assert.isUndefined( asyncStorage.mItems[SystemUpdatable.KNOWN_UPDATE_FLAG]); }); testSystemApplyPrompt(); }); suite('update-error', function() { setup(function() { subject = new SystemUpdatable(42); var event = new MockChromeEvent(errorObject); subject.handleEvent(event); }); test('should send error notification', function() { assert.equal(MockNotificationHelper.mTitleL10n, 'systemUpdateError'); assert.equal(MockNotificationHelper.mOptions.bodyL10n, 'systemUpdateErrorDetails'); assert.equal(MockNotificationHelper.mOptions.tag, 'systemUpdateError'); assert.equal(MockNotificationHelper.mOptions.mozbehavior.showOnlyOnce, true); assert.equal(MockNotificationHelper.mOptions.closeOnClick, false); }); test('should remove self from active downloads', function() { assert.isNotNull(MockUpdateManager.mLastDownloadsRemoval); assert.equal(subject, MockUpdateManager.mLastDownloadsRemoval); }); test('should remove the downloading flag', function() { assert.isFalse(subject.downloading); }); }); suite('update error notification details', function() { setup(function() { subject = new SystemUpdatable(42); var event = new MockChromeEvent(errorObject); subject.showUpdateErrorDetails(event); }); test('utility tray hidden', function() { assert.isTrue(MockService.request.calledWith('UtilityTray:hide')); }); test('show custom dialog', function() { assert.isTrue(MockService.request.calledWith( 'showCustomDialog', 'systemUpdateError')); assert.equal(MockService.request.lastCall.args[2].id, 'wantToReportNow'); assert.equal(MockService.request.lastCall.args[3].title, 'later'); assert.equal(MockService.request.lastCall.args[4].title, 'report'); }); test('custom dialog cancel callback', function() { var cancel = MockService.request.lastCall.args[3].callback; cancel(); assert.isTrue(MockService.request.calledWith('hideCustomDialog')); }); test('custom dialog report callback', function() { var dispatchSpy = this.sinon.spy(window, 'dispatchEvent'); var report = MockService.request.lastCall.args[4].callback; report(); assert.isTrue(MockService.request.calledWith('hideCustomDialog')); sinon.assert.calledOnce(dispatchSpy); var contentEvent = dispatchSpy.lastCall.args[0]; assert.equal(contentEvent.type, 'requestSystemLogs'); }); }); suite('update download events', function() { var event; setup(function() { subject = new SystemUpdatable(98734); subject.download(); }); suite('when the download starts', function() { setup(function() { event = new MockChromeEvent({ type: 'update-download-started', total: 98734 }); }); test('should clear paused flag', function() { subject.paused = true; subject.handleEvent(event); assert.isFalse(subject.paused); }); }); suite('when the download receives progress', function() { setup(function() { event = new MockChromeEvent({ type: 'update-download-progress', progress: 1234, total: 98734 }); }); test('should send progress to update manager', function() { subject.handleEvent(event); assert.equal(1234, MockUpdateManager.mProgressCalledWith); }); test('should send progress delta to update manager', function() { subject.handleEvent(event); event.detail.progress = 2234; subject.handleEvent(event); assert.equal(1000, MockUpdateManager.mProgressCalledWith); }); }); suite('when the download is paused', function() { setup(function() { asyncStorage.setItem(SystemUpdatable.KNOWN_UPDATE_FLAG, true); event = new MockChromeEvent({ type: 'update-download-stopped', paused: true }); subject.handleEvent(event); }); test('should set the paused flag', function() { assert.isTrue(subject.paused); }); test('shouldn\'t signal "started uncompressing"', function() { assert.isFalse(MockUpdateManager.mStartedUncompressingCalled); }); test('should not reset SystemUpdatable.KNOWN_UPDATE_FLAG', function() { assert.isTrue( asyncStorage.mItems[SystemUpdatable.KNOWN_UPDATE_FLAG]); }); }); suite('when the download is complete', function() { setup(function() { asyncStorage.setItem(SystemUpdatable.KNOWN_UPDATE_FLAG, true); event = new MockChromeEvent({ type: 'update-download-stopped', paused: false }); subject.handleEvent(event); }); test('should clear the paused flag', function() { assert.isFalse(subject.paused); }); test('should signal the UpdateManager', function() { assert.isTrue(MockUpdateManager.mStartedUncompressingCalled); }); test('should not reset SystemUpdatable.KNOWN_UPDATE_FLAG', function() { assert.isTrue( asyncStorage.mItems[SystemUpdatable.KNOWN_UPDATE_FLAG]); }); }); suite('when an error occurs', function() { setup(function() { MockUpdateManager.mTeardown(); subject = new SystemUpdatable(98734); subject._dispatchEvent = function errorDuringDispatch(type, result) { fakeDispatchEvent.call(subject, type, result); subject.handleEvent(new MockChromeEvent({ type: 'update-error' })); }; subject.download(); subject._dispatchEvent = fakeDispatchEvent; }); test('should request error banner', function() { assert.isTrue(MockUpdateManager.mErrorBannerRequested); }); test('should remove self from active downloads', function() { assert.isNotNull(MockUpdateManager.mLastDownloadsRemoval); assert.equal(subject, MockUpdateManager.mLastDownloadsRemoval); assert.equal(MockUpdateManager.mDownloads.length, 0); }); test('should remove the downloading flag', function() { assert.isFalse(subject.downloading); }); }); }); }); }); function testSystemApplyPrompt() { function testSystemApplyPromptBatteryOk() { test('apply prompt shown', function() { assert.isTrue(MockCustomDialog.mShown); assert.equal('systemUpdateReady', MockCustomDialog.mShowedTitle); assert.equal('wantToInstallNow', MockCustomDialog.mShowedMsg); assert.equal( 'later', MockCustomDialog.mShowedCancel.title ); assert.equal( 'installNow', MockCustomDialog.mShowedConfirm.title); }); } function testSystemApplyPromptBatteryNok(expectedThreshold) { test('battery prompt shown', function() { assert.isTrue(MockCustomDialog.mShown); assert.equal('systemUpdateReady', MockCustomDialog.mShowedTitle); assert.deepEqual( MockCustomDialog.mShowedMsg, { id: SYSTEM_LOW_BATTERY_L10N_KEY, args: { threshold: expectedThreshold } } ); assert.equal('ok', MockCustomDialog.mShowedCancel.title); }); test('battery prompt callback', function() { assert.equal(subject.declineInstallBattery.name, MockCustomDialog.mShowedCancel.callback.name); subject.declineInstallBattery(); assert.isFalse(MockCustomDialog.mShown); assert.equal('update-prompt-apply-result', lastDispatchedEvent.type); assert.equal('low-battery', lastDispatchedEvent.value); }); } testSystemApplyPromptBatteryOk(); test('utility tray hidden', function() { assert.isTrue(MockService.request.calledWith('UtilityTray:hide')); }); test('apply prompt cancel callback', function() { assert.equal(subject.declineInstall.name, MockCustomDialog.mShowedCancel.callback.name); subject.declineInstallWait(); assert.isFalse(MockCustomDialog.mShown); assert.equal('update-prompt-apply-result', lastDispatchedEvent.type); assert.equal('wait', lastDispatchedEvent.value); }); test('apply prompt confirm callback', function() { assert.equal(subject.acceptInstall.name, MockCustomDialog.mShowedConfirm.callback.name); subject.acceptInstall(); assert.isFalse(MockCustomDialog.mShown); assert.equal('update-prompt-apply-result', lastDispatchedEvent.type); assert.equal('restart', lastDispatchedEvent.value); }); suite('battery level', function() { var realNavigatorBattery; setup(function() { realNavigatorBattery = window.navigator.battery; Object.defineProperty(window.navigator, 'battery', { configurable: true, value: MockNavigatorBattery }); }); teardown(function() { Object.defineProperty(window.navigator, 'battery', { configurable: true, value: realNavigatorBattery }); }); suite('get threshold depending on charging state', function() { setup(function() { subject.getBatteryPercentageThreshold = subject.constructor.prototype.getBatteryPercentageThreshold; }); test('threshold while charging', function(done) { MockNavigatorBattery.charging = true; subject.getBatteryPercentageThreshold().then( function(threshold) { assert.equal( threshold, MockNavigatorSettings.mSettings[BATTERY_THRESHOLD_PLUGGED] ); done(); }, function() { assert.ok(false); done(); } ); }); test('threshold while not charging', function(done) { MockNavigatorBattery.charging = false; subject.getBatteryPercentageThreshold().then( function(threshold) { assert.equal( threshold, MockNavigatorSettings.mSettings[BATTERY_THRESHOLD_UNPLUGGED] ); done(); }, function() { assert.ok(false); done(); } ); }); test('threshold has a default value if not defined', function(done) { delete MockNavigatorSettings.mSettings[BATTERY_THRESHOLD_PLUGGED]; delete MockNavigatorSettings.mSettings[BATTERY_THRESHOLD_UNPLUGGED]; subject.getBatteryPercentageThreshold().then( function(threshold) { assert.equal( threshold, subject.BATTERY_FALLBACK_THRESHOLD ); done(); }, function() { assert.ok(false); done(); } ); }); test('threshold has a default value if over the range. ', function(done) { MockNavigatorSettings.mSettings[BATTERY_THRESHOLD_PLUGGED] = 105; MockNavigatorSettings.mSettings[BATTERY_THRESHOLD_UNPLUGGED] = 105; subject.getBatteryPercentageThreshold().then( function(threshold) { assert.equal( threshold, subject.BATTERY_FALLBACK_THRESHOLD ); done(); }, function() { assert.ok(false); done(); } ); } ); test('threshold has a default value if under the range. ', function(done) { MockNavigatorSettings.mSettings[BATTERY_THRESHOLD_PLUGGED] = -10; MockNavigatorSettings.mSettings[BATTERY_THRESHOLD_UNPLUGGED] = -10; subject.getBatteryPercentageThreshold().then( function(threshold) { assert.equal( threshold, subject.BATTERY_FALLBACK_THRESHOLD ); done(); }, function() { assert.ok(false); done(); } ); } ); test('threshold has a default even if Settings fails', function(done) { // Current MockSettings can not be forced to fail, so preparing our // own stub. navigator.mozSettings = { createLock: function() { return { get: function(key) { var fakedFailingRequest = {}; setTimeout(function() { fakedFailingRequest.onerror('error'); }); return fakedFailingRequest; } }; } }; subject.getBatteryPercentageThreshold().then( function(threshold) { assert.equal( threshold, subject.BATTERY_FALLBACK_THRESHOLD ); done(); }, function() { assert.ok(false); done(); } ); navigator.mozSettings = MockNavigatorSettings; }); }); suite('low battery', function() { var event; setup(function() { asyncStorage.setItem(SystemUpdatable.KNOWN_UPDATE_FLAG, true); MockUtilityTray.show(); MockNavigatorBattery.level = 0.1; event = new MockChromeEvent({ type: 'update-prompt-apply' }); }); suite('ota update package', function() { setup(function() { event.detail.isOSUpdate = false; subject.handleEvent(event); }); testSystemApplyPromptBatteryOk(); }); suite('fota update package', function() { setup(function() { event.detail.isOSUpdate = true; subject.handleEvent(event); }); testSystemApplyPromptBatteryNok(MID_CHARGE); }); }); suite('high battery', function() { var event; setup(function() { asyncStorage.setItem(SystemUpdatable.KNOWN_UPDATE_FLAG, true); MockUtilityTray.show(); MockNavigatorBattery.level = 0.9; event = new MockChromeEvent({ type: 'update-prompt-apply' }); subject.handleEvent(event); }); suite('ota update package', function() { setup(function() { event.detail.isOSUpdate = false; subject.handleEvent(event); }); testSystemApplyPromptBatteryOk(); }); suite('fota update package', function() { setup(function() { event.detail.isOSUpdate = true; subject.handleEvent(event); }); testSystemApplyPromptBatteryOk(); }); }); }); } });