Add more typings & refactor code accordingly

Change-type: patch
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
This commit is contained in:
Lorenzo Alberto Maria Ambrosi 2020-09-03 15:46:18 +02:00
parent eeab351636
commit b76366a514
14 changed files with 140 additions and 233 deletions

View File

@ -23,7 +23,11 @@ import * as ReactDOM from 'react-dom';
import { v4 as uuidV4 } from 'uuid'; import { v4 as uuidV4 } from 'uuid';
import * as packageJSON from '../../../package.json'; import * as packageJSON from '../../../package.json';
import { isDriveValid, isSourceDrive } from '../../shared/drive-constraints'; import {
DrivelistDrive,
isDriveValid,
isSourceDrive,
} from '../../shared/drive-constraints';
import * as EXIT_CODES from '../../shared/exit-codes'; import * as EXIT_CODES from '../../shared/exit-codes';
import * as messages from '../../shared/messages'; import * as messages from '../../shared/messages';
import * as availableDrives from './models/available-drives'; import * as availableDrives from './models/available-drives';
@ -231,12 +235,12 @@ function prepareDrive(drive: Drive) {
} }
} }
function setDrives(drives: _.Dictionary<any>) { function setDrives(drives: _.Dictionary<DrivelistDrive>) {
availableDrives.setDrives(_.values(drives)); availableDrives.setDrives(_.values(drives));
} }
function getDrives() { function getDrives() {
return _.keyBy(availableDrives.getDrives() || [], 'device'); return _.keyBy(availableDrives.getDrives(), 'device');
} }
async function addDrive(drive: Drive) { async function addDrive(drive: Drive) {

View File

@ -289,8 +289,8 @@ export class DriveSelector extends React.Component<
{ {
field: 'description', field: 'description',
key: 'extra', key: 'extra',
// Space as empty string would use the field name as label // We use an empty React fragment otherwise it uses the field name as label
label: <Txt></Txt>, label: <></>,
render: (_description: string, drive: Drive) => { render: (_description: string, drive: Drive) => {
if (isUsbbootDrive(drive)) { if (isUsbbootDrive(drive)) {
return this.renderProgress(drive.progress); return this.renderProgress(drive.progress);

View File

@ -66,7 +66,7 @@ const DriveStatusWarningModal = ({
<> <>
<Flex justifyContent="space-between" alignItems="baseline"> <Flex justifyContent="space-between" alignItems="baseline">
<strong>{middleEllipsis(drive.description, 28)}</strong>{' '} <strong>{middleEllipsis(drive.description, 28)}</strong>{' '}
{prettyBytes(drive.size || 0)}{' '} {drive.size && prettyBytes(drive.size) + ' '}
<Badge shade={5}>{drive.statuses[0].message}</Badge> <Badge shade={5}>{drive.statuses[0].message}</Badge>
</Flex> </Flex>
{i !== array.length - 1 ? <hr style={{ width: '100%' }} /> : null} {i !== array.length - 1 ? <hr style={{ width: '100%' }} /> : null}

View File

@ -23,8 +23,8 @@ import { SVGIcon } from '../svg-icon/svg-icon';
import { middleEllipsis } from '../../utils/middle-ellipsis'; import { middleEllipsis } from '../../utils/middle-ellipsis';
interface ReducedFlashingInfosProps { interface ReducedFlashingInfosProps {
imageLogo: string; imageLogo?: string;
imageName: string; imageName?: string;
imageSize: string; imageSize: string;
driveTitle: string; driveTitle: string;
driveLabel: string; driveLabel: string;
@ -40,6 +40,7 @@ export class ReducedFlashingInfos extends React.Component<
} }
public render() { public render() {
const { imageName = '' } = this.props;
return ( return (
<Flex <Flex
flexDirection="column" flexDirection="column"
@ -56,9 +57,9 @@ export class ReducedFlashingInfos extends React.Component<
/> />
<Txt <Txt
style={{ marginRight: '9px' }} style={{ marginRight: '9px' }}
tooltip={{ text: this.props.imageName, placement: 'right' }} tooltip={{ text: imageName, placement: 'right' }}
> >
{middleEllipsis(this.props.imageName, 16)} {middleEllipsis(imageName, 16)}
</Txt> </Txt>
<Txt color="#7e8085">{this.props.imageSize}</Txt> <Txt color="#7e8085">{this.props.imageSize}</Txt>
</Flex> </Flex>

View File

@ -254,6 +254,7 @@ export interface SourceMetadata extends sourceDestination.Metadata {
SourceType: Source; SourceType: Source;
drive?: DrivelistDrive; drive?: DrivelistDrive;
extension?: string; extension?: string;
archiveExtension?: string;
} }
interface SourceSelectorProps { interface SourceSelectorProps {
@ -262,8 +263,8 @@ interface SourceSelectorProps {
interface SourceSelectorState { interface SourceSelectorState {
hasImage: boolean; hasImage: boolean;
imageName: string; imageName?: string;
imageSize: number; imageSize?: number;
warning: { message: string; title: string | null } | null; warning: { message: string; title: string | null } | null;
showImageDetails: boolean; showImageDetails: boolean;
showURLSelector: boolean; showURLSelector: boolean;
@ -543,7 +544,7 @@ export class SourceSelector extends React.Component<
const imagePath = image.path || image.displayName || ''; const imagePath = image.path || image.displayName || '';
const imageBasename = path.basename(imagePath); const imageBasename = path.basename(imagePath);
const imageName = image.name || ''; const imageName = image.name || '';
const imageSize = image.size || 0; const imageSize = image.size;
const imageLogo = image.logo || ''; const imageLogo = image.logo || '';
return ( return (
@ -585,7 +586,9 @@ export class SourceSelector extends React.Component<
Remove Remove
</ChangeButton> </ChangeButton>
)} )}
<DetailsText>{prettyBytes(imageSize)}</DetailsText> {!_.isNil(imageSize) && (
<DetailsText>{prettyBytes(imageSize)}</DetailsText>
)}
</> </>
) : ( ) : (
<> <>

View File

@ -37,8 +37,9 @@ function tryParseSVGContents(contents?: string): string | undefined {
} }
interface SVGIconProps { interface SVGIconProps {
// List of embedded SVG contents to be tried in succession if any fails // Optional string representing the SVG contents to be tried
contents: string; contents?: string;
// Fallback SVG element to show if `contents` is invalid/undefined
fallback: React.FunctionComponent<React.SVGProps<HTMLOrSVGElement>>; fallback: React.FunctionComponent<React.SVGProps<HTMLOrSVGElement>>;
// SVG image width unit // SVG image width unit
width?: string; width?: string;

View File

@ -96,7 +96,9 @@ export function TargetSelectorButton(props: TargetSelectorProps) {
Change Change
</ChangeButton> </ChangeButton>
)} )}
<DetailsText>{prettyBytes(target.size)}</DetailsText> {target.size != null && (
<DetailsText>{prettyBytes(target.size)}</DetailsText>
)}
</> </>
); );
} }
@ -110,16 +112,16 @@ export function TargetSelectorButton(props: TargetSelectorProps) {
targetsTemplate.push( targetsTemplate.push(
<DetailsText <DetailsText
key={target.device} key={target.device}
tooltip={`${target.description} ${target.displayName} ${prettyBytes( tooltip={`${target.description} ${target.displayName} ${
target.size, target.size != null ? prettyBytes(target.size) : ''
)}`} }`}
px={21} px={21}
> >
{warnings.length && ( {warnings.length > 0 ? (
<DriveCompatibilityWarning warnings={warnings} mr={2} /> <DriveCompatibilityWarning warnings={warnings} mr={2} />
)} ) : null}
<Txt mr={2}>{middleEllipsis(target.description, 14)}</Txt> <Txt mr={2}>{middleEllipsis(target.description, 14)}</Txt>
<Txt>{prettyBytes(target.size)}</Txt> {target.size != null && <Txt>{prettyBytes(target.size)}</Txt>}
</DetailsText>, </DetailsText>,
); );
} }

View File

@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { DrivelistDrive } from '../../../shared/drive-constraints';
import { Actions, store } from './store'; import { Actions, store } from './store';
export function hasAvailableDrives() { export function hasAvailableDrives() {
@ -27,6 +28,6 @@ export function setDrives(drives: any[]) {
}); });
} }
export function getDrives(): any[] { export function getDrives(): DrivelistDrive[] {
return store.getState().toJS().availableDrives; return store.getState().toJS().availableDrives;
} }

View File

@ -1,3 +1,4 @@
import { DrivelistDrive } from '../../../shared/drive-constraints';
/* /*
* Copyright 2016 balena.io * Copyright 2016 balena.io
* *
@ -40,7 +41,7 @@ export function toggleDrive(driveDevice: string) {
} }
} }
export function selectSource(source: any) { export function selectSource(source: SourceMetadata) {
store.dispatch({ store.dispatch({
type: Actions.SELECT_SOURCE, type: Actions.SELECT_SOURCE,
data: source, data: source,
@ -57,11 +58,11 @@ export function getSelectedDevices(): string[] {
/** /**
* @summary Get all selected drive objects * @summary Get all selected drive objects
*/ */
export function getSelectedDrives(): any[] { export function getSelectedDrives(): DrivelistDrive[] {
const drives = availableDrives.getDrives(); const selectedDevices = getSelectedDevices();
return getSelectedDevices().map((device) => { return availableDrives
return drives.find((drive) => drive.device === device); .getDrives()
}); .filter((drive) => selectedDevices.includes(drive.device));
} }
/** /**
@ -71,32 +72,24 @@ export function getImage(): SourceMetadata | undefined {
return store.getState().toJS().selection.image; return store.getState().toJS().selection.image;
} }
export function getImagePath(): string { export function getImagePath() {
return store.getState().toJS().selection.image?.path; return getImage()?.path;
} }
export function getImageSize(): number { export function getImageSize() {
return store.getState().toJS().selection.image?.size; return getImage()?.size;
} }
export function getImageUrl(): string { export function getImageName() {
return store.getState().toJS().selection.image?.url; return getImage()?.name;
} }
export function getImageName(): string { export function getImageLogo() {
return store.getState().toJS().selection.image?.name; return getImage()?.logo;
} }
export function getImageLogo(): string { export function getImageSupportUrl() {
return store.getState().toJS().selection.image?.logo; return getImage()?.supportUrl;
}
export function getImageSupportUrl(): string {
return store.getState().toJS().selection.image?.supportUrl;
}
export function getImageRecommendedDriveSize(): number {
return store.getState().toJS().selection.image?.recommendedDriveSize;
} }
/** /**

View File

@ -198,18 +198,12 @@ export class FlashStep extends React.PureComponent<
} }
private async tryFlash() { private async tryFlash() {
const devices = selection.getSelectedDevices(); const drives = selection.getSelectedDrives().map((drive) => {
const drives = availableDrives return {
.getDrives() ...drive,
.filter((drive: { device: string }) => { statuses: constraints.getDriveImageCompatibilityStatuses(drive),
return devices.includes(drive.device); };
}) });
.map((drive) => {
return {
...drive,
statuses: constraints.getDriveImageCompatibilityStatuses(drive),
};
});
if (drives.length === 0 || this.props.isFlashing) { if (drives.length === 0 || this.props.isFlashing) {
return; return;
} }

View File

@ -103,9 +103,9 @@ interface MainPageStateFromStore {
isFlashing: boolean; isFlashing: boolean;
hasImage: boolean; hasImage: boolean;
hasDrive: boolean; hasDrive: boolean;
imageLogo: string; imageLogo?: string;
imageSize: number; imageSize?: number;
imageName: string; imageName?: string;
driveTitle: string; driveTitle: string;
driveLabel: string; driveLabel: string;
} }
@ -272,7 +272,7 @@ export class MainPage extends React.Component<
imageName={this.state.imageName} imageName={this.state.imageName}
imageSize={ imageSize={
typeof this.state.imageSize === 'number' typeof this.state.imageSize === 'number'
? (prettyBytes(this.state.imageSize) as string) ? prettyBytes(this.state.imageSize)
: '' : ''
} }
driveTitle={this.state.driveTitle} driveTitle={this.state.driveTitle}

View File

@ -15,6 +15,7 @@
*/ */
import { Dictionary } from 'lodash'; import { Dictionary } from 'lodash';
import { outdent } from 'outdent';
import * as prettyBytes from 'pretty-bytes'; import * as prettyBytes from 'pretty-bytes';
export const progress: Dictionary<(quantity: number) => string> = { export const progress: Dictionary<(quantity: number) => string> = {
@ -84,10 +85,10 @@ export const warning = {
image: { recommendedDriveSize: number }, image: { recommendedDriveSize: number },
drive: { device: string; size: number }, drive: { device: string; size: number },
) => { ) => {
return [ return outdent({ newline: ' ' })`
`This image recommends a ${prettyBytes(image.recommendedDriveSize)}`, This image recommends a ${prettyBytes(image.recommendedDriveSize)}
`drive, however ${drive.device} is only ${prettyBytes(drive.size)}.`, drive, however ${drive.device} is only ${prettyBytes(drive.size)}.
].join(' '); `;
}, },
exitWhileFlashing: () => { exitWhileFlashing: () => {
@ -150,10 +151,11 @@ export const error = {
}, },
openSource: (sourceName: string, errorMessage: string) => { openSource: (sourceName: string, errorMessage: string) => {
return [ return outdent`
`Something went wrong while opening ${sourceName}\n\n`, Something went wrong while opening ${sourceName}
`Error: ${errorMessage}`,
].join(''); Error: ${errorMessage}
`;
}, },
flashFailure: ( flashFailure: (

View File

@ -15,6 +15,7 @@
*/ */
import { expect } from 'chai'; import { expect } from 'chai';
import { File } from 'etcher-sdk/build/source-destination';
import * as path from 'path'; import * as path from 'path';
import * as availableDrives from '../../../lib/gui/app/models/available-drives'; import * as availableDrives from '../../../lib/gui/app/models/available-drives';
@ -158,10 +159,13 @@ describe('Model: availableDrives', function () {
selectionState.clear(); selectionState.clear();
selectionState.selectSource({ selectionState.selectSource({
description: this.imagePath.split('/').pop(),
displayName: this.imagePath,
path: this.imagePath, path: this.imagePath,
extension: 'img', extension: 'img',
size: 999999999, size: 999999999,
isSizeEstimated: false, isSizeEstimated: false,
SourceType: File,
recommendedDriveSize: 2000000000, recommendedDriveSize: 2000000000,
}); });
}); });

View File

@ -15,11 +15,13 @@
*/ */
import { expect } from 'chai'; import { expect } from 'chai';
import * as _ from 'lodash'; import { File } from 'etcher-sdk/build/source-destination';
import * as path from 'path'; import * as path from 'path';
import { SourceMetadata } from '../../../lib/gui/app/components/source-selector/source-selector';
import * as availableDrives from '../../../lib/gui/app/models/available-drives'; import * as availableDrives from '../../../lib/gui/app/models/available-drives';
import * as selectionState from '../../../lib/gui/app/models/selection-state'; import * as selectionState from '../../../lib/gui/app/models/selection-state';
import { DrivelistDrive } from '../../../lib/shared/drive-constraints';
describe('Model: selectionState', function () { describe('Model: selectionState', function () {
describe('given a clean state', function () { describe('given a clean state', function () {
@ -39,10 +41,6 @@ describe('Model: selectionState', function () {
expect(selectionState.getImageSize()).to.be.undefined; expect(selectionState.getImageSize()).to.be.undefined;
}); });
it('getImageUrl() should return undefined', function () {
expect(selectionState.getImageUrl()).to.be.undefined;
});
it('getImageName() should return undefined', function () { it('getImageName() should return undefined', function () {
expect(selectionState.getImageName()).to.be.undefined; expect(selectionState.getImageName()).to.be.undefined;
}); });
@ -55,10 +53,6 @@ describe('Model: selectionState', function () {
expect(selectionState.getImageSupportUrl()).to.be.undefined; expect(selectionState.getImageSupportUrl()).to.be.undefined;
}); });
it('getImageRecommendedDriveSize() should return undefined', function () {
expect(selectionState.getImageRecommendedDriveSize()).to.be.undefined;
});
it('hasDrive() should return false', function () { it('hasDrive() should return false', function () {
const hasDrive = selectionState.hasDrive(); const hasDrive = selectionState.hasDrive();
expect(hasDrive).to.be.false; expect(hasDrive).to.be.false;
@ -138,10 +132,10 @@ describe('Model: selectionState', function () {
it('should queue the drive', function () { it('should queue the drive', function () {
selectionState.selectDrive('/dev/disk5'); selectionState.selectDrive('/dev/disk5');
const drives = selectionState.getSelectedDevices(); const drives = selectionState.getSelectedDevices();
const lastDriveDevice = _.last(drives); const lastDriveDevice = drives.pop();
const lastDrive = _.find(availableDrives.getDrives(), { const lastDrive = availableDrives
device: lastDriveDevice, .getDrives()
}); .find((drive) => drive.device === lastDriveDevice);
expect(lastDrive).to.deep.equal({ expect(lastDrive).to.deep.equal({
device: '/dev/disk5', device: '/dev/disk5',
name: 'USB Drive', name: 'USB Drive',
@ -214,7 +208,7 @@ describe('Model: selectionState', function () {
it('should be able to add more drives', function () { it('should be able to add more drives', function () {
selectionState.selectDrive(this.drives[2].device); selectionState.selectDrive(this.drives[2].device);
expect(selectionState.getSelectedDevices()).to.deep.equal( expect(selectionState.getSelectedDevices()).to.deep.equal(
_.map(this.drives, 'device'), this.drives.map((drive: DrivelistDrive) => drive.device),
); );
}); });
@ -234,13 +228,13 @@ describe('Model: selectionState', function () {
system: true, system: true,
}; };
const newDrives = [..._.initial(this.drives), systemDrive]; const newDrives = [...this.drives.slice(0, -1), systemDrive];
availableDrives.setDrives(newDrives); availableDrives.setDrives(newDrives);
selectionState.selectDrive(systemDrive.device); selectionState.selectDrive(systemDrive.device);
availableDrives.setDrives(newDrives); availableDrives.setDrives(newDrives);
expect(selectionState.getSelectedDevices()).to.deep.equal( expect(selectionState.getSelectedDevices()).to.deep.equal(
_.map(newDrives, 'device'), newDrives.map((drive: DrivelistDrive) => drive.device),
); );
}); });
@ -271,6 +265,12 @@ describe('Model: selectionState', function () {
describe('.getSelectedDrives()', function () { describe('.getSelectedDrives()', function () {
it('should return the selected drives', function () { it('should return the selected drives', function () {
expect(selectionState.getSelectedDrives()).to.deep.equal([ expect(selectionState.getSelectedDrives()).to.deep.equal([
{
device: '/dev/disk2',
name: 'USB Drive 2',
size: 999999999,
isReadOnly: false,
},
{ {
device: '/dev/sdb', device: '/dev/sdb',
description: 'DataTraveler 2.0', description: 'DataTraveler 2.0',
@ -280,12 +280,6 @@ describe('Model: selectionState', function () {
system: false, system: false,
isReadOnly: false, isReadOnly: false,
}, },
{
device: '/dev/disk2',
name: 'USB Drive 2',
size: 999999999,
isReadOnly: false,
},
]); ]);
}); });
}); });
@ -399,13 +393,6 @@ describe('Model: selectionState', function () {
}); });
}); });
describe('.getImageUrl()', function () {
it('should return the image url', function () {
const imageUrl = selectionState.getImageUrl();
expect(imageUrl).to.equal('https://www.raspbian.org');
});
});
describe('.getImageName()', function () { describe('.getImageName()', function () {
it('should return the image name', function () { it('should return the image name', function () {
const imageName = selectionState.getImageName(); const imageName = selectionState.getImageName();
@ -429,13 +416,6 @@ describe('Model: selectionState', function () {
}); });
}); });
describe('.getImageRecommendedDriveSize()', function () {
it('should return the image recommended drive size', function () {
const imageRecommendedDriveSize = selectionState.getImageRecommendedDriveSize();
expect(imageRecommendedDriveSize).to.equal(1000000000);
});
});
describe('.hasImage()', function () { describe('.hasImage()', function () {
it('should return true', function () { it('should return true', function () {
const hasImage = selectionState.hasImage(); const hasImage = selectionState.hasImage();
@ -446,10 +426,13 @@ describe('Model: selectionState', function () {
describe('.selectImage()', function () { describe('.selectImage()', function () {
it('should override the image', function () { it('should override the image', function () {
selectionState.selectSource({ selectionState.selectSource({
description: 'bar.img',
displayName: 'bar.img',
path: 'bar.img', path: 'bar.img',
extension: 'img', extension: 'img',
size: 999999999, size: 999999999,
isSizeEstimated: false, isSizeEstimated: false,
SourceType: File,
}); });
const imagePath = selectionState.getImagePath(); const imagePath = selectionState.getImagePath();
@ -475,13 +458,19 @@ describe('Model: selectionState', function () {
describe('.selectImage()', function () { describe('.selectImage()', function () {
afterEach(selectionState.clear); afterEach(selectionState.clear);
const image: SourceMetadata = {
description: 'foo.img',
displayName: 'foo.img',
path: 'foo.img',
extension: 'img',
size: 999999999,
isSizeEstimated: false,
SourceType: File,
recommendedDriveSize: 2000000000,
};
it('should be able to set an image', function () { it('should be able to set an image', function () {
selectionState.selectSource({ selectionState.selectSource(image);
path: 'foo.img',
extension: 'img',
size: 999999999,
isSizeEstimated: false,
});
const imagePath = selectionState.getImagePath(); const imagePath = selectionState.getImagePath();
expect(imagePath).to.equal('foo.img'); expect(imagePath).to.equal('foo.img');
@ -491,11 +480,9 @@ describe('Model: selectionState', function () {
it('should be able to set an image with an archive extension', function () { it('should be able to set an image with an archive extension', function () {
selectionState.selectSource({ selectionState.selectSource({
...image,
path: 'foo.zip', path: 'foo.zip',
extension: 'img',
archiveExtension: 'zip', archiveExtension: 'zip',
size: 999999999,
isSizeEstimated: false,
}); });
const imagePath = selectionState.getImagePath(); const imagePath = selectionState.getImagePath();
@ -504,11 +491,9 @@ describe('Model: selectionState', function () {
it('should infer a compressed raw image if the penultimate extension is missing', function () { it('should infer a compressed raw image if the penultimate extension is missing', function () {
selectionState.selectSource({ selectionState.selectSource({
...image,
path: 'foo.xz', path: 'foo.xz',
extension: 'img',
archiveExtension: 'xz', archiveExtension: 'xz',
size: 999999999,
isSizeEstimated: false,
}); });
const imagePath = selectionState.getImagePath(); const imagePath = selectionState.getImagePath();
@ -517,53 +502,19 @@ describe('Model: selectionState', function () {
it('should infer a compressed raw image if the penultimate extension is not a file extension', function () { it('should infer a compressed raw image if the penultimate extension is not a file extension', function () {
selectionState.selectSource({ selectionState.selectSource({
...image,
path: 'something.linux-x86-64.gz', path: 'something.linux-x86-64.gz',
extension: 'img',
archiveExtension: 'gz', archiveExtension: 'gz',
size: 999999999,
isSizeEstimated: false,
}); });
const imagePath = selectionState.getImagePath(); const imagePath = selectionState.getImagePath();
expect(imagePath).to.equal('something.linux-x86-64.gz'); expect(imagePath).to.equal('something.linux-x86-64.gz');
}); });
it('should throw if no path', function () {
expect(function () {
selectionState.selectSource({
extension: 'img',
size: 999999999,
isSizeEstimated: false,
});
}).to.throw('Missing image fields: path');
});
it('should throw if path is not a string', function () {
expect(function () {
selectionState.selectSource({
path: 123,
extension: 'img',
size: 999999999,
isSizeEstimated: false,
});
}).to.throw('Invalid image path: 123');
});
it('should throw if the original size is not a number', function () {
expect(function () {
selectionState.selectSource({
path: 'foo.img',
extension: 'img',
size: 999999999,
compressedSize: '999999999',
isSizeEstimated: false,
});
}).to.throw('Invalid image compressed size: 999999999');
});
it('should throw if the original size is a float number', function () { it('should throw if the original size is a float number', function () {
expect(function () { expect(function () {
selectionState.selectSource({ selectionState.selectSource({
...image,
path: 'foo.img', path: 'foo.img',
extension: 'img', extension: 'img',
size: 999999999, size: 999999999,
@ -576,33 +527,17 @@ describe('Model: selectionState', function () {
it('should throw if the original size is negative', function () { it('should throw if the original size is negative', function () {
expect(function () { expect(function () {
selectionState.selectSource({ selectionState.selectSource({
path: 'foo.img', ...image,
extension: 'img',
size: 999999999,
compressedSize: -1, compressedSize: -1,
isSizeEstimated: false,
}); });
}).to.throw('Invalid image compressed size: -1'); }).to.throw('Invalid image compressed size: -1');
}); });
it('should throw if the final size is not a number', function () {
expect(function () {
selectionState.selectSource({
path: 'foo.img',
extension: 'img',
size: '999999999',
isSizeEstimated: false,
});
}).to.throw('Invalid image size: 999999999');
});
it('should throw if the final size is a float number', function () { it('should throw if the final size is a float number', function () {
expect(function () { expect(function () {
selectionState.selectSource({ selectionState.selectSource({
path: 'foo.img', ...image,
extension: 'img',
size: 999999999.999, size: 999999999.999,
isSizeEstimated: false,
}); });
}).to.throw('Invalid image size: 999999999.999'); }).to.throw('Invalid image size: 999999999.999');
}); });
@ -610,50 +545,12 @@ describe('Model: selectionState', function () {
it('should throw if the final size is negative', function () { it('should throw if the final size is negative', function () {
expect(function () { expect(function () {
selectionState.selectSource({ selectionState.selectSource({
path: 'foo.img', ...image,
extension: 'img',
size: -1, size: -1,
isSizeEstimated: false,
}); });
}).to.throw('Invalid image size: -1'); }).to.throw('Invalid image size: -1');
}); });
it("should throw if url is defined but it's not a string", function () {
expect(function () {
selectionState.selectSource({
path: 'foo.img',
extension: 'img',
size: 999999999,
isSizeEstimated: false,
url: 1234,
});
}).to.throw('Invalid image url: 1234');
});
it("should throw if name is defined but it's not a string", function () {
expect(function () {
selectionState.selectSource({
path: 'foo.img',
extension: 'img',
size: 999999999,
isSizeEstimated: false,
name: 1234,
});
}).to.throw('Invalid image name: 1234');
});
it("should throw if logo is defined but it's not a string", function () {
expect(function () {
selectionState.selectSource({
path: 'foo.img',
extension: 'img',
size: 999999999,
isSizeEstimated: false,
logo: 1234,
});
}).to.throw('Invalid image logo: 1234');
});
it('should de-select a previously selected not-large-enough drive', function () { it('should de-select a previously selected not-large-enough drive', function () {
availableDrives.setDrives([ availableDrives.setDrives([
{ {
@ -668,10 +565,8 @@ describe('Model: selectionState', function () {
expect(selectionState.hasDrive()).to.be.true; expect(selectionState.hasDrive()).to.be.true;
selectionState.selectSource({ selectionState.selectSource({
path: 'foo.img', ...image,
extension: 'img',
size: 1234567890, size: 1234567890,
isSizeEstimated: false,
}); });
expect(selectionState.hasDrive()).to.be.false; expect(selectionState.hasDrive()).to.be.false;
@ -692,10 +587,7 @@ describe('Model: selectionState', function () {
expect(selectionState.hasDrive()).to.be.true; expect(selectionState.hasDrive()).to.be.true;
selectionState.selectSource({ selectionState.selectSource({
path: 'foo.img', ...image,
extension: 'img',
size: 999999999,
isSizeEstimated: false,
recommendedDriveSize: 1500000000, recommendedDriveSize: 1500000000,
}); });
@ -727,10 +619,10 @@ describe('Model: selectionState', function () {
expect(selectionState.hasDrive()).to.be.true; expect(selectionState.hasDrive()).to.be.true;
selectionState.selectSource({ selectionState.selectSource({
...image,
path: imagePath, path: imagePath,
extension: 'img', extension: 'img',
size: 999999999, size: 999999999,
isSizeEstimated: false,
}); });
expect(selectionState.hasDrive()).to.be.false; expect(selectionState.hasDrive()).to.be.false;
@ -740,6 +632,16 @@ describe('Model: selectionState', function () {
}); });
describe('given a drive and an image', function () { describe('given a drive and an image', function () {
const image: SourceMetadata = {
description: 'foo.img',
displayName: 'foo.img',
path: 'foo.img',
extension: 'img',
size: 999999999,
SourceType: File,
isSizeEstimated: false,
};
beforeEach(function () { beforeEach(function () {
availableDrives.setDrives([ availableDrives.setDrives([
{ {
@ -752,12 +654,7 @@ describe('Model: selectionState', function () {
selectionState.selectDrive('/dev/disk1'); selectionState.selectDrive('/dev/disk1');
selectionState.selectSource({ selectionState.selectSource(image);
path: 'foo.img',
extension: 'img',
size: 999999999,
isSizeEstimated: false,
});
}); });
describe('.clear()', function () { describe('.clear()', function () {
@ -824,6 +721,16 @@ describe('Model: selectionState', function () {
}); });
describe('given several drives', function () { describe('given several drives', function () {
const image: SourceMetadata = {
description: 'foo.img',
displayName: 'foo.img',
path: 'foo.img',
extension: 'img',
size: 999999999,
SourceType: File,
isSizeEstimated: false,
};
beforeEach(function () { beforeEach(function () {
availableDrives.setDrives([ availableDrives.setDrives([
{ {
@ -850,12 +757,7 @@ describe('Model: selectionState', function () {
selectionState.selectDrive('/dev/disk2'); selectionState.selectDrive('/dev/disk2');
selectionState.selectDrive('/dev/disk3'); selectionState.selectDrive('/dev/disk3');
selectionState.selectSource({ selectionState.selectSource(image);
path: 'foo.img',
extension: 'img',
size: 999999999,
isSizeEstimated: false,
});
}); });
describe('.clear()', function () { describe('.clear()', function () {