Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22
31 changes: 25 additions & 6 deletions src/commands/upload-folder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { AuthService } from '../services/auth.service';
import { ValidationService } from '../services/validation.service';
import { ConfigService } from '../services/config.service';
import { UploadFacade } from '../services/network/upload/upload-facade.service';
import { NotValidDirectoryError } from '../types/command.types';

export default class UploadFolder extends Command {
static readonly args = {};
Expand All @@ -15,7 +16,7 @@ export default class UploadFolder extends Command {
folder: Flags.string({
char: 'f',
description: 'The path to the folder on your system.',
required: true,
required: false,
}),
destination: Flags.string({
char: 'i',
Expand All @@ -29,10 +30,7 @@ export default class UploadFolder extends Command {
public run = async () => {
const { user } = await AuthService.instance.getAuthDetails();
const { flags } = await this.parse(UploadFolder);
const doesDirectoryExist = await ValidationService.instance.validateDirectoryExists(flags['folder']);
if (!doesDirectoryExist) {
throw new Error(`The provided folder path is not a valid directory: ${flags['folder']}`);
}
const localPath = await this.getFolderPath(flags['folder'], flags['non-interactive']);

// If destinationFolderUuid is empty from flags&prompt, means we should use RootFolderUuid
const destinationFolderUuid =
Expand All @@ -52,7 +50,7 @@ export default class UploadFolder extends Command {
);
progressBar?.start(100, 0);
const data = await UploadFacade.instance.uploadFolder({
localPath: flags['folder'],
localPath,
destinationFolderUuid,
loginUserDetails: user,
jsonFlag: flags['json'],
Expand Down Expand Up @@ -80,4 +78,25 @@ export default class UploadFolder extends Command {
});
this.exit(1);
};

private getFolderPath = async (folderFlag: string | undefined, nonInteractive: boolean): Promise<string> => {
return await CLIUtils.getValueFromFlag(
{
value: folderFlag,
name: UploadFolder.flags['folder'].name,
},
{
nonInteractive,
prompt: {
message: 'What is the path to the folder on your computer?',
options: { type: 'input' },
},
},
{
validate: ValidationService.instance.validateDirectoryExists,
error: new NotValidDirectoryError(),
},
this.log.bind(this),
);
};
}
72 changes: 70 additions & 2 deletions test/commands/upload-folder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AuthService } from '../../src/services/auth.service';
import { LoginCredentials, MissingCredentialsError } from '../../src/types/command.types';
import { ValidationService } from '../../src/services/validation.service';
import { UserFixture } from '../fixtures/auth.fixture';
import { CLIUtils } from '../../src/utils/cli.utils';
import { CLIUtils, NoFlagProvidedError } from '../../src/utils/cli.utils';
import { UploadResult } from '../../src/services/network/upload/upload.types';
import { UploadFacade } from '../../src/services/network/upload/upload-facade.service';

Expand Down Expand Up @@ -107,7 +107,7 @@ describe('Upload Folder Command', () => {
.mockResolvedValue(false);

const invalidPath = '/invalid/folder/path.txt';
const result = UploadFolder.run([`--folder=${invalidPath}`]);
const result = UploadFolder.run([`--folder=${invalidPath}`, '--non-interactive']);

await expect(result).rejects.toMatchObject({
message: expect.stringContaining('EEXIT: 1'),
Expand All @@ -134,4 +134,72 @@ describe('Upload Folder Command', () => {
expect(validateDirectoryExistsSpy).not.toHaveBeenCalled();
expect(UploadFacadeSpy).not.toHaveBeenCalled();
});

describe('Folder path resolution (getFolderPath)', () => {
it('should prompt user for folder path in interactive mode when --folder flag is not provided', async () => {
const getValueFromFlagSpy = vi.spyOn(CLIUtils, 'getValueFromFlag').mockResolvedValue('/prompted/folder/path');

await UploadFolder.run([]);

expect(getValueFromFlagSpy).toHaveBeenCalledWith(
{ value: undefined, name: 'folder' },
expect.objectContaining({
prompt: {
message: 'What is the path to the folder on your computer?',
options: { type: 'input' },
},
}),
expect.objectContaining({
validate: ValidationService.instance.validateDirectoryExists,
}),
expect.any(Function),
);
expect(UploadFacadeSpy).toHaveBeenCalledWith(
expect.objectContaining({
localPath: '/prompted/folder/path',
}),
);
});

it('should throw NoFlagProvidedError in non-interactive mode when --folder flag is not provided', async () => {
const getValueFromFlagSpy = vi
.spyOn(CLIUtils, 'getValueFromFlag')
.mockRejectedValue(new NoFlagProvidedError('folder'));

const result = UploadFolder.run(['--non-interactive']);

await expect(result).rejects.toMatchObject({
message: expect.stringContaining('EEXIT: 1'),
oclif: { exit: 1 },
});

expect(getValueFromFlagSpy).toHaveBeenCalledWith(
{ value: undefined, name: 'folder' },
{
nonInteractive: true,
prompt: {
message: 'What is the path to the folder on your computer?',
options: { type: 'input' },
},
},
{
validate: ValidationService.instance.validateDirectoryExists,
error: expect.any(Error),
},
expect.any(Function),
);
expect(UploadFacadeSpy).not.toHaveBeenCalled();
});

it('should use folder path from --folder flag when provided', async () => {
await UploadFolder.run(['--folder=/explicit/folder/path']);

expect(validateDirectoryExistsSpy).toHaveBeenCalledWith('/explicit/folder/path');
expect(UploadFacadeSpy).toHaveBeenCalledWith(
expect.objectContaining({
localPath: '/explicit/folder/path',
}),
);
});
});
});