refactor(GUI): make settings model setter asynchronous (#1597)

This is part of the process of implementing support for a configuration
file. We previously decoupled the Redux store from localStorage by
moving the logic that actually persists the data to localStorage to a
local-settings.js file, however the localStorage API is synchronous, so
it follows that at the moment, all functions that interact with are also
synchronous.

Moving to storing the settings to a file means turning all these
functions to promises, which we do in this commit, in order to not mix
the addition of the configuration file feature with the huge amount of
refactoring it requires.

See: https://github.com/resin-io/etcher/issues/1356
Change-Type: patch
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
This commit is contained in:
Juan Cruz Viotti 2017-08-01 10:27:15 -04:00 committed by GitHub
parent 205711da7e
commit fc3eeff1c9
6 changed files with 325 additions and 220 deletions

View File

@ -93,65 +93,66 @@ app.run(() => {
version: currentVersion version: currentVersion
}); });
settings.load(); settings.load().then(() => {
const shouldCheckForUpdates = updateNotifier.shouldCheckForUpdates({
const shouldCheckForUpdates = updateNotifier.shouldCheckForUpdates({ currentVersion,
currentVersion, lastSleptUpdateNotifier: settings.get('lastSleptUpdateNotifier'),
lastSleptUpdateNotifier: settings.get('lastSleptUpdateNotifier'), lastSleptUpdateNotifierVersion: settings.get('lastSleptUpdateNotifierVersion')
lastSleptUpdateNotifierVersion: settings.get('lastSleptUpdateNotifierVersion')
});
const currentReleaseType = release.getReleaseType(currentVersion);
const updatesEnabled = settings.get('updatesEnabled');
if (!shouldCheckForUpdates || !updatesEnabled) {
analytics.logEvent('Not checking for updates', {
shouldCheckForUpdates,
updatesEnabled,
releaseType: currentReleaseType
}); });
return;
}
const updateSemverRange = packageJSON.updates.semverRange; const currentReleaseType = release.getReleaseType(currentVersion);
const includeUnstableChannel = settings.get('includeUnstableUpdateChannel'); const updatesEnabled = settings.get('updatesEnabled');
analytics.logEvent('Checking for updates', { if (!shouldCheckForUpdates || !updatesEnabled) {
currentVersion, analytics.logEvent('Not checking for updates', {
releaseType: currentReleaseType, shouldCheckForUpdates,
updateSemverRange, updatesEnabled,
includeUnstableChannel releaseType: currentReleaseType
});
s3Packages.getLatestVersion(currentReleaseType, {
range: updateSemverRange,
includeUnstableChannel
}).then((latestVersion) => {
if (semver.gte(currentVersion, latestVersion || '0.0.0')) {
analytics.logEvent('Update notification skipped', {
reason: 'Latest version'
}); });
return Bluebird.resolve(); return Bluebird.resolve();
} }
// In case the internet connection is not good and checking the const updateSemverRange = packageJSON.updates.semverRange;
// latest published version takes too long, only show notify const includeUnstableChannel = settings.get('includeUnstableUpdateChannel');
// the user about the new version if he didn't start the flash
// process (e.g: selected an image), otherwise such interruption
// might be annoying.
if (selectionState.hasImage()) {
analytics.logEvent('Update notification skipped', {
reason: 'Image selected'
});
return Bluebird.resolve();
}
analytics.logEvent('Notifying update', { analytics.logEvent('Checking for updates', {
latestVersion currentVersion,
releaseType: currentReleaseType,
updateSemverRange,
includeUnstableChannel
}); });
return updateNotifier.notify(latestVersion, { return s3Packages.getLatestVersion(currentReleaseType, {
allowSleepUpdateCheck: currentReleaseType === release.RELEASE_TYPE.PRODUCTION range: updateSemverRange,
includeUnstableChannel
}).then((latestVersion) => {
if (semver.gte(currentVersion, latestVersion || '0.0.0')) {
analytics.logEvent('Update notification skipped', {
reason: 'Latest version'
});
return Bluebird.resolve();
}
// In case the internet connection is not good and checking the
// latest published version takes too long, only show notify
// the user about the new version if he didn't start the flash
// process (e.g: selected an image), otherwise such interruption
// might be annoying.
if (selectionState.hasImage()) {
analytics.logEvent('Update notification skipped', {
reason: 'Image selected'
});
return Bluebird.resolve();
}
analytics.logEvent('Notifying update', {
latestVersion
});
return updateNotifier.notify(latestVersion, {
allowSleepUpdateCheck: currentReleaseType === release.RELEASE_TYPE.PRODUCTION
});
}); });
}).catch(exceptionReporter.report); }).catch(exceptionReporter.report);
}); });

