mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-18 16:56:32 +00:00
feat: integrate bmap support (#635)
This PR integrates `.bmap` support recently added to `etcher-image-write` into Etcher itself. It does it in the following way: - It adds a `--bmap` option to the Etcher CLI. - It saves a potential `bmap` file contents to the `SelectionStateModel`. - In the GUI, at the time of writing, if there is a `bmap` file content in `SelectionStateModel`, it gets written to a temporary file and such path is passed as the `--bmap` option to the CLI. Since validation checksums don't make sense anymore, the finish screen doesn't show the checksum box in this case. Change-Type: minor Changelog-Entry: Add `.bmap` support. Fixes: https://github.com/resin-io/etcher/issues/171 Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com> Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This commit is contained in:
parent
b69d03a58b
commit
a5a195e8fb
@ -39,6 +39,7 @@ Options
|
|||||||
--check, -c validate write
|
--check, -c validate write
|
||||||
--robot, -r parse-able output without interactivity
|
--robot, -r parse-able output without interactivity
|
||||||
--log, -l output log file
|
--log, -l output log file
|
||||||
|
--bmap, -b bmap file
|
||||||
--yes, -y confirm non-interactively
|
--yes, -y confirm non-interactively
|
||||||
--unmount, -u unmount on success
|
--unmount, -u unmount on success
|
||||||
```
|
```
|
||||||
|
@ -120,6 +120,11 @@ module.exports = yargs
|
|||||||
string: true,
|
string: true,
|
||||||
alias: 'l'
|
alias: 'l'
|
||||||
},
|
},
|
||||||
|
bmap: {
|
||||||
|
describe: 'bmap file',
|
||||||
|
string: true,
|
||||||
|
alias: 'b'
|
||||||
|
},
|
||||||
yes: {
|
yes: {
|
||||||
describe: 'confirm non-interactively',
|
describe: 'confirm non-interactively',
|
||||||
boolean: true,
|
boolean: true,
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const Bluebird = require('bluebird');
|
const Bluebird = require('bluebird');
|
||||||
|
const fs = Bluebird.promisifyAll(require('fs'));
|
||||||
const visuals = require('resin-cli-visuals');
|
const visuals = require('resin-cli-visuals');
|
||||||
const form = require('resin-cli-form');
|
const form = require('resin-cli-form');
|
||||||
const drivelist = Bluebird.promisifyAll(require('drivelist'));
|
const drivelist = Bluebird.promisifyAll(require('drivelist'));
|
||||||
@ -59,8 +60,19 @@ form.run([
|
|||||||
check: new visuals.Progress('Validating')
|
check: new visuals.Progress('Validating')
|
||||||
};
|
};
|
||||||
|
|
||||||
return drivelist.listAsync().then((drives) => {
|
return Bluebird.props({
|
||||||
const selectedDrive = _.find(drives, {
|
drives: drivelist.listAsync(),
|
||||||
|
bmap: _.attempt(() => {
|
||||||
|
if (!options.bmap) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs.readFileAsync(options.bmap, {
|
||||||
|
encoding: 'utf8'
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}).then((results) => {
|
||||||
|
const selectedDrive = _.find(results.drives, {
|
||||||
device: answers.drive
|
device: answers.drive
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -70,7 +82,8 @@ form.run([
|
|||||||
|
|
||||||
return writer.writeImage(options._[0], selectedDrive, {
|
return writer.writeImage(options._[0], selectedDrive, {
|
||||||
unmountOnSuccess: options.unmount,
|
unmountOnSuccess: options.unmount,
|
||||||
validateWriteOnSuccess: options.check
|
validateWriteOnSuccess: options.check,
|
||||||
|
bmapContents: results.bmap
|
||||||
}, (state) => {
|
}, (state) => {
|
||||||
|
|
||||||
if (options.robot) {
|
if (options.robot) {
|
||||||
|
@ -37,6 +37,7 @@ const isWindows = os.platform() === 'win32';
|
|||||||
* @param {Object} options - options
|
* @param {Object} options - options
|
||||||
* @param {Boolean} [options.unmountOnSuccess=false] - unmount on success
|
* @param {Boolean} [options.unmountOnSuccess=false] - unmount on success
|
||||||
* @param {Boolean} [options.validateWriteOnSuccess=false] - validate write on success
|
* @param {Boolean} [options.validateWriteOnSuccess=false] - validate write on success
|
||||||
|
* @param {String} [options.bmapContents] - bmap file contents
|
||||||
* @param {Function} onProgress - on progress callback (state)
|
* @param {Function} onProgress - on progress callback (state)
|
||||||
*
|
*
|
||||||
* @fulfil {Boolean} - whether the operation was successful
|
* @fulfil {Boolean} - whether the operation was successful
|
||||||
@ -60,7 +61,8 @@ exports.writeImage = (imagePath, drive, options, onProgress) => {
|
|||||||
}).then((image) => {
|
}).then((image) => {
|
||||||
return imageWrite.write(drive, image, {
|
return imageWrite.write(drive, image, {
|
||||||
check: options.validateWriteOnSuccess,
|
check: options.validateWriteOnSuccess,
|
||||||
transform: image.transform
|
transform: image.transform,
|
||||||
|
bmap: options.bmapContents
|
||||||
});
|
});
|
||||||
}).then((writer) => {
|
}).then((writer) => {
|
||||||
return new Bluebird((resolve, reject) => {
|
return new Bluebird((resolve, reject) => {
|
||||||
|
@ -260,6 +260,20 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
|
|||||||
return _.get(Store.getState().toJS(), 'selection.image.logo');
|
return _.get(Store.getState().toJS(), 'selection.image.logo');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Get image bmap
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @returns {String} image bmap
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const imageBmap = SelectionStateModel.getImageBmap();
|
||||||
|
*/
|
||||||
|
this.getImageBmap = () => {
|
||||||
|
return _.get(Store.getState().toJS(), 'selection.image.bmap');
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Check if there is a selected drive
|
* @summary Check if there is a selected drive
|
||||||
* @function
|
* @function
|
||||||
|
@ -191,11 +191,7 @@ const storeReducer = (state, action) => {
|
|||||||
throw new Error('The passedValidation value can\'t be true if the flashing was cancelled');
|
throw new Error('The passedValidation value can\'t be true if the flashing was cancelled');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.data.passedValidation && !action.data.sourceChecksum) {
|
if (action.data.passedValidation && action.data.sourceChecksum && !_.isString(action.data.sourceChecksum)) {
|
||||||
throw new Error('Missing results sourceChecksum');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.data.passedValidation && !_.isString(action.data.sourceChecksum)) {
|
|
||||||
throw new Error(`Invalid results sourceChecksum: ${action.data.sourceChecksum}`);
|
throw new Error(`Invalid results sourceChecksum: ${action.data.sourceChecksum}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,10 +26,11 @@ const childWriter = require('../../src/child-writer');
|
|||||||
const MODULE_NAME = 'Etcher.Modules.ImageWriter';
|
const MODULE_NAME = 'Etcher.Modules.ImageWriter';
|
||||||
const imageWriter = angular.module(MODULE_NAME, [
|
const imageWriter = angular.module(MODULE_NAME, [
|
||||||
require('../models/settings'),
|
require('../models/settings'),
|
||||||
|
require('../models/selection-state'),
|
||||||
require('../models/flash-state')
|
require('../models/flash-state')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
imageWriter.service('ImageWriterService', function($q, $rootScope, SettingsModel, FlashStateModel) {
|
imageWriter.service('ImageWriterService', function($q, $rootScope, SettingsModel, SelectionStateModel, FlashStateModel) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Perform write operation
|
* @summary Perform write operation
|
||||||
@ -57,7 +58,8 @@ imageWriter.service('ImageWriterService', function($q, $rootScope, SettingsModel
|
|||||||
return $q((resolve, reject) => {
|
return $q((resolve, reject) => {
|
||||||
const child = childWriter.write(image, drive, {
|
const child = childWriter.write(image, drive, {
|
||||||
validateWriteOnSuccess: SettingsModel.get('validateWriteOnSuccess'),
|
validateWriteOnSuccess: SettingsModel.get('validateWriteOnSuccess'),
|
||||||
unmountOnSuccess: SettingsModel.get('unmountOnSuccess')
|
unmountOnSuccess: SettingsModel.get('unmountOnSuccess'),
|
||||||
|
bmapContents: SelectionStateModel.getImageBmap()
|
||||||
});
|
});
|
||||||
child.on('error', reject);
|
child.on('error', reject);
|
||||||
child.on('done', resolve);
|
child.on('done', resolve);
|
||||||
|
@ -76,6 +76,7 @@ module.exports = function($q, SupportedFormatsModel) {
|
|||||||
path: imagePath,
|
path: imagePath,
|
||||||
size: metadata.estimatedSize,
|
size: metadata.estimatedSize,
|
||||||
name: metadata.name,
|
name: metadata.name,
|
||||||
|
bmap: metadata.bmap,
|
||||||
url: metadata.url,
|
url: metadata.url,
|
||||||
logo: metadata.logo
|
logo: metadata.logo
|
||||||
});
|
});
|
||||||
|
@ -28,7 +28,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="label label-big label-default">CRC32 CHECKSUM : <b class="monospace">{{ ::finish.checksum }}</b></span>
|
<span class="label label-big label-default"
|
||||||
|
ng-if="finish.checksum">CRC32 CHECKSUM : <b class="monospace">{{ ::finish.checksum }}</b></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -107,7 +107,7 @@ module.exports = function(
|
|||||||
return 'Flash!';
|
return 'Flash!';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flashState.percentage === 0) {
|
if (flashState.percentage === 0 && !flashState.speed) {
|
||||||
return 'Starting...';
|
return 'Starting...';
|
||||||
} else if (flashState.percentage === 100) {
|
} else if (flashState.percentage === 100) {
|
||||||
if (isChecking && SettingsModel.get('unmountOnSuccess')) {
|
if (isChecking && SettingsModel.get('unmountOnSuccess')) {
|
||||||
|
@ -58,7 +58,13 @@ module.exports = function(SupportedFormatsModel, SelectionStateModel, AnalyticsS
|
|||||||
}
|
}
|
||||||
|
|
||||||
SelectionStateModel.setImage(image);
|
SelectionStateModel.setImage(image);
|
||||||
AnalyticsService.logEvent('Select image', _.omit(image, 'logo'));
|
|
||||||
|
// An easy way so we can quickly identify if we're making use of
|
||||||
|
// certain features without printing pages of text to DevTools.
|
||||||
|
image.logo = Boolean(image.logo);
|
||||||
|
image.bmap = Boolean(image.bmap);
|
||||||
|
|
||||||
|
AnalyticsService.logEvent('Select image', image);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const _ = require('lodash');
|
||||||
|
const Bluebird = require('bluebird');
|
||||||
|
const fs = Bluebird.promisifyAll(require('fs'));
|
||||||
const childProcess = require('child_process');
|
const childProcess = require('child_process');
|
||||||
const rendererUtils = require('./renderer-utils');
|
const rendererUtils = require('./renderer-utils');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
@ -58,10 +61,22 @@ const EXIT_CODES = require('../exit-codes');
|
|||||||
exports.write = (image, drive, options) => {
|
exports.write = (image, drive, options) => {
|
||||||
const emitter = new EventEmitter();
|
const emitter = new EventEmitter();
|
||||||
|
|
||||||
utils.getTemporaryLogFilePath().then((logFile) => {
|
Bluebird.props({
|
||||||
|
logFile: utils.getTemporaryLogFilePath(),
|
||||||
|
bmapFile: _.attempt(() => {
|
||||||
|
if (!options.bmapContents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.getTemporaryBmapFilePath().tap((bmapFilePath) => {
|
||||||
|
return fs.writeFileAsync(bmapFilePath, options.bmapContents);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}).then((results) => {
|
||||||
const argv = utils.getCLIWriterArguments({
|
const argv = utils.getCLIWriterArguments({
|
||||||
entryPoint: rendererUtils.getApplicationEntryPoint(),
|
entryPoint: rendererUtils.getApplicationEntryPoint(),
|
||||||
logFile: logFile,
|
logFile: results.logFile,
|
||||||
|
bmap: results.bmapFile,
|
||||||
image: image,
|
image: image,
|
||||||
device: drive.device,
|
device: drive.device,
|
||||||
validateWriteOnSuccess: options.validateWriteOnSuccess,
|
validateWriteOnSuccess: options.validateWriteOnSuccess,
|
||||||
@ -70,7 +85,7 @@ exports.write = (image, drive, options) => {
|
|||||||
|
|
||||||
// Make writer proxy inherit the temporary log file location
|
// Make writer proxy inherit the temporary log file location
|
||||||
// while keeping current environment variables intact.
|
// while keeping current environment variables intact.
|
||||||
process.env[CONSTANTS.TEMPORARY_LOG_FILE_ENVIRONMENT_VARIABLE] = logFile;
|
process.env[CONSTANTS.TEMPORARY_LOG_FILE_ENVIRONMENT_VARIABLE] = results.logFile;
|
||||||
|
|
||||||
const child = childProcess.fork(CONSTANTS.WRITER_PROXY_SCRIPT, argv, {
|
const child = childProcess.fork(CONSTANTS.WRITER_PROXY_SCRIPT, argv, {
|
||||||
silent: true,
|
silent: true,
|
||||||
|
@ -60,6 +60,7 @@ exports.getBooleanArgumentForm = (argumentName, value) => {
|
|||||||
* @param {String} options.device - device
|
* @param {String} options.device - device
|
||||||
* @param {String} options.entryPoint - entry point
|
* @param {String} options.entryPoint - entry point
|
||||||
* @param {String} [options.logFile] - log file
|
* @param {String} [options.logFile] - log file
|
||||||
|
* @param {String} [options.bmap] - bmap file
|
||||||
* @param {Boolean} [options.validateWriteOnSuccess] - validate write on success
|
* @param {Boolean} [options.validateWriteOnSuccess] - validate write on success
|
||||||
* @param {Boolean} [options.unmountOnSuccess] - unmount on success
|
* @param {Boolean} [options.unmountOnSuccess] - unmount on success
|
||||||
* @returns {String[]} arguments
|
* @returns {String[]} arguments
|
||||||
@ -107,6 +108,10 @@ exports.getCLIWriterArguments = (options) => {
|
|||||||
argv.push('--log', options.logFile);
|
argv.push('--log', options.logFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.bmap) {
|
||||||
|
argv.push('--bmap', options.bmap);
|
||||||
|
}
|
||||||
|
|
||||||
return argv;
|
return argv;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -146,3 +151,23 @@ exports.getTemporaryLogFilePath = () => {
|
|||||||
postfix: '.log'
|
postfix: '.log'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Get a temporary bmap file path
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @fulfil {String} - bmap path
|
||||||
|
* @returns {Promise}
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* utils.getTemporaryBmapFilePath().then((bmapFilePath) => {
|
||||||
|
* console.log(bmapFilePath);
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
exports.getTemporaryBmapFilePath = () => {
|
||||||
|
return tmp.fileAsync({
|
||||||
|
prefix: `${packageJSON.name}-`,
|
||||||
|
postfix: '.bmap'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
43
npm-shrinkwrap.json
generated
43
npm-shrinkwrap.json
generated
@ -398,6 +398,43 @@
|
|||||||
"from": "bluebird-retry@>=0.7.0 <0.8.0",
|
"from": "bluebird-retry@>=0.7.0 <0.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/bluebird-retry/-/bluebird-retry-0.7.0.tgz"
|
"resolved": "https://registry.npmjs.org/bluebird-retry/-/bluebird-retry-0.7.0.tgz"
|
||||||
},
|
},
|
||||||
|
"bmapflash": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"from": "bmapflash@>=1.1.2 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bmapflash/-/bmapflash-1.1.2.tgz",
|
||||||
|
"dependencies": {
|
||||||
|
"isarray": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"from": "isarray@~1.0.0",
|
||||||
|
"resolved": "http://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
|
||||||
|
},
|
||||||
|
"lodash": {
|
||||||
|
"version": "4.15.0",
|
||||||
|
"from": "lodash@>=4.14.2 <5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.15.0.tgz"
|
||||||
|
},
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"from": "readable-stream@~2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz"
|
||||||
|
},
|
||||||
|
"through2": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"from": "through2@^2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.1.tgz"
|
||||||
|
},
|
||||||
|
"xml2js": {
|
||||||
|
"version": "0.4.17",
|
||||||
|
"from": "xml2js@>=0.4.17 <0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz"
|
||||||
|
},
|
||||||
|
"xtend": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"from": "xtend@~4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"bn.js": {
|
"bn.js": {
|
||||||
"version": "4.11.4",
|
"version": "4.11.4",
|
||||||
"from": "bn.js@>=4.1.1 <5.0.0",
|
"from": "bn.js@>=4.1.1 <5.0.0",
|
||||||
@ -1371,9 +1408,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"etcher-image-write": {
|
"etcher-image-write": {
|
||||||
"version": "6.0.1",
|
"version": "6.1.1",
|
||||||
"from": "etcher-image-write@6.0.1",
|
"from": "etcher-image-write@6.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/etcher-image-write/-/etcher-image-write-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/etcher-image-write/-/etcher-image-write-6.1.1.tgz",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"isarray": {
|
"isarray": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
"drivelist": "^3.2.6",
|
"drivelist": "^3.2.6",
|
||||||
"electron-is-running-in-asar": "^1.0.0",
|
"electron-is-running-in-asar": "^1.0.0",
|
||||||
"etcher-image-stream": "^3.1.0",
|
"etcher-image-stream": "^3.1.0",
|
||||||
"etcher-image-write": "^6.0.1",
|
"etcher-image-write": "^6.1.1",
|
||||||
"etcher-latest-version": "^1.0.0",
|
"etcher-latest-version": "^1.0.0",
|
||||||
"file-tail": "^0.3.0",
|
"file-tail": "^0.3.0",
|
||||||
"flexboxgrid": "^6.3.0",
|
"flexboxgrid": "^6.3.0",
|
||||||
|
@ -338,13 +338,13 @@ describe('Browser: FlashStateModel', function() {
|
|||||||
}).to.throw('Invalid results cancelled: false');
|
}).to.throw('Invalid results cancelled: false');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if passedValidation is true and sourceChecksum does not exist', function() {
|
it('should not throw if passedValidation is true and sourceChecksum does not exist', function() {
|
||||||
m.chai.expect(function() {
|
m.chai.expect(function() {
|
||||||
FlashStateModel.unsetFlashingFlag({
|
FlashStateModel.unsetFlashingFlag({
|
||||||
passedValidation: true,
|
passedValidation: true,
|
||||||
cancelled: false
|
cancelled: false
|
||||||
});
|
});
|
||||||
}).to.throw('Missing results sourceChecksum');
|
}).to.not.throw();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if passedValidation is true and sourceChecksum is not a string', function() {
|
it('should throw if passedValidation is true and sourceChecksum is not a string', function() {
|
||||||
|
@ -55,6 +55,10 @@ describe('Browser: SelectionState', function() {
|
|||||||
m.chai.expect(SelectionStateModel.getImageLogo()).to.be.undefined;
|
m.chai.expect(SelectionStateModel.getImageLogo()).to.be.undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('getImageBmap() should return undefined', function() {
|
||||||
|
m.chai.expect(SelectionStateModel.getImageBmap()).to.be.undefined;
|
||||||
|
});
|
||||||
|
|
||||||
it('hasDrive() should return false', function() {
|
it('hasDrive() should return false', function() {
|
||||||
const hasDrive = SelectionStateModel.hasDrive();
|
const hasDrive = SelectionStateModel.hasDrive();
|
||||||
m.chai.expect(hasDrive).to.be.false;
|
m.chai.expect(hasDrive).to.be.false;
|
||||||
@ -272,7 +276,8 @@ describe('Browser: SelectionState', function() {
|
|||||||
size: 999999999,
|
size: 999999999,
|
||||||
url: 'https://www.raspbian.org',
|
url: 'https://www.raspbian.org',
|
||||||
name: 'Raspbian',
|
name: 'Raspbian',
|
||||||
logo: '<svg><text fill="red">Raspbian</text></svg>'
|
logo: '<svg><text fill="red">Raspbian</text></svg>',
|
||||||
|
bmap: '<Range>Foo Bar</Range>'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -425,6 +430,15 @@ describe('Browser: SelectionState', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('.getImageBmap()', function() {
|
||||||
|
|
||||||
|
it('should return the image bmap', function() {
|
||||||
|
const imageBmap = SelectionStateModel.getImageBmap();
|
||||||
|
m.chai.expect(imageBmap).to.equal('<Range>Foo Bar</Range>');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe('.hasImage()', function() {
|
describe('.hasImage()', function() {
|
||||||
|
|
||||||
it('should return true', function() {
|
it('should return true', function() {
|
||||||
|
@ -177,6 +177,22 @@ describe('Browser: MainPage', function() {
|
|||||||
FlashStateModel.setFlashingFlag();
|
FlashStateModel.setFlashingFlag();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should report 0% if percentage == 0 but speed != 0', function() {
|
||||||
|
const controller = $controller('FlashController', {
|
||||||
|
$scope: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
FlashStateModel.setProgressState({
|
||||||
|
type: 'write',
|
||||||
|
percentage: 0,
|
||||||
|
eta: 15,
|
||||||
|
speed: 100000000000000
|
||||||
|
});
|
||||||
|
|
||||||
|
SettingsModel.set('unmountOnSuccess', true);
|
||||||
|
m.chai.expect(controller.getProgressButtonLabel()).to.equal('0%');
|
||||||
|
});
|
||||||
|
|
||||||
it('should handle percentage == 0, type = write, unmountOnSuccess', function() {
|
it('should handle percentage == 0, type = write, unmountOnSuccess', function() {
|
||||||
const controller = $controller('FlashController', {
|
const controller = $controller('FlashController', {
|
||||||
$scope: {}
|
$scope: {}
|
||||||
@ -186,7 +202,7 @@ describe('Browser: MainPage', function() {
|
|||||||
type: 'write',
|
type: 'write',
|
||||||
percentage: 0,
|
percentage: 0,
|
||||||
eta: 15,
|
eta: 15,
|
||||||
speed: 1000
|
speed: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
SettingsModel.set('unmountOnSuccess', true);
|
SettingsModel.set('unmountOnSuccess', true);
|
||||||
@ -202,7 +218,7 @@ describe('Browser: MainPage', function() {
|
|||||||
type: 'write',
|
type: 'write',
|
||||||
percentage: 0,
|
percentage: 0,
|
||||||
eta: 15,
|
eta: 15,
|
||||||
speed: 1000
|
speed: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
SettingsModel.set('unmountOnSuccess', false);
|
SettingsModel.set('unmountOnSuccess', false);
|
||||||
@ -218,7 +234,7 @@ describe('Browser: MainPage', function() {
|
|||||||
type: 'check',
|
type: 'check',
|
||||||
percentage: 0,
|
percentage: 0,
|
||||||
eta: 15,
|
eta: 15,
|
||||||
speed: 1000
|
speed: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
SettingsModel.set('unmountOnSuccess', true);
|
SettingsModel.set('unmountOnSuccess', true);
|
||||||
@ -234,7 +250,7 @@ describe('Browser: MainPage', function() {
|
|||||||
type: 'check',
|
type: 'check',
|
||||||
percentage: 0,
|
percentage: 0,
|
||||||
eta: 15,
|
eta: 15,
|
||||||
speed: 1000
|
speed: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
SettingsModel.set('unmountOnSuccess', false);
|
SettingsModel.set('unmountOnSuccess', false);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user