diff --git a/lib/gui/app.js b/lib/gui/app.js
index 3fb65219..7742e8bc 100644
--- a/lib/gui/app.js
+++ b/lib/gui/app.js
@@ -47,6 +47,7 @@ const app = angular.module('Etcher', [
require('./models/settings'),
require('./models/supported-formats'),
require('./models/drives'),
+ require('./models/flash-state'),
// Components
require('./components/progress-button/progress-button'),
@@ -95,9 +96,9 @@ app.run((AnalyticsService, UpdateNotifierService, SelectionStateModel) => {
});
-app.run((AnalyticsService, OSWindowProgressService, ImageWriterService) => {
+app.run((AnalyticsService, OSWindowProgressService, FlashStateModel) => {
Store.subscribe(() => {
- const flashState = ImageWriterService.getFlashState();
+ const flashState = FlashStateModel.getFlashState();
// There is usually a short time period between the `isFlashing()`
// property being set, and the flashing actually starting, which
@@ -106,7 +107,7 @@ app.run((AnalyticsService, OSWindowProgressService, ImageWriterService) => {
//
// We use the presence of `.eta` to determine that the actual
// writing started.
- if (!ImageWriterService.isFlashing() || !flashState.eta) {
+ if (!FlashStateModel.isFlashing() || !flashState.eta) {
return;
}
@@ -135,6 +136,7 @@ app.controller('AppController', function(
$state,
DriveScannerService,
SelectionStateModel,
+ FlashStateModel,
SettingsModel,
SupportedFormatsModel,
DrivesModel,
@@ -152,6 +154,7 @@ app.controller('AppController', function(
this.selection = SelectionStateModel;
this.drives = DrivesModel;
this.writer = ImageWriterService;
+ this.state = FlashStateModel;
this.settings = SettingsModel;
this.tooltipModal = TooltipModalService;
@@ -174,7 +177,7 @@ app.controller('AppController', function(
// This catches the case where the user enters
// the settings screen when a flash finished
// and goes back to the main screen with the back button.
- if (!this.writer.isFlashing()) {
+ if (!FlashStateModel.isFlashing()) {
this.selection.clear({
@@ -248,7 +251,7 @@ app.controller('AppController', function(
};
this.reselectImage = () => {
- if (this.writer.isFlashing()) {
+ if (FlashStateModel.isFlashing()) {
return;
}
@@ -263,7 +266,7 @@ app.controller('AppController', function(
};
this.reselectDrive = () => {
- if (this.writer.isFlashing()) {
+ if (FlashStateModel.isFlashing()) {
return;
}
@@ -276,12 +279,12 @@ app.controller('AppController', function(
preserveImage: true
});
- this.writer.resetState();
+ FlashStateModel.resetState();
AnalyticsService.logEvent('Restart after failure');
};
this.wasLastFlashSuccessful = () => {
- const flashResults = this.writer.getFlashResults();
+ const flashResults = FlashStateModel.getFlashResults();
if (_.get(flashResults, 'cancelled', false)) {
return true;
@@ -292,7 +295,7 @@ app.controller('AppController', function(
this.flash = (image, drive) => {
- if (this.writer.isFlashing()) {
+ if (FlashStateModel.isFlashing()) {
return;
}
@@ -306,7 +309,7 @@ app.controller('AppController', function(
});
return this.writer.flash(image, drive).then(() => {
- const results = ImageWriterService.getFlashResults();
+ const results = FlashStateModel.getFlashResults();
if (results.cancelled) {
return;
diff --git a/lib/gui/models/flash-state.js b/lib/gui/models/flash-state.js
new file mode 100644
index 00000000..a883de22
--- /dev/null
+++ b/lib/gui/models/flash-state.js
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2016 Resin.io
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+/**
+ * @module Etcher.Models.FlashState
+ */
+
+const angular = require('angular');
+const _ = require('lodash');
+const Store = require('./store');
+const MODULE_NAME = 'Etcher.Models.FlashState';
+const FlashState = angular.module(MODULE_NAME, []);
+
+FlashState.service('FlashStateModel', function() {
+
+ /**
+ * @summary Reset flash state
+ * @function
+ * @public
+ *
+ * @example
+ * FlashStateModel.resetState();
+ */
+ this.resetState = () => {
+ Store.dispatch({
+ type: Store.Actions.RESET_FLASH_STATE
+ });
+ };
+
+ /**
+ * @summary Check if currently flashing
+ * @function
+ * @private
+ *
+ * @returns {Boolean} whether is flashing or not
+ *
+ * @example
+ * if (FlashStateModel.isFlashing()) {
+ * console.log('We\'re currently flashing');
+ * }
+ */
+ this.isFlashing = () => {
+ return Store.getState().toJS().isFlashing;
+ };
+
+ /**
+ * @summary Set the flashing flag
+ * @function
+ * @private
+ *
+ * @description
+ * This function is extracted for testing purposes.
+ *
+ * The flag is used to signify that we're going to
+ * start a flash process.
+ *
+ * @example
+ * FlashStateModel.setFlashingFlag();
+ */
+ this.setFlashingFlag = () => {
+ Store.dispatch({
+ type: Store.Actions.SET_FLASHING_FLAG
+ });
+ };
+
+ /**
+ * @summary Unset the flashing flag
+ * @function
+ * @private
+ *
+ * @description
+ * This function is extracted for testing purposes.
+ *
+ * The flag is used to signify that the write process ended.
+ *
+ * @param {Object} results - flash results
+ *
+ * @example
+ * FlashStateModel.unsetFlashingFlag({
+ * passedValidation: true,
+ * cancelled: false,
+ * sourceChecksum: 'a1b45d'
+ * });
+ */
+ this.unsetFlashingFlag = (results) => {
+ Store.dispatch({
+ type: Store.Actions.UNSET_FLASHING_FLAG,
+ data: results
+ });
+ };
+
+ /**
+ * @summary Set the flashing state
+ * @function
+ * @private
+ *
+ * @description
+ * This function is extracted for testing purposes.
+ *
+ * @param {Object} state - flashing state
+ *
+ * @example
+ * FlashStateModel.setProgressState({
+ * type: 'write',
+ * percentage: 50,
+ * eta: 15,
+ * speed: 100000000000
+ * });
+ */
+ this.setProgressState = (state) => {
+ Store.dispatch({
+ type: Store.Actions.SET_FLASH_STATE,
+ data: {
+ type: state.type,
+ percentage: state.percentage,
+ eta: state.eta,
+
+ speed: _.attempt(() => {
+ if (_.isNumber(state.speed) && !_.isNaN(state.speed)) {
+
+ // Transform bytes to megabytes preserving only two decimal places
+ return Math.floor(state.speed / 1e+6 * 100) / 100;
+
+ }
+ })
+ }
+ });
+ };
+
+ /**
+ * @summary Get the flash results
+ * @function
+ * @public
+ *
+ * @returns {Object} flash results
+ *
+ * @example
+ * const results = FlashStateModel.getFlashResults();
+ */
+ this.getFlashResults = () => {
+ return Store.getState().toJS().flashResults;
+ };
+
+ /**
+ * @summary Get the current flash state
+ * @function
+ * @public
+ *
+ * @returns {Object} flash state
+ *
+ * @example
+ * const flashState = FlashStateModel.getFlashState();
+ */
+ this.getFlashState = () => {
+ return Store.getState().get('flashState').toJS();
+ };
+
+});
+
+module.exports = MODULE_NAME;
diff --git a/lib/gui/modules/image-writer.js b/lib/gui/modules/image-writer.js
index 0f029a44..4701d86a 100644
--- a/lib/gui/modules/image-writer.js
+++ b/lib/gui/modules/image-writer.js
@@ -22,157 +22,15 @@
const angular = require('angular');
const _ = require('lodash');
-const Store = require('../models/store');
const childWriter = require('../../src/child-writer');
const MODULE_NAME = 'Etcher.Modules.ImageWriter';
const imageWriter = angular.module(MODULE_NAME, [
- require('../models/settings')
+ require('../models/settings'),
+ require('../models/flash-state')
]);
-imageWriter.service('ImageWriterService', function($q, $rootScope, SettingsModel) {
-
- /**
- * @summary Reset flash state
- * @function
- * @public
- *
- * @example
- * ImageWriterService.resetState();
- */
- this.resetState = () => {
- Store.dispatch({
- type: Store.Actions.RESET_FLASH_STATE
- });
- };
-
- /**
- * @summary Check if currently flashing
- * @function
- * @private
- *
- * @returns {Boolean} whether is flashing or not
- *
- * @example
- * if (ImageWriterService.isFlashing()) {
- * console.log('We\'re currently flashing');
- * }
- */
- this.isFlashing = () => {
- return Store.getState().toJS().isFlashing;
- };
-
- /**
- * @summary Set the flashing flag
- * @function
- * @private
- *
- * @description
- * This function is extracted for testing purposes.
- *
- * The flag is used to signify that we're going to
- * start a flash process.
- *
- * @example
- * ImageWriterService.setFlashingFlag();
- */
- this.setFlashingFlag = () => {
- Store.dispatch({
- type: Store.Actions.SET_FLASHING_FLAG
- });
- };
-
- /**
- * @summary Unset the flashing flag
- * @function
- * @private
- *
- * @description
- * This function is extracted for testing purposes.
- *
- * The flag is used to signify that the write process ended.
- *
- * @param {Object} results - flash results
- *
- * @example
- * ImageWriterService.unsetFlashingFlag({
- * passedValidation: true,
- * cancelled: false,
- * sourceChecksum: 'a1b45d'
- * });
- */
- this.unsetFlashingFlag = (results) => {
- Store.dispatch({
- type: Store.Actions.UNSET_FLASHING_FLAG,
- data: results
- });
- };
-
- /**
- * @summary Set the flashing state
- * @function
- * @private
- *
- * @description
- * This function is extracted for testing purposes.
- *
- * @param {Object} state - flashing state
- *
- * @example
- * ImageWriterService.setProgressState({
- * type: 'write',
- * percentage: 50,
- * eta: 15,
- * speed: 100000000000
- * });
- */
- this.setProgressState = (state) => {
- Store.dispatch({
- type: Store.Actions.SET_FLASH_STATE,
- data: {
- type: state.type,
- percentage: state.percentage,
- eta: state.eta,
-
- speed: _.attempt(() => {
- if (_.isNumber(state.speed) && !_.isNaN(state.speed)) {
-
- // Transform bytes to megabytes preserving only two decimal places
- return Math.floor(state.speed / 1e+6 * 100) / 100;
-
- }
- })
- }
- });
- };
-
- /**
- * @summary Get the flash results
- * @function
- * @public
- *
- * @returns {Object} flash results
- *
- * @example
- * const results = ImageWriterService.getFlashResults();
- */
- this.getFlashResults = () => {
- return Store.getState().toJS().flashResults;
- };
-
- /**
- * @summary Get the current flash state
- * @function
- * @public
- *
- * @returns {Object} flash state
- *
- * @example
- * const flashState = ImageWriterService.getFlashState();
- */
- this.getFlashState = () => {
- return Store.getState().get('flashState').toJS();
- };
+imageWriter.service('ImageWriterService', function($q, $rootScope, SettingsModel, FlashStateModel) {
/**
* @summary Perform write operation
@@ -228,11 +86,11 @@ imageWriter.service('ImageWriterService', function($q, $rootScope, SettingsModel
* });
*/
this.flash = (image, drive) => {
- if (this.isFlashing()) {
+ if (FlashStateModel.isFlashing()) {
return $q.reject(new Error('There is already a flash in progress'));
}
- this.setFlashingFlag();
+ FlashStateModel.setFlashingFlag();
return this.performWrite(image, drive, (state) => {
@@ -241,7 +99,7 @@ imageWriter.service('ImageWriterService', function($q, $rootScope, SettingsModel
// `.getFlashState()` will not return
// the latest updated progress state.
$rootScope.$apply(() => {
- this.setProgressState(state);
+ FlashStateModel.setProgressState(state);
});
}).then((results) => {
@@ -253,9 +111,9 @@ imageWriter.service('ImageWriterService', function($q, $rootScope, SettingsModel
passedValidation: false
});
- this.unsetFlashingFlag(results);
+ FlashStateModel.unsetFlashingFlag(results);
}).catch((error) => {
- this.unsetFlashingFlag({
+ FlashStateModel.unsetFlashingFlag({
cancelled: false,
passedValidation: false,
errorCode: error.code
diff --git a/lib/gui/pages/finish/controllers/finish.js b/lib/gui/pages/finish/controllers/finish.js
index 24094ee9..c64a564f 100644
--- a/lib/gui/pages/finish/controllers/finish.js
+++ b/lib/gui/pages/finish/controllers/finish.js
@@ -16,7 +16,7 @@
'use strict';
-module.exports = function($state, ImageWriterService, SelectionStateModel, AnalyticsService, SettingsModel) {
+module.exports = function($state, FlashStateModel, SelectionStateModel, AnalyticsService, SettingsModel) {
/**
* @summary Settings model
@@ -30,7 +30,7 @@ module.exports = function($state, ImageWriterService, SelectionStateModel, Analy
* @type String
* @public
*/
- this.checksum = ImageWriterService.getFlashResults().sourceChecksum;
+ this.checksum = FlashStateModel.getFlashResults().sourceChecksum;
/**
* @summary Restart the flashing process
diff --git a/lib/gui/pages/finish/finish.js b/lib/gui/pages/finish/finish.js
index 6c5e0484..0f725dd9 100644
--- a/lib/gui/pages/finish/finish.js
+++ b/lib/gui/pages/finish/finish.js
@@ -31,7 +31,7 @@ const MODULE_NAME = 'Etcher.Pages.Finish';
const FinishPage = angular.module(MODULE_NAME, [
require('angular-ui-router'),
require('../../modules/analytics'),
- require('../../modules/image-writer'),
+ require('../../models/flash-state'),
require('../../models/selection-state'),
require('../../models/settings')
]);
diff --git a/lib/gui/partials/main.html b/lib/gui/partials/main.html
index 0e143eb0..6bb68088 100644
--- a/lib/gui/partials/main.html
+++ b/lib/gui/partials/main.html
@@ -27,7 +27,7 @@
+ ng-hide="app.state.isFlashing()">Change
@@ -66,7 +66,7 @@
}">{{ app.selection.getDrive().name }} - {{ app.selection.getDrive().size | gigabyte | number:1 }} GB
+ ng-hide="app.state.isFlashing()">Change
@@ -84,30 +84,30 @@
- Finishing...
- Flash!
- Starting...
-
-
+ Finishing...
+ Flash!
+ Starting...
+
+
-
+
Not enough space on the drive. Please insert larger one and try again
-
+
Your removable drive may be corrupted. Try inserting a different one and press "retry"
-
+
Oops, seems something went wrong. Click here to retry
@@ -116,9 +116,9 @@
Retry
-
diff --git a/tests/gui/models/flash-state.spec.js b/tests/gui/models/flash-state.spec.js
new file mode 100644
index 00000000..500322bd
--- /dev/null
+++ b/tests/gui/models/flash-state.spec.js
@@ -0,0 +1,407 @@
+'use strict';
+
+const m = require('mochainon');
+const angular = require('angular');
+require('angular-mocks');
+
+describe('Browser: FlashStateModel', function() {
+
+ beforeEach(angular.mock.module(
+ require('../../../lib/gui/models/flash-state')
+ ));
+
+ describe('FlashStateModel', function() {
+
+ let FlashStateModel;
+
+ beforeEach(angular.mock.inject(function(_FlashStateModel_) {
+ FlashStateModel = _FlashStateModel_;
+ }));
+
+ describe('.resetState()', function() {
+
+ it('should be able to reset the progress state', function() {
+ FlashStateModel.setFlashingFlag();
+ FlashStateModel.setProgressState({
+ type: 'write',
+ percentage: 50,
+ eta: 15,
+ speed: 100000000000
+ });
+
+ FlashStateModel.resetState();
+
+ m.chai.expect(FlashStateModel.getFlashState()).to.deep.equal({
+ percentage: 0,
+ speed: 0
+ });
+ });
+
+ it('should be able to reset the progress state', function() {
+ FlashStateModel.unsetFlashingFlag({
+ passedValidation: true,
+ cancelled: false,
+ sourceChecksum: '1234'
+ });
+
+ FlashStateModel.resetState();
+ m.chai.expect(FlashStateModel.getFlashResults()).to.deep.equal({});
+ });
+
+ });
+
+ describe('.isFlashing()', function() {
+
+ it('should return false by default', function() {
+ m.chai.expect(FlashStateModel.isFlashing()).to.be.false;
+ });
+
+ it('should return true if flashing', function() {
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(FlashStateModel.isFlashing()).to.be.true;
+ });
+
+ });
+
+ describe('.setProgressState()', function() {
+
+ it('should not allow setting the state if flashing is false', function() {
+ FlashStateModel.unsetFlashingFlag({
+ passedValidation: true,
+ cancelled: false,
+ sourceChecksum: '1234'
+ });
+
+ m.chai.expect(function() {
+ FlashStateModel.setProgressState({
+ type: 'write',
+ percentage: 50,
+ eta: 15,
+ speed: 100000000000
+ });
+ }).to.throw('Can\'t set the flashing state when not flashing');
+ });
+
+ it('should throw if type is missing', function() {
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(function() {
+ FlashStateModel.setProgressState({
+ percentage: 50,
+ eta: 15,
+ speed: 100000000000
+ });
+ }).to.throw('Missing state type');
+ });
+
+ it('should throw if type is not a string', function() {
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(function() {
+ FlashStateModel.setProgressState({
+ type: 1234,
+ percentage: 50,
+ eta: 15,
+ speed: 100000000000
+ });
+ }).to.throw('Invalid state type: 1234');
+ });
+
+ it('should not throw if percentage is 0', function() {
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(function() {
+ FlashStateModel.setProgressState({
+ type: 'write',
+ percentage: 0,
+ eta: 15,
+ speed: 100000000000
+ });
+ }).to.not.throw('Missing state percentage');
+ });
+
+ it('should throw if percentage is missing', function() {
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(function() {
+ FlashStateModel.setProgressState({
+ type: 'write',
+ eta: 15,
+ speed: 100000000000
+ });
+ }).to.throw('Missing state percentage');
+ });
+
+ it('should throw if percentage is not a number', function() {
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(function() {
+ FlashStateModel.setProgressState({
+ type: 'write',
+ percentage: '50',
+ eta: 15,
+ speed: 100000000000
+ });
+ }).to.throw('Invalid state percentage: 50');
+ });
+
+ it('should throw if eta is missing', function() {
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(function() {
+ FlashStateModel.setProgressState({
+ type: 'write',
+ percentage: 50,
+ speed: 100000000000
+ });
+ }).to.throw('Missing state eta');
+ });
+
+ it('should not throw if eta is equal to zero', function() {
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(function() {
+ FlashStateModel.setProgressState({
+ type: 'write',
+ percentage: 50,
+ eta: 0,
+ speed: 100000000000
+ });
+ }).to.not.throw('Missing state eta');
+ });
+
+ it('should throw if eta is not a number', function() {
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(function() {
+ FlashStateModel.setProgressState({
+ type: 'write',
+ percentage: 50,
+ eta: '15',
+ speed: 100000000000
+ });
+ }).to.throw('Invalid state eta: 15');
+ });
+
+ it('should throw if speed is missing', function() {
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(function() {
+ FlashStateModel.setProgressState({
+ type: 'write',
+ percentage: 50,
+ eta: 15
+ });
+ }).to.throw('Missing state speed');
+ });
+
+ it('should not throw if speed is 0', function() {
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(function() {
+ FlashStateModel.setProgressState({
+ type: 'write',
+ percentage: 50,
+ eta: 15,
+ speed: 0
+ });
+ }).to.not.throw('Missing state speed');
+ });
+
+ });
+
+ describe('.getFlashResults()', function() {
+
+ it('should get the flash results', function() {
+ FlashStateModel.setFlashingFlag();
+
+ const expectedResults = {
+ passedValidation: true,
+ cancelled: false,
+ sourceChecksum: '1234'
+ };
+
+ FlashStateModel.unsetFlashingFlag(expectedResults);
+ const results = FlashStateModel.getFlashResults();
+ m.chai.expect(results).to.deep.equal(expectedResults);
+ });
+
+ });
+
+ describe('.getFlashState()', function() {
+
+ it('should initially return an empty state', function() {
+ FlashStateModel.resetState();
+ const flashState = FlashStateModel.getFlashState();
+ m.chai.expect(flashState).to.deep.equal({
+ percentage: 0,
+ speed: 0
+ });
+ });
+
+ it('should return the current flash state', function() {
+ const state = {
+ type: 'write',
+ percentage: 50,
+ eta: 15,
+ speed: 0
+ };
+
+ FlashStateModel.setFlashingFlag();
+ FlashStateModel.setProgressState(state);
+ const flashState = FlashStateModel.getFlashState();
+ m.chai.expect(flashState).to.deep.equal(state);
+ });
+
+ });
+
+ describe('.unsetFlashingFlag()', function() {
+
+ it('should throw if no flashing results', function() {
+ m.chai.expect(function() {
+ FlashStateModel.unsetFlashingFlag();
+ }).to.throw('Missing results');
+ });
+
+ it('should throw if errorCode is defined but it is not a number', function() {
+ m.chai.expect(function() {
+ FlashStateModel.unsetFlashingFlag({
+ passedValidation: true,
+ cancelled: false,
+ sourceChecksum: '1234',
+ errorCode: 123
+ });
+ }).to.throw('Invalid results errorCode: 123');
+ });
+
+ it('should throw if no passedValidation', function() {
+ m.chai.expect(function() {
+ FlashStateModel.unsetFlashingFlag({
+ cancelled: false,
+ sourceChecksum: '1234'
+ });
+ }).to.throw('Missing results passedValidation');
+ });
+
+ it('should throw if passedValidation is not boolean', function() {
+ m.chai.expect(function() {
+ FlashStateModel.unsetFlashingFlag({
+ passedValidation: 'true',
+ cancelled: false,
+ sourceChecksum: '1234'
+ });
+ }).to.throw('Invalid results passedValidation: true');
+ });
+
+ it('should throw if no cancelled', function() {
+ m.chai.expect(function() {
+ FlashStateModel.unsetFlashingFlag({
+ passedValidation: true,
+ sourceChecksum: '1234'
+ });
+ }).to.throw('Missing results cancelled');
+ });
+
+ it('should throw if cancelled is not boolean', function() {
+ m.chai.expect(function() {
+ FlashStateModel.unsetFlashingFlag({
+ passedValidation: true,
+ cancelled: 'false',
+ sourceChecksum: '1234'
+ });
+ }).to.throw('Invalid results cancelled: false');
+ });
+
+ it('should throw if passedValidation is true and sourceChecksum does not exist', function() {
+ m.chai.expect(function() {
+ FlashStateModel.unsetFlashingFlag({
+ passedValidation: true,
+ cancelled: false
+ });
+ }).to.throw('Missing results sourceChecksum');
+ });
+
+ it('should throw if passedValidation is true and sourceChecksum is not a string', function() {
+ m.chai.expect(function() {
+ FlashStateModel.unsetFlashingFlag({
+ passedValidation: true,
+ cancelled: false,
+ sourceChecksum: 12345
+ });
+ }).to.throw('Invalid results sourceChecksum: 12345');
+ });
+
+ it('should throw if cancelled is true and sourceChecksum exists', function() {
+ m.chai.expect(function() {
+ FlashStateModel.unsetFlashingFlag({
+ passedValidation: false,
+ cancelled: true,
+ sourceChecksum: '1234'
+ });
+ }).to.throw('The sourceChecksum value can\'t exist if the flashing was cancelled');
+ });
+
+ it('should throw if cancelled is true and passedValidation is true', function() {
+ m.chai.expect(function() {
+ FlashStateModel.unsetFlashingFlag({
+ passedValidation: true,
+ cancelled: true
+ });
+ }).to.throw('The passedValidation value can\'t be true if the flashing was cancelled');
+ });
+
+ it('should be able to set flashing to false', function() {
+ FlashStateModel.unsetFlashingFlag({
+ passedValidation: true,
+ cancelled: false,
+ sourceChecksum: '1234'
+ });
+
+ m.chai.expect(FlashStateModel.isFlashing()).to.be.false;
+ });
+
+ it('should reset the flashing state', function() {
+ FlashStateModel.setFlashingFlag();
+
+ FlashStateModel.setProgressState({
+ type: 'write',
+ percentage: 50,
+ eta: 15,
+ speed: 100000000000
+ });
+
+ m.chai.expect(FlashStateModel.getFlashState()).to.not.deep.equal({
+ percentage: 0,
+ speed: 0
+ });
+
+ FlashStateModel.unsetFlashingFlag({
+ passedValidation: true,
+ cancelled: false,
+ sourceChecksum: '1234'
+ });
+
+ m.chai.expect(FlashStateModel.getFlashState()).to.deep.equal({
+ percentage: 0,
+ speed: 0
+ });
+ });
+
+ });
+
+ describe('.setFlashingFlag()', function() {
+
+ it('should be able to set flashing to true', function() {
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(FlashStateModel.isFlashing()).to.be.true;
+ });
+
+ it('should reset the flash results', function() {
+ const expectedResults = {
+ passedValidation: true,
+ cancelled: false,
+ sourceChecksum: '1234'
+ };
+
+ FlashStateModel.unsetFlashingFlag(expectedResults);
+ const results = FlashStateModel.getFlashResults();
+ m.chai.expect(results).to.deep.equal(expectedResults);
+ FlashStateModel.setFlashingFlag();
+ m.chai.expect(FlashStateModel.getFlashResults()).to.deep.equal({});
+ });
+
+ });
+
+ });
+
+});
diff --git a/tests/gui/modules/image-writer.spec.js b/tests/gui/modules/image-writer.spec.js
index 16540dd9..504555f5 100644
--- a/tests/gui/modules/image-writer.spec.js
+++ b/tests/gui/modules/image-writer.spec.js
@@ -10,402 +10,24 @@ describe('Browser: ImageWriter', function() {
require('../../../lib/gui/modules/image-writer')
));
+ beforeEach(angular.mock.module(
+ require('../../../lib/gui/models/flash-state')
+ ));
+
describe('ImageWriterService', function() {
let $q;
let $rootScope;
let ImageWriterService;
+ let FlashStateModel;
- beforeEach(angular.mock.inject(function(_$q_, _$rootScope_, _ImageWriterService_) {
+ beforeEach(angular.mock.inject(function(_$q_, _$rootScope_, _ImageWriterService_, _FlashStateModel_) {
$q = _$q_;
$rootScope = _$rootScope_;
ImageWriterService = _ImageWriterService_;
+ FlashStateModel = _FlashStateModel_;
}));
- describe('.resetState()', function() {
-
- it('should be able to reset the progress state', function() {
- ImageWriterService.setFlashingFlag();
- ImageWriterService.setProgressState({
- type: 'write',
- percentage: 50,
- eta: 15,
- speed: 100000000000
- });
-
- ImageWriterService.resetState();
-
- m.chai.expect(ImageWriterService.getFlashState()).to.deep.equal({
- percentage: 0,
- speed: 0
- });
- });
-
- it('should be able to reset the progress state', function() {
- ImageWriterService.unsetFlashingFlag({
- passedValidation: true,
- cancelled: false,
- sourceChecksum: '1234'
- });
-
- ImageWriterService.resetState();
- m.chai.expect(ImageWriterService.getFlashResults()).to.deep.equal({});
- });
-
- });
-
- describe('.isFlashing()', function() {
-
- it('should return false by default', function() {
- m.chai.expect(ImageWriterService.isFlashing()).to.be.false;
- });
-
- it('should return true if flashing', function() {
- ImageWriterService.setFlashingFlag();
- m.chai.expect(ImageWriterService.isFlashing()).to.be.true;
- });
-
- });
-
- describe('.setProgressState()', function() {
-
- it('should not allow setting the state if flashing is false', function() {
- ImageWriterService.unsetFlashingFlag({
- passedValidation: true,
- cancelled: false,
- sourceChecksum: '1234'
- });
-
- m.chai.expect(function() {
- ImageWriterService.setProgressState({
- type: 'write',
- percentage: 50,
- eta: 15,
- speed: 100000000000
- });
- }).to.throw('Can\'t set the flashing state when not flashing');
- });
-
- it('should throw if type is missing', function() {
- ImageWriterService.setFlashingFlag();
- m.chai.expect(function() {
- ImageWriterService.setProgressState({
- percentage: 50,
- eta: 15,
- speed: 100000000000
- });
- }).to.throw('Missing state type');
- });
-
- it('should throw if type is not a string', function() {
- ImageWriterService.setFlashingFlag();
- m.chai.expect(function() {
- ImageWriterService.setProgressState({
- type: 1234,
- percentage: 50,
- eta: 15,
- speed: 100000000000
- });
- }).to.throw('Invalid state type: 1234');
- });
-
- it('should not throw if percentage is 0', function() {
- ImageWriterService.setFlashingFlag();
- m.chai.expect(function() {
- ImageWriterService.setProgressState({
- type: 'write',
- percentage: 0,
- eta: 15,
- speed: 100000000000
- });
- }).to.not.throw('Missing state percentage');
- });
-
- it('should throw if percentage is missing', function() {
- ImageWriterService.setFlashingFlag();
- m.chai.expect(function() {
- ImageWriterService.setProgressState({
- type: 'write',
- eta: 15,
- speed: 100000000000
- });
- }).to.throw('Missing state percentage');
- });
-
- it('should throw if percentage is not a number', function() {
- ImageWriterService.setFlashingFlag();
- m.chai.expect(function() {
- ImageWriterService.setProgressState({
- type: 'write',
- percentage: '50',
- eta: 15,
- speed: 100000000000
- });
- }).to.throw('Invalid state percentage: 50');
- });
-
- it('should throw if eta is missing', function() {
- ImageWriterService.setFlashingFlag();
- m.chai.expect(function() {
- ImageWriterService.setProgressState({
- type: 'write',
- percentage: 50,
- speed: 100000000000
- });
- }).to.throw('Missing state eta');
- });
-
- it('should not throw if eta is equal to zero', function() {
- ImageWriterService.setFlashingFlag();
- m.chai.expect(function() {
- ImageWriterService.setProgressState({
- type: 'write',
- percentage: 50,
- eta: 0,
- speed: 100000000000
- });
- }).to.not.throw('Missing state eta');
- });
-
- it('should throw if eta is not a number', function() {
- ImageWriterService.setFlashingFlag();
- m.chai.expect(function() {
- ImageWriterService.setProgressState({
- type: 'write',
- percentage: 50,
- eta: '15',
- speed: 100000000000
- });
- }).to.throw('Invalid state eta: 15');
- });
-
- it('should throw if speed is missing', function() {
- ImageWriterService.setFlashingFlag();
- m.chai.expect(function() {
- ImageWriterService.setProgressState({
- type: 'write',
- percentage: 50,
- eta: 15
- });
- }).to.throw('Missing state speed');
- });
-
- it('should not throw if speed is 0', function() {
- ImageWriterService.setFlashingFlag();
- m.chai.expect(function() {
- ImageWriterService.setProgressState({
- type: 'write',
- percentage: 50,
- eta: 15,
- speed: 0
- });
- }).to.not.throw('Missing state speed');
- });
-
- });
-
- describe('.getFlashResults()', function() {
-
- it('should get the flash results', function() {
- ImageWriterService.setFlashingFlag();
-
- const expectedResults = {
- passedValidation: true,
- cancelled: false,
- sourceChecksum: '1234'
- };
-
- ImageWriterService.unsetFlashingFlag(expectedResults);
- const results = ImageWriterService.getFlashResults();
- m.chai.expect(results).to.deep.equal(expectedResults);
- });
-
- });
-
- describe('.getFlashState()', function() {
-
- it('should initially return an empty state', function() {
- ImageWriterService.resetState();
- const flashState = ImageWriterService.getFlashState();
- m.chai.expect(flashState).to.deep.equal({
- percentage: 0,
- speed: 0
- });
- });
-
- it('should return the current flash state', function() {
- const state = {
- type: 'write',
- percentage: 50,
- eta: 15,
- speed: 0
- };
-
- ImageWriterService.setFlashingFlag();
- ImageWriterService.setProgressState(state);
- const flashState = ImageWriterService.getFlashState();
- m.chai.expect(flashState).to.deep.equal(state);
- });
-
- });
-
- describe('.unsetFlashingFlag()', function() {
-
- it('should throw if no flashing results', function() {
- m.chai.expect(function() {
- ImageWriterService.unsetFlashingFlag();
- }).to.throw('Missing results');
- });
-
- it('should throw if errorCode is defined but it is not a number', function() {
- m.chai.expect(function() {
- ImageWriterService.unsetFlashingFlag({
- passedValidation: true,
- cancelled: false,
- sourceChecksum: '1234',
- errorCode: 123
- });
- }).to.throw('Invalid results errorCode: 123');
- });
-
- it('should throw if no passedValidation', function() {
- m.chai.expect(function() {
- ImageWriterService.unsetFlashingFlag({
- cancelled: false,
- sourceChecksum: '1234'
- });
- }).to.throw('Missing results passedValidation');
- });
-
- it('should throw if passedValidation is not boolean', function() {
- m.chai.expect(function() {
- ImageWriterService.unsetFlashingFlag({
- passedValidation: 'true',
- cancelled: false,
- sourceChecksum: '1234'
- });
- }).to.throw('Invalid results passedValidation: true');
- });
-
- it('should throw if no cancelled', function() {
- m.chai.expect(function() {
- ImageWriterService.unsetFlashingFlag({
- passedValidation: true,
- sourceChecksum: '1234'
- });
- }).to.throw('Missing results cancelled');
- });
-
- it('should throw if cancelled is not boolean', function() {
- m.chai.expect(function() {
- ImageWriterService.unsetFlashingFlag({
- passedValidation: true,
- cancelled: 'false',
- sourceChecksum: '1234'
- });
- }).to.throw('Invalid results cancelled: false');
- });
-
- it('should throw if passedValidation is true and sourceChecksum does not exist', function() {
- m.chai.expect(function() {
- ImageWriterService.unsetFlashingFlag({
- passedValidation: true,
- cancelled: false
- });
- }).to.throw('Missing results sourceChecksum');
- });
-
- it('should throw if passedValidation is true and sourceChecksum is not a string', function() {
- m.chai.expect(function() {
- ImageWriterService.unsetFlashingFlag({
- passedValidation: true,
- cancelled: false,
- sourceChecksum: 12345
- });
- }).to.throw('Invalid results sourceChecksum: 12345');
- });
-
- it('should throw if cancelled is true and sourceChecksum exists', function() {
- m.chai.expect(function() {
- ImageWriterService.unsetFlashingFlag({
- passedValidation: false,
- cancelled: true,
- sourceChecksum: '1234'
- });
- }).to.throw('The sourceChecksum value can\'t exist if the flashing was cancelled');
- });
-
- it('should throw if cancelled is true and passedValidation is true', function() {
- m.chai.expect(function() {
- ImageWriterService.unsetFlashingFlag({
- passedValidation: true,
- cancelled: true
- });
- }).to.throw('The passedValidation value can\'t be true if the flashing was cancelled');
- });
-
- it('should be able to set flashing to false', function() {
- ImageWriterService.unsetFlashingFlag({
- passedValidation: true,
- cancelled: false,
- sourceChecksum: '1234'
- });
-
- m.chai.expect(ImageWriterService.isFlashing()).to.be.false;
- });
-
- it('should reset the flashing state', function() {
- ImageWriterService.setFlashingFlag();
-
- ImageWriterService.setProgressState({
- type: 'write',
- percentage: 50,
- eta: 15,
- speed: 100000000000
- });
-
- m.chai.expect(ImageWriterService.getFlashState()).to.not.deep.equal({
- percentage: 0,
- speed: 0
- });
-
- ImageWriterService.unsetFlashingFlag({
- passedValidation: true,
- cancelled: false,
- sourceChecksum: '1234'
- });
-
- m.chai.expect(ImageWriterService.getFlashState()).to.deep.equal({
- percentage: 0,
- speed: 0
- });
- });
-
- });
-
- describe('.setFlashingFlag()', function() {
-
- it('should be able to set flashing to true', function() {
- ImageWriterService.setFlashingFlag();
- m.chai.expect(ImageWriterService.isFlashing()).to.be.true;
- });
-
- it('should reset the flash results', function() {
- const expectedResults = {
- passedValidation: true,
- cancelled: false,
- sourceChecksum: '1234'
- };
-
- ImageWriterService.unsetFlashingFlag(expectedResults);
- const results = ImageWriterService.getFlashResults();
- m.chai.expect(results).to.deep.equal(expectedResults);
- ImageWriterService.setFlashingFlag();
- m.chai.expect(ImageWriterService.getFlashResults()).to.deep.equal({});
- });
-
- });
-
describe('.flash()', function() {
describe('given a succesful write', function() {
@@ -424,7 +46,7 @@ describe('Browser: ImageWriter', function() {
});
it('should set flashing to false when done', function() {
- ImageWriterService.unsetFlashingFlag({
+ FlashStateModel.unsetFlashingFlag({
passedValidation: true,
cancelled: false,
sourceChecksum: '1234'
@@ -432,11 +54,11 @@ describe('Browser: ImageWriter', function() {
ImageWriterService.flash('foo.img', '/dev/disk2');
$rootScope.$apply();
- m.chai.expect(ImageWriterService.isFlashing()).to.be.false;
+ m.chai.expect(FlashStateModel.isFlashing()).to.be.false;
});
it('should prevent writing more than once', function() {
- ImageWriterService.unsetFlashingFlag({
+ FlashStateModel.unsetFlashingFlag({
passedValidation: true,
cancelled: false,
sourceChecksum: '1234'
@@ -480,18 +102,18 @@ describe('Browser: ImageWriter', function() {
it('should set flashing to false when done', function() {
ImageWriterService.flash('foo.img', '/dev/disk2');
$rootScope.$apply();
- m.chai.expect(ImageWriterService.isFlashing()).to.be.false;
+ m.chai.expect(FlashStateModel.isFlashing()).to.be.false;
});
it('should set the error code in the flash results', function() {
ImageWriterService.flash('foo.img', '/dev/disk2');
$rootScope.$apply();
- const flashResults = ImageWriterService.getFlashResults();
+ const flashResults = FlashStateModel.getFlashResults();
m.chai.expect(flashResults.errorCode).to.equal('FOO');
});
it('should be rejected with the error', function() {
- ImageWriterService.unsetFlashingFlag({
+ FlashStateModel.unsetFlashingFlag({
passedValidation: true,
cancelled: false,
sourceChecksum: '1234'