View File

@ -124,16 +124,20 @@ exports.notify = (version, options = {}) => {
sleepUpdateCheck: checkboxChecked || false sleepUpdateCheck: checkboxChecked || false
}); });
}); });
}).then((results) => { }).tap((results) => {
// Only update the last slept update timestamp if the // Only update the last slept update timestamp if the
// user ticked the "Remind me again in ..." checkbox, // user ticked the "Remind me again in ..." checkbox,
// but didn't agree. // but didn't agree.
if (results.sleepUpdateCheck && !results.agreed) { if (results.sleepUpdateCheck && !results.agreed) {
settings.set('lastSleptUpdateNotifier', Date.now()); return Bluebird.all([
settings.set('lastSleptUpdateNotifierVersion', packageJSON.version); settings.set('lastSleptUpdateNotifier', Date.now()),
settings.set('lastSleptUpdateNotifierVersion', packageJSON.version)
]);
} }
return Bluebird.resolve();
}).then((results) => {
analytics.logEvent('Close update modal', { analytics.logEvent('Close update modal', {
sleepUpdateCheck: results.sleepUpdateCheck, sleepUpdateCheck: results.sleepUpdateCheck,
notifyVersion: version, notifyVersion: version,

View File

@ -16,6 +16,8 @@
'use strict'; 'use strict';
const Bluebird = require('bluebird');
/** /**
* @summary Local storage settings key * @summary Local storage settings key
* @constant * @constant
@ -28,13 +30,18 @@ const LOCAL_STORAGE_SETTINGS_KEY = 'etcher-settings';
* @function * @function
* @public * @public
* *
* @returns {Object} local settings * @fulfil {Object} - local settings
* @returns {Promise}
* *
* @example * @example
* const settings = localSettings.readAll(); * localSettings.readAll().then((settings) => {
* console.log(settings);
* });
*/ */
exports.readAll = () => { exports.readAll = () => {
return JSON.parse(localStorage.getItem(LOCAL_STORAGE_SETTINGS_KEY)) || {}; return Bluebird.try(() => {
return JSON.parse(localStorage.getItem(LOCAL_STORAGE_SETTINGS_KEY)) || {};
});
}; };
/** /**
@ -43,15 +50,20 @@ exports.readAll = () => {
* @public * @public
* *
* @param {Object} settings - settings * @param {Object} settings - settings
* @returns {Promise}
* *
* @example * @example
* localSettings.writeAll({ * localSettings.writeAll({
* foo: 'bar' * foo: 'bar'
* }).then(() => {
* console.log('Done!');
* }); * });
*/ */
exports.writeAll = (settings) => { exports.writeAll = (settings) => {
const INDENTATION_SPACES = 2; const INDENTATION_SPACES = 2;
localStorage.setItem(LOCAL_STORAGE_SETTINGS_KEY, JSON.stringify(settings, null, INDENTATION_SPACES)); return Bluebird.try(() => {
localStorage.setItem(LOCAL_STORAGE_SETTINGS_KEY, JSON.stringify(settings, null, INDENTATION_SPACES));
});
}; };
/** /**
@ -62,9 +74,15 @@ exports.writeAll = (settings) => {
* @description * @description
* Exported for testing purposes * Exported for testing purposes
* *
* @returns {Promise}
*
* @example * @example
* localSettings.clear(); * localSettings.clear().then(() => {
* console.log('Done!');
* });
*/ */
exports.clear = () => { exports.clear = () => {
localStorage.removeItem(LOCAL_STORAGE_SETTINGS_KEY); return Bluebird.try(() => {
localStorage.removeItem(LOCAL_STORAGE_SETTINGS_KEY);
});
}; };

View File

@ -21,6 +21,7 @@
*/ */
const _ = require('lodash'); const _ = require('lodash');
const Bluebird = require('bluebird');
const localSettings = require('./local-settings'); const localSettings = require('./local-settings');
const store = require('../../shared/store'); const store = require('../../shared/store');
const errors = require('../../shared/errors'); const errors = require('../../shared/errors');
@ -39,30 +40,35 @@ const errors = require('../../shared/errors');
* write issues by rolling back to the previous settings if so. * write issues by rolling back to the previous settings if so.
* *
* @param {Object} settings - settings * @param {Object} settings - settings
* @returns {Promise}
* *
* @example * @example
* setSettingsObject({ foo: 'bar' }); * setSettingsObject({ foo: 'bar' }).then(() => {
* console.log('Done!');
* });
*/ */
const setSettingsObject = (settings) => { const setSettingsObject = (settings) => {
const currentSettings = exports.getAll(); const currentSettings = exports.getAll();
store.dispatch({ return Bluebird.try(() => {
type: store.Actions.SET_SETTINGS,
data: settings
});
const result = _.attempt(localSettings.writeAll, settings);
// Revert the application state if writing the data
// to the local machine was not successful
if (_.isError(result)) {
store.dispatch({ store.dispatch({
type: store.Actions.SET_SETTINGS, type: store.Actions.SET_SETTINGS,
data: currentSettings data: settings
});
}).then(() => {
// Revert the application state if writing the data
// to the local machine was not successful
return localSettings.writeAll(settings).catch((error) => {
store.dispatch({
type: store.Actions.SET_SETTINGS,
data: currentSettings
});
throw error;
}); });
throw result; });
}
}; };
/** /**
@ -77,10 +83,16 @@ const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS();
* @function * @function
* @public * @public
* *
* @returns {Promise}
*
* @example * @example
* settings.reset(); * settings.reset().then(() => {
* console.log('Done!');
* });
*/ */
exports.reset = _.partial(setSettingsObject, DEFAULT_SETTINGS); exports.reset = () => {
return setSettingsObject(DEFAULT_SETTINGS);
};
/** /**
* @summary Extend the current settings * @summary Extend the current settings
@ -88,20 +100,23 @@ exports.reset = _.partial(setSettingsObject, DEFAULT_SETTINGS);
* @public * @public
* *
* @param {Object} settings - settings * @param {Object} settings - settings
* @returns {Promise}
* *
* @example * @example
* settings.assign({ * settings.assign({
* foo: 'bar' * foo: 'bar'
* }).then(() => {
* console.log('Done!');
* }); * });
*/ */
exports.assign = (settings) => { exports.assign = (settings) => {
if (_.isNil(settings)) { if (_.isNil(settings)) {
throw errors.createError({ return Bluebird.reject(errors.createError({
title: 'Missing settings' title: 'Missing settings'
}); }));
} }
setSettingsObject(_.assign(exports.getAll(), settings)); return setSettingsObject(_.assign(exports.getAll(), settings));
}; };
/** /**
@ -109,11 +124,15 @@ exports.assign = (settings) => {
* @function * @function
* @public * @public
* *
* @returns {Promise}
*
* @example * @example
* settings.load(); * settings.load().then(() => {
* console.log('Done!');
* });
*/ */
exports.load = () => { exports.load = () => {
exports.assign(localSettings.readAll()); return localSettings.readAll().then(exports.assign);
}; };
/** /**
@ -123,24 +142,27 @@ exports.load = () => {
* *
* @param {String} key - setting key * @param {String} key - setting key
* @param {*} value - setting value * @param {*} value - setting value
* @returns {Promise}
* *
* @example * @example
* settings.set('unmountOnSuccess', true); * settings.set('unmountOnSuccess', true).then(() => {
* console.log('Done!');
* });
*/ */
exports.set = (key, value) => { exports.set = (key, value) => {
if (_.isNil(key)) { if (_.isNil(key)) {
throw errors.createError({ return Bluebird.reject(errors.createError({
title: 'Missing setting key' title: 'Missing setting key'
}); }));
} }
if (!_.isString(key)) { if (!_.isString(key)) {
throw errors.createError({ return Bluebird.reject(errors.createError({
title: `Invalid setting key: ${key}` title: `Invalid setting key: ${key}`
}); }));
} }
exports.assign({ return exports.assign({
[key]: value [key]: value
}); });
}; };

View File

@ -2,6 +2,7 @@
const m = require('mochainon'); const m = require('mochainon');
const _ = require('lodash'); const _ = require('lodash');
const Bluebird = require('bluebird');
const store = require('../../../lib/shared/store'); const store = require('../../../lib/shared/store');
const settings = require('../../../lib/gui/models/settings'); const settings = require('../../../lib/gui/models/settings');
const localSettings = require('../../../lib/gui/models/local-settings'); const localSettings = require('../../../lib/gui/models/local-settings');
@ -9,45 +10,52 @@ const localSettings = require('../../../lib/gui/models/local-settings');
describe('Browser: settings', function() { describe('Browser: settings', function() {
beforeEach(function() { beforeEach(function() {
settings.reset(); return settings.reset();
}); });
const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS(); const DEFAULT_SETTINGS = store.Defaults.get('settings').toJS();
it('should be able to set and read values', function() { it('should be able to set and read values', function() {
m.chai.expect(settings.get('foo')).to.be.undefined; m.chai.expect(settings.get('foo')).to.be.undefined;
settings.set('foo', true); return settings.set('foo', true).then(() => {
m.chai.expect(settings.get('foo')).to.be.true; m.chai.expect(settings.get('foo')).to.be.true;
settings.set('foo', false); return settings.set('foo', false);
m.chai.expect(settings.get('foo')).to.be.false; }).then(() => {
m.chai.expect(settings.get('foo')).to.be.false;
});
}); });
describe('.reset()', function() { describe('.reset()', function() {
it('should reset the settings to their default values', function() { it('should reset the settings to their default values', function() {
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS); m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
settings.set('foo', 1234); return settings.set('foo', 1234).then(() => {
m.chai.expect(settings.getAll()).to.not.deep.equal(DEFAULT_SETTINGS); m.chai.expect(settings.getAll()).to.not.deep.equal(DEFAULT_SETTINGS);
settings.reset(); return settings.reset();
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS); }).then(() => {
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
});
}); });
it('should reset the local settings to their default values', function() { it('should reset the local settings to their default values', function() {
settings.set('foo', 1234); return settings.set('foo', 1234).then(localSettings.readAll).then((data) => {
m.chai.expect(localSettings.readAll()).to.not.deep.equal(DEFAULT_SETTINGS); m.chai.expect(data).to.not.deep.equal(DEFAULT_SETTINGS);
settings.reset(); return settings.reset();
m.chai.expect(localSettings.readAll()).to.deep.equal(DEFAULT_SETTINGS); }).then(localSettings.readAll).then((data) => {
m.chai.expect(data).to.deep.equal(DEFAULT_SETTINGS);
});
}); });
describe('given the local settings are cleared', function() { describe('given the local settings are cleared', function() {
beforeEach(function() { beforeEach(function() {
localSettings.clear(); return localSettings.clear();
}); });
it('should set the local settings to their default values', function() { it('should set the local settings to their default values', function() {
settings.reset(); return settings.reset().then(localSettings.readAll).then((data) => {
m.chai.expect(localSettings.readAll()).to.deep.equal(DEFAULT_SETTINGS); m.chai.expect(data).to.deep.equal(DEFAULT_SETTINGS);
});
}); });
}); });
@ -56,73 +64,87 @@ describe('Browser: settings', function() {
describe('.assign()', function() { describe('.assign()', function() {
it('should throw if no settings', function() { it('should throw if no settings', function(done) {
m.chai.expect(function() { settings.assign().asCallback((error) => {
settings.assign(); m.chai.expect(error).to.be.an.instanceof(Error);
}).to.throw('Missing setting'); m.chai.expect(error.message).to.equal('Missing settings');
done();
});
}); });
it('should throw if setting an array', function() { it('should throw if setting an array', function(done) {
m.chai.expect(function() { settings.assign({
settings.assign({ foo: 'bar',
foo: 'bar', bar: [ 1, 2, 3 ]
bar: [ 1, 2, 3 ] }).asCallback((error) => {
}); m.chai.expect(error).to.be.an.instanceof(Error);
}).to.throw('Invalid setting value: 1,2,3 for bar'); m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for bar');
done();
});
}); });
it('should not override all settings', function() { it('should not override all settings', function() {
settings.assign({ return settings.assign({
foo: 'bar', foo: 'bar',
bar: 'baz' bar: 'baz'
}).then(() => {
m.chai.expect(settings.getAll()).to.deep.equal(_.assign({}, DEFAULT_SETTINGS, {
foo: 'bar',
bar: 'baz'
}));
}); });
m.chai.expect(settings.getAll()).to.deep.equal(_.assign({}, DEFAULT_SETTINGS, {
foo: 'bar',
bar: 'baz'
}));
}); });
it('should not store invalid settings to the local machine', function() { it('should not store invalid settings to the local machine', function() {
m.chai.expect(localSettings.readAll().foo).to.be.undefined; return localSettings.readAll().then((data) => {
m.chai.expect(data.foo).to.be.undefined;
m.chai.expect(() => { return new Bluebird((resolve) => {
settings.assign({ settings.assign({
foo: [ 1, 2, 3 ] foo: [ 1, 2, 3 ]
}).asCallback((error) => {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for foo');
return resolve();
});
}); });
}).to.throw('Invalid setting value: 1,2,3'); }).then(localSettings.readAll).then((data) => {
m.chai.expect(data.foo).to.be.undefined;
m.chai.expect(localSettings.readAll().foo).to.be.undefined; });
}); });
it('should store the settings to the local machine', function() { it('should store the settings to the local machine', function() {
m.chai.expect(localSettings.readAll().foo).to.be.undefined; return localSettings.readAll().then((data) => {
m.chai.expect(localSettings.readAll().bar).to.be.undefined; m.chai.expect(data.foo).to.be.undefined;
m.chai.expect(data.bar).to.be.undefined;
settings.assign({ return settings.assign({
foo: 'bar', foo: 'bar',
bar: 'baz' bar: 'baz'
});
}).then(localSettings.readAll).then((data) => {
m.chai.expect(data.foo).to.equal('bar');
m.chai.expect(data.bar).to.equal('baz');
}); });
m.chai.expect(localSettings.readAll().foo).to.equal('bar');
m.chai.expect(localSettings.readAll().bar).to.equal('baz');
}); });
it('should not change the application state if storing to the local machine results in an error', function() { it('should not change the application state if storing to the local machine results in an error', function(done) {
settings.set('foo', 'bar'); settings.set('foo', 'bar').then(() => {
m.chai.expect(settings.get('foo')).to.equal('bar'); m.chai.expect(settings.get('foo')).to.equal('bar');
const localSettingsWriteAllStub = m.sinon.stub(localSettings, 'writeAll'); const localSettingsWriteAllStub = m.sinon.stub(localSettings, 'writeAll');
localSettingsWriteAllStub.throws(new Error('localSettings error')); localSettingsWriteAllStub.returns(Bluebird.reject(new Error('localSettings error')));
m.chai.expect(() => {
settings.assign({ settings.assign({
foo: 'baz' foo: 'baz'
}).asCallback((error) => {
m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('localSettings error');
localSettingsWriteAllStub.restore();
m.chai.expect(settings.get('foo')).to.equal('bar');
done();
}); });
}).to.throw('localSettings error'); }).catch(done);
localSettingsWriteAllStub.restore();
m.chai.expect(settings.get('foo')).to.equal('bar');
}); });
}); });
@ -135,17 +157,20 @@ describe('Browser: settings', function() {
}; };
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS); m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
localSettings.writeAll(object);
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS); return localSettings.writeAll(object).then(() => {
settings.load(); m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
m.chai.expect(settings.getAll()).to.deep.equal(_.assign({}, DEFAULT_SETTINGS, object)); return settings.load();
}).then(() => {
m.chai.expect(settings.getAll()).to.deep.equal(_.assign({}, DEFAULT_SETTINGS, object));
});
}); });
it('should keep the application state intact if there are no local settings', function() { it('should keep the application state intact if there are no local settings', function() {
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS); m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
localSettings.clear(); return localSettings.clear().then(settings.load).then(() => {
settings.load(); m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS);
m.chai.expect(settings.getAll()).to.deep.equal(DEFAULT_SETTINGS); });
}); });
}); });
@ -154,72 +179,94 @@ describe('Browser: settings', function() {
it('should set an unknown key', function() { it('should set an unknown key', function() {
m.chai.expect(settings.get('foobar')).to.be.undefined; m.chai.expect(settings.get('foobar')).to.be.undefined;
settings.set('foobar', true); return settings.set('foobar', true).then(() => {
m.chai.expect(settings.get('foobar')).to.be.true; m.chai.expect(settings.get('foobar')).to.be.true;
});
}); });
it('should throw if no key', function() { it('should reject if no key', function(done) {
m.chai.expect(function() { settings.set(null, true).asCallback((error) => {
settings.set(null, true); m.chai.expect(error).to.be.an.instanceof(Error);
}).to.throw('Missing setting key'); m.chai.expect(error.message).to.equal('Missing setting key');
done();
});
}); });
it('should throw if key is not a string', function() { it('should throw if key is not a string', function(done) {
m.chai.expect(function() { settings.set(1234, true).asCallback((error) => {
settings.set(1234, true); m.chai.expect(error).to.be.an.instanceof(Error);
}).to.throw('Invalid setting key: 1234'); m.chai.expect(error.message).to.equal('Invalid setting key: 1234');
done();
});
}); });
it('should throw if setting an object', function() { it('should throw if setting an object', function(done) {
m.chai.expect(function() { settings.set('foo', {
settings.set('foo', { setting: 1
setting: 1 }).asCallback((error) => {
}); m.chai.expect(error).to.be.an.instanceof(Error);
}).to.throw('Invalid setting value: [object Object] for foo'); m.chai.expect(error.message).to.equal('Invalid setting value: [object Object] for foo');
done();
});
}); });
it('should throw if setting an array', function() { it('should throw if setting an array', function(done) {
m.chai.expect(function() { settings.set('foo', [ 1, 2, 3 ]).asCallback((error) => {
settings.set('foo', [ 1, 2, 3 ]); m.chai.expect(error).to.be.an.instanceof(Error);
}).to.throw('Invalid setting value: 1,2,3 for foo'); m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for foo');
done();
});
}); });
it('should set the key to undefined if no value', function() { it('should set the key to undefined if no value', function() {
settings.set('foo', 'bar'); return settings.set('foo', 'bar').then(() => {
m.chai.expect(settings.get('foo')).to.equal('bar'); m.chai.expect(settings.get('foo')).to.equal('bar');
settings.set('foo'); return settings.set('foo');
m.chai.expect(settings.get('foo')).to.be.undefined; }).then(() => {
m.chai.expect(settings.get('foo')).to.be.undefined;
});
}); });
it('should store the setting to the local machine', function() { it('should store the setting to the local machine', function() {
m.chai.expect(localSettings.readAll().foo).to.be.undefined; return localSettings.readAll().then((data) => {
settings.set('foo', 'bar'); m.chai.expect(data.foo).to.be.undefined;
m.chai.expect(localSettings.readAll().foo).to.equal('bar'); return settings.set('foo', 'bar');
}).then(localSettings.readAll).then((data) => {
m.chai.expect(data.foo).to.equal('bar');
});
}); });
it('should not store invalid settings to the local machine', function() { it('should not store invalid settings to the local machine', function() {
m.chai.expect(localSettings.readAll().foo).to.be.undefined; return localSettings.readAll().then((data) => {
m.chai.expect(data.foo).to.be.undefined;
m.chai.expect(() => { return new Bluebird((resolve) => {
settings.set('foo', [ 1, 2, 3 ]); settings.set('foo', [ 1, 2, 3 ]).asCallback((error) => {
}).to.throw('Invalid setting value: 1,2,3'); m.chai.expect(error).to.be.an.instanceof(Error);
m.chai.expect(error.message).to.equal('Invalid setting value: 1,2,3 for foo');
m.chai.expect(localSettings.readAll().foo).to.be.undefined; return resolve();
});
});
}).then(localSettings.readAll).then((data) => {
m.chai.expect(data.foo).to.be.undefined;
});
}); });
it('should not change the application state if storing to the local machine results in an error', function() { it('should not change the application state if storing to the local machine results in an error', function(done) {
settings.set('foo', 'bar'); settings.set('foo', 'bar').then(() => {
m.chai.expect(settings.get('foo')).to.equal('bar'); m.chai.expect(settings.get('foo')).to.equal('bar');
const localSettingsWriteAllStub = m.sinon.stub(localSettings, 'writeAll'); const localSettingsWriteAllStub = m.sinon.stub(localSettings, 'writeAll');
localSettingsWriteAllStub.throws(new Error('localSettings error')); localSettingsWriteAllStub.returns(Bluebird.reject(new Error('localSettings error')));
m.chai.expect(() => { settings.set('foo', 'baz').asCallback((error) => {
settings.set('foo', 'baz'); m.chai.expect(error).to.be.an.instanceof(Error);
}).to.throw('localSettings error'); m.chai.expect(error.message).to.equal('localSettings error');
localSettingsWriteAllStub.restore();
localSettingsWriteAllStub.restore(); m.chai.expect(settings.get('foo')).to.equal('bar');
m.chai.expect(settings.get('foo')).to.equal('bar'); done();
});
}).catch(done);
}); });
}); });

