From ef739fb2222705e78256a5a14604ca934abcd3d9 Mon Sep 17 00:00:00 2001 From: Benedict Aas Date: Mon, 12 Jun 2017 13:40:52 +0100 Subject: [PATCH] refactor(GUI): remove angular dependency from selection-state (#1509) We remove the dependency on Angular from SelectionStateModel and rename it to selectionState. --- lib/gui/app.js | 12 +- .../controllers/drive-selector.js | 18 +- .../drive-selector/drive-selector.js | 1 - .../flash-error-modal/flash-error-modal.js | 3 +- .../services/flash-error-modal.js | 5 +- lib/gui/models/selection-state.js | 605 +++--- lib/gui/pages/finish/controllers/finish.js | 5 +- lib/gui/pages/finish/finish.js | 3 +- .../pages/main/controllers/drive-selection.js | 5 +- .../pages/main/controllers/image-selection.js | 10 +- lib/gui/pages/main/controllers/main.js | 12 +- lib/gui/pages/main/main.js | 1 - tests/gui/components/drive-selector.spec.js | 4 - tests/gui/models/drives.spec.js | 65 +- tests/gui/models/selection-state.spec.js | 1735 ++++++++--------- tests/gui/pages/main.spec.js | 35 +- 16 files changed, 1235 insertions(+), 1284 deletions(-) diff --git a/lib/gui/app.js b/lib/gui/app.js index 12c797af..57d3f1f6 100644 --- a/lib/gui/app.js +++ b/lib/gui/app.js @@ -41,6 +41,7 @@ const windowProgress = require('./os/window-progress'); const analytics = require('./modules/analytics'); const updateNotifier = require('./components/update-notifier'); const availableDrives = require('./models/available-drives'); +const selectionState = require('./models/selection-state'); const Store = require('./models/store'); @@ -53,9 +54,6 @@ const app = angular.module('Etcher', [ require('./modules/error'), require('./modules/drive-scanner'), - // Models - require('./models/selection-state'), - // Components require('./components/svg-icon/svg-icon'), require('./components/warning-modal/warning-modal'), @@ -89,7 +87,7 @@ app.run(() => { ].join('\n')); }); -app.run((ErrorService, SelectionStateModel) => { +app.run((ErrorService) => { analytics.logEvent('Application start'); const currentVersion = packageJSON.version; @@ -139,7 +137,7 @@ app.run((ErrorService, SelectionStateModel) => { // 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 (SelectionStateModel.hasImage()) { + if (selectionState.hasImage()) { analytics.logEvent('Update notification skipped', { reason: 'Image selected' }); @@ -278,7 +276,7 @@ app.config(($provide) => { }); }); -app.controller('HeaderController', function(SelectionStateModel, OSOpenExternalService) { +app.controller('HeaderController', function(OSOpenExternalService) { /** * @summary Open help page @@ -294,7 +292,7 @@ app.controller('HeaderController', function(SelectionStateModel, OSOpenExternalS */ this.openHelpPage = () => { const DEFAULT_SUPPORT_URL = 'https://github.com/resin-io/etcher/blob/master/SUPPORT.md'; - const supportUrl = SelectionStateModel.getImageSupportUrl() || DEFAULT_SUPPORT_URL; + const supportUrl = selectionState.getImageSupportUrl() || DEFAULT_SUPPORT_URL; OSOpenExternalService.open(supportUrl); }; diff --git a/lib/gui/components/drive-selector/controllers/drive-selector.js b/lib/gui/components/drive-selector/controllers/drive-selector.js index 7aecf825..0e82aa54 100644 --- a/lib/gui/components/drive-selector/controllers/drive-selector.js +++ b/lib/gui/components/drive-selector/controllers/drive-selector.js @@ -22,11 +22,11 @@ const messages = require('../../../../shared/messages'); const constraints = require('../../../../shared/drive-constraints'); const analytics = require('../../../modules/analytics'); const availableDrives = require('../../../models/available-drives'); +const selectionState = require('../../../models/selection-state'); module.exports = function( $q, $uibModalInstance, - SelectionStateModel, WarningModalService ) { @@ -35,7 +35,7 @@ module.exports = function( * @type {Object} * @public */ - this.state = SelectionStateModel; + this.state = selectionState; /** * @summary Static methods to check a drive's properties @@ -72,11 +72,11 @@ module.exports = function( * }); */ const shouldChangeDriveSelectionState = (drive) => { - if (!constraints.isDriveValid(drive, SelectionStateModel.getImage())) { + if (!constraints.isDriveValid(drive, selectionState.getImage())) { return $q.resolve(false); } - if (constraints.isDriveSizeRecommended(drive, SelectionStateModel.getImage())) { + if (constraints.isDriveSizeRecommended(drive, selectionState.getImage())) { return $q.resolve(true); } @@ -84,7 +84,7 @@ module.exports = function( confirmationLabel: 'Yes, continue', description: [ messages.warning.unrecommendedDriveSize({ - image: SelectionStateModel.getImage(), + image: selectionState.getImage(), drive }), 'Are you sure you want to continue?' @@ -111,12 +111,12 @@ module.exports = function( analytics.logEvent('Toggle drive', { drive, - previouslySelected: SelectionStateModel.isCurrentDrive(drive.device) + previouslySelected: selectionState.isCurrentDrive(drive.device) }); return shouldChangeDriveSelectionState(drive).then((canChangeDriveSelectionState) => { if (canChangeDriveSelectionState) { - SelectionStateModel.toggleSetDrive(drive.device); + selectionState.toggleSetDrive(drive.device); } }); @@ -131,7 +131,7 @@ module.exports = function( * DriveSelectorController.closeModal(); */ this.closeModal = () => { - const selectedDrive = SelectionStateModel.getDrive(); + const selectedDrive = selectionState.getDrive(); // Sanity check to cover the case where a drive is selected, // the drive is then unplugged from the computer and the modal @@ -162,7 +162,7 @@ module.exports = function( this.selectDriveAndClose = (drive) => { return shouldChangeDriveSelectionState(drive).then((canChangeDriveSelectionState) => { if (canChangeDriveSelectionState) { - SelectionStateModel.setDrive(drive.device); + selectionState.setDrive(drive.device); analytics.logEvent('Drive selected (double click)'); diff --git a/lib/gui/components/drive-selector/drive-selector.js b/lib/gui/components/drive-selector/drive-selector.js index 658300d1..235b2c3d 100644 --- a/lib/gui/components/drive-selector/drive-selector.js +++ b/lib/gui/components/drive-selector/drive-selector.js @@ -25,7 +25,6 @@ const MODULE_NAME = 'Etcher.Components.DriveSelector'; const DriveSelector = angular.module(MODULE_NAME, [ require('../modal/modal'), require('../warning-modal/warning-modal'), - require('../../models/selection-state'), require('../../utils/byte-size/byte-size') ]); diff --git a/lib/gui/components/flash-error-modal/flash-error-modal.js b/lib/gui/components/flash-error-modal/flash-error-modal.js index 6d9a4dfb..c1ce152f 100644 --- a/lib/gui/components/flash-error-modal/flash-error-modal.js +++ b/lib/gui/components/flash-error-modal/flash-error-modal.js @@ -23,8 +23,7 @@ const angular = require('angular'); const MODULE_NAME = 'Etcher.Components.FlashErrorModal'; const FlashErrorModal = angular.module(MODULE_NAME, [ - require('../warning-modal/warning-modal'), - require('../../models/selection-state') + require('../warning-modal/warning-modal') ]); FlashErrorModal.service('FlashErrorModalService', require('./services/flash-error-modal')); diff --git a/lib/gui/components/flash-error-modal/services/flash-error-modal.js b/lib/gui/components/flash-error-modal/services/flash-error-modal.js index a136b78c..3b948aa6 100644 --- a/lib/gui/components/flash-error-modal/services/flash-error-modal.js +++ b/lib/gui/components/flash-error-modal/services/flash-error-modal.js @@ -17,9 +17,10 @@ 'use strict'; const flashState = require('../../../models/flash-state'); +const selectionState = require('../../../models/selection-state'); const analytics = require('../../../modules/analytics'); -module.exports = function(WarningModalService, SelectionStateModel) { +module.exports = function(WarningModalService) { /** * @summary Open the flash error modal @@ -42,7 +43,7 @@ module.exports = function(WarningModalService, SelectionStateModel) { if (confirmed) { analytics.logEvent('Restart after failure'); } else { - SelectionStateModel.clear(); + selectionState.clear(); } }); }; diff --git a/lib/gui/models/selection-state.js b/lib/gui/models/selection-state.js index 04c1b10e..6b1d1b8c 100644 --- a/lib/gui/models/selection-state.js +++ b/lib/gui/models/selection-state.js @@ -16,338 +16,325 @@ 'use strict'; -/** - * @module Etcher.Models.SelectionState - */ - const _ = require('lodash'); -const angular = require('angular'); const Store = require('./store'); const availableDrives = require('./available-drives'); -const MODULE_NAME = 'Etcher.Models.SelectionState'; -const SelectionStateModel = angular.module(MODULE_NAME, []); -SelectionStateModel.service('SelectionStateModel', function() { +/** + * @summary Set a drive + * @function + * @public + * + * @param {String} drive - drive device + * + * @example + * selectionState.setDrive('/dev/disk2'); + */ +exports.setDrive = (drive) => { + Store.dispatch({ + type: Store.Actions.SELECT_DRIVE, + data: drive + }); +}; - /** - * @summary Set a drive - * @function - * @public - * - * @param {String} drive - drive device - * - * @example - * SelectionStateModel.setDrive('/dev/disk2'); - */ - this.setDrive = (drive) => { - Store.dispatch({ - type: Store.Actions.SELECT_DRIVE, - data: drive - }); - }; +/** + * @summary Toggle set drive + * @function + * @public + * + * @param {String} drive - drive device + * + * @example + * selectionState.toggleSetDrive('/dev/disk2'); + */ +exports.toggleSetDrive = (drive) => { + if (exports.isCurrentDrive(drive)) { + exports.removeDrive(); + } else { + exports.setDrive(drive); + } +}; - /** - * @summary Toggle set drive - * @function - * @public - * - * @param {String} drive - drive device - * - * @example - * SelectionStateModel.toggleSetDrive('/dev/disk2'); - */ - this.toggleSetDrive = (drive) => { - if (this.isCurrentDrive(drive)) { - this.removeDrive(); - } else { - this.setDrive(drive); - } - }; +/** + * @summary Set a image + * @function + * @public + * + * @param {Object} image - image + * + * @example + * selectionState.setImage({ + * path: 'foo.img' + * }); + */ +exports.setImage = (image) => { + Store.dispatch({ + type: Store.Actions.SELECT_IMAGE, + data: image + }); +}; - /** - * @summary Set a image - * @function - * @public - * - * @param {Object} image - image - * - * @example - * SelectionStateModel.setImage({ - * path: 'foo.img' - * }); - */ - this.setImage = (image) => { - Store.dispatch({ - type: Store.Actions.SELECT_IMAGE, - data: image - }); - }; +/** + * @summary Get drive + * @function + * @public + * + * @returns {Object} drive + * + * @example + * const drive = selectionState.getDrive(); + */ +exports.getDrive = () => { + return _.find(availableDrives.getDrives(), { + device: Store.getState().getIn([ 'selection', 'drive' ]) + }); +}; - /** - * @summary Get drive - * @function - * @public - * - * @returns {Object} drive - * - * @example - * const drive = SelectionStateModel.getDrive(); - */ - this.getDrive = () => { - return _.find(availableDrives.getDrives(), { - device: Store.getState().getIn([ 'selection', 'drive' ]) - }); - }; +/** + * @summary Get the selected image + * @function + * @public + * + * @returns {Object} image + * + * @example + * const image = selectionState.getImage(); + */ +exports.getImage = () => { + return _.get(Store.getState().toJS(), [ 'selection', 'image' ]); +}; - /** - * @summary Get the selected image - * @function - * @public - * - * @returns {Object} image - * - * @example - * const image = SelectionStateModel.getImage(); - */ - this.getImage = () => { - return _.get(Store.getState().toJS(), [ 'selection', 'image' ]); - }; +/** + * @summary Get image path + * @function + * @public + * + * @returns {String} image path + * + * @example + * const imagePath = selectionState.getImagePath(); + */ +exports.getImagePath = () => { + return _.get(Store.getState().toJS(), [ + 'selection', + 'image', + 'path' + ]); +}; - /** - * @summary Get image path - * @function - * @public - * - * @returns {String} image path - * - * @example - * const imagePath = SelectionStateModel.getImagePath(); - */ - this.getImagePath = () => { - return _.get(Store.getState().toJS(), [ - 'selection', - 'image', - 'path' - ]); - }; +/** + * @summary Get image size + * @function + * @public + * + * @returns {Number} image size + * + * @example + * const imageSize = selectionState.getImageSize(); + */ +exports.getImageSize = () => { + return _.get(Store.getState().toJS(), [ + 'selection', + 'image', + 'size', + 'final', + 'value' + ]); +}; - /** - * @summary Get image size - * @function - * @public - * - * @returns {Number} image size - * - * @example - * const imageSize = SelectionStateModel.getImageSize(); - */ - this.getImageSize = () => { - return _.get(Store.getState().toJS(), [ - 'selection', - 'image', - 'size', - 'final', - 'value' - ]); - }; +/** + * @summary Get image url + * @function + * @public + * + * @returns {String} image url + * + * @example + * const imageUrl = selectionState.getImageUrl(); + */ +exports.getImageUrl = () => { + return _.get(Store.getState().toJS(), [ + 'selection', + 'image', + 'url' + ]); +}; - /** - * @summary Get image url - * @function - * @public - * - * @returns {String} image url - * - * @example - * const imageUrl = SelectionStateModel.getImageUrl(); - */ - this.getImageUrl = () => { - return _.get(Store.getState().toJS(), [ - 'selection', - 'image', - 'url' - ]); - }; +/** + * @summary Get image name + * @function + * @public + * + * @returns {String} image name + * + * @example + * const imageName = selectionState.getImageName(); + */ +exports.getImageName = () => { + return _.get(Store.getState().toJS(), [ + 'selection', + 'image', + 'name' + ]); +}; - /** - * @summary Get image name - * @function - * @public - * - * @returns {String} image name - * - * @example - * const imageName = SelectionStateModel.getImageName(); - */ - this.getImageName = () => { - return _.get(Store.getState().toJS(), [ - 'selection', - 'image', - 'name' - ]); - }; +/** + * @summary Get image logo + * @function + * @public + * + * @returns {String} image logo + * + * @example + * const imageLogo = selectionState.getImageLogo(); + */ +exports.getImageLogo = () => { + return _.get(Store.getState().toJS(), [ + 'selection', + 'image', + 'logo' + ]); +}; - /** - * @summary Get image logo - * @function - * @public - * - * @returns {String} image logo - * - * @example - * const imageLogo = SelectionStateModel.getImageLogo(); - */ - this.getImageLogo = () => { - return _.get(Store.getState().toJS(), [ - 'selection', - 'image', - 'logo' - ]); - }; +/** + * @summary Get image support url + * @function + * @public + * + * @returns {String} image support url + * + * @example + * const imageSupportUrl = selectionState.getImageSupportUrl(); + */ +exports.getImageSupportUrl = () => { + return _.get(Store.getState().toJS(), [ + 'selection', + 'image', + 'supportUrl' + ]); +}; - /** - * @summary Get image support url - * @function - * @public - * - * @returns {String} image support url - * - * @example - * const imageSupportUrl = SelectionStateModel.getImageSupportUrl(); - */ - this.getImageSupportUrl = () => { - return _.get(Store.getState().toJS(), [ - 'selection', - 'image', - 'supportUrl' - ]); - }; +/** + * @summary Get image recommended drive size + * @function + * @public + * + * @returns {String} image recommended drive size + * + * @example + * const imageRecommendedDriveSize = selectionState.getImageRecommendedDriveSize(); + */ +exports.getImageRecommendedDriveSize = () => { + return _.get(Store.getState().toJS(), [ + 'selection', + 'image', + 'recommendedDriveSize' + ]); +}; - /** - * @summary Get image recommended drive size - * @function - * @public - * - * @returns {String} image recommended drive size - * - * @example - * const imageRecommendedDriveSize = SelectionStateModel.getImageRecommendedDriveSize(); - */ - this.getImageRecommendedDriveSize = () => { - return _.get(Store.getState().toJS(), [ - 'selection', - 'image', - 'recommendedDriveSize' - ]); - }; +/** + * @summary Check if there is a selected drive + * @function + * @public + * + * @returns {Boolean} whether there is a selected drive + * + * @example + * if (selectionState.hasDrive()) { + * console.log('There is a drive!'); + * } + */ +exports.hasDrive = () => { + return Boolean(exports.getDrive()); +}; - /** - * @summary Check if there is a selected drive - * @function - * @public - * - * @returns {Boolean} whether there is a selected drive - * - * @example - * if (SelectionStateModel.hasDrive()) { - * console.log('There is a drive!'); - * } - */ - this.hasDrive = () => { - return Boolean(this.getDrive()); - }; +/** + * @summary Check if there is a selected image + * @function + * @public + * + * @returns {Boolean} whether there is a selected image + * + * @example + * if (selectionState.hasImage()) { + * console.log('There is an image!'); + * } + */ +exports.hasImage = () => { + return Boolean(exports.getImage()); +}; - /** - * @summary Check if there is a selected image - * @function - * @public - * - * @returns {Boolean} whether there is a selected image - * - * @example - * if (SelectionStateModel.hasImage()) { - * console.log('There is an image!'); - * } - */ - this.hasImage = () => { - return Boolean(this.getImage()); - }; +/** + * @summary Remove drive + * @function + * @public + * + * @example + * selectionState.removeDrive(); + */ +exports.removeDrive = () => { + Store.dispatch({ + type: Store.Actions.REMOVE_DRIVE + }); +}; - /** - * @summary Remove drive - * @function - * @public - * - * @example - * SelectionStateModel.removeDrive(); - */ - this.removeDrive = () => { - Store.dispatch({ - type: Store.Actions.REMOVE_DRIVE - }); - }; +/** + * @summary Remove image + * @function + * @public + * + * @example + * selectionState.removeImage(); + */ +exports.removeImage = () => { + Store.dispatch({ + type: Store.Actions.REMOVE_IMAGE + }); +}; - /** - * @summary Remove image - * @function - * @public - * - * @example - * SelectionStateModel.removeImage(); - */ - this.removeImage = () => { +/** + * @summary Clear selections + * @function + * @public + * + * @param {Object} options - options + * @param {Boolean} [options.preserveImage] - preserve image + * + * @example + * selectionState.clear(); + * + * @example + * selectionState.clear({ preserveImage: true }); + */ +exports.clear = (options = {}) => { + if (!options.preserveImage) { Store.dispatch({ type: Store.Actions.REMOVE_IMAGE }); - }; + } - /** - * @summary Clear selections - * @function - * @public - * - * @param {Object} options - options - * @param {Boolean} [options.preserveImage] - preserve image - * - * @example - * SelectionStateModel.clear(); - * - * @example - * SelectionStateModel.clear({ preserveImage: true }); - */ - this.clear = (options = {}) => { - if (!options.preserveImage) { - Store.dispatch({ - type: Store.Actions.REMOVE_IMAGE - }); - } + Store.dispatch({ + type: Store.Actions.REMOVE_DRIVE + }); +}; - Store.dispatch({ - type: Store.Actions.REMOVE_DRIVE - }); - }; +/** + * @summary Check if a drive is the current drive + * @function + * @public + * + * @param {String} drive - drive device + * @returns {Boolean} whether the drive is the current drive + * + * @example + * if (selectionState.isCurrentDrive('/dev/sdb')) { + * console.log('This is the current drive!'); + * } + */ +exports.isCurrentDrive = (drive) => { + if (!drive) { + return false; + } - /** - * @summary Check if a drive is the current drive - * @function - * @public - * - * @param {String} drive - drive device - * @returns {Boolean} whether the drive is the current drive - * - * @example - * if (SelectionStateModel.isCurrentDrive('/dev/sdb')) { - * console.log('This is the current drive!'); - * } - */ - this.isCurrentDrive = (drive) => { - if (!drive) { - return false; - } - - return drive === _.get(this.getDrive(), [ 'device' ]); - }; - -}); - -module.exports = MODULE_NAME; + return drive === _.get(exports.getDrive(), [ 'device' ]); +}; diff --git a/lib/gui/pages/finish/controllers/finish.js b/lib/gui/pages/finish/controllers/finish.js index 3d727623..15f853c7 100644 --- a/lib/gui/pages/finish/controllers/finish.js +++ b/lib/gui/pages/finish/controllers/finish.js @@ -18,9 +18,10 @@ const settings = require('../../../models/settings'); const flashState = require('../../../models/flash-state'); +const selectionState = require('../../../models/selection-state'); const analytics = require('../../../modules/analytics'); -module.exports = function($state, SelectionStateModel) { +module.exports = function($state) { /** * @summary Settings model @@ -48,7 +49,7 @@ module.exports = function($state, SelectionStateModel) { * FinishController.restart({ preserveImage: true }); */ this.restart = (options) => { - SelectionStateModel.clear(options); + selectionState.clear(options); analytics.logEvent('Restart', options); $state.go('main'); }; diff --git a/lib/gui/pages/finish/finish.js b/lib/gui/pages/finish/finish.js index e8431714..373d4ad7 100644 --- a/lib/gui/pages/finish/finish.js +++ b/lib/gui/pages/finish/finish.js @@ -29,8 +29,7 @@ const angular = require('angular'); const MODULE_NAME = 'Etcher.Pages.Finish'; const FinishPage = angular.module(MODULE_NAME, [ - require('angular-ui-router'), - require('../../models/selection-state') + require('angular-ui-router') ]); FinishPage.controller('FinishController', require('./controllers/finish')); diff --git a/lib/gui/pages/main/controllers/drive-selection.js b/lib/gui/pages/main/controllers/drive-selection.js index a316a865..850398ed 100644 --- a/lib/gui/pages/main/controllers/drive-selection.js +++ b/lib/gui/pages/main/controllers/drive-selection.js @@ -17,9 +17,10 @@ 'use strict'; const settings = require('../../../models/settings'); +const selectionState = require('../../../models/selection-state'); const analytics = require('../../../modules/analytics'); -module.exports = function(SelectionStateModel, ErrorService, DriveSelectorService) { +module.exports = function(ErrorService, DriveSelectorService) { /** * @summary Open drive selector @@ -35,7 +36,7 @@ module.exports = function(SelectionStateModel, ErrorService, DriveSelectorServic return; } - SelectionStateModel.setDrive(drive.device); + selectionState.setDrive(drive.device); analytics.logEvent('Select drive', { device: drive.device, diff --git a/lib/gui/pages/main/controllers/image-selection.js b/lib/gui/pages/main/controllers/image-selection.js index 46a6a28d..8afdfa11 100644 --- a/lib/gui/pages/main/controllers/image-selection.js +++ b/lib/gui/pages/main/controllers/image-selection.js @@ -24,9 +24,9 @@ const errors = require('../../../../shared/errors'); const imageStream = require('../../../../image-stream'); const supportedFormats = require('../../../../shared/supported-formats'); const analytics = require('../../../modules/analytics'); +const selectionState = require('../../../models/selection-state'); module.exports = function( - SelectionStateModel, ErrorService, OSDialogService, WarningModalService @@ -100,7 +100,7 @@ module.exports = function( return this.reselectImage(); } - SelectionStateModel.setImage(image); + selectionState.setImage(image); // An easy way so we can quickly identify if we're making use of // certain features without printing pages of text to DevTools. @@ -161,7 +161,7 @@ module.exports = function( */ this.reselectImage = () => { analytics.logEvent('Reselect image', { - previousImage: SelectionStateModel.getImage() + previousImage: selectionState.getImage() }); this.openImageSelector(); @@ -178,11 +178,11 @@ module.exports = function( * const imageBasename = ImageSelectionController.getImageBasename(); */ this.getImageBasename = () => { - if (!SelectionStateModel.hasImage()) { + if (!selectionState.hasImage()) { return ''; } - return path.basename(SelectionStateModel.getImagePath()); + return path.basename(selectionState.getImagePath()); }; }; diff --git a/lib/gui/pages/main/controllers/main.js b/lib/gui/pages/main/controllers/main.js index 9072fe5f..d01f066c 100644 --- a/lib/gui/pages/main/controllers/main.js +++ b/lib/gui/pages/main/controllers/main.js @@ -20,16 +20,16 @@ const settings = require('../../../models/settings'); const flashState = require('../../../models/flash-state'); const analytics = require('../../../modules/analytics'); const availableDrives = require('../../../models/available-drives'); +const selectionState = require('../../../models/selection-state'); module.exports = function( - SelectionStateModel, TooltipModalService, ErrorService, OSOpenExternalService ) { // Expose several modules to the template for convenience - this.selection = SelectionStateModel; + this.selection = selectionState; this.drives = availableDrives; this.state = flashState; this.settings = settings; @@ -48,7 +48,7 @@ module.exports = function( * } */ this.shouldDriveStepBeDisabled = () => { - return !SelectionStateModel.hasImage(); + return !selectionState.hasImage(); }; /** @@ -64,7 +64,7 @@ module.exports = function( * } */ this.shouldFlashStepBeDisabled = () => { - return !SelectionStateModel.hasDrive() || this.shouldDriveStepBeDisabled(); + return !selectionState.hasDrive() || this.shouldDriveStepBeDisabled(); }; /** @@ -79,12 +79,12 @@ module.exports = function( */ this.showSelectedImageDetails = () => { analytics.logEvent('Show selected image tooltip', { - imagePath: SelectionStateModel.getImagePath() + imagePath: selectionState.getImagePath() }); return TooltipModalService.show({ title: 'Image File Name', - message: SelectionStateModel.getImagePath() + message: selectionState.getImagePath() }).catch(ErrorService.reportException); }; diff --git a/lib/gui/pages/main/main.js b/lib/gui/pages/main/main.js index 4896342b..fe75faea 100644 --- a/lib/gui/pages/main/main.js +++ b/lib/gui/pages/main/main.js @@ -46,7 +46,6 @@ const MainPage = angular.module(MODULE_NAME, [ require('../../modules/drive-scanner'), require('../../modules/image-writer'), require('../../modules/error'), - require('../../models/selection-state'), require('../../utils/byte-size/byte-size') ]); diff --git a/tests/gui/components/drive-selector.spec.js b/tests/gui/components/drive-selector.spec.js index d7d584cb..f5aa9547 100644 --- a/tests/gui/components/drive-selector.spec.js +++ b/tests/gui/components/drive-selector.spec.js @@ -17,7 +17,6 @@ describe('Browser: DriveSelector', function() { let $rootScope; let $q; let $uibModalInstance; - let SelectionStateModel; let WarningModalService; let controller; @@ -26,14 +25,12 @@ describe('Browser: DriveSelector', function() { _$controller_, _$rootScope_, _$q_, - _SelectionStateModel_, _WarningModalService_ ) { $controller = _$controller_; $rootScope = _$rootScope_; $q = _$q_; $uibModalInstance = {}; - SelectionStateModel = _SelectionStateModel_; WarningModalService = _WarningModalService_; })); @@ -42,7 +39,6 @@ describe('Browser: DriveSelector', function() { $scope: $rootScope.$new(), $q, $uibModalInstance, - SelectionStateModel, WarningModalService }); }); diff --git a/tests/gui/models/drives.spec.js b/tests/gui/models/drives.spec.js index dff13f7e..aed98ea4 100644 --- a/tests/gui/models/drives.spec.js +++ b/tests/gui/models/drives.spec.js @@ -2,24 +2,13 @@ const m = require('mochainon'); const path = require('path'); -const angular = require('angular'); const availableDrives = require('../../../lib/gui/models/available-drives'); -require('angular-mocks'); +const selectionState = require('../../../lib/gui/models/selection-state'); describe('Browser: availableDrives', function() { - beforeEach(angular.mock.module( - require('../../../lib/gui/models/selection-state') - )); - describe('availableDrives', function() { - let SelectionStateModel; - - beforeEach(angular.mock.inject(function(_SelectionStateModel_) { - SelectionStateModel = _SelectionStateModel_; - })); - it('should have no drives by default', function() { m.chai.expect(availableDrives.getDrives()).to.deep.equal([]); }); @@ -80,12 +69,12 @@ describe('Browser: availableDrives', function() { describe('given no selected image and no selected drive', function() { beforeEach(function() { - SelectionStateModel.removeDrive(); - SelectionStateModel.removeImage(); + selectionState.removeDrive(); + selectionState.removeImage(); }); it('should auto-select a single valid available drive', function() { - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; availableDrives.setDrives([ { @@ -98,8 +87,8 @@ describe('Browser: availableDrives', function() { } ]); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.true; - m.chai.expect(SelectionStateModel.getDrive().device).to.equal('/dev/sdb'); + m.chai.expect(selectionState.hasDrive()).to.be.true; + m.chai.expect(selectionState.getDrive().device).to.equal('/dev/sdb'); }); }); @@ -113,8 +102,8 @@ describe('Browser: availableDrives', function() { this.imagePath = '/mnt/bar/foo.img'; } - SelectionStateModel.removeDrive(); - SelectionStateModel.setImage({ + selectionState.removeDrive(); + selectionState.setImage({ path: this.imagePath, extension: 'img', size: { @@ -129,11 +118,11 @@ describe('Browser: availableDrives', function() { }); afterEach(function() { - SelectionStateModel.removeImage(); + selectionState.removeImage(); }); it('should not auto-select when there are multiple valid available drives', function() { - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; availableDrives.setDrives([ { @@ -154,11 +143,11 @@ describe('Browser: availableDrives', function() { } ]); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; }); it('should auto-select a single valid available drive', function() { - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; availableDrives.setDrives([ { @@ -171,7 +160,7 @@ describe('Browser: availableDrives', function() { } ]); - m.chai.expect(SelectionStateModel.getDrive()).to.deep.equal({ + m.chai.expect(selectionState.getDrive()).to.deep.equal({ device: '/dev/sdb', name: 'Foo', size: 2000000000, @@ -182,7 +171,7 @@ describe('Browser: availableDrives', function() { }); it('should not auto-select a single too small drive', function() { - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; availableDrives.setDrives([ { @@ -195,11 +184,11 @@ describe('Browser: availableDrives', function() { } ]); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; }); it('should not auto-select a single drive that doesn\'t meet the recommended size', function() { - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; availableDrives.setDrives([ { @@ -212,11 +201,11 @@ describe('Browser: availableDrives', function() { } ]); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; }); it('should not auto-select a single protected drive', function() { - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; availableDrives.setDrives([ { @@ -229,11 +218,11 @@ describe('Browser: availableDrives', function() { } ]); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; }); it('should not auto-select a source drive', function() { - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; availableDrives.setDrives([ { @@ -250,11 +239,11 @@ describe('Browser: availableDrives', function() { } ]); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; }); it('should not auto-select a single system drive', function() { - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; availableDrives.setDrives([ { @@ -267,7 +256,7 @@ describe('Browser: availableDrives', function() { } ]); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; }); }); @@ -315,15 +304,15 @@ describe('Browser: availableDrives', function() { } ]); - SelectionStateModel.setDrive('/dev/sdc'); + selectionState.setDrive('/dev/sdc'); }); afterEach(function() { - SelectionStateModel.removeDrive(); + selectionState.removeDrive(); }); it('should be deleted if its not contained in the available drives anymore', function() { - m.chai.expect(SelectionStateModel.hasDrive()).to.be.true; + m.chai.expect(selectionState.hasDrive()).to.be.true; // We have to provide at least two drives, otherwise, // if we only provide one, the single drive will be @@ -347,7 +336,7 @@ describe('Browser: availableDrives', function() { } ]); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasDrive()).to.be.false; }); }); diff --git a/tests/gui/models/selection-state.spec.js b/tests/gui/models/selection-state.spec.js index d9d9939a..26aadc9d 100644 --- a/tests/gui/models/selection-state.spec.js +++ b/tests/gui/models/selection-state.spec.js @@ -3,89 +3,143 @@ const m = require('mochainon'); const _ = require('lodash'); const path = require('path'); -const angular = require('angular'); const availableDrives = require('../../../lib/gui/models/available-drives'); -require('angular-mocks'); +const selectionState = require('../../../lib/gui/models/selection-state'); -describe('Browser: SelectionState', function() { +describe('Browser: selectionState', function() { - beforeEach(angular.mock.module( - require('../../../lib/gui/models/selection-state') - )); + describe('given a clean state', function() { - describe('SelectionStateModel', function() { + beforeEach(function() { + selectionState.clear(); + }); - let SelectionStateModel; + it('getDrive() should return undefined', function() { + const drive = selectionState.getDrive(); + m.chai.expect(drive).to.be.undefined; + }); - beforeEach(angular.mock.inject(function(_SelectionStateModel_) { - SelectionStateModel = _SelectionStateModel_; - })); + it('getImage() should return undefined', function() { + m.chai.expect(selectionState.getImage()).to.be.undefined; + }); - describe('given a clean state', function() { + it('getImagePath() should return undefined', function() { + m.chai.expect(selectionState.getImagePath()).to.be.undefined; + }); - beforeEach(function() { - SelectionStateModel.clear(); - }); + it('getImageSize() should return undefined', function() { + m.chai.expect(selectionState.getImageSize()).to.be.undefined; + }); - it('getDrive() should return undefined', function() { - const drive = SelectionStateModel.getDrive(); - m.chai.expect(drive).to.be.undefined; - }); + it('getImageUrl() should return undefined', function() { + m.chai.expect(selectionState.getImageUrl()).to.be.undefined; + }); - it('getImage() should return undefined', function() { - m.chai.expect(SelectionStateModel.getImage()).to.be.undefined; - }); + it('getImageName() should return undefined', function() { + m.chai.expect(selectionState.getImageName()).to.be.undefined; + }); - it('getImagePath() should return undefined', function() { - m.chai.expect(SelectionStateModel.getImagePath()).to.be.undefined; - }); + it('getImageLogo() should return undefined', function() { + m.chai.expect(selectionState.getImageLogo()).to.be.undefined; + }); - it('getImageSize() should return undefined', function() { - m.chai.expect(SelectionStateModel.getImageSize()).to.be.undefined; - }); + it('getImageSupportUrl() should return undefined', function() { + m.chai.expect(selectionState.getImageSupportUrl()).to.be.undefined; + }); - it('getImageUrl() should return undefined', function() { - m.chai.expect(SelectionStateModel.getImageUrl()).to.be.undefined; - }); + it('getImageRecommendedDriveSize() should return undefined', function() { + m.chai.expect(selectionState.getImageRecommendedDriveSize()).to.be.undefined; + }); - it('getImageName() should return undefined', function() { - m.chai.expect(SelectionStateModel.getImageName()).to.be.undefined; - }); + it('hasDrive() should return false', function() { + const hasDrive = selectionState.hasDrive(); + m.chai.expect(hasDrive).to.be.false; + }); - it('getImageLogo() should return undefined', function() { - m.chai.expect(SelectionStateModel.getImageLogo()).to.be.undefined; - }); + it('hasImage() should return false', function() { + const hasImage = selectionState.hasImage(); + m.chai.expect(hasImage).to.be.false; + }); - it('getImageSupportUrl() should return undefined', function() { - m.chai.expect(SelectionStateModel.getImageSupportUrl()).to.be.undefined; - }); + }); - it('getImageRecommendedDriveSize() should return undefined', function() { - m.chai.expect(SelectionStateModel.getImageRecommendedDriveSize()).to.be.undefined; - }); + describe('given a drive', function() { - it('hasDrive() should return false', function() { - const hasDrive = SelectionStateModel.hasDrive(); - m.chai.expect(hasDrive).to.be.false; - }); + beforeEach(function() { + availableDrives.setDrives([ + { + device: '/dev/disk2', + name: 'USB Drive', + size: 999999999, + protected: false + }, + { + device: '/dev/disk5', + name: 'USB Drive', + size: 999999999, + protected: false + } + ]); - it('hasImage() should return false', function() { - const hasImage = SelectionStateModel.hasImage(); - m.chai.expect(hasImage).to.be.false; + selectionState.setDrive('/dev/disk2'); + }); + + describe('.getDrive()', function() { + + it('should return the drive', function() { + const drive = selectionState.getDrive(); + m.chai.expect(drive).to.deep.equal({ + device: '/dev/disk2', + name: 'USB Drive', + size: 999999999, + protected: false + }); }); }); - describe('given a drive', function() { + describe('.hasDrive()', function() { - beforeEach(function() { + it('should return true', function() { + const hasDrive = selectionState.hasDrive(); + m.chai.expect(hasDrive).to.be.true; + }); + + }); + + describe('.setDrive()', function() { + + it('should override the drive', function() { + selectionState.setDrive('/dev/disk5'); + const drive = selectionState.getDrive(); + m.chai.expect(drive).to.deep.equal({ + device: '/dev/disk5', + name: 'USB Drive', + size: 999999999, + protected: false + }); + }); + + }); + + describe('.removeDrive()', function() { + + it('should clear the drive', function() { + selectionState.removeDrive(); + const drive = selectionState.getDrive(); + m.chai.expect(drive).to.be.undefined; + }); + + }); + + }); + + describe('given no drive', function() { + + describe('.setDrive()', function() { + + it('should be able to set a drive', function() { availableDrives.setDrives([ - { - device: '/dev/disk2', - name: 'USB Drive', - size: 999999999, - protected: false - }, { device: '/dev/disk5', name: 'USB Drive', @@ -94,127 +148,222 @@ describe('Browser: SelectionState', function() { } ]); - SelectionStateModel.setDrive('/dev/disk2'); + selectionState.setDrive('/dev/disk5'); + const drive = selectionState.getDrive(); + m.chai.expect(drive).to.deep.equal({ + device: '/dev/disk5', + name: 'USB Drive', + size: 999999999, + protected: false + }); }); - describe('.getDrive()', function() { + it('should throw if drive is write protected', function() { + availableDrives.setDrives([ + { + device: '/dev/disk1', + name: 'USB Drive', + size: 999999999, + protected: true + } + ]); - it('should return the drive', function() { - const drive = SelectionStateModel.getDrive(); - m.chai.expect(drive).to.deep.equal({ + m.chai.expect(function() { + selectionState.setDrive('/dev/disk1'); + }).to.throw('The drive is write-protected'); + }); + + it('should throw if the drive is not available', function() { + availableDrives.setDrives([ + { + device: '/dev/disk1', + name: 'USB Drive', + size: 999999999, + protected: true + } + ]); + + m.chai.expect(function() { + selectionState.setDrive('/dev/disk5'); + }).to.throw('The drive is not available: /dev/disk5'); + }); + + it('should throw if device is not a string', function() { + m.chai.expect(function() { + selectionState.setDrive(123); + }).to.throw('Invalid drive: 123'); + }); + + }); + + }); + + describe('given an image', function() { + + beforeEach(function() { + this.image = { + path: 'foo.img', + extension: 'img', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + }, + recommendedDriveSize: 1000000000, + url: 'https://www.raspbian.org', + supportUrl: 'https://www.raspbian.org/forums/', + name: 'Raspbian', + logo: 'Raspbian' + }; + + selectionState.setImage(this.image); + }); + + describe('.setDrive()', function() { + + it('should throw if drive is not large enough', function() { + availableDrives.setDrives([ + { device: '/dev/disk2', name: 'USB Drive', - size: 999999999, + size: 999999998, protected: false - }); - }); - - }); - - describe('.hasDrive()', function() { - - it('should return true', function() { - const hasDrive = SelectionStateModel.hasDrive(); - m.chai.expect(hasDrive).to.be.true; - }); - - }); - - describe('.setDrive()', function() { - - it('should override the drive', function() { - SelectionStateModel.setDrive('/dev/disk5'); - const drive = SelectionStateModel.getDrive(); - m.chai.expect(drive).to.deep.equal({ - device: '/dev/disk5', - name: 'USB Drive', - size: 999999999, - protected: false - }); - }); - - }); - - describe('.removeDrive()', function() { - - it('should clear the drive', function() { - SelectionStateModel.removeDrive(); - const drive = SelectionStateModel.getDrive(); - m.chai.expect(drive).to.be.undefined; - }); + } + ]); + m.chai.expect(function() { + selectionState.setDrive('/dev/disk2'); + }).to.throw('The drive is not large enough'); }); }); - describe('given no drive', function() { - - describe('.setDrive()', function() { - - it('should be able to set a drive', function() { - availableDrives.setDrives([ - { - device: '/dev/disk5', - name: 'USB Drive', - size: 999999999, - protected: false - } - ]); - - SelectionStateModel.setDrive('/dev/disk5'); - const drive = SelectionStateModel.getDrive(); - m.chai.expect(drive).to.deep.equal({ - device: '/dev/disk5', - name: 'USB Drive', - size: 999999999, - protected: false - }); - }); - - it('should throw if drive is write protected', function() { - availableDrives.setDrives([ - { - device: '/dev/disk1', - name: 'USB Drive', - size: 999999999, - protected: true - } - ]); - - m.chai.expect(function() { - SelectionStateModel.setDrive('/dev/disk1'); - }).to.throw('The drive is write-protected'); - }); - - it('should throw if the drive is not available', function() { - availableDrives.setDrives([ - { - device: '/dev/disk1', - name: 'USB Drive', - size: 999999999, - protected: true - } - ]); - - m.chai.expect(function() { - SelectionStateModel.setDrive('/dev/disk5'); - }).to.throw('The drive is not available: /dev/disk5'); - }); - - it('should throw if device is not a string', function() { - m.chai.expect(function() { - SelectionStateModel.setDrive(123); - }).to.throw('Invalid drive: 123'); - }); + describe('.getImage()', function() { + it('should return the image', function() { + m.chai.expect(selectionState.getImage()).to.deep.equal(this.image); }); }); - describe('given an image', function() { + describe('.getImagePath()', function() { - beforeEach(function() { - this.image = { + it('should return the image path', function() { + const imagePath = selectionState.getImagePath(); + m.chai.expect(imagePath).to.equal('foo.img'); + }); + + }); + + describe('.getImageSize()', function() { + + it('should return the image size', function() { + const imageSize = selectionState.getImageSize(); + m.chai.expect(imageSize).to.equal(999999999); + }); + + }); + + describe('.getImageUrl()', function() { + + it('should return the image url', function() { + const imageUrl = selectionState.getImageUrl(); + m.chai.expect(imageUrl).to.equal('https://www.raspbian.org'); + }); + + }); + + describe('.getImageName()', function() { + + it('should return the image name', function() { + const imageName = selectionState.getImageName(); + m.chai.expect(imageName).to.equal('Raspbian'); + }); + + }); + + describe('.getImageLogo()', function() { + + it('should return the image logo', function() { + const imageLogo = selectionState.getImageLogo(); + m.chai.expect(imageLogo).to.equal('Raspbian'); + }); + + }); + + describe('.getImageSupportUrl()', function() { + + it('should return the image support url', function() { + const imageSupportUrl = selectionState.getImageSupportUrl(); + m.chai.expect(imageSupportUrl).to.equal('https://www.raspbian.org/forums/'); + }); + + }); + + describe('.getImageRecommendedDriveSize()', function() { + + it('should return the image recommended drive size', function() { + const imageRecommendedDriveSize = selectionState.getImageRecommendedDriveSize(); + m.chai.expect(imageRecommendedDriveSize).to.equal(1000000000); + }); + + }); + + describe('.hasImage()', function() { + + it('should return true', function() { + const hasImage = selectionState.hasImage(); + m.chai.expect(hasImage).to.be.true; + }); + + }); + + describe('.setImage()', function() { + + it('should override the image', function() { + selectionState.setImage({ + path: 'bar.img', + extension: 'img', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } + }); + + const imagePath = selectionState.getImagePath(); + m.chai.expect(imagePath).to.equal('bar.img'); + const imageSize = selectionState.getImageSize(); + m.chai.expect(imageSize).to.equal(999999999); + }); + + }); + + describe('.removeImage()', function() { + + it('should clear the image', function() { + selectionState.removeImage(); + + const imagePath = selectionState.getImagePath(); + m.chai.expect(imagePath).to.be.undefined; + const imageSize = selectionState.getImageSize(); + m.chai.expect(imageSize).to.be.undefined; + }); + + }); + + }); + + describe('given no image', function() { + + describe('.setImage()', function() { + + it('should be able to set an image', function() { + selectionState.setImage({ path: 'foo.img', extension: 'img', size: { @@ -223,121 +372,36 @@ describe('Browser: SelectionState', function() { estimation: false, value: 999999999 } - }, - recommendedDriveSize: 1000000000, - url: 'https://www.raspbian.org', - supportUrl: 'https://www.raspbian.org/forums/', - name: 'Raspbian', - logo: 'Raspbian' - }; + } + }); - SelectionStateModel.setImage(this.image); + const imagePath = selectionState.getImagePath(); + m.chai.expect(imagePath).to.equal('foo.img'); + const imageSize = selectionState.getImageSize(); + m.chai.expect(imageSize).to.equal(999999999); }); - describe('.setDrive()', function() { - - it('should throw if drive is not large enough', function() { - availableDrives.setDrives([ - { - device: '/dev/disk2', - name: 'USB Drive', - size: 999999998, - protected: false + it('should be able to set an image with an archive extension', function() { + selectionState.setImage({ + path: 'foo.zip', + extension: 'img', + archiveExtension: 'zip', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 } - ]); - - m.chai.expect(function() { - SelectionStateModel.setDrive('/dev/disk2'); - }).to.throw('The drive is not large enough'); + } }); + const imagePath = selectionState.getImagePath(); + m.chai.expect(imagePath).to.equal('foo.zip'); }); - describe('.getImage()', function() { - - it('should return the image', function() { - m.chai.expect(SelectionStateModel.getImage()).to.deep.equal(this.image); - }); - - }); - - describe('.getImagePath()', function() { - - it('should return the image path', function() { - const imagePath = SelectionStateModel.getImagePath(); - m.chai.expect(imagePath).to.equal('foo.img'); - }); - - }); - - describe('.getImageSize()', function() { - - it('should return the image size', function() { - const imageSize = SelectionStateModel.getImageSize(); - m.chai.expect(imageSize).to.equal(999999999); - }); - - }); - - describe('.getImageUrl()', function() { - - it('should return the image url', function() { - const imageUrl = SelectionStateModel.getImageUrl(); - m.chai.expect(imageUrl).to.equal('https://www.raspbian.org'); - }); - - }); - - describe('.getImageName()', function() { - - it('should return the image name', function() { - const imageName = SelectionStateModel.getImageName(); - m.chai.expect(imageName).to.equal('Raspbian'); - }); - - }); - - describe('.getImageLogo()', function() { - - it('should return the image logo', function() { - const imageLogo = SelectionStateModel.getImageLogo(); - m.chai.expect(imageLogo).to.equal('Raspbian'); - }); - - }); - - describe('.getImageSupportUrl()', function() { - - it('should return the image support url', function() { - const imageSupportUrl = SelectionStateModel.getImageSupportUrl(); - m.chai.expect(imageSupportUrl).to.equal('https://www.raspbian.org/forums/'); - }); - - }); - - describe('.getImageRecommendedDriveSize()', function() { - - it('should return the image recommended drive size', function() { - const imageRecommendedDriveSize = SelectionStateModel.getImageRecommendedDriveSize(); - m.chai.expect(imageRecommendedDriveSize).to.equal(1000000000); - }); - - }); - - describe('.hasImage()', function() { - - it('should return true', function() { - const hasImage = SelectionStateModel.hasImage(); - m.chai.expect(hasImage).to.be.true; - }); - - }); - - describe('.setImage()', function() { - - it('should override the image', function() { - SelectionStateModel.setImage({ - path: 'bar.img', + it('should throw if no path', function() { + m.chai.expect(function() { + selectionState.setImage({ extension: 'img', size: { original: 999999999, @@ -347,458 +411,290 @@ describe('Browser: SelectionState', function() { } } }); - - const imagePath = SelectionStateModel.getImagePath(); - m.chai.expect(imagePath).to.equal('bar.img'); - const imageSize = SelectionStateModel.getImageSize(); - m.chai.expect(imageSize).to.equal(999999999); - }); - + }).to.throw('Missing image path'); }); - describe('.removeImage()', function() { - - it('should clear the image', function() { - SelectionStateModel.removeImage(); - - const imagePath = SelectionStateModel.getImagePath(); - m.chai.expect(imagePath).to.be.undefined; - const imageSize = SelectionStateModel.getImageSize(); - m.chai.expect(imageSize).to.be.undefined; - }); - + it('should throw if path is not a string', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 123, + extension: 'img', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Invalid image path: 123'); }); - }); + it('should throw if no extension', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Missing image extension'); + }); - describe('given no image', function() { + it('should throw if extension is not a string', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', + extension: 1, + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Invalid image extension: 1'); + }); - describe('.setImage()', function() { + it('should throw if the extension doesn\'t match the path and there is no archive extension', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', + extension: 'iso', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Missing image archive extension'); + }); - it('should be able to set an image', function() { - SelectionStateModel.setImage({ + it('should throw if the extension doesn\'t match the path and the archive extension is not a string', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', + extension: 'iso', + archiveExtension: 1, + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Invalid image archive extension: 1'); + }); + + it('should throw if the archive extension doesn\'t match the last path extension in a compressed image', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img.xz', + extension: 'img', + archiveExtension: 'gz', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Image archive extension mismatch: gz and xz'); + }); + + it('should throw if the extension is not recognised in an uncompressed image', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.ifg', + extension: 'ifg', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Invalid image extension: ifg'); + }); + + it('should throw if the extension is not recognised in a compressed image', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.ifg.gz', + extension: 'ifg', + archiveExtension: 'gz', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Invalid image extension: ifg'); + }); + + it('should throw if the archive extension is not recognised', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img.ifg', + extension: 'img', + archiveExtension: 'ifg', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Invalid image archive extension: ifg'); + }); + + it('should throw if no size', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', + extension: 'img' + }); + }).to.throw('Missing image size'); + }); + + it('should throw if size is not a plain object', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', + extension: 'img', + size: 999999999 + }); + }).to.throw('Invalid image size: 999999999'); + }); + + it('should throw if the original size is not a number', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', + extension: 'img', + size: { + original: '999999999', + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Invalid original image size: 999999999'); + }); + + it('should throw if the original size is a float number', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', + extension: 'img', + size: { + original: 999999999.999, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Invalid original image size: 999999999.999'); + }); + + it('should throw if the original size is negative', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', + extension: 'img', + size: { + original: -1, + final: { + estimation: false, + value: 999999999 + } + } + }); + }).to.throw('Invalid original image size: -1'); + }); + + it('should throw if the final size is not a number', function() { + m.chai.expect(function() { + selectionState.setImage({ path: 'foo.img', extension: 'img', size: { original: 999999999, final: { estimation: false, - value: 999999999 + value: '999999999' } } }); + }).to.throw('Invalid final image size: 999999999'); + }); - const imagePath = SelectionStateModel.getImagePath(); - m.chai.expect(imagePath).to.equal('foo.img'); - const imageSize = SelectionStateModel.getImageSize(); - m.chai.expect(imageSize).to.equal(999999999); - }); - - it('should be able to set an image with an archive extension', function() { - SelectionStateModel.setImage({ - path: 'foo.zip', + it('should throw if the final size is a float number', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', extension: 'img', - archiveExtension: 'zip', size: { original: 999999999, final: { estimation: false, + value: 999999999.999 + } + } + }); + }).to.throw('Invalid final image size: 999999999.999'); + }); + + it('should throw if the final size is negative', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', + extension: 'img', + size: { + original: 999999999, + final: { + estimation: false, + value: -1 + } + } + }); + }).to.throw('Invalid final image size: -1'); + }); + + it('should throw if the final size estimation flag is not a boolean', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', + extension: 'img', + size: { + original: 999999999, + final: { + estimation: 'false', value: 999999999 } } }); + }).to.throw('Invalid final image size estimation flag: false'); + }); - const imagePath = SelectionStateModel.getImagePath(); - m.chai.expect(imagePath).to.equal('foo.zip'); - }); - - it('should throw if no path', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - extension: 'img', - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Missing image path'); - }); - - it('should throw if path is not a string', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 123, - extension: 'img', - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Invalid image path: 123'); - }); - - it('should throw if no extension', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Missing image extension'); - }); - - it('should throw if extension is not a string', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 1, - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Invalid image extension: 1'); - }); - - it('should throw if the extension doesn\'t match the path and there is no archive extension', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'iso', - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Missing image archive extension'); - }); - - it('should throw if the extension doesn\'t match the path and the archive extension is not a string', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'iso', - archiveExtension: 1, - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Invalid image archive extension: 1'); - }); - - it('should throw if the archive extension doesn\'t match the last path extension in a compressed image', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img.xz', - extension: 'img', - archiveExtension: 'gz', - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Image archive extension mismatch: gz and xz'); - }); - - it('should throw if the extension is not recognised in an uncompressed image', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.ifg', - extension: 'ifg', - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Invalid image extension: ifg'); - }); - - it('should throw if the extension is not recognised in a compressed image', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.ifg.gz', - extension: 'ifg', - archiveExtension: 'gz', - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Invalid image extension: ifg'); - }); - - it('should throw if the archive extension is not recognised', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img.ifg', - extension: 'img', - archiveExtension: 'ifg', - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Invalid image archive extension: ifg'); - }); - - it('should throw if no size', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img' - }); - }).to.throw('Missing image size'); - }); - - it('should throw if size is not a plain object', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img', - size: 999999999 - }); - }).to.throw('Invalid image size: 999999999'); - }); - - it('should throw if the original size is not a number', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img', - size: { - original: '999999999', - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Invalid original image size: 999999999'); - }); - - it('should throw if the original size is a float number', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img', - size: { - original: 999999999.999, - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Invalid original image size: 999999999.999'); - }); - - it('should throw if the original size is negative', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img', - size: { - original: -1, - final: { - estimation: false, - value: 999999999 - } - } - }); - }).to.throw('Invalid original image size: -1'); - }); - - it('should throw if the final size is not a number', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img', - size: { - original: 999999999, - final: { - estimation: false, - value: '999999999' - } - } - }); - }).to.throw('Invalid final image size: 999999999'); - }); - - it('should throw if the final size is a float number', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img', - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999.999 - } - } - }); - }).to.throw('Invalid final image size: 999999999.999'); - }); - - it('should throw if the final size is negative', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img', - size: { - original: 999999999, - final: { - estimation: false, - value: -1 - } - } - }); - }).to.throw('Invalid final image size: -1'); - }); - - it('should throw if the final size estimation flag is not a boolean', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img', - size: { - original: 999999999, - final: { - estimation: 'false', - value: 999999999 - } - } - }); - }).to.throw('Invalid final image size estimation flag: false'); - }); - - it('should throw if url is defined but it\'s not a string', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img', - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - }, - url: 1234 - }); - }).to.throw('Invalid image url: 1234'); - }); - - it('should throw if name is defined but it\'s not a string', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img', - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - }, - name: 1234 - }); - }).to.throw('Invalid image name: 1234'); - }); - - it('should throw if logo is defined but it\'s not a string', function() { - m.chai.expect(function() { - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img', - size: { - original: 999999999, - final: { - estimation: false, - value: 999999999 - } - }, - logo: 1234 - }); - }).to.throw('Invalid image logo: 1234'); - }); - - it('should de-select a previously selected not-large-enough drive', function() { - availableDrives.setDrives([ - { - device: '/dev/disk1', - name: 'USB Drive', - size: 999999999, - protected: false - } - ]); - - SelectionStateModel.setDrive('/dev/disk1'); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.true; - - SelectionStateModel.setImage({ - path: 'foo.img', - extension: 'img', - size: { - original: 9999999999, - final: { - estimation: false, - value: 9999999999 - } - } - }); - - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; - SelectionStateModel.removeImage(); - }); - - it('should de-select a previously selected not-recommended drive', function() { - availableDrives.setDrives([ - { - device: '/dev/disk1', - name: 'USB Drive', - size: 1200000000, - protected: false - } - ]); - - SelectionStateModel.setDrive('/dev/disk1'); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.true; - - SelectionStateModel.setImage({ + it('should throw if url is defined but it\'s not a string', function() { + m.chai.expect(function() { + selectionState.setImage({ path: 'foo.img', extension: 'img', size: { @@ -808,41 +704,15 @@ describe('Browser: SelectionState', function() { value: 999999999 } }, - recommendedDriveSize: 1500000000 + url: 1234 }); + }).to.throw('Invalid image url: 1234'); + }); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; - SelectionStateModel.removeImage(); - }); - - it('should de-select a previously selected source drive', function() { - const imagePath = _.attempt(() => { - if (process.platform === 'win32') { - return 'E:\\bar\\foo.img'; - } - - return '/mnt/bar/foo.img'; - }); - - availableDrives.setDrives([ - { - device: '/dev/disk1', - name: 'USB Drive', - size: 1200000000, - mountpoints: [ - { - path: path.dirname(imagePath) - } - ], - protected: false - } - ]); - - SelectionStateModel.setDrive('/dev/disk1'); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.true; - - SelectionStateModel.setImage({ - path: imagePath, + it('should throw if name is defined but it\'s not a string', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', extension: 'img', size: { original: 999999999, @@ -850,20 +720,30 @@ describe('Browser: SelectionState', function() { estimation: false, value: 999999999 } - } + }, + name: 1234 }); - - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; - SelectionStateModel.removeImage(); - }); - + }).to.throw('Invalid image name: 1234'); }); - }); + it('should throw if logo is defined but it\'s not a string', function() { + m.chai.expect(function() { + selectionState.setImage({ + path: 'foo.img', + extension: 'img', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + }, + logo: 1234 + }); + }).to.throw('Invalid image logo: 1234'); + }); - describe('given a drive', function() { - - beforeEach(function() { + it('should de-select a previously selected not-large-enough drive', function() { availableDrives.setDrives([ { device: '/dev/disk1', @@ -873,11 +753,84 @@ describe('Browser: SelectionState', function() { } ]); - SelectionStateModel.setDrive('/dev/disk1'); + selectionState.setDrive('/dev/disk1'); + m.chai.expect(selectionState.hasDrive()).to.be.true; - SelectionStateModel.setImage({ + selectionState.setImage({ path: 'foo.img', extension: 'img', + size: { + original: 9999999999, + final: { + estimation: false, + value: 9999999999 + } + } + }); + + m.chai.expect(selectionState.hasDrive()).to.be.false; + selectionState.removeImage(); + }); + + it('should de-select a previously selected not-recommended drive', function() { + availableDrives.setDrives([ + { + device: '/dev/disk1', + name: 'USB Drive', + size: 1200000000, + protected: false + } + ]); + + selectionState.setDrive('/dev/disk1'); + m.chai.expect(selectionState.hasDrive()).to.be.true; + + selectionState.setImage({ + path: 'foo.img', + extension: 'img', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + }, + recommendedDriveSize: 1500000000 + }); + + m.chai.expect(selectionState.hasDrive()).to.be.false; + selectionState.removeImage(); + }); + + it('should de-select a previously selected source drive', function() { + const imagePath = _.attempt(() => { + if (process.platform === 'win32') { + return 'E:\\bar\\foo.img'; + } + + return '/mnt/bar/foo.img'; + }); + + availableDrives.setDrives([ + { + device: '/dev/disk1', + name: 'USB Drive', + size: 1200000000, + mountpoints: [ + { + path: path.dirname(imagePath) + } + ], + protected: false + } + ]); + + selectionState.setDrive('/dev/disk1'); + m.chai.expect(selectionState.hasDrive()).to.be.true; + + selectionState.setImage({ + path: imagePath, + extension: 'img', size: { original: 999999999, final: { @@ -886,117 +839,100 @@ describe('Browser: SelectionState', function() { } } }); - }); - - describe('.clear()', function() { - - it('should clear all selections', function() { - m.chai.expect(SelectionStateModel.hasDrive()).to.be.true; - m.chai.expect(SelectionStateModel.hasImage()).to.be.true; - - SelectionStateModel.clear(); - - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; - m.chai.expect(SelectionStateModel.hasImage()).to.be.false; - }); - - }); - - describe('given the preserveImage option', function() { - - beforeEach(function() { - SelectionStateModel.clear({ - preserveImage: true - }); - }); - - it('getDrive() should return undefined', function() { - const drive = SelectionStateModel.getDrive(); - m.chai.expect(drive).to.be.undefined; - }); - - it('getImagePath() should return the image path', function() { - const imagePath = SelectionStateModel.getImagePath(); - m.chai.expect(imagePath).to.equal('foo.img'); - }); - - it('getImageSize() should return the image size', function() { - const imageSize = SelectionStateModel.getImageSize(); - m.chai.expect(imageSize).to.equal(999999999); - }); - - it('hasDrive() should return false', function() { - const hasDrive = SelectionStateModel.hasDrive(); - m.chai.expect(hasDrive).to.be.false; - }); - - it('hasImage() should return true', function() { - const hasImage = SelectionStateModel.hasImage(); - m.chai.expect(hasImage).to.be.true; - }); + m.chai.expect(selectionState.hasDrive()).to.be.false; + selectionState.removeImage(); }); }); - describe('.isCurrentDrive()', function() { + }); - describe('given a selected drive', function() { + describe('given a drive', function() { - beforeEach(function() { - availableDrives.setDrives([ - { - device: '/dev/sdb', - description: 'DataTraveler 2.0', - size: 999999999, - mountpoint: '/media/UNTITLED', - name: '/dev/sdb', - system: false, - protected: false - } - ]); + beforeEach(function() { + availableDrives.setDrives([ + { + device: '/dev/disk1', + name: 'USB Drive', + size: 999999999, + protected: false + } + ]); - SelectionStateModel.setDrive('/dev/sdb'); - }); - - it('should return false if an undefined value is passed', function() { - m.chai.expect(SelectionStateModel.isCurrentDrive()).to.be.false; - }); - - it('should return true given the exact same drive', function() { - m.chai.expect(SelectionStateModel.isCurrentDrive('/dev/sdb')).to.be.true; - }); - - it('should return false if it is not the current drive', function() { - m.chai.expect(SelectionStateModel.isCurrentDrive('/dev/sdc')).to.be.false; - }); + selectionState.setDrive('/dev/disk1'); + selectionState.setImage({ + path: 'foo.img', + extension: 'img', + size: { + original: 999999999, + final: { + estimation: false, + value: 999999999 + } + } }); + }); - describe('given no selected drive', function() { + describe('.clear()', function() { - beforeEach(function() { - SelectionStateModel.removeDrive(); - }); + it('should clear all selections', function() { + m.chai.expect(selectionState.hasDrive()).to.be.true; + m.chai.expect(selectionState.hasImage()).to.be.true; - it('should return false if an undefined value is passed', function() { - m.chai.expect(SelectionStateModel.isCurrentDrive()).to.be.false; - }); - - it('should return false for anything', function() { - m.chai.expect(SelectionStateModel.isCurrentDrive('/dev/sdb')).to.be.false; - }); + selectionState.clear(); + m.chai.expect(selectionState.hasDrive()).to.be.false; + m.chai.expect(selectionState.hasImage()).to.be.false; }); }); - describe('.toggleSetDrive()', function() { + describe('given the preserveImage option', function() { - describe('given a selected drive', function() { + beforeEach(function() { + selectionState.clear({ + preserveImage: true + }); + }); - beforeEach(function() { - this.drive = { + it('getDrive() should return undefined', function() { + const drive = selectionState.getDrive(); + m.chai.expect(drive).to.be.undefined; + }); + + it('getImagePath() should return the image path', function() { + const imagePath = selectionState.getImagePath(); + m.chai.expect(imagePath).to.equal('foo.img'); + }); + + it('getImageSize() should return the image size', function() { + const imageSize = selectionState.getImageSize(); + m.chai.expect(imageSize).to.equal(999999999); + }); + + it('hasDrive() should return false', function() { + const hasDrive = selectionState.hasDrive(); + m.chai.expect(hasDrive).to.be.false; + }); + + it('hasImage() should return true', function() { + const hasImage = selectionState.hasImage(); + m.chai.expect(hasImage).to.be.true; + }); + + }); + + }); + + describe('.isCurrentDrive()', function() { + + describe('given a selected drive', function() { + + beforeEach(function() { + availableDrives.setDrives([ + { device: '/dev/sdb', description: 'DataTraveler 2.0', size: 999999999, @@ -1004,62 +940,111 @@ describe('Browser: SelectionState', function() { name: '/dev/sdb', system: false, protected: false - }; - - availableDrives.setDrives([ - this.drive, - { - device: '/dev/disk2', - name: 'USB Drive', - size: 999999999, - protected: false - } - ]); - - SelectionStateModel.setDrive(this.drive.device); - }); - - it('should be able to remove the drive', function() { - m.chai.expect(SelectionStateModel.hasDrive()).to.be.true; - SelectionStateModel.toggleSetDrive(this.drive.device); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; - }); - - it('should be able to replace the drive', function() { - const drive = { - device: '/dev/disk2', - name: 'USB Drive', - size: 999999999, - protected: false - }; - - m.chai.expect(SelectionStateModel.getDrive()).to.deep.equal(this.drive); - SelectionStateModel.toggleSetDrive(drive.device); - m.chai.expect(SelectionStateModel.getDrive()).to.deep.equal(drive); - m.chai.expect(SelectionStateModel.getDrive()).to.not.deep.equal(this.drive); - }); + } + ]); + selectionState.setDrive('/dev/sdb'); }); - describe('given no selected drive', function() { + it('should return false if an undefined value is passed', function() { + m.chai.expect(selectionState.isCurrentDrive()).to.be.false; + }); - beforeEach(function() { - SelectionStateModel.removeDrive(); - }); + it('should return true given the exact same drive', function() { + m.chai.expect(selectionState.isCurrentDrive('/dev/sdb')).to.be.true; + }); - it('should set the drive', function() { - const drive = { + it('should return false if it is not the current drive', function() { + m.chai.expect(selectionState.isCurrentDrive('/dev/sdc')).to.be.false; + }); + + }); + + describe('given no selected drive', function() { + + beforeEach(function() { + selectionState.removeDrive(); + }); + + it('should return false if an undefined value is passed', function() { + m.chai.expect(selectionState.isCurrentDrive()).to.be.false; + }); + + it('should return false for anything', function() { + m.chai.expect(selectionState.isCurrentDrive('/dev/sdb')).to.be.false; + }); + + }); + + }); + + describe('.toggleSetDrive()', function() { + + describe('given a selected drive', function() { + + beforeEach(function() { + this.drive = { + device: '/dev/sdb', + description: 'DataTraveler 2.0', + size: 999999999, + mountpoint: '/media/UNTITLED', + name: '/dev/sdb', + system: false, + protected: false + }; + + availableDrives.setDrives([ + this.drive, + { device: '/dev/disk2', name: 'USB Drive', size: 999999999, protected: false - }; + } + ]); - m.chai.expect(SelectionStateModel.hasDrive()).to.be.false; - SelectionStateModel.toggleSetDrive(drive.device); - m.chai.expect(SelectionStateModel.getDrive()).to.deep.equal(drive); - }); + selectionState.setDrive(this.drive.device); + }); + it('should be able to remove the drive', function() { + m.chai.expect(selectionState.hasDrive()).to.be.true; + selectionState.toggleSetDrive(this.drive.device); + m.chai.expect(selectionState.hasDrive()).to.be.false; + }); + + it('should be able to replace the drive', function() { + const drive = { + device: '/dev/disk2', + name: 'USB Drive', + size: 999999999, + protected: false + }; + + m.chai.expect(selectionState.getDrive()).to.deep.equal(this.drive); + selectionState.toggleSetDrive(drive.device); + m.chai.expect(selectionState.getDrive()).to.deep.equal(drive); + m.chai.expect(selectionState.getDrive()).to.not.deep.equal(this.drive); + }); + + }); + + describe('given no selected drive', function() { + + beforeEach(function() { + selectionState.removeDrive(); + }); + + it('should set the drive', function() { + const drive = { + device: '/dev/disk2', + name: 'USB Drive', + size: 999999999, + protected: false + }; + + m.chai.expect(selectionState.hasDrive()).to.be.false; + selectionState.toggleSetDrive(drive.device); + m.chai.expect(selectionState.getDrive()).to.deep.equal(drive); }); }); diff --git a/tests/gui/pages/main.spec.js b/tests/gui/pages/main.spec.js index c21df8cf..e0afe6d6 100644 --- a/tests/gui/pages/main.spec.js +++ b/tests/gui/pages/main.spec.js @@ -8,6 +8,7 @@ const angular = require('angular'); const settings = require('../../../lib/gui/models/settings'); const flashState = require('../../../lib/gui/models/flash-state'); const availableDrives = require('../../../lib/gui/models/available-drives'); +const selectionState = require('../../../lib/gui/models/selection-state'); require('angular-mocks'); describe('Browser: MainPage', function() { @@ -19,11 +20,9 @@ describe('Browser: MainPage', function() { describe('MainController', function() { let $controller; - let SelectionStateModel; - beforeEach(angular.mock.inject(function(_$controller_, _SelectionStateModel_) { + beforeEach(angular.mock.inject(function(_$controller_) { $controller = _$controller_; - SelectionStateModel = _SelectionStateModel_; })); describe('.shouldDriveStepBeDisabled()', function() { @@ -33,7 +32,7 @@ describe('Browser: MainPage', function() { $scope: {} }); - SelectionStateModel.clear(); + selectionState.clear(); m.chai.expect(controller.shouldDriveStepBeDisabled()).to.be.true; }); @@ -43,7 +42,7 @@ describe('Browser: MainPage', function() { $scope: {} }); - SelectionStateModel.setImage({ + selectionState.setImage({ path: 'rpi.img', extension: 'img', size: { @@ -67,7 +66,7 @@ describe('Browser: MainPage', function() { $scope: {} }); - SelectionStateModel.clear(); + selectionState.clear(); m.chai.expect(controller.shouldFlashStepBeDisabled()).to.be.true; }); @@ -77,8 +76,8 @@ describe('Browser: MainPage', function() { $scope: {} }); - SelectionStateModel.clear(); - SelectionStateModel.setImage({ + selectionState.clear(); + selectionState.setImage({ path: 'rpi.img', extension: 'img', size: { @@ -108,8 +107,8 @@ describe('Browser: MainPage', function() { } ]); - SelectionStateModel.clear(); - SelectionStateModel.setDrive('/dev/disk2'); + selectionState.clear(); + selectionState.setDrive('/dev/disk2'); m.chai.expect(controller.shouldFlashStepBeDisabled()).to.be.true; }); @@ -129,10 +128,10 @@ describe('Browser: MainPage', function() { } ]); - SelectionStateModel.clear(); - SelectionStateModel.setDrive('/dev/disk2'); + selectionState.clear(); + selectionState.setDrive('/dev/disk2'); - SelectionStateModel.setImage({ + selectionState.setImage({ path: 'rpi.img', extension: 'img', size: { @@ -154,11 +153,9 @@ describe('Browser: MainPage', function() { describe('ImageSelectionController', function() { let $controller; - let SelectionStateModel; - beforeEach(angular.mock.inject(function(_$controller_, _SelectionStateModel_) { + beforeEach(angular.mock.inject(function(_$controller_) { $controller = _$controller_; - SelectionStateModel = _SelectionStateModel_; })); it('should contain all available extensions in mainSupportedExtensions and extraSupportedExtensions', function() { @@ -178,7 +175,7 @@ describe('Browser: MainPage', function() { $scope: {} }); - SelectionStateModel.setImage({ + selectionState.setImage({ path: path.join(__dirname, 'foo', 'bar.img'), extension: 'img', size: { @@ -191,7 +188,7 @@ describe('Browser: MainPage', function() { }); m.chai.expect(controller.getImageBasename()).to.equal('bar.img'); - SelectionStateModel.removeImage(); + selectionState.removeImage(); }); it('should return an empty string if no selected image', function() { @@ -199,7 +196,7 @@ describe('Browser: MainPage', function() { $scope: {} }); - SelectionStateModel.removeImage(); + selectionState.removeImage(); m.chai.expect(controller.getImageBasename()).to.equal(''); });