View File

@ -241,8 +241,9 @@ describe('Browser: MainPage', function() {
speed: 100000000000000 speed: 100000000000000
}); });
settings.set('unmountOnSuccess', true); return settings.set('unmountOnSuccess', true).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('0%'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('0%');
});
}); });
it('should handle percentage == 0, type = write, unmountOnSuccess', function() { it('should handle percentage == 0, type = write, unmountOnSuccess', function() {
@ -257,8 +258,9 @@ describe('Browser: MainPage', function() {
speed: 0 speed: 0
}); });
settings.set('unmountOnSuccess', true); return settings.set('unmountOnSuccess', true).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('Starting...'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('Starting...');
});
}); });
it('should handle percentage == 0, type = write, !unmountOnSuccess', function() { it('should handle percentage == 0, type = write, !unmountOnSuccess', function() {
@ -273,8 +275,9 @@ describe('Browser: MainPage', function() {
speed: 0 speed: 0
}); });
settings.set('unmountOnSuccess', false); return settings.set('unmountOnSuccess', false).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('Starting...'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('Starting...');
});
}); });
it('should handle percentage == 0, type = check, unmountOnSuccess', function() { it('should handle percentage == 0, type = check, unmountOnSuccess', function() {
@ -289,8 +292,9 @@ describe('Browser: MainPage', function() {
speed: 0 speed: 0
}); });
settings.set('unmountOnSuccess', true); return settings.set('unmountOnSuccess', true).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('Starting...'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('Starting...');
});
}); });
it('should handle percentage == 0, type = check, !unmountOnSuccess', function() { it('should handle percentage == 0, type = check, !unmountOnSuccess', function() {
@ -305,8 +309,9 @@ describe('Browser: MainPage', function() {
speed: 0 speed: 0
}); });
settings.set('unmountOnSuccess', false); return settings.set('unmountOnSuccess', false).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('Starting...'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('Starting...');
});
}); });
it('should handle percentage == 50, type = write, unmountOnSuccess', function() { it('should handle percentage == 50, type = write, unmountOnSuccess', function() {
@ -321,8 +326,9 @@ describe('Browser: MainPage', function() {
speed: 1000 speed: 1000
}); });
settings.set('unmountOnSuccess', true); return settings.set('unmountOnSuccess', true).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('50%'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('50%');
});
}); });
it('should handle percentage == 50, type = write, !unmountOnSuccess', function() { it('should handle percentage == 50, type = write, !unmountOnSuccess', function() {
@ -337,8 +343,9 @@ describe('Browser: MainPage', function() {
speed: 1000 speed: 1000
}); });
settings.set('unmountOnSuccess', false); return settings.set('unmountOnSuccess', false).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('50%'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('50%');
});
}); });
it('should handle percentage == 50, type = check, unmountOnSuccess', function() { it('should handle percentage == 50, type = check, unmountOnSuccess', function() {
@ -353,8 +360,9 @@ describe('Browser: MainPage', function() {
speed: 1000 speed: 1000
}); });
settings.set('unmountOnSuccess', true); return settings.set('unmountOnSuccess', true).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('50% Validating...'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('50% Validating...');
});
}); });
it('should handle percentage == 50, type = check, !unmountOnSuccess', function() { it('should handle percentage == 50, type = check, !unmountOnSuccess', function() {
@ -369,8 +377,9 @@ describe('Browser: MainPage', function() {
speed: 1000 speed: 1000
}); });
settings.set('unmountOnSuccess', false); return settings.set('unmountOnSuccess', false).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('50% Validating...'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('50% Validating...');
});
}); });
it('should handle percentage == 100, type = write, unmountOnSuccess', function() { it('should handle percentage == 100, type = write, unmountOnSuccess', function() {
@ -385,8 +394,9 @@ describe('Browser: MainPage', function() {
speed: 1000 speed: 1000
}); });
settings.set('unmountOnSuccess', true); return settings.set('unmountOnSuccess', true).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('Finishing...'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('Finishing...');
});
}); });
it('should handle percentage == 100, type = write, !unmountOnSuccess', function() { it('should handle percentage == 100, type = write, !unmountOnSuccess', function() {
@ -401,8 +411,9 @@ describe('Browser: MainPage', function() {
speed: 1000 speed: 1000
}); });
settings.set('unmountOnSuccess', false); return settings.set('unmountOnSuccess', false).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('Finishing...'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('Finishing...');
});
}); });
it('should handle percentage == 100, type = check, unmountOnSuccess', function() { it('should handle percentage == 100, type = check, unmountOnSuccess', function() {
@ -417,8 +428,9 @@ describe('Browser: MainPage', function() {
speed: 1000 speed: 1000
}); });
settings.set('unmountOnSuccess', true); return settings.set('unmountOnSuccess', true).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('Unmounting...'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('Unmounting...');
});
}); });
it('should handle percentage == 100, type = check, !unmountOnSuccess', function() { it('should handle percentage == 100, type = check, !unmountOnSuccess', function() {
@ -433,8 +445,9 @@ describe('Browser: MainPage', function() {
speed: 1000 speed: 1000
}); });
settings.set('unmountOnSuccess', false); return settings.set('unmountOnSuccess', false).then(() => {
m.chai.expect(controller.getProgressButtonLabel()).to.equal('Finishing...'); m.chai.expect(controller.getProgressButtonLabel()).to.equal('Finishing...');
});
}); });
}